1 /*
2  * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3  *
4  * This source code is subject to the terms of the BSD 2 Clause License and
5  * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6  * was not distributed with this source code in the LICENSE file, you can
7  * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8  * Media Patent License 1.0 was not distributed with this source code in the
9  * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
10  */
11 
12 #include "common/ivfdec.h"
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include "aom_ports/mem_ops.h"
19 #include "aom_ports/sanitizer.h"
20 
21 static const char *IVF_SIGNATURE = "DKIF";
22 
fix_framerate(int * num,int * den)23 static void fix_framerate(int *num, int *den) {
24   if (*den <= 0 || *den >= 1000000000 || *num <= 0 || *num >= 1000) {
25     // framerate seems to be invalid, just default to 30fps.
26     *num = 30;
27     *den = 1;
28   }
29 }
30 
file_is_ivf(struct AvxInputContext * input_ctx)31 int file_is_ivf(struct AvxInputContext *input_ctx) {
32   char raw_hdr[32];
33   int is_ivf = 0;
34 
35   if (fread(raw_hdr, 1, 32, input_ctx->file) == 32) {
36     if (memcmp(IVF_SIGNATURE, raw_hdr, 4) == 0) {
37       is_ivf = 1;
38 
39       if (mem_get_le16(raw_hdr + 4) != 0) {
40         fprintf(stderr,
41                 "Error: Unrecognized IVF version! This file may not"
42                 " decode properly.");
43       }
44 
45       input_ctx->fourcc = mem_get_le32(raw_hdr + 8);
46       input_ctx->width = mem_get_le16(raw_hdr + 12);
47       input_ctx->height = mem_get_le16(raw_hdr + 14);
48       input_ctx->framerate.numerator = mem_get_le32(raw_hdr + 16);
49       input_ctx->framerate.denominator = mem_get_le32(raw_hdr + 20);
50       fix_framerate(&input_ctx->framerate.numerator,
51                     &input_ctx->framerate.denominator);
52     }
53   }
54 
55   if (!is_ivf) {
56     rewind(input_ctx->file);
57     input_ctx->detect.buf_read = 0;
58   } else {
59     input_ctx->detect.position = 4;
60   }
61   return is_ivf;
62 }
63 
ivf_read_frame(FILE * infile,uint8_t ** buffer,size_t * bytes_read,size_t * buffer_size,aom_codec_pts_t * pts)64 int ivf_read_frame(FILE *infile, uint8_t **buffer, size_t *bytes_read,
65                    size_t *buffer_size, aom_codec_pts_t *pts) {
66   char raw_header[IVF_FRAME_HDR_SZ] = { 0 };
67   size_t frame_size = 0;
68 
69   if (fread(raw_header, IVF_FRAME_HDR_SZ, 1, infile) != 1) {
70     if (!feof(infile)) warn("Failed to read frame size");
71   } else {
72     frame_size = mem_get_le32(raw_header);
73 
74     if (frame_size > 256 * 1024 * 1024) {
75       warn("Read invalid frame size (%u)", (unsigned int)frame_size);
76       frame_size = 0;
77     }
78 
79     if (frame_size > *buffer_size) {
80       uint8_t *new_buffer = (uint8_t *)realloc(*buffer, 2 * frame_size);
81 
82       if (new_buffer) {
83         *buffer = new_buffer;
84         *buffer_size = 2 * frame_size;
85       } else {
86         warn("Failed to allocate compressed data buffer");
87         frame_size = 0;
88       }
89     }
90 
91     if (pts) {
92       *pts = mem_get_le32(&raw_header[4]);
93       *pts += ((aom_codec_pts_t)mem_get_le32(&raw_header[8]) << 32);
94     }
95   }
96 
97   if (!feof(infile)) {
98     ASAN_UNPOISON_MEMORY_REGION(*buffer, *buffer_size);
99     if (fread(*buffer, 1, frame_size, infile) != frame_size) {
100       warn("Failed to read full frame");
101       return 1;
102     }
103 
104     ASAN_POISON_MEMORY_REGION(*buffer + frame_size, *buffer_size - frame_size);
105     *bytes_read = frame_size;
106     return 0;
107   }
108 
109   return 1;
110 }
111