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
);