Merge "Fix show existing frame"
[platform/upstream/libvpx.git] / webmdec.c
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 "./webmdec.h"
12
13 #include <stdarg.h>
14
15 #include "nestegg/include/nestegg/nestegg.h"
16
17 static int nestegg_read_cb(void *buffer, size_t length, void *userdata) {
18   FILE *f = userdata;
19
20   if (fread(buffer, 1, length, f) < length) {
21     if (ferror(f))
22       return -1;
23     if (feof(f))
24       return 0;
25   }
26   return 1;
27 }
28
29 static int nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
30   switch (whence) {
31     case NESTEGG_SEEK_SET:
32       whence = SEEK_SET;
33       break;
34     case NESTEGG_SEEK_CUR:
35       whence = SEEK_CUR;
36       break;
37     case NESTEGG_SEEK_END:
38       whence = SEEK_END;
39       break;
40   };
41   return fseek(userdata, (int32_t)offset, whence) ? -1 : 0;
42 }
43
44 static int64_t nestegg_tell_cb(void *userdata) {
45   return ftell(userdata);
46 }
47
48 static void nestegg_log_cb(nestegg *context,
49                            unsigned int severity,
50                            char const *format, ...) {
51   va_list ap;
52   va_start(ap, format);
53   vfprintf(stderr, format, ap);
54   fprintf(stderr, "\n");
55   va_end(ap);
56 }
57
58 int file_is_webm(struct WebmInputContext *webm_ctx,
59                  struct VpxInputContext *vpx_ctx) {
60   uint32_t i, n;
61   int track_type = -1;
62   int codec_id;
63
64   nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
65   nestegg_video_params params;
66
67   io.userdata = vpx_ctx->file;
68   if (nestegg_init(&webm_ctx->nestegg_ctx, io, NULL))
69     goto fail;
70
71   if (nestegg_track_count(webm_ctx->nestegg_ctx, &n))
72     goto fail;
73
74   for (i = 0; i < n; i++) {
75     track_type = nestegg_track_type(webm_ctx->nestegg_ctx, i);
76
77     if (track_type == NESTEGG_TRACK_VIDEO)
78       break;
79     else if (track_type < 0)
80       goto fail;
81   }
82
83   codec_id = nestegg_track_codec_id(webm_ctx->nestegg_ctx, i);
84   if (codec_id == NESTEGG_CODEC_VP8) {
85     vpx_ctx->fourcc = VP8_FOURCC_MASK;
86   } else if (codec_id == NESTEGG_CODEC_VP9) {
87     vpx_ctx->fourcc = VP9_FOURCC_MASK;
88   } else {
89     fatal("Not VPx video, quitting.\n");
90   }
91
92   webm_ctx->video_track = i;
93
94   if (nestegg_track_video_params(webm_ctx->nestegg_ctx, i, &params))
95     goto fail;
96
97   vpx_ctx->framerate.denominator = 0;
98   vpx_ctx->framerate.numerator = 0;
99   vpx_ctx->width = params.width;
100   vpx_ctx->height = params.height;
101
102   return 1;
103
104  fail:
105   webm_ctx->nestegg_ctx = NULL;
106   rewind(vpx_ctx->file);
107
108   return 0;
109 }
110
111 int webm_read_frame(struct WebmInputContext *webm_ctx,
112                     uint8_t **buffer,
113                     size_t *bytes_in_buffer,
114                     size_t *buffer_size) {
115   if (webm_ctx->chunk >= webm_ctx->chunks) {
116     uint32_t track;
117
118     do {
119       /* End of this packet, get another. */
120       if (webm_ctx->pkt) {
121         nestegg_free_packet(webm_ctx->pkt);
122         webm_ctx->pkt = NULL;
123       }
124
125       if (nestegg_read_packet(webm_ctx->nestegg_ctx, &webm_ctx->pkt) <= 0 ||
126           nestegg_packet_track(webm_ctx->pkt, &track)) {
127         return 1;
128       }
129     } while (track != webm_ctx->video_track);
130
131     if (nestegg_packet_count(webm_ctx->pkt, &webm_ctx->chunks))
132       return 1;
133
134     webm_ctx->chunk = 0;
135   }
136
137   if (nestegg_packet_data(webm_ctx->pkt, webm_ctx->chunk,
138                           buffer, bytes_in_buffer)) {
139     return 1;
140   }
141
142   webm_ctx->chunk++;
143   return 0;
144 }
145
146 int webm_guess_framerate(struct WebmInputContext *webm_ctx,
147                          struct VpxInputContext *vpx_ctx) {
148   uint32_t i;
149   uint64_t tstamp = 0;
150
151   /* Check to see if we can seek before we parse any data. */
152   if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0)) {
153     warn("Failed to guess framerate (no Cues), set to 30fps.\n");
154     vpx_ctx->framerate.numerator = 30;
155     vpx_ctx->framerate.denominator  = 1;
156     return 0;
157   }
158
159   /* Guess the framerate. Read up to 1 second, or 50 video packets,
160    * whichever comes first.
161    */
162   for (i = 0; tstamp < 1000000000 && i < 50;) {
163     nestegg_packet *pkt;
164     uint32_t track;
165
166     if (nestegg_read_packet(webm_ctx->nestegg_ctx, &pkt) <= 0)
167       break;
168
169     nestegg_packet_track(pkt, &track);
170     if (track == webm_ctx->video_track) {
171       nestegg_packet_tstamp(pkt, &tstamp);
172       ++i;
173     }
174
175     nestegg_free_packet(pkt);
176   }
177
178   if (nestegg_track_seek(webm_ctx->nestegg_ctx, webm_ctx->video_track, 0))
179     goto fail;
180
181   vpx_ctx->framerate.numerator = (i - 1) * 1000000;
182   vpx_ctx->framerate.denominator = (int)(tstamp / 1000);
183   return 0;
184
185  fail:
186   nestegg_destroy(webm_ctx->nestegg_ctx);
187   webm_ctx->nestegg_ctx = NULL;
188   rewind(vpx_ctx->file);
189   return 1;
190 }
191
192 void webm_free(struct WebmInputContext *webm_ctx) {
193   if (webm_ctx && webm_ctx->nestegg_ctx) {
194     if (webm_ctx->pkt)
195       nestegg_free_packet(webm_ctx->pkt);
196     nestegg_destroy(webm_ctx->nestegg_ctx);
197   }
198 }