OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 | |
12 /* This is a simple program that reads ivf files and decodes them | |
13 * using the new interface. Decoded frames are output as YV12 raw. | |
14 */ | |
15 #include <assert.h> | 11 #include <assert.h> |
16 #include <stdio.h> | 12 #include <stdio.h> |
17 #include <stdlib.h> | 13 #include <stdlib.h> |
18 #include <stdarg.h> | 14 #include <stdarg.h> |
19 #include <string.h> | 15 #include <string.h> |
20 #include <limits.h> | 16 #include <limits.h> |
21 | 17 |
| 18 #include "third_party/libyuv/include/libyuv/scale.h" |
| 19 |
| 20 #include "./args.h" |
| 21 #include "./ivfdec.h" |
| 22 |
22 #define VPX_CODEC_DISABLE_COMPAT 1 | 23 #define VPX_CODEC_DISABLE_COMPAT 1 |
23 #include "vpx_config.h" | 24 #include "./vpx_config.h" |
24 #include "vpx/vpx_decoder.h" | 25 #include "vpx/vpx_decoder.h" |
25 #include "vpx_ports/vpx_timer.h" | 26 #include "vpx_ports/vpx_timer.h" |
| 27 |
26 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER | 28 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER |
27 #include "vpx/vp8dx.h" | 29 #include "vpx/vp8dx.h" |
28 #endif | 30 #endif |
| 31 |
29 #if CONFIG_MD5 | 32 #if CONFIG_MD5 |
30 #include "md5_utils.h" | 33 #include "./md5_utils.h" |
31 #endif | |
32 #include "tools_common.h" | |
33 #include "nestegg/include/nestegg/nestegg.h" | |
34 #include "third_party/libyuv/include/libyuv/scale.h" | |
35 | |
36 #if CONFIG_OS_SUPPORT | |
37 #if defined(_MSC_VER) | |
38 #include <io.h> | |
39 #define snprintf _snprintf | |
40 #define isatty _isatty | |
41 #define fileno _fileno | |
42 #else | |
43 #include <unistd.h> | |
44 #endif | |
45 #endif | 34 #endif |
46 | 35 |
47 #ifndef PATH_MAX | 36 #include "./tools_common.h" |
48 #define PATH_MAX 256 | 37 #include "./webmdec.h" |
49 #endif | |
50 | 38 |
51 static const char *exec_name; | 39 static const char *exec_name; |
52 | 40 |
53 #define VP8_FOURCC (0x00385056) | |
54 #define VP9_FOURCC (0x00395056) | |
55 static const struct { | 41 static const struct { |
56 char const *name; | 42 char const *name; |
57 const vpx_codec_iface_t *(*iface)(void); | 43 const vpx_codec_iface_t *(*iface)(void); |
58 unsigned int fourcc; | 44 uint32_t fourcc; |
59 unsigned int fourcc_mask; | 45 uint32_t fourcc_mask; |
60 } ifaces[] = { | 46 } ifaces[] = { |
61 #if CONFIG_VP8_DECODER | 47 #if CONFIG_VP8_DECODER |
62 {"vp8", vpx_codec_vp8_dx, VP8_FOURCC, 0x00FFFFFF}, | 48 {"vp8", vpx_codec_vp8_dx, VP8_FOURCC_MASK, 0x00FFFFFF}, |
63 #endif | 49 #endif |
64 #if CONFIG_VP9_DECODER | 50 #if CONFIG_VP9_DECODER |
65 {"vp9", vpx_codec_vp9_dx, VP9_FOURCC, 0x00FFFFFF}, | 51 {"vp9", vpx_codec_vp9_dx, VP9_FOURCC_MASK, 0x00FFFFFF}, |
66 #endif | 52 #endif |
67 }; | 53 }; |
68 | 54 |
69 #include "args.h" | 55 struct VpxDecInputContext { |
| 56 struct VpxInputContext *vpx_input_ctx; |
| 57 struct WebmInputContext *webm_ctx; |
| 58 }; |
| 59 |
70 static const arg_def_t looparg = ARG_DEF(NULL, "loops", 1, | 60 static const arg_def_t looparg = ARG_DEF(NULL, "loops", 1, |
71 "Number of times to decode the file"); | 61 "Number of times to decode the file"); |
72 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, | 62 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, |
73 "Codec to use"); | 63 "Codec to use"); |
74 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, | 64 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, |
75 "Output raw YV12 frames"); | 65 "Output raw YV12 frames"); |
76 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, | 66 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, |
77 "Output raw I420 frames"); | 67 "Output raw I420 frames"); |
78 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0, | 68 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0, |
79 "Flip the chroma planes in the output
"); | 69 "Flip the chroma planes in the output
"); |
(...skipping 12 matching lines...) Expand all Loading... |
92 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, | 82 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, |
93 "Output file name pattern (see below
)"); | 83 "Output file name pattern (see below
)"); |
94 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1, | 84 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1, |
95 "Max threads to use"); | 85 "Max threads to use"); |
96 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, | 86 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, |
97 "Show version string"); | 87 "Show version string"); |
98 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0, | 88 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0, |
99 "Enable decoder error-conceal
ment"); | 89 "Enable decoder error-conceal
ment"); |
100 static const arg_def_t scalearg = ARG_DEF("S", "scale", 0, | 90 static const arg_def_t scalearg = ARG_DEF("S", "scale", 0, |
101 "Scale output frames uniformly"); | 91 "Scale output frames uniformly"); |
| 92 static const arg_def_t fb_arg = |
| 93 ARG_DEF(NULL, "frame-buffers", 1, "Number of frame buffers to use"); |
| 94 static const arg_def_t fb_lru_arg = |
| 95 ARG_DEF(NULL, "frame-buffers-lru", 1, "Turn on/off frame buffer lru"); |
102 | 96 |
103 | 97 |
104 #if CONFIG_MD5 | 98 #if CONFIG_MD5 |
105 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, | 99 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, |
106 "Compute the MD5 sum of the decoded fram
e"); | 100 "Compute the MD5 sum of the decoded fram
e"); |
107 #endif | 101 #endif |
108 static const arg_def_t *all_args[] = { | 102 static const arg_def_t *all_args[] = { |
109 &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg, | 103 &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg, |
110 &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile, | 104 &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile, |
111 &threadsarg, &verbosearg, &scalearg, | 105 &threadsarg, &verbosearg, &scalearg, &fb_arg, &fb_lru_arg, |
112 #if CONFIG_MD5 | 106 #if CONFIG_MD5 |
113 &md5arg, | 107 &md5arg, |
114 #endif | 108 #endif |
115 &error_concealment, | 109 &error_concealment, |
116 NULL | 110 NULL |
117 }; | 111 }; |
118 | 112 |
119 #if CONFIG_VP8_DECODER | 113 #if CONFIG_VP8_DECODER |
120 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1, | 114 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1, |
121 "Enable VP8 postproc add noise")
; | 115 "Enable VP8 postproc add noise")
; |
(...skipping 14 matching lines...) Expand all Loading... |
136 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0, | 130 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0, |
137 "Enable multiframe quality enhancement"); | 131 "Enable multiframe quality enhancement"); |
138 | 132 |
139 static const arg_def_t *vp8_pp_args[] = { | 133 static const arg_def_t *vp8_pp_args[] = { |
140 &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info, | 134 &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info, |
141 &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe, | 135 &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe, |
142 NULL | 136 NULL |
143 }; | 137 }; |
144 #endif | 138 #endif |
145 | 139 |
146 static void usage_exit() { | 140 void usage_exit() { |
147 int i; | 141 int i; |
148 | 142 |
149 fprintf(stderr, "Usage: %s <options> filename\n\n" | 143 fprintf(stderr, "Usage: %s <options> filename\n\n" |
150 "Options:\n", exec_name); | 144 "Options:\n", exec_name); |
151 arg_show_usage(stderr, all_args); | 145 arg_show_usage(stderr, all_args); |
152 #if CONFIG_VP8_DECODER | 146 #if CONFIG_VP8_DECODER |
153 fprintf(stderr, "\nVP8 Postprocessing Options:\n"); | 147 fprintf(stderr, "\nVP8 Postprocessing Options:\n"); |
154 arg_show_usage(stderr, vp8_pp_args); | 148 arg_show_usage(stderr, vp8_pp_args); |
155 #endif | 149 #endif |
156 fprintf(stderr, | 150 fprintf(stderr, |
(...skipping 14 matching lines...) Expand all Loading... |
171 fprintf(stderr, "\nIncluded decoders:\n\n"); | 165 fprintf(stderr, "\nIncluded decoders:\n\n"); |
172 | 166 |
173 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) | 167 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) |
174 fprintf(stderr, " %-6s - %s\n", | 168 fprintf(stderr, " %-6s - %s\n", |
175 ifaces[i].name, | 169 ifaces[i].name, |
176 vpx_codec_iface_name(ifaces[i].iface())); | 170 vpx_codec_iface_name(ifaces[i].iface())); |
177 | 171 |
178 exit(EXIT_FAILURE); | 172 exit(EXIT_FAILURE); |
179 } | 173 } |
180 | 174 |
181 void die(const char *fmt, ...) { | 175 static int read_frame(struct VpxDecInputContext *input, |
182 va_list ap; | 176 uint8_t **buf, |
183 va_start(ap, fmt); | 177 size_t *bytes_in_buffer, |
184 vfprintf(stderr, fmt, ap); | 178 size_t *buffer_size) { |
185 fprintf(stderr, "\n"); | 179 char raw_hdr[RAW_FRAME_HDR_SZ]; |
186 usage_exit(); | 180 size_t bytes_to_read = 0; |
187 } | 181 FILE *infile = input->vpx_input_ctx->file; |
| 182 enum VideoFileType kind = input->vpx_input_ctx->file_type; |
| 183 if (kind == FILE_TYPE_WEBM) { |
| 184 return webm_read_frame(input->webm_ctx, |
| 185 buf, bytes_in_buffer, buffer_size); |
| 186 } else if (kind == FILE_TYPE_RAW) { |
| 187 if (fread(raw_hdr, RAW_FRAME_HDR_SZ, 1, infile) != 1) { |
| 188 if (!feof(infile)) |
| 189 warn("Failed to read RAW frame size\n"); |
| 190 } else { |
| 191 const int kCorruptFrameThreshold = 256 * 1024 * 1024; |
| 192 const int kFrameTooSmallThreshold = 256 * 1024; |
| 193 bytes_to_read = mem_get_le32(raw_hdr); |
188 | 194 |
189 static unsigned int mem_get_le16(const void *vmem) { | 195 if (bytes_to_read > kCorruptFrameThreshold) { |
190 unsigned int val; | 196 warn("Read invalid frame size (%u)\n", (unsigned int)bytes_to_read); |
191 const unsigned char *mem = (const unsigned char *)vmem; | 197 bytes_to_read = 0; |
| 198 } |
192 | 199 |
193 val = mem[1] << 8; | 200 if (kind == FILE_TYPE_RAW && bytes_to_read < kFrameTooSmallThreshold) { |
194 val |= mem[0]; | 201 warn("Warning: Read invalid frame size (%u) - not a raw file?\n", |
195 return val; | 202 (unsigned int)bytes_to_read); |
196 } | 203 } |
197 | 204 |
198 static unsigned int mem_get_le32(const void *vmem) { | 205 if (bytes_to_read > *buffer_size) { |
199 unsigned int val; | 206 uint8_t *new_buf = realloc(*buf, 2 * bytes_to_read); |
200 const unsigned char *mem = (const unsigned char *)vmem; | |
201 | 207 |
202 val = mem[3] << 24; | 208 if (new_buf) { |
203 val |= mem[2] << 16; | 209 *buf = new_buf; |
204 val |= mem[1] << 8; | 210 *buffer_size = 2 * bytes_to_read; |
205 val |= mem[0]; | 211 } else { |
206 return val; | 212 warn("Failed to allocate compressed data buffer\n"); |
207 } | 213 bytes_to_read = 0; |
208 | 214 } |
209 enum file_kind { | 215 } |
210 RAW_FILE, | |
211 IVF_FILE, | |
212 WEBM_FILE | |
213 }; | |
214 | |
215 struct input_ctx { | |
216 enum file_kind kind; | |
217 FILE *infile; | |
218 nestegg *nestegg_ctx; | |
219 nestegg_packet *pkt; | |
220 unsigned int chunk; | |
221 unsigned int chunks; | |
222 unsigned int video_track; | |
223 }; | |
224 | |
225 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t)) | |
226 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t)) | |
227 static int read_frame(struct input_ctx *input, | |
228 uint8_t **buf, | |
229 size_t *buf_sz, | |
230 size_t *buf_alloc_sz) { | |
231 char raw_hdr[IVF_FRAME_HDR_SZ]; | |
232 size_t new_buf_sz; | |
233 FILE *infile = input->infile; | |
234 enum file_kind kind = input->kind; | |
235 if (kind == WEBM_FILE) { | |
236 if (input->chunk >= input->chunks) { | |
237 unsigned int track; | |
238 | |
239 do { | |
240 /* End of this packet, get another. */ | |
241 if (input->pkt) | |
242 nestegg_free_packet(input->pkt); | |
243 | |
244 if (nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0 | |
245 || nestegg_packet_track(input->pkt, &track)) | |
246 return 1; | |
247 | |
248 } while (track != input->video_track); | |
249 | |
250 if (nestegg_packet_count(input->pkt, &input->chunks)) | |
251 return 1; | |
252 input->chunk = 0; | |
253 } | 216 } |
254 | 217 |
255 if (nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz)) | 218 if (!feof(infile)) { |
256 return 1; | 219 if (fread(*buf, 1, bytes_to_read, infile) != bytes_to_read) { |
257 input->chunk++; | 220 warn("Failed to read full frame\n"); |
258 | 221 return 1; |
259 return 0; | |
260 } | |
261 /* For both the raw and ivf formats, the frame size is the first 4 bytes | |
262 * of the frame header. We just need to special case on the header | |
263 * size. | |
264 */ | |
265 else if (fread(raw_hdr, kind == IVF_FILE | |
266 ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) { | |
267 if (!feof(infile)) | |
268 fprintf(stderr, "Failed to read frame size\n"); | |
269 | |
270 new_buf_sz = 0; | |
271 } else { | |
272 new_buf_sz = mem_get_le32(raw_hdr); | |
273 | |
274 if (new_buf_sz > 256 * 1024 * 1024) { | |
275 fprintf(stderr, "Error: Read invalid frame size (%u)\n", | |
276 (unsigned int)new_buf_sz); | |
277 new_buf_sz = 0; | |
278 } | |
279 | |
280 if (kind == RAW_FILE && new_buf_sz > 256 * 1024) | |
281 fprintf(stderr, "Warning: Read invalid frame size (%u)" | |
282 " - not a raw file?\n", (unsigned int)new_buf_sz); | |
283 | |
284 if (new_buf_sz > *buf_alloc_sz) { | |
285 uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz); | |
286 | |
287 if (new_buf) { | |
288 *buf = new_buf; | |
289 *buf_alloc_sz = 2 * new_buf_sz; | |
290 } else { | |
291 fprintf(stderr, "Failed to allocate compressed data buffer\n"); | |
292 new_buf_sz = 0; | |
293 } | 222 } |
294 } | 223 *bytes_in_buffer = bytes_to_read; |
295 } | |
296 | |
297 *buf_sz = new_buf_sz; | |
298 | |
299 if (!feof(infile)) { | |
300 if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) { | |
301 fprintf(stderr, "Failed to read full frame\n"); | |
302 return 1; | |
303 } | 224 } |
304 | 225 |
305 return 0; | 226 return 0; |
| 227 } else if (kind == FILE_TYPE_IVF) { |
| 228 return ivf_read_frame(input->vpx_input_ctx, |
| 229 buf, bytes_in_buffer, buffer_size); |
306 } | 230 } |
307 | 231 |
308 return 1; | 232 return 1; |
309 } | 233 } |
310 | 234 |
311 void *out_open(const char *out_fn, int do_md5) { | 235 void *out_open(const char *out_fn, int do_md5) { |
312 void *out = NULL; | 236 void *out = NULL; |
313 | 237 |
314 if (do_md5) { | 238 if (do_md5) { |
315 #if CONFIG_MD5 | 239 #if CONFIG_MD5 |
316 MD5Context *md5_ctx = out = malloc(sizeof(MD5Context)); | 240 MD5Context *md5_ctx = out = malloc(sizeof(MD5Context)); |
317 (void)out_fn; | 241 (void)out_fn; |
318 MD5Init(md5_ctx); | 242 MD5Init(md5_ctx); |
319 #endif | 243 #endif |
320 } else { | 244 } else { |
321 FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") | 245 FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") |
322 : set_binary_mode(stdout); | 246 : set_binary_mode(stdout); |
323 | 247 |
324 if (!outfile) { | 248 if (!outfile) { |
325 fprintf(stderr, "Failed to output file"); | 249 fatal("Failed to output file"); |
326 exit(EXIT_FAILURE); | |
327 } | 250 } |
328 } | 251 } |
329 | 252 |
330 return out; | 253 return out; |
331 } | 254 } |
332 | 255 |
333 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) { | 256 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) { |
334 if (do_md5) { | 257 if (do_md5) { |
335 #if CONFIG_MD5 | 258 #if CONFIG_MD5 |
336 MD5Update(out, buf, len); | 259 MD5Update(out, buf, len); |
(...skipping 15 matching lines...) Expand all Loading... |
352 for (i = 0; i < 16; i++) | 275 for (i = 0; i < 16; i++) |
353 printf("%02x", md5[i]); | 276 printf("%02x", md5[i]); |
354 | 277 |
355 printf(" %s\n", out_fn); | 278 printf(" %s\n", out_fn); |
356 #endif | 279 #endif |
357 } else { | 280 } else { |
358 fclose(out); | 281 fclose(out); |
359 } | 282 } |
360 } | 283 } |
361 | 284 |
362 unsigned int file_is_ivf(FILE *infile, | 285 int file_is_raw(struct VpxInputContext *input) { |
363 unsigned int *fourcc, | 286 uint8_t buf[32]; |
364 unsigned int *width, | |
365 unsigned int *height, | |
366 unsigned int *fps_den, | |
367 unsigned int *fps_num) { | |
368 char raw_hdr[32]; | |
369 int is_ivf = 0; | |
370 | |
371 if (fread(raw_hdr, 1, 32, infile) == 32) { | |
372 if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' | |
373 && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') { | |
374 is_ivf = 1; | |
375 | |
376 if (mem_get_le16(raw_hdr + 4) != 0) | |
377 fprintf(stderr, "Error: Unrecognized IVF version! This file may not" | |
378 " decode properly."); | |
379 | |
380 *fourcc = mem_get_le32(raw_hdr + 8); | |
381 *width = mem_get_le16(raw_hdr + 12); | |
382 *height = mem_get_le16(raw_hdr + 14); | |
383 *fps_num = mem_get_le32(raw_hdr + 16); | |
384 *fps_den = mem_get_le32(raw_hdr + 20); | |
385 | |
386 /* Some versions of vpxenc used 1/(2*fps) for the timebase, so | |
387 * we can guess the framerate using only the timebase in this | |
388 * case. Other files would require reading ahead to guess the | |
389 * timebase, like we do for webm. | |
390 */ | |
391 if (*fps_num < 1000) { | |
392 /* Correct for the factor of 2 applied to the timebase in the | |
393 * encoder. | |
394 */ | |
395 if (*fps_num & 1)*fps_den <<= 1; | |
396 else *fps_num >>= 1; | |
397 } else { | |
398 /* Don't know FPS for sure, and don't have readahead code | |
399 * (yet?), so just default to 30fps. | |
400 */ | |
401 *fps_num = 30; | |
402 *fps_den = 1; | |
403 } | |
404 } | |
405 } | |
406 | |
407 if (!is_ivf) | |
408 rewind(infile); | |
409 | |
410 return is_ivf; | |
411 } | |
412 | |
413 | |
414 unsigned int file_is_raw(FILE *infile, | |
415 unsigned int *fourcc, | |
416 unsigned int *width, | |
417 unsigned int *height, | |
418 unsigned int *fps_den, | |
419 unsigned int *fps_num) { | |
420 unsigned char buf[32]; | |
421 int is_raw = 0; | 287 int is_raw = 0; |
422 vpx_codec_stream_info_t si; | 288 vpx_codec_stream_info_t si; |
423 | 289 |
424 si.sz = sizeof(si); | 290 si.sz = sizeof(si); |
425 | 291 |
426 if (fread(buf, 1, 32, infile) == 32) { | 292 if (fread(buf, 1, 32, input->file) == 32) { |
427 int i; | 293 int i; |
428 | 294 |
429 if (mem_get_le32(buf) < 256 * 1024 * 1024) | 295 if (mem_get_le32(buf) < 256 * 1024 * 1024) { |
430 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) | 296 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) { |
431 if (!vpx_codec_peek_stream_info(ifaces[i].iface(), | 297 if (!vpx_codec_peek_stream_info(ifaces[i].iface(), |
432 buf + 4, 32 - 4, &si)) { | 298 buf + 4, 32 - 4, &si)) { |
433 is_raw = 1; | 299 is_raw = 1; |
434 *fourcc = ifaces[i].fourcc; | 300 input->fourcc = ifaces[i].fourcc; |
435 *width = si.w; | 301 input->width = si.w; |
436 *height = si.h; | 302 input->height = si.h; |
437 *fps_num = 30; | 303 input->framerate.numerator = 30; |
438 *fps_den = 1; | 304 input->framerate.denominator = 1; |
439 break; | 305 break; |
440 } | 306 } |
| 307 } |
| 308 } |
441 } | 309 } |
442 | 310 |
443 rewind(infile); | 311 rewind(input->file); |
444 return is_raw; | 312 return is_raw; |
445 } | 313 } |
446 | 314 |
447 | |
448 static int | |
449 nestegg_read_cb(void *buffer, size_t length, void *userdata) { | |
450 FILE *f = userdata; | |
451 | |
452 if (fread(buffer, 1, length, f) < length) { | |
453 if (ferror(f)) | |
454 return -1; | |
455 if (feof(f)) | |
456 return 0; | |
457 } | |
458 return 1; | |
459 } | |
460 | |
461 | |
462 static int | |
463 nestegg_seek_cb(int64_t offset, int whence, void *userdata) { | |
464 switch (whence) { | |
465 case NESTEGG_SEEK_SET: | |
466 whence = SEEK_SET; | |
467 break; | |
468 case NESTEGG_SEEK_CUR: | |
469 whence = SEEK_CUR; | |
470 break; | |
471 case NESTEGG_SEEK_END: | |
472 whence = SEEK_END; | |
473 break; | |
474 }; | |
475 return fseek(userdata, (long)offset, whence) ? -1 : 0; | |
476 } | |
477 | |
478 | |
479 static int64_t | |
480 nestegg_tell_cb(void *userdata) { | |
481 return ftell(userdata); | |
482 } | |
483 | |
484 | |
485 static void | |
486 nestegg_log_cb(nestegg *context, unsigned int severity, char const *format, | |
487 ...) { | |
488 va_list ap; | |
489 | |
490 va_start(ap, format); | |
491 vfprintf(stderr, format, ap); | |
492 fprintf(stderr, "\n"); | |
493 va_end(ap); | |
494 } | |
495 | |
496 | |
497 static int | |
498 webm_guess_framerate(struct input_ctx *input, | |
499 unsigned int *fps_den, | |
500 unsigned int *fps_num) { | |
501 unsigned int i; | |
502 uint64_t tstamp = 0; | |
503 | |
504 /* Check to see if we can seek before we parse any data. */ | |
505 if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) { | |
506 fprintf(stderr, | |
507 "WARNING: Failed to guess framerate (no Cues), set to 30fps.\n"); | |
508 *fps_num = 30; | |
509 *fps_den = 1; | |
510 return 0; | |
511 } | |
512 | |
513 /* Guess the framerate. Read up to 1 second, or 50 video packets, | |
514 * whichever comes first. | |
515 */ | |
516 for (i = 0; tstamp < 1000000000 && i < 50;) { | |
517 nestegg_packet *pkt; | |
518 unsigned int track; | |
519 | |
520 if (nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0) | |
521 break; | |
522 | |
523 nestegg_packet_track(pkt, &track); | |
524 if (track == input->video_track) { | |
525 nestegg_packet_tstamp(pkt, &tstamp); | |
526 i++; | |
527 } | |
528 | |
529 nestegg_free_packet(pkt); | |
530 } | |
531 | |
532 if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) | |
533 goto fail; | |
534 | |
535 *fps_num = (i - 1) * 1000000; | |
536 *fps_den = (unsigned int)(tstamp / 1000); | |
537 return 0; | |
538 fail: | |
539 nestegg_destroy(input->nestegg_ctx); | |
540 input->nestegg_ctx = NULL; | |
541 rewind(input->infile); | |
542 return 1; | |
543 } | |
544 | |
545 | |
546 static int | |
547 file_is_webm(struct input_ctx *input, | |
548 unsigned int *fourcc, | |
549 unsigned int *width, | |
550 unsigned int *height, | |
551 unsigned int *fps_den, | |
552 unsigned int *fps_num) { | |
553 unsigned int i, n; | |
554 int track_type = -1; | |
555 int codec_id; | |
556 | |
557 nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0}; | |
558 nestegg_video_params params; | |
559 | |
560 io.userdata = input->infile; | |
561 if (nestegg_init(&input->nestegg_ctx, io, NULL)) | |
562 goto fail; | |
563 | |
564 if (nestegg_track_count(input->nestegg_ctx, &n)) | |
565 goto fail; | |
566 | |
567 for (i = 0; i < n; i++) { | |
568 track_type = nestegg_track_type(input->nestegg_ctx, i); | |
569 | |
570 if (track_type == NESTEGG_TRACK_VIDEO) | |
571 break; | |
572 else if (track_type < 0) | |
573 goto fail; | |
574 } | |
575 | |
576 codec_id = nestegg_track_codec_id(input->nestegg_ctx, i); | |
577 if (codec_id == NESTEGG_CODEC_VP8) { | |
578 *fourcc = VP8_FOURCC; | |
579 } else if (codec_id == NESTEGG_CODEC_VP9) { | |
580 *fourcc = VP9_FOURCC; | |
581 } else { | |
582 fprintf(stderr, "Not VPx video, quitting.\n"); | |
583 exit(1); | |
584 } | |
585 | |
586 input->video_track = i; | |
587 | |
588 if (nestegg_track_video_params(input->nestegg_ctx, i, ¶ms)) | |
589 goto fail; | |
590 | |
591 *fps_den = 0; | |
592 *fps_num = 0; | |
593 *width = params.width; | |
594 *height = params.height; | |
595 return 1; | |
596 fail: | |
597 input->nestegg_ctx = NULL; | |
598 rewind(input->infile); | |
599 return 0; | |
600 } | |
601 | |
602 | |
603 void show_progress(int frame_in, int frame_out, unsigned long dx_time) { | 315 void show_progress(int frame_in, int frame_out, unsigned long dx_time) { |
604 fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r", | 316 fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r", |
605 frame_in, frame_out, dx_time, | 317 frame_in, frame_out, dx_time, |
606 (float)frame_out * 1000000.0 / (float)dx_time); | 318 (float)frame_out * 1000000.0 / (float)dx_time); |
607 } | 319 } |
608 | 320 |
| 321 // Called by libvpx if the frame buffer size needs to increase. |
| 322 // |
| 323 // Parameters: |
| 324 // user_priv Data passed into libvpx. |
| 325 // new_size Minimum size needed by libvpx to decompress the next frame. |
| 326 // fb Pointer to the frame buffer to update. |
| 327 // |
| 328 // Returns 0 on success. Returns < 0 on failure. |
| 329 int realloc_vp9_frame_buffer(void *user_priv, size_t new_size, |
| 330 vpx_codec_frame_buffer_t *fb) { |
| 331 (void)user_priv; |
| 332 if (!fb) |
| 333 return -1; |
| 334 |
| 335 free(fb->data); |
| 336 fb->data = (uint8_t*)malloc(new_size); |
| 337 if (!fb->data) { |
| 338 fb->size = 0; |
| 339 return -1; |
| 340 } |
| 341 |
| 342 fb->size = new_size; |
| 343 return 0; |
| 344 } |
609 | 345 |
610 void generate_filename(const char *pattern, char *out, size_t q_len, | 346 void generate_filename(const char *pattern, char *out, size_t q_len, |
611 unsigned int d_w, unsigned int d_h, | 347 unsigned int d_w, unsigned int d_h, |
612 unsigned int frame_in) { | 348 unsigned int frame_in) { |
613 const char *p = pattern; | 349 const char *p = pattern; |
614 char *q = out; | 350 char *q = out; |
615 | 351 |
616 do { | 352 do { |
617 char *next_pat = strchr(p, '%'); | 353 char *next_pat = strchr(p, '%'); |
618 | 354 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 q[copy_len] = '\0'; | 417 q[copy_len] = '\0'; |
682 q += copy_len; | 418 q += copy_len; |
683 p += copy_len; | 419 p += copy_len; |
684 q_len -= copy_len; | 420 q_len -= copy_len; |
685 } | 421 } |
686 } while (*p); | 422 } while (*p); |
687 } | 423 } |
688 | 424 |
689 | 425 |
690 int main_loop(int argc, const char **argv_) { | 426 int main_loop(int argc, const char **argv_) { |
691 vpx_codec_ctx_t decoder; | 427 vpx_codec_ctx_t decoder; |
692 char *fn = NULL; | 428 char *fn = NULL; |
693 int i; | 429 int i; |
694 uint8_t *buf = NULL; | 430 uint8_t *buf = NULL; |
695 size_t buf_sz = 0, buf_alloc_sz = 0; | 431 size_t bytes_in_buffer = 0, buffer_size = 0; |
696 FILE *infile; | 432 FILE *infile; |
697 int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do
_md5 = 0, progress = 0; | 433 int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0; |
| 434 int do_md5 = 0, progress = 0; |
698 int stop_after = 0, postproc = 0, summary = 0, quiet = 1; | 435 int stop_after = 0, postproc = 0, summary = 0, quiet = 1; |
699 int arg_skip = 0; | 436 int arg_skip = 0; |
700 int ec_enabled = 0; | 437 int ec_enabled = 0; |
701 vpx_codec_iface_t *iface = NULL; | 438 vpx_codec_iface_t *iface = NULL; |
702 unsigned int fourcc; | |
703 unsigned long dx_time = 0; | 439 unsigned long dx_time = 0; |
704 struct arg arg; | 440 struct arg arg; |
705 char **argv, **argi, **argj; | 441 char **argv, **argi, **argj; |
706 const char *outfile_pattern = 0; | 442 const char *outfile_pattern = 0; |
707 char outfile[PATH_MAX]; | 443 char outfile[PATH_MAX]; |
708 int single_file; | 444 int single_file; |
709 int use_y4m = 1; | 445 int use_y4m = 1; |
710 unsigned int width; | |
711 unsigned int height; | |
712 unsigned int fps_den; | |
713 unsigned int fps_num; | |
714 void *out = NULL; | 446 void *out = NULL; |
715 vpx_codec_dec_cfg_t cfg = {0}; | 447 vpx_codec_dec_cfg_t cfg = {0}; |
716 #if CONFIG_VP8_DECODER | 448 #if CONFIG_VP8_DECODER |
717 vp8_postproc_cfg_t vp8_pp_cfg = {0}; | 449 vp8_postproc_cfg_t vp8_pp_cfg = {0}; |
718 int vp8_dbg_color_ref_frame = 0; | 450 int vp8_dbg_color_ref_frame = 0; |
719 int vp8_dbg_color_mb_modes = 0; | 451 int vp8_dbg_color_mb_modes = 0; |
720 int vp8_dbg_color_b_modes = 0; | 452 int vp8_dbg_color_b_modes = 0; |
721 int vp8_dbg_display_mv = 0; | 453 int vp8_dbg_display_mv = 0; |
722 #endif | 454 #endif |
723 struct input_ctx input = {0}; | |
724 int frames_corrupted = 0; | 455 int frames_corrupted = 0; |
725 int dec_flags = 0; | 456 int dec_flags = 0; |
726 int do_scale = 0; | 457 int do_scale = 0; |
727 int stream_w = 0, stream_h = 0; | |
728 vpx_image_t *scaled_img = NULL; | 458 vpx_image_t *scaled_img = NULL; |
729 int frame_avail, got_data; | 459 int frame_avail, got_data; |
| 460 int num_external_frame_buffers = 0; |
| 461 int fb_lru_cache = 0; |
| 462 vpx_codec_frame_buffer_t *frame_buffers = NULL; |
| 463 |
| 464 struct VpxDecInputContext input = {0}; |
| 465 struct VpxInputContext vpx_input_ctx = {0}; |
| 466 struct WebmInputContext webm_ctx = {0}; |
| 467 input.vpx_input_ctx = &vpx_input_ctx; |
| 468 input.webm_ctx = &webm_ctx; |
730 | 469 |
731 /* Parse command line */ | 470 /* Parse command line */ |
732 exec_name = argv_[0]; | 471 exec_name = argv_[0]; |
733 argv = argv_dup(argc - 1, argv_ + 1); | 472 argv = argv_dup(argc - 1, argv_ + 1); |
734 | 473 |
735 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { | 474 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { |
736 memset(&arg, 0, sizeof(arg)); | 475 memset(&arg, 0, sizeof(arg)); |
737 arg.argv_step = 1; | 476 arg.argv_step = 1; |
738 | 477 |
739 if (arg_match(&arg, &codecarg, argi)) { | 478 if (arg_match(&arg, &codecarg, argi)) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
773 else if (arg_match(&arg, &md5arg, argi)) | 512 else if (arg_match(&arg, &md5arg, argi)) |
774 do_md5 = 1; | 513 do_md5 = 1; |
775 else if (arg_match(&arg, &summaryarg, argi)) | 514 else if (arg_match(&arg, &summaryarg, argi)) |
776 summary = 1; | 515 summary = 1; |
777 else if (arg_match(&arg, &threadsarg, argi)) | 516 else if (arg_match(&arg, &threadsarg, argi)) |
778 cfg.threads = arg_parse_uint(&arg); | 517 cfg.threads = arg_parse_uint(&arg); |
779 else if (arg_match(&arg, &verbosearg, argi)) | 518 else if (arg_match(&arg, &verbosearg, argi)) |
780 quiet = 0; | 519 quiet = 0; |
781 else if (arg_match(&arg, &scalearg, argi)) | 520 else if (arg_match(&arg, &scalearg, argi)) |
782 do_scale = 1; | 521 do_scale = 1; |
| 522 else if (arg_match(&arg, &fb_arg, argi)) |
| 523 num_external_frame_buffers = arg_parse_uint(&arg); |
| 524 else if (arg_match(&arg, &fb_lru_arg, argi)) |
| 525 fb_lru_cache = arg_parse_uint(&arg); |
783 | 526 |
784 #if CONFIG_VP8_DECODER | 527 #if CONFIG_VP8_DECODER |
785 else if (arg_match(&arg, &addnoise_level, argi)) { | 528 else if (arg_match(&arg, &addnoise_level, argi)) { |
786 postproc = 1; | 529 postproc = 1; |
787 vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE; | 530 vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE; |
788 vp8_pp_cfg.noise_level = arg_parse_uint(&arg); | 531 vp8_pp_cfg.noise_level = arg_parse_uint(&arg); |
789 } else if (arg_match(&arg, &demacroblock_level, argi)) { | 532 } else if (arg_match(&arg, &demacroblock_level, argi)) { |
790 postproc = 1; | 533 postproc = 1; |
791 vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK; | 534 vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK; |
792 vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg); | 535 vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
858 } | 601 } |
859 #if CONFIG_OS_SUPPORT | 602 #if CONFIG_OS_SUPPORT |
860 /* Make sure we don't dump to the terminal, unless forced to with -o - */ | 603 /* Make sure we don't dump to the terminal, unless forced to with -o - */ |
861 if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) { | 604 if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) { |
862 fprintf(stderr, | 605 fprintf(stderr, |
863 "Not dumping raw video to your terminal. Use '-o -' to " | 606 "Not dumping raw video to your terminal. Use '-o -' to " |
864 "override.\n"); | 607 "override.\n"); |
865 return EXIT_FAILURE; | 608 return EXIT_FAILURE; |
866 } | 609 } |
867 #endif | 610 #endif |
868 input.infile = infile; | 611 input.vpx_input_ctx->file = infile; |
869 if (file_is_ivf(infile, &fourcc, &width, &height, &fps_den, | 612 if (file_is_ivf(input.vpx_input_ctx)) |
870 &fps_num)) | 613 input.vpx_input_ctx->file_type = FILE_TYPE_IVF; |
871 input.kind = IVF_FILE; | 614 else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx)) |
872 else if (file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num)) | 615 input.vpx_input_ctx->file_type = FILE_TYPE_WEBM; |
873 input.kind = WEBM_FILE; | 616 else if (file_is_raw(input.vpx_input_ctx)) |
874 else if (file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num)) | 617 input.vpx_input_ctx->file_type = FILE_TYPE_RAW; |
875 input.kind = RAW_FILE; | |
876 else { | 618 else { |
877 fprintf(stderr, "Unrecognized input file type.\n"); | 619 fprintf(stderr, "Unrecognized input file type.\n"); |
878 return EXIT_FAILURE; | 620 return EXIT_FAILURE; |
879 } | 621 } |
880 | 622 |
881 /* If the output file is not set or doesn't have a sequence number in | 623 /* If the output file is not set or doesn't have a sequence number in |
882 * it, then we only open it once. | 624 * it, then we only open it once. |
883 */ | 625 */ |
884 outfile_pattern = outfile_pattern ? outfile_pattern : "-"; | 626 outfile_pattern = outfile_pattern ? outfile_pattern : "-"; |
885 single_file = 1; | 627 single_file = 1; |
886 { | 628 { |
887 const char *p = outfile_pattern; | 629 const char *p = outfile_pattern; |
888 do { | 630 do { |
889 p = strchr(p, '%'); | 631 p = strchr(p, '%'); |
890 if (p && p[1] >= '1' && p[1] <= '9') { | 632 if (p && p[1] >= '1' && p[1] <= '9') { |
891 /* pattern contains sequence number, so it's not unique. */ | 633 /* pattern contains sequence number, so it's not unique. */ |
892 single_file = 0; | 634 single_file = 0; |
893 break; | 635 break; |
894 } | 636 } |
895 if (p) | 637 if (p) |
896 p++; | 638 p++; |
897 } while (p); | 639 } while (p); |
898 } | 640 } |
899 | 641 |
900 if (single_file && !noblit) { | 642 if (single_file && !noblit) { |
901 generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1, | 643 generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1, |
902 width, height, 0); | 644 vpx_input_ctx.width, vpx_input_ctx.height, 0); |
903 out = out_open(outfile, do_md5); | 645 out = out_open(outfile, do_md5); |
904 } | 646 } |
905 | 647 |
906 if (use_y4m && !noblit) { | 648 if (use_y4m && !noblit) { |
907 char buffer[128]; | 649 char buffer[128]; |
908 | 650 |
909 if (!single_file) { | 651 if (!single_file) { |
910 fprintf(stderr, "YUV4MPEG2 not supported with output patterns," | 652 fprintf(stderr, "YUV4MPEG2 not supported with output patterns," |
911 " try --i420 or --yv12.\n"); | 653 " try --i420 or --yv12.\n"); |
912 return EXIT_FAILURE; | 654 return EXIT_FAILURE; |
913 } | 655 } |
914 | 656 |
915 if (input.kind == WEBM_FILE) | 657 if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) |
916 if (webm_guess_framerate(&input, &fps_den, &fps_num)) { | 658 if (webm_guess_framerate(input.webm_ctx, input.vpx_input_ctx)) { |
917 fprintf(stderr, "Failed to guess framerate -- error parsing " | 659 fprintf(stderr, "Failed to guess framerate -- error parsing " |
918 "webm file?\n"); | 660 "webm file?\n"); |
919 return EXIT_FAILURE; | 661 return EXIT_FAILURE; |
920 } | 662 } |
921 | 663 |
922 | 664 |
923 /*Note: We can't output an aspect ratio here because IVF doesn't | 665 /*Note: We can't output an aspect ratio here because IVF doesn't |
924 store one, and neither does VP8. | 666 store one, and neither does VP8. |
925 That will have to wait until these tools support WebM natively.*/ | 667 That will have to wait until these tools support WebM natively.*/ |
926 snprintf(buffer, sizeof(buffer), "YUV4MPEG2 W%u H%u F%u:%u I%c ", | 668 snprintf(buffer, sizeof(buffer), "YUV4MPEG2 W%u H%u F%u:%u I%c ", |
927 width, height, fps_num, fps_den, 'p'); | 669 vpx_input_ctx.width, vpx_input_ctx.height, |
| 670 vpx_input_ctx.framerate.numerator, |
| 671 vpx_input_ctx.framerate.denominator, |
| 672 'p'); |
928 out_put(out, (unsigned char *)buffer, | 673 out_put(out, (unsigned char *)buffer, |
929 (unsigned int)strlen(buffer), do_md5); | 674 (unsigned int)strlen(buffer), do_md5); |
930 } | 675 } |
931 | 676 |
932 /* Try to determine the codec from the fourcc. */ | 677 /* Try to determine the codec from the fourcc. */ |
933 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) | 678 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) |
934 if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) { | 679 if ((vpx_input_ctx.fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) { |
935 vpx_codec_iface_t *ivf_iface = ifaces[i].iface(); | 680 vpx_codec_iface_t *vpx_iface = ifaces[i].iface(); |
936 | 681 |
937 if (iface && iface != ivf_iface) | 682 if (iface && iface != vpx_iface) |
938 fprintf(stderr, "Notice -- IVF header indicates codec: %s\n", | 683 warn("Header indicates codec: %s\n", ifaces[i].name); |
939 ifaces[i].name); | |
940 else | 684 else |
941 iface = ivf_iface; | 685 iface = vpx_iface; |
942 | 686 |
943 break; | 687 break; |
944 } | 688 } |
945 | 689 |
946 dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | | 690 dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | |
947 (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); | 691 (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); |
948 if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface(), &cfg, | 692 if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface(), &cfg, |
949 dec_flags)) { | 693 dec_flags)) { |
950 fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decod
er)); | 694 fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decod
er)); |
951 return EXIT_FAILURE; | 695 return EXIT_FAILURE; |
(...skipping 29 matching lines...) Expand all Loading... |
981 } | 725 } |
982 | 726 |
983 if (vp8_dbg_display_mv | 727 if (vp8_dbg_display_mv |
984 && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)
) { | 728 && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)
) { |
985 fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_co
dec_error(&decoder)); | 729 fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_co
dec_error(&decoder)); |
986 return EXIT_FAILURE; | 730 return EXIT_FAILURE; |
987 } | 731 } |
988 #endif | 732 #endif |
989 | 733 |
990 | 734 |
991 if(arg_skip) | 735 if (arg_skip) |
992 fprintf(stderr, "Skiping first %d frames.\n", arg_skip); | 736 fprintf(stderr, "Skipping first %d frames.\n", arg_skip); |
993 while (arg_skip) { | 737 while (arg_skip) { |
994 if (read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) | 738 if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) |
995 break; | 739 break; |
996 arg_skip--; | 740 arg_skip--; |
997 } | 741 } |
998 | 742 |
| 743 if (num_external_frame_buffers > 0) { |
| 744 // Allocate the frame buffer list, setting all of the values to 0. |
| 745 // Including the size of frame buffers. Libvpx will request the |
| 746 // application to realloc the frame buffer data if the size is too small. |
| 747 frame_buffers = (vpx_codec_frame_buffer_t*)calloc( |
| 748 num_external_frame_buffers, sizeof(*frame_buffers)); |
| 749 if (vpx_codec_set_frame_buffers(&decoder, frame_buffers, |
| 750 num_external_frame_buffers, |
| 751 realloc_vp9_frame_buffer, |
| 752 NULL)) { |
| 753 fprintf(stderr, "Failed to configure external frame buffers: %s\n", |
| 754 vpx_codec_error(&decoder)); |
| 755 return EXIT_FAILURE; |
| 756 } |
| 757 } |
| 758 |
| 759 if (fb_lru_cache > 0 && |
| 760 vpx_codec_control(&decoder, VP9D_SET_FRAME_BUFFER_LRU_CACHE, |
| 761 fb_lru_cache)) { |
| 762 fprintf(stderr, "Failed to set frame buffer lru cache: %s\n", |
| 763 vpx_codec_error(&decoder)); |
| 764 return EXIT_FAILURE; |
| 765 } |
| 766 |
999 frame_avail = 1; | 767 frame_avail = 1; |
1000 got_data = 0; | 768 got_data = 0; |
1001 | 769 |
1002 /* Decode file */ | 770 /* Decode file */ |
1003 while (frame_avail || got_data) { | 771 while (frame_avail || got_data) { |
1004 vpx_codec_iter_t iter = NULL; | 772 vpx_codec_iter_t iter = NULL; |
1005 vpx_image_t *img; | 773 vpx_image_t *img; |
1006 struct vpx_usec_timer timer; | 774 struct vpx_usec_timer timer; |
1007 int corrupted; | 775 int corrupted; |
1008 | 776 |
1009 frame_avail = 0; | 777 frame_avail = 0; |
1010 if (!stop_after || frame_in < stop_after) { | 778 if (!stop_after || frame_in < stop_after) { |
1011 if(!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) { | 779 if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) { |
1012 frame_avail = 1; | 780 frame_avail = 1; |
1013 frame_in++; | 781 frame_in++; |
1014 | 782 |
1015 vpx_usec_timer_start(&timer); | 783 vpx_usec_timer_start(&timer); |
1016 | 784 |
1017 if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) { | 785 if (vpx_codec_decode(&decoder, buf, bytes_in_buffer, NULL, 0)) { |
1018 const char *detail = vpx_codec_error_detail(&decoder); | 786 const char *detail = vpx_codec_error_detail(&decoder); |
1019 fprintf(stderr, "Failed to decode frame: %s\n", | 787 warn("Failed to decode frame %d: %s", |
1020 vpx_codec_error(&decoder)); | 788 frame_in, vpx_codec_error(&decoder)); |
1021 | 789 |
1022 if (detail) | 790 if (detail) |
1023 fprintf(stderr, " Additional information: %s\n", detail); | 791 warn("Additional information: %s", detail); |
1024 goto fail; | 792 goto fail; |
1025 } | 793 } |
1026 | 794 |
1027 vpx_usec_timer_mark(&timer); | 795 vpx_usec_timer_mark(&timer); |
1028 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); | 796 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); |
1029 } | 797 } |
1030 } | 798 } |
1031 | 799 |
1032 vpx_usec_timer_start(&timer); | 800 vpx_usec_timer_start(&timer); |
1033 | 801 |
1034 got_data = 0; | 802 got_data = 0; |
1035 if ((img = vpx_codec_get_frame(&decoder, &iter))) { | 803 if ((img = vpx_codec_get_frame(&decoder, &iter))) { |
1036 ++frame_out; | 804 ++frame_out; |
1037 got_data = 1; | 805 got_data = 1; |
1038 } | 806 } |
1039 | 807 |
1040 vpx_usec_timer_mark(&timer); | 808 vpx_usec_timer_mark(&timer); |
1041 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); | 809 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); |
1042 | 810 |
1043 if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) { | 811 if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) { |
1044 fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n", | 812 warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder)); |
1045 vpx_codec_error(&decoder)); | |
1046 goto fail; | 813 goto fail; |
1047 } | 814 } |
1048 frames_corrupted += corrupted; | 815 frames_corrupted += corrupted; |
1049 | 816 |
1050 if (progress) | 817 if (progress) |
1051 show_progress(frame_in, frame_out, dx_time); | 818 show_progress(frame_in, frame_out, dx_time); |
1052 | 819 |
1053 if (!noblit) { | 820 if (!noblit) { |
1054 if (frame_out == 1 && img && use_y4m) { | 821 if (frame_out == 1 && img && use_y4m) { |
1055 /* Write out the color format to terminate the header line */ | 822 /* Write out the color format to terminate the header line */ |
1056 const char *color = | 823 const char *color = |
1057 img->fmt == VPX_IMG_FMT_444A ? "C444alpha\n" : | 824 img->fmt == VPX_IMG_FMT_444A ? "C444alpha\n" : |
1058 img->fmt == VPX_IMG_FMT_I444 ? "C444\n" : | 825 img->fmt == VPX_IMG_FMT_I444 ? "C444\n" : |
1059 img->fmt == VPX_IMG_FMT_I422 ? "C422\n" : | 826 img->fmt == VPX_IMG_FMT_I422 ? "C422\n" : |
1060 "C420jpeg\n"; | 827 "C420jpeg\n"; |
1061 | 828 |
1062 out_put(out, (const unsigned char*)color, strlen(color), do_md5); | 829 out_put(out, (const unsigned char*)color, strlen(color), do_md5); |
1063 } | 830 } |
1064 | 831 |
1065 if (do_scale) { | 832 if (do_scale) { |
| 833 int stream_w = 0, stream_h = 0; |
1066 if (img && frame_out == 1) { | 834 if (img && frame_out == 1) { |
1067 stream_w = img->d_w; | 835 int display_size[2]; |
1068 stream_h = img->d_h; | 836 if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE, |
| 837 display_size)) { |
| 838 // Fallback to use raw image size if display size not available. |
| 839 stream_w = img->d_w; |
| 840 stream_h = img->d_h; |
| 841 } else { |
| 842 stream_w = display_size[0]; |
| 843 stream_h = display_size[1]; |
| 844 } |
1069 scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, | 845 scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, |
1070 stream_w, stream_h, 16); | 846 stream_w, stream_h, 16); |
1071 } | 847 } |
1072 if (img && (img->d_w != stream_w || img->d_h != stream_h)) { | 848 if (img && (img->d_w != stream_w || img->d_h != stream_h)) { |
1073 assert(img->fmt == VPX_IMG_FMT_I420); | 849 assert(img->fmt == VPX_IMG_FMT_I420); |
1074 I420Scale(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y], | 850 I420Scale(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y], |
1075 img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U], | 851 img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U], |
1076 img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], | 852 img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], |
1077 img->d_w, img->d_h, | 853 img->d_w, img->d_h, |
1078 scaled_img->planes[VPX_PLANE_Y], | 854 scaled_img->planes[VPX_PLANE_Y], |
1079 scaled_img->stride[VPX_PLANE_Y], | 855 scaled_img->stride[VPX_PLANE_Y], |
1080 scaled_img->planes[VPX_PLANE_U], | 856 scaled_img->planes[VPX_PLANE_U], |
1081 scaled_img->stride[VPX_PLANE_U], | 857 scaled_img->stride[VPX_PLANE_U], |
1082 scaled_img->planes[VPX_PLANE_V], | 858 scaled_img->planes[VPX_PLANE_V], |
1083 scaled_img->stride[VPX_PLANE_V], | 859 scaled_img->stride[VPX_PLANE_V], |
1084 stream_w, stream_h, | 860 stream_w, stream_h, |
1085 kFilterBox); | 861 kFilterBox); |
1086 img = scaled_img; | 862 img = scaled_img; |
1087 } | 863 } |
1088 } | 864 } |
1089 | |
1090 if (img) { | 865 if (img) { |
1091 unsigned int y; | 866 unsigned int y; |
1092 char out_fn[PATH_MAX]; | 867 char out_fn[PATH_MAX]; |
1093 uint8_t *buf; | 868 uint8_t *buf; |
1094 unsigned int c_w = | 869 unsigned int c_w = |
1095 img->x_chroma_shift ? (1 + img->d_w) >> img->x_chroma_shift | 870 img->x_chroma_shift ? (1 + img->d_w) >> img->x_chroma_shift |
1096 : img->d_w; | 871 : img->d_w; |
1097 unsigned int c_h = | 872 unsigned int c_h = |
1098 img->y_chroma_shift ? (1 + img->d_h) >> img->y_chroma_shift | 873 img->y_chroma_shift ? (1 + img->d_h) >> img->y_chroma_shift |
1099 : img->d_h; | 874 : img->d_h; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1142 show_progress(frame_in, frame_out, dx_time); | 917 show_progress(frame_in, frame_out, dx_time); |
1143 fprintf(stderr, "\n"); | 918 fprintf(stderr, "\n"); |
1144 } | 919 } |
1145 | 920 |
1146 if (frames_corrupted) | 921 if (frames_corrupted) |
1147 fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted); | 922 fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted); |
1148 | 923 |
1149 fail: | 924 fail: |
1150 | 925 |
1151 if (vpx_codec_destroy(&decoder)) { | 926 if (vpx_codec_destroy(&decoder)) { |
1152 fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder)
); | 927 fprintf(stderr, "Failed to destroy decoder: %s\n", |
| 928 vpx_codec_error(&decoder)); |
1153 return EXIT_FAILURE; | 929 return EXIT_FAILURE; |
1154 } | 930 } |
1155 | 931 |
1156 if (single_file && !noblit) | 932 if (single_file && !noblit) |
1157 out_close(out, outfile, do_md5); | 933 out_close(out, outfile, do_md5); |
1158 | 934 |
1159 if (input.nestegg_ctx) | 935 if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM) |
1160 nestegg_destroy(input.nestegg_ctx); | 936 webm_free(input.webm_ctx); |
1161 if (input.kind != WEBM_FILE) | 937 else |
1162 free(buf); | 938 free(buf); |
| 939 |
| 940 if (scaled_img) vpx_img_free(scaled_img); |
| 941 for (i = 0; i < num_external_frame_buffers; ++i) { |
| 942 free(frame_buffers[i].data); |
| 943 } |
| 944 free(frame_buffers); |
| 945 |
1163 fclose(infile); | 946 fclose(infile); |
1164 free(argv); | 947 free(argv); |
1165 | 948 |
1166 return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS; | 949 return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS; |
1167 } | 950 } |
1168 | 951 |
1169 int main(int argc, const char **argv_) { | 952 int main(int argc, const char **argv_) { |
1170 unsigned int loops = 1, i; | 953 unsigned int loops = 1, i; |
1171 char **argv, **argi, **argj; | 954 char **argv, **argi, **argj; |
1172 struct arg arg; | 955 struct arg arg; |
1173 int error = 0; | 956 int error = 0; |
1174 | 957 |
1175 argv = argv_dup(argc - 1, argv_ + 1); | 958 argv = argv_dup(argc - 1, argv_ + 1); |
1176 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { | 959 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { |
1177 memset(&arg, 0, sizeof(arg)); | 960 memset(&arg, 0, sizeof(arg)); |
1178 arg.argv_step = 1; | 961 arg.argv_step = 1; |
1179 | 962 |
1180 if (arg_match(&arg, &looparg, argi)) { | 963 if (arg_match(&arg, &looparg, argi)) { |
1181 loops = arg_parse_uint(&arg); | 964 loops = arg_parse_uint(&arg); |
1182 break; | 965 break; |
1183 } | 966 } |
1184 } | 967 } |
1185 free(argv); | 968 free(argv); |
1186 for (i = 0; !error && i < loops; i++) | 969 for (i = 0; !error && i < loops; i++) |
1187 error = main_loop(argc, argv_); | 970 error = main_loop(argc, argv_); |
1188 return error; | 971 return error; |
1189 } | 972 } |
OLD | NEW |