Merge "reorder data to use wider instructions"
[libvpx.git] / ivfdec.c
blob3919d6bb26f9ba03251b4a0a51d6c73f4e62c4b0
1 /*
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.
9 */
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.
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <string.h>
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"
25 #endif
26 #if CONFIG_MD5
27 #include "md5_utils.h"
28 #endif
30 static const char *exec_name;
32 static const struct
34 char const *name;
35 const vpx_codec_iface_t *iface;
36 unsigned int fourcc;
37 unsigned int fourcc_mask;
38 } ifaces[] =
40 #if CONFIG_VP8_DECODER
41 {"vp8", &vpx_codec_vp8_dx_algo, 0x00385056, 0x00FFFFFF},
42 #endif
45 #include "args.h"
46 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
47 "Codec to use");
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");
75 #if CONFIG_MD5
76 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0,
77 "Compute the MD5 sum of the decoded frame");
78 #endif
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,
84 #if CONFIG_MD5
85 &md5arg,
86 #endif
87 NULL
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,
104 NULL
106 #endif
108 static void usage_exit()
110 int i;
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);
118 #endif
119 fprintf(stderr, "\nIncluded decoders:\n\n");
121 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
122 fprintf(stderr, " %-6s - %s\n",
123 ifaces[i].name,
124 vpx_codec_iface_name(ifaces[i].iface));
126 exit(EXIT_FAILURE);
129 void die(const char *fmt, ...)
131 va_list ap;
132 va_start(ap, fmt);
133 vfprintf(stderr, fmt, ap);
134 fprintf(stderr, "\n");
135 usage_exit();
138 static unsigned int mem_get_le16(const void *vmem)
140 unsigned int val;
141 const unsigned char *mem = (const unsigned char *)vmem;
143 val = mem[1] << 8;
144 val |= mem[0];
145 return val;
148 static unsigned int mem_get_le32(const void *vmem)
150 unsigned int val;
151 const unsigned char *mem = (const unsigned char *)vmem;
153 val = mem[3] << 24;
154 val |= mem[2] << 16;
155 val |= mem[1] << 8;
156 val |= mem[0];
157 return val;
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,
163 uint8_t **buf,
164 uint32_t *buf_sz,
165 uint32_t *buf_alloc_sz,
166 int is_ivf)
168 char raw_hdr[IVF_FRAME_HDR_SZ];
169 uint32_t new_buf_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
173 * size.
175 if (fread(raw_hdr, is_ivf ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1,
176 infile) != 1)
178 if (!feof(infile))
179 fprintf(stderr, "Failed to read frame size\n");
181 new_buf_sz = 0;
183 else
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",
190 new_buf_sz);
191 new_buf_sz = 0;
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);
202 if (new_buf)
204 *buf = new_buf;
205 *buf_alloc_sz = 2 * new_buf_sz;
207 else
209 fprintf(stderr, "Failed to allocate compressed data buffer\n");
210 new_buf_sz = 0;
215 *buf_sz = new_buf_sz;
217 if (*buf_sz)
219 if (fread(*buf, 1, *buf_sz, infile) != *buf_sz)
221 fprintf(stderr, "Failed to read full frame\n");
222 return 1;
225 return 0;
228 return 1;
231 void *out_open(const char *out_fn, int do_md5)
233 void *out = NULL;
235 if (do_md5)
237 #if CONFIG_MD5
238 MD5Context *md5_ctx = out = malloc(sizeof(MD5Context));
239 (void)out_fn;
240 MD5Init(md5_ctx);
241 #endif
243 else
245 FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") : stdout;
247 if (!outfile)
249 fprintf(stderr, "Failed to output file");
250 exit(EXIT_FAILURE);
254 return out;
257 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5)
259 if (do_md5)
261 #if CONFIG_MD5
262 MD5Update(out, buf, len);
263 #endif
265 else
267 fwrite(buf, 1, len, out);
271 void out_close(void *out, const char *out_fn, int do_md5)
273 if (do_md5)
275 #if CONFIG_MD5
276 uint8_t md5[16];
277 int i;
279 MD5Final(md5, out);
280 free(out);
282 for (i = 0; i < 16; i++)
283 printf("%02x", md5[i]);
285 printf(" %s\n", out_fn);
286 #endif
288 else
290 fclose(out);
294 unsigned int file_is_ivf(FILE *infile,
295 unsigned int *fourcc,
296 unsigned int *width,
297 unsigned int *height,
298 unsigned int *timebase_num,
299 unsigned int *timebase_den)
301 char raw_hdr[32];
302 int is_ivf = 0;
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')
309 is_ivf = 1;
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);
323 if (!is_ivf)
324 rewind(infile);
326 return is_ivf;
329 int main(int argc, const char **argv_)
331 vpx_codec_ctx_t decoder;
332 char *prefix = NULL, *fn = NULL;
333 int i;
334 uint8_t *buf = NULL;
335 uint32_t buf_sz = 0, buf_alloc_sz = 0;
336 FILE *infile;
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;
342 struct arg arg;
343 char **argv, **argi, **argj;
344 const char *fn2 = 0;
345 int use_y4m = 0;
346 unsigned int width;
347 unsigned int height;
348 unsigned int timebase_num;
349 unsigned int timebase_den;
350 void *out = NULL;
351 vpx_codec_dec_cfg_t cfg = {0};
352 #if CONFIG_VP8_DECODER
353 vp8_postproc_cfg_t vp8_pp_cfg = {0};
354 #endif
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));
363 arg.argv_step = 1;
365 if (arg_match(&arg, &codecarg, argi))
367 int j, k = -1;
369 for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++)
370 if (!strcmp(ifaces[j].name, arg.val))
371 k = j;
373 if (k >= 0)
374 iface = ifaces[k].iface;
375 else
376 die("Error: Unrecognized argument (%s) to --codec\n",
377 arg.val);
379 else if (arg_match(&arg, &outputfile, argi))
380 fn2 = arg.val;
381 else if (arg_match(&arg, &usey4marg, argi))
382 use_y4m = 1;
383 else if (arg_match(&arg, &prefixarg, argi))
384 prefix = strdup(arg.val);
385 else if (arg_match(&arg, &use_yv12, argi))
386 flipuv = 1;
387 else if (arg_match(&arg, &use_i420, argi))
388 flipuv = 0;
389 else if (arg_match(&arg, &flipuvarg, argi))
390 flipuv = 1;
391 else if (arg_match(&arg, &noblitarg, argi))
392 noblit = 1;
393 else if (arg_match(&arg, &progressarg, argi))
394 progress = 1;
395 else if (arg_match(&arg, &limitarg, argi))
396 stop_after = arg_parse_uint(&arg);
397 else if (arg_match(&arg, &postprocarg, argi))
398 postproc = 1;
399 else if (arg_match(&arg, &md5arg, argi))
400 do_md5 = 1;
401 else if (arg_match(&arg, &summaryarg, argi))
402 summary = 1;
403 else if (arg_match(&arg, &threadsarg, argi))
404 cfg.threads = arg_parse_uint(&arg);
405 else if (arg_match(&arg, &quietarg, argi))
406 quiet = 1;
408 #if CONFIG_VP8_DECODER
409 else if (arg_match(&arg, &addnoise_level, argi))
411 postproc = 1;
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))
417 postproc = 1;
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))
423 postproc = 1;
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);
430 postproc = 1;
431 vp8_pp_cfg.post_proc_flag &= ~0x7;
433 if (level)
434 vp8_pp_cfg.post_proc_flag |= 8 << (level - 1);
437 #endif
438 else
439 argj++;
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 */
448 fn = argv[0];
450 if (!fn)
451 usage_exit();
453 if (!prefix)
454 prefix = strdup("img");
456 /* Open file */
457 infile = strcmp(fn, "-") ? fopen(fn, "rb") : stdin;
459 if (!infile)
461 fprintf(stderr, "Failed to open file");
462 return EXIT_FAILURE;
465 if (fn2)
466 out = out_open(fn2, do_md5);
468 is_ivf = file_is_ivf(infile, &fourcc, &width, &height,
469 &timebase_num, &timebase_den);
471 if (is_ivf)
473 if (use_y4m)
475 char buffer[128];
476 if (!fn2)
478 fprintf(stderr, "YUV4MPEG2 output only supported with -o.\n");
479 return EXIT_FAILURE;
481 /*Correct for the factor of 2 applied to the timebase in the
482 encoder.*/
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",
501 ifaces[i].name);
502 else
503 iface = ivf_iface;
505 break;
508 else if(use_y4m)
510 fprintf(stderr, "YUV4MPEG2 output only supported from IVF input.\n");
511 return EXIT_FAILURE;
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));
518 return EXIT_FAILURE;
521 if (!quiet)
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));
530 return EXIT_FAILURE;
533 #endif
535 /* Decode file */
536 while (!read_frame(infile, &buf, &buf_sz, &buf_alloc_sz, is_ivf))
538 vpx_codec_iter_t iter = NULL;
539 vpx_image_t *img;
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));
549 if (detail)
550 fprintf(stderr, " Additional information: %s\n", detail);
552 goto fail;
555 vpx_usec_timer_mark(&timer);
556 dx_time += vpx_usec_timer_elapsed(&timer);
558 ++frame_in;
560 if (progress)
561 fprintf(stderr, "decoded frame %d.\n", frame_in);
563 if ((img = vpx_codec_get_frame(&decoder, &iter)))
564 ++frame_out;
566 if (!noblit)
568 if (img)
570 unsigned int y;
571 char out_fn[128+24];
572 uint8_t *buf;
573 const char *sfx = flipuv ? "yv12" : "i420";
575 if (!fn2)
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);
581 else if(use_y4m)
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];
608 if (!fn2)
609 out_close(out, out_fn, do_md5);
613 if (stop_after && frame_in >= stop_after)
614 break;
617 if (summary)
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);
623 fail:
625 if (vpx_codec_destroy(&decoder))
627 fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder));
628 return EXIT_FAILURE;
631 if (fn2)
632 out_close(out, fn2, do_md5);
634 free(buf);
635 fclose(infile);
636 free(prefix);
637 free(argv);
639 return EXIT_SUCCESS;