1/*
2 *  Copyright (c) 2013 The WebM project authors. All Rights Reserved.
3 *
4 *  Use of this source code is governed by a BSD-style license
5 *  that can be found in the LICENSE file in the root of the source
6 *  tree. An additional intellectual property rights grant can be found
7 *  in the file PATENTS.  All contributing project authors may
8 *  be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include "vpx_ports/mem_ops.h"
16
17#include "./ivfdec.h"
18
19static const char *IVF_SIGNATURE = "DKIF";
20
21static void fix_framerate(int *num, int *den) {
22  // Some versions of vpxenc used 1/(2*fps) for the timebase, so
23  // we can guess the framerate using only the timebase in this
24  // case. Other files would require reading ahead to guess the
25  // timebase, like we do for webm.
26  if (*num < 1000) {
27    // Correct for the factor of 2 applied to the timebase in the encoder.
28    if (*num & 1)
29      *den *= 2;
30    else
31      *num /= 2;
32  } else {
33    // Don't know FPS for sure, and don't have readahead code
34    // (yet?), so just default to 30fps.
35    *num = 30;
36    *den = 1;
37  }
38}
39
40int file_is_ivf(struct VpxInputContext *input_ctx) {
41  char raw_hdr[32];
42  int is_ivf = 0;
43
44  if (fread(raw_hdr, 1, 32, input_ctx->file) == 32) {
45    if (memcmp(IVF_SIGNATURE, raw_hdr, 4) == 0) {
46      is_ivf = 1;
47
48      if (mem_get_le16(raw_hdr + 4) != 0) {
49        fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
50                " decode properly.");
51      }
52
53      input_ctx->fourcc = mem_get_le32(raw_hdr + 8);
54      input_ctx->width = mem_get_le16(raw_hdr + 12);
55      input_ctx->height = mem_get_le16(raw_hdr + 14);
56      input_ctx->framerate.numerator = mem_get_le32(raw_hdr + 16);
57      input_ctx->framerate.denominator = mem_get_le32(raw_hdr + 20);
58      fix_framerate(&input_ctx->framerate.numerator,
59                    &input_ctx->framerate.denominator);
60    }
61  }
62
63  if (!is_ivf) {
64    rewind(input_ctx->file);
65    input_ctx->detect.buf_read = 0;
66  } else {
67    input_ctx->detect.position = 4;
68  }
69  return is_ivf;
70}
71
72int ivf_read_frame(FILE *infile, uint8_t **buffer,
73                   size_t *bytes_read, size_t *buffer_size) {
74  char raw_header[IVF_FRAME_HDR_SZ] = {0};
75  size_t frame_size = 0;
76
77  if (fread(raw_header, IVF_FRAME_HDR_SZ, 1, infile) != 1) {
78    if (!feof(infile))
79      warn("Failed to read frame size\n");
80  } else {
81    frame_size = mem_get_le32(raw_header);
82
83    if (frame_size > 256 * 1024 * 1024) {
84      warn("Read invalid frame size (%u)\n", (unsigned int)frame_size);
85      frame_size = 0;
86    }
87
88    if (frame_size > *buffer_size) {
89      uint8_t *new_buffer = realloc(*buffer, 2 * frame_size);
90
91      if (new_buffer) {
92        *buffer = new_buffer;
93        *buffer_size = 2 * frame_size;
94      } else {
95        warn("Failed to allocate compressed data buffer\n");
96        frame_size = 0;
97      }
98    }
99  }
100
101  if (!feof(infile)) {
102    if (fread(*buffer, 1, frame_size, infile) != frame_size) {
103      warn("Failed to read full frame\n");
104      return 1;
105    }
106
107    *bytes_read = frame_size;
108    return 0;
109  }
110
111  return 1;
112}
113