2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
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.
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.
19 #define VPX_CODEC_DISABLE_COMPAT 1
20 #include "vpx_config.h"
21 #include "vpx/vpx_decoder.h"
22 #include "vpx_ports/vpx_timer.h"
23 #if CONFIG_VP8_DECODER
24 #include "vpx/vp8dx.h"
27 #include "md5_utils.h"
30 static const char *exec_name;
35 const vpx_codec_iface_t *iface;
37 unsigned int fourcc_mask;
40 #if CONFIG_VP8_DECODER
41 {"vp8", &vpx_codec_vp8_dx_algo, 0x00385056, 0x00FFFFFF},
46 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
48 static const arg_def_t prefixarg = ARG_DEF("p", "prefix", 1,
49 "Prefix to use when saving frames");
50 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
51 "Output file is YV12 ");
52 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
53 "Output file is I420 (default)");
54 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0,
55 "Synonym for --yv12");
56 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0,
57 "Don't process the decoded frames");
58 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0,
59 "Show progress after each frame decodes");
60 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1,
61 "Stop decoding after n frames");
62 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0,
63 "Postprocess decoded frames");
64 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0,
65 "Show timing summary");
66 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
67 "Output raw yv12 file instead of images");
68 static const arg_def_t usey4marg = ARG_DEF("y", "y4m", 0,
69 "Output file is YUV4MPEG2");
70 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1,
71 "Max threads to use");
72 static const arg_def_t quietarg = ARG_DEF("q", "quiet", 0,
73 "Suppress version string");
76 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0,
77 "Compute the MD5 sum of the decoded frame");
79 static const arg_def_t *all_args[] =
81 &codecarg, &prefixarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg,
82 &progressarg, &limitarg, &postprocarg, &summaryarg, &outputfile,
83 &usey4marg, &threadsarg, &quietarg,
90 #if CONFIG_VP8_DECODER
91 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1,
92 "Enable VP8 postproc add noise");
93 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0,
94 "Enable VP8 deblocking");
95 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1,
96 "Enable VP8 demacroblocking, w/ level");
97 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1,
98 "Enable VP8 visible debug info");
101 static const arg_def_t *vp8_pp_args[] =
103 &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info,
108 static void usage_exit()
112 fprintf(stderr, "Usage: %s <options> filename\n\n"
113 "Options:\n", exec_name);
114 arg_show_usage(stderr, all_args);
115 #if CONFIG_VP8_DECODER
116 fprintf(stderr, "\nvp8 Postprocessing Options:\n");
117 arg_show_usage(stderr, vp8_pp_args);
119 fprintf(stderr, "\nIncluded decoders:\n\n");
121 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
122 fprintf(stderr, " %-6s - %s\n",
124 vpx_codec_iface_name(ifaces[i].iface));
129 void die(const char *fmt, ...)
133 vfprintf(stderr, fmt, ap);
134 fprintf(stderr, "\n");
138 static unsigned int mem_get_le16(const void *vmem)
141 const unsigned char *mem = (const unsigned char *)vmem;
148 static unsigned int mem_get_le32(const void *vmem)
151 const unsigned char *mem = (const unsigned char *)vmem;
160 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t))
161 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t))
162 static int read_frame(FILE *infile,
165 uint32_t *buf_alloc_sz,
168 char raw_hdr[IVF_FRAME_HDR_SZ];
171 /* For both the raw and ivf formats, the frame size is the first 4 bytes
172 * of the frame header. We just need to special case on the header
175 if (fread(raw_hdr, is_ivf ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1,
179 fprintf(stderr, "Failed to read frame size\n");
185 new_buf_sz = mem_get_le32(raw_hdr);
187 if (new_buf_sz > 256 * 1024 * 1024)
189 fprintf(stderr, "Error: Read invalid frame size (%u)\n",
194 if (!is_ivf && new_buf_sz > 256 * 1024)
195 fprintf(stderr, "Warning: Read invalid frame size (%u)"
196 " - not a raw file?\n", new_buf_sz);
198 if (new_buf_sz > *buf_alloc_sz)
200 uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz);
205 *buf_alloc_sz = 2 * new_buf_sz;
209 fprintf(stderr, "Failed to allocate compressed data buffer\n");
215 *buf_sz = new_buf_sz;
219 if (fread(*buf, 1, *buf_sz, infile) != *buf_sz)
221 fprintf(stderr, "Failed to read full frame\n");
231 void *out_open(const char *out_fn, int do_md5)
238 MD5Context *md5_ctx = out = malloc(sizeof(MD5Context));
245 FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") : stdout;
249 fprintf(stderr, "Failed to output file");
257 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5)
262 MD5Update(out, buf, len);
267 fwrite(buf, 1, len, out);
271 void out_close(void *out, const char *out_fn, int do_md5)
282 for (i = 0; i < 16; i++)
283 printf("%02x", md5[i]);
285 printf(" %s\n", out_fn);
294 unsigned int file_is_ivf(FILE *infile,
295 unsigned int *fourcc,
297 unsigned int *height,
298 unsigned int *timebase_num,
299 unsigned int *timebase_den)
304 if (fread(raw_hdr, 1, 32, infile) == 32)
306 if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K'
307 && raw_hdr[2] == 'I' && raw_hdr[3] == 'F')
311 if (mem_get_le16(raw_hdr + 4) != 0)
312 fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
313 " decode properly.");
315 *fourcc = mem_get_le32(raw_hdr + 8);
316 *width = mem_get_le16(raw_hdr + 12);
317 *height = mem_get_le16(raw_hdr + 14);
318 *timebase_den = mem_get_le32(raw_hdr + 16);
319 *timebase_num = mem_get_le32(raw_hdr + 20);
329 int main(int argc, const char **argv_)
331 vpx_codec_ctx_t decoder;
332 char *prefix = NULL, *fn = NULL;
335 uint32_t buf_sz = 0, buf_alloc_sz = 0;
337 int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0;
338 int stop_after = 0, postproc = 0, summary = 0, quiet = 0;
339 vpx_codec_iface_t *iface = NULL;
340 unsigned int is_ivf, fourcc;
341 unsigned long dx_time = 0;
343 char **argv, **argi, **argj;
348 unsigned int timebase_num;
349 unsigned int timebase_den;
351 vpx_codec_dec_cfg_t cfg = {0};
352 #if CONFIG_VP8_DECODER
353 vp8_postproc_cfg_t vp8_pp_cfg = {0};
356 /* Parse command line */
357 exec_name = argv_[0];
358 argv = argv_dup(argc - 1, argv_ + 1);
360 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
362 memset(&arg, 0, sizeof(arg));
365 if (arg_match(&arg, &codecarg, argi))
369 for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++)
370 if (!strcmp(ifaces[j].name, arg.val))
374 iface = ifaces[k].iface;
376 die("Error: Unrecognized argument (%s) to --codec\n",
379 else if (arg_match(&arg, &outputfile, argi))
381 else if (arg_match(&arg, &usey4marg, argi))
383 else if (arg_match(&arg, &prefixarg, argi))
384 prefix = strdup(arg.val);
385 else if (arg_match(&arg, &use_yv12, argi))
387 else if (arg_match(&arg, &use_i420, argi))
389 else if (arg_match(&arg, &flipuvarg, argi))
391 else if (arg_match(&arg, &noblitarg, argi))
393 else if (arg_match(&arg, &progressarg, argi))
395 else if (arg_match(&arg, &limitarg, argi))
396 stop_after = arg_parse_uint(&arg);
397 else if (arg_match(&arg, &postprocarg, argi))
399 else if (arg_match(&arg, &md5arg, argi))
401 else if (arg_match(&arg, &summaryarg, argi))
403 else if (arg_match(&arg, &threadsarg, argi))
404 cfg.threads = arg_parse_uint(&arg);
405 else if (arg_match(&arg, &quietarg, argi))
408 #if CONFIG_VP8_DECODER
409 else if (arg_match(&arg, &addnoise_level, argi))
412 vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
413 vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
415 else if (arg_match(&arg, &demacroblock_level, argi))
418 vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
419 vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
421 else if (arg_match(&arg, &deblock, argi))
424 vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
426 else if (arg_match(&arg, &pp_debug_info, argi))
428 unsigned int level = arg_parse_uint(&arg);
431 vp8_pp_cfg.post_proc_flag &= ~0x7;
434 vp8_pp_cfg.post_proc_flag |= 8 << (level - 1);
442 /* Check for unrecognized options */
443 for (argi = argv; *argi; argi++)
444 if (argi[0][0] == '-' && strlen(argi[0]) > 1)
445 die("Error: Unrecognized option %s\n", *argi);
447 /* Handle non-option arguments */
454 prefix = strdup("img");
457 infile = strcmp(fn, "-") ? fopen(fn, "rb") : stdin;
461 fprintf(stderr, "Failed to open file");
466 out = out_open(fn2, do_md5);
468 is_ivf = file_is_ivf(infile, &fourcc, &width, &height,
469 &timebase_num, &timebase_den);
478 fprintf(stderr, "YUV4MPEG2 output only supported with -o.\n");
481 /*Correct for the factor of 2 applied to the timebase in the
483 if(timebase_den&1)timebase_num<<=1;
484 else timebase_den>>=1;
485 /*Note: We can't output an aspect ratio here because IVF doesn't
486 store one, and neither does VP8.
487 That will have to wait until these tools support WebM natively.*/
488 sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n",
489 "420jpeg", width, height, timebase_den, timebase_num, 'p');
490 out_put(out, (unsigned char *)buffer, strlen(buffer), do_md5);
493 /* Try to determine the codec from the fourcc. */
494 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
495 if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc)
497 vpx_codec_iface_t *ivf_iface = ifaces[i].iface;
499 if (iface && iface != ivf_iface)
500 fprintf(stderr, "Notice -- IVF header indicates codec: %s\n",
510 fprintf(stderr, "YUV4MPEG2 output only supported from IVF input.\n");
514 if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface, &cfg,
515 postproc ? VPX_CODEC_USE_POSTPROC : 0))
517 fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder));
522 fprintf(stderr, "%s\n", decoder.name);
524 #if CONFIG_VP8_DECODER
526 if (vp8_pp_cfg.post_proc_flag
527 && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg))
529 fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
536 while (!read_frame(infile, &buf, &buf_sz, &buf_alloc_sz, is_ivf))
538 vpx_codec_iter_t iter = NULL;
540 struct vpx_usec_timer timer;
542 vpx_usec_timer_start(&timer);
544 if (vpx_codec_decode(&decoder, buf, buf_sz, NULL, 0))
546 const char *detail = vpx_codec_error_detail(&decoder);
547 fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder));
550 fprintf(stderr, " Additional information: %s\n", detail);
555 vpx_usec_timer_mark(&timer);
556 dx_time += vpx_usec_timer_elapsed(&timer);
561 fprintf(stderr, "decoded frame %d.\n", frame_in);
563 if ((img = vpx_codec_get_frame(&decoder, &iter)))
573 const char *sfx = flipuv ? "yv12" : "i420";
577 sprintf(out_fn, "%s-%dx%d-%04d.%s",
578 prefix, img->d_w, img->d_h, frame_in, sfx);
579 out = out_open(out_fn, do_md5);
582 out_put(out, (unsigned char *)"FRAME\n", 6, do_md5);
584 buf = img->planes[VPX_PLANE_Y];
586 for (y = 0; y < img->d_h; y++)
588 out_put(out, buf, img->d_w, do_md5);
589 buf += img->stride[VPX_PLANE_Y];
592 buf = img->planes[flipuv?VPX_PLANE_V:VPX_PLANE_U];
594 for (y = 0; y < (1 + img->d_h) / 2; y++)
596 out_put(out, buf, (1 + img->d_w) / 2, do_md5);
597 buf += img->stride[VPX_PLANE_U];
600 buf = img->planes[flipuv?VPX_PLANE_U:VPX_PLANE_V];
602 for (y = 0; y < (1 + img->d_h) / 2; y++)
604 out_put(out, buf, (1 + img->d_w) / 2, do_md5);
605 buf += img->stride[VPX_PLANE_V];
609 out_close(out, out_fn, do_md5);
613 if (stop_after && frame_in >= stop_after)
619 fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\n",
620 frame_in, frame_out, dx_time, (float)frame_out * 1000000.0 / (float)dx_time);
625 if (vpx_codec_destroy(&decoder))
627 fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder));
632 out_close(out, fn2, do_md5);