]> granicus.if.org Git - libvpx/blob - vpxdec.c
Merge "Re-distribute hierarchical vector match pattern"
[libvpx] / vpxdec.c
1 /*
2  *  Copyright (c) 2010 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 <assert.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <limits.h>
17
18 #include "./vpx_config.h"
19
20 #if CONFIG_LIBYUV
21 #include "third_party/libyuv/include/libyuv/scale.h"
22 #endif
23
24 #include "./args.h"
25 #include "./ivfdec.h"
26
27 #include "vpx/vpx_decoder.h"
28 #include "vpx_ports/mem_ops.h"
29 #include "vpx_ports/vpx_timer.h"
30
31 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
32 #include "vpx/vp8dx.h"
33 #endif
34
35 #include "./md5_utils.h"
36
37 #include "./tools_common.h"
38 #if CONFIG_WEBM_IO
39 #include "./webmdec.h"
40 #endif
41 #include "./y4menc.h"
42
43 static const char *exec_name;
44
45 struct VpxDecInputContext {
46   struct VpxInputContext *vpx_input_ctx;
47   struct WebmInputContext *webm_ctx;
48 };
49
50 static const arg_def_t looparg = ARG_DEF(
51     NULL, "loops", 1, "Number of times to decode the file");
52 static const arg_def_t codecarg = ARG_DEF(
53     NULL, "codec", 1, "Codec to use");
54 static const arg_def_t use_yv12 = ARG_DEF(
55     NULL, "yv12", 0, "Output raw YV12 frames");
56 static const arg_def_t use_i420 = ARG_DEF(
57     NULL, "i420", 0, "Output raw I420 frames");
58 static const arg_def_t flipuvarg = ARG_DEF(
59     NULL, "flipuv", 0, "Flip the chroma planes in the output");
60 static const arg_def_t rawvideo = ARG_DEF(
61     NULL, "rawvideo", 0, "Output raw YUV frames");
62 static const arg_def_t noblitarg = ARG_DEF(
63     NULL, "noblit", 0, "Don't process the decoded frames");
64 static const arg_def_t progressarg = ARG_DEF(
65     NULL, "progress", 0, "Show progress after each frame decodes");
66 static const arg_def_t limitarg = ARG_DEF(
67     NULL, "limit", 1, "Stop decoding after n frames");
68 static const arg_def_t skiparg = ARG_DEF(
69     NULL, "skip", 1, "Skip the first n input frames");
70 static const arg_def_t postprocarg = ARG_DEF(
71     NULL, "postproc", 0, "Postprocess decoded frames");
72 static const arg_def_t summaryarg = ARG_DEF(
73     NULL, "summary", 0, "Show timing summary");
74 static const arg_def_t outputfile = ARG_DEF(
75     "o", "output", 1, "Output file name pattern (see below)");
76 static const arg_def_t threadsarg = ARG_DEF(
77     "t", "threads", 1, "Max threads to use");
78 static const arg_def_t verbosearg = ARG_DEF(
79     "v", "verbose", 0, "Show version string");
80 static const arg_def_t error_concealment = ARG_DEF(
81     NULL, "error-concealment", 0, "Enable decoder error-concealment");
82 static const arg_def_t scalearg = ARG_DEF(
83     "S", "scale", 0, "Scale output frames uniformly");
84 static const arg_def_t continuearg = ARG_DEF(
85     "k", "keep-going", 0, "(debug) Continue decoding after error");
86 static const arg_def_t fb_arg = ARG_DEF(
87     NULL, "frame-buffers", 1, "Number of frame buffers to use");
88 static const arg_def_t md5arg = ARG_DEF(
89     NULL, "md5", 0, "Compute the MD5 sum of the decoded frame");
90 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
91 static const arg_def_t outbitdeptharg = ARG_DEF(
92     NULL, "output-bit-depth", 1, "Output bit-depth for decoded frames");
93 #endif
94
95 static const arg_def_t *all_args[] = {
96   &codecarg, &use_yv12, &use_i420, &flipuvarg, &rawvideo, &noblitarg,
97   &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile,
98   &threadsarg, &verbosearg, &scalearg, &fb_arg,
99   &md5arg, &error_concealment, &continuearg,
100 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
101   &outbitdeptharg,
102 #endif
103   NULL
104 };
105
106 #if CONFIG_VP8_DECODER
107 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1,
108                                                 "Enable VP8 postproc add noise");
109 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0,
110                                          "Enable VP8 deblocking");
111 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1,
112                                                     "Enable VP8 demacroblocking, w/ level");
113 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1,
114                                                "Enable VP8 visible debug info");
115 static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1,
116                                                    "Display only selected reference frame per macro block");
117 static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1,
118                                                   "Display only selected macro block modes");
119 static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1,
120                                                  "Display only selected block modes");
121 static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1,
122                                              "Draw only selected motion vectors");
123 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0,
124                                       "Enable multiframe quality enhancement");
125
126 static const arg_def_t *vp8_pp_args[] = {
127   &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info,
128   &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe,
129   NULL
130 };
131 #endif
132
133 #if CONFIG_LIBYUV
134 static INLINE int libyuv_scale(vpx_image_t *src, vpx_image_t *dst,
135                                   FilterModeEnum mode) {
136 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
137   if (src->fmt == VPX_IMG_FMT_I42016) {
138     assert(dst->fmt == VPX_IMG_FMT_I42016);
139     return I420Scale_16((uint16_t*)src->planes[VPX_PLANE_Y],
140                         src->stride[VPX_PLANE_Y]/2,
141                         (uint16_t*)src->planes[VPX_PLANE_U],
142                         src->stride[VPX_PLANE_U]/2,
143                         (uint16_t*)src->planes[VPX_PLANE_V],
144                         src->stride[VPX_PLANE_V]/2,
145                         src->d_w, src->d_h,
146                         (uint16_t*)dst->planes[VPX_PLANE_Y],
147                         dst->stride[VPX_PLANE_Y]/2,
148                         (uint16_t*)dst->planes[VPX_PLANE_U],
149                         dst->stride[VPX_PLANE_U]/2,
150                         (uint16_t*)dst->planes[VPX_PLANE_V],
151                         dst->stride[VPX_PLANE_V]/2,
152                         dst->d_w, dst->d_h,
153                         mode);
154   }
155 #endif
156   assert(src->fmt == VPX_IMG_FMT_I420);
157   assert(dst->fmt == VPX_IMG_FMT_I420);
158   return I420Scale(src->planes[VPX_PLANE_Y], src->stride[VPX_PLANE_Y],
159                    src->planes[VPX_PLANE_U], src->stride[VPX_PLANE_U],
160                    src->planes[VPX_PLANE_V], src->stride[VPX_PLANE_V],
161                    src->d_w, src->d_h,
162                    dst->planes[VPX_PLANE_Y], dst->stride[VPX_PLANE_Y],
163                    dst->planes[VPX_PLANE_U], dst->stride[VPX_PLANE_U],
164                    dst->planes[VPX_PLANE_V], dst->stride[VPX_PLANE_V],
165                    dst->d_w, dst->d_h,
166                    mode);
167 }
168 #endif
169
170 void usage_exit() {
171   int i;
172
173   fprintf(stderr, "Usage: %s <options> filename\n\n"
174           "Options:\n", exec_name);
175   arg_show_usage(stderr, all_args);
176 #if CONFIG_VP8_DECODER
177   fprintf(stderr, "\nVP8 Postprocessing Options:\n");
178   arg_show_usage(stderr, vp8_pp_args);
179 #endif
180   fprintf(stderr,
181           "\nOutput File Patterns:\n\n"
182           "  The -o argument specifies the name of the file(s) to "
183           "write to. If the\n  argument does not include any escape "
184           "characters, the output will be\n  written to a single file. "
185           "Otherwise, the filename will be calculated by\n  expanding "
186           "the following escape characters:\n");
187   fprintf(stderr,
188           "\n\t%%w   - Frame width"
189           "\n\t%%h   - Frame height"
190           "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)"
191           "\n\n  Pattern arguments are only supported in conjunction "
192           "with the --yv12 and\n  --i420 options. If the -o option is "
193           "not specified, the output will be\n  directed to stdout.\n"
194          );
195   fprintf(stderr, "\nIncluded decoders:\n\n");
196
197   for (i = 0; i < get_vpx_decoder_count(); ++i) {
198     const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
199     fprintf(stderr, "    %-6s - %s\n",
200             decoder->name, vpx_codec_iface_name(decoder->codec_interface()));
201   }
202
203   exit(EXIT_FAILURE);
204 }
205
206 static int raw_read_frame(FILE *infile, uint8_t **buffer,
207                           size_t *bytes_read, size_t *buffer_size) {
208   char raw_hdr[RAW_FRAME_HDR_SZ];
209   size_t frame_size = 0;
210
211   if (fread(raw_hdr, RAW_FRAME_HDR_SZ, 1, infile) != 1) {
212     if (!feof(infile))
213       warn("Failed to read RAW frame size\n");
214   } else {
215     const size_t kCorruptFrameThreshold = 256 * 1024 * 1024;
216     const size_t kFrameTooSmallThreshold = 256 * 1024;
217     frame_size = mem_get_le32(raw_hdr);
218
219     if (frame_size > kCorruptFrameThreshold) {
220       warn("Read invalid frame size (%u)\n", (unsigned int)frame_size);
221       frame_size = 0;
222     }
223
224     if (frame_size < kFrameTooSmallThreshold) {
225       warn("Warning: Read invalid frame size (%u) - not a raw file?\n",
226            (unsigned int)frame_size);
227     }
228
229     if (frame_size > *buffer_size) {
230       uint8_t *new_buf = realloc(*buffer, 2 * frame_size);
231       if (new_buf) {
232         *buffer = new_buf;
233         *buffer_size = 2 * frame_size;
234       } else {
235         warn("Failed to allocate compressed data buffer\n");
236         frame_size = 0;
237       }
238     }
239   }
240
241   if (!feof(infile)) {
242     if (fread(*buffer, 1, frame_size, infile) != frame_size) {
243       warn("Failed to read full frame\n");
244       return 1;
245     }
246     *bytes_read = frame_size;
247   }
248
249   return 0;
250 }
251
252 static int read_frame(struct VpxDecInputContext *input, uint8_t **buf,
253                       size_t *bytes_in_buffer, size_t *buffer_size) {
254   switch (input->vpx_input_ctx->file_type) {
255 #if CONFIG_WEBM_IO
256     case FILE_TYPE_WEBM:
257       return webm_read_frame(input->webm_ctx,
258                              buf, bytes_in_buffer, buffer_size);
259 #endif
260     case FILE_TYPE_RAW:
261       return raw_read_frame(input->vpx_input_ctx->file,
262                             buf, bytes_in_buffer, buffer_size);
263     case FILE_TYPE_IVF:
264       return ivf_read_frame(input->vpx_input_ctx->file,
265                             buf, bytes_in_buffer, buffer_size);
266     default:
267       return 1;
268   }
269 }
270
271 static void update_image_md5(const vpx_image_t *img, const int planes[3],
272                              MD5Context *md5) {
273   int i, y;
274
275   for (i = 0; i < 3; ++i) {
276     const int plane = planes[i];
277     const unsigned char *buf = img->planes[plane];
278     const int stride = img->stride[plane];
279     const int w = vpx_img_plane_width(img, plane) *
280                 ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
281     const int h = vpx_img_plane_height(img, plane);
282
283     for (y = 0; y < h; ++y) {
284       MD5Update(md5, buf, w);
285       buf += stride;
286     }
287   }
288 }
289
290 static void write_image_file(const vpx_image_t *img, const int planes[3],
291                              FILE *file) {
292   int i, y;
293 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
294   const int bytes_per_sample = ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
295 #else
296   const int bytes_per_sample = 1;
297 #endif
298
299   for (i = 0; i < 3; ++i) {
300     const int plane = planes[i];
301     const unsigned char *buf = img->planes[plane];
302     const int stride = img->stride[plane];
303     const int w = vpx_img_plane_width(img, plane);
304     const int h = vpx_img_plane_height(img, plane);
305
306     for (y = 0; y < h; ++y) {
307       fwrite(buf, bytes_per_sample, w, file);
308       buf += stride;
309     }
310   }
311 }
312
313 int file_is_raw(struct VpxInputContext *input) {
314   uint8_t buf[32];
315   int is_raw = 0;
316   vpx_codec_stream_info_t si;
317
318   si.sz = sizeof(si);
319
320   if (fread(buf, 1, 32, input->file) == 32) {
321     int i;
322
323     if (mem_get_le32(buf) < 256 * 1024 * 1024) {
324       for (i = 0; i < get_vpx_decoder_count(); ++i) {
325         const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
326         if (!vpx_codec_peek_stream_info(decoder->codec_interface(),
327                                         buf + 4, 32 - 4, &si)) {
328           is_raw = 1;
329           input->fourcc = decoder->fourcc;
330           input->width = si.w;
331           input->height = si.h;
332           input->framerate.numerator = 30;
333           input->framerate.denominator = 1;
334           break;
335         }
336       }
337     }
338   }
339
340   rewind(input->file);
341   return is_raw;
342 }
343
344 void show_progress(int frame_in, int frame_out, uint64_t dx_time) {
345   fprintf(stderr,
346           "%d decoded frames/%d showed frames in %"PRId64" us (%.2f fps)\r",
347           frame_in, frame_out, dx_time,
348           (double)frame_out * 1000000.0 / (double)dx_time);
349 }
350
351 struct ExternalFrameBuffer {
352   uint8_t* data;
353   size_t size;
354   int in_use;
355 };
356
357 struct ExternalFrameBufferList {
358   int num_external_frame_buffers;
359   struct ExternalFrameBuffer *ext_fb;
360 };
361
362 // Callback used by libvpx to request an external frame buffer. |cb_priv|
363 // Application private data passed into the set function. |min_size| is the
364 // minimum size in bytes needed to decode the next frame. |fb| pointer to the
365 // frame buffer.
366 int get_vp9_frame_buffer(void *cb_priv, size_t min_size,
367                          vpx_codec_frame_buffer_t *fb) {
368   int i;
369   struct ExternalFrameBufferList *const ext_fb_list =
370       (struct ExternalFrameBufferList *)cb_priv;
371   if (ext_fb_list == NULL)
372     return -1;
373
374   // Find a free frame buffer.
375   for (i = 0; i < ext_fb_list->num_external_frame_buffers; ++i) {
376     if (!ext_fb_list->ext_fb[i].in_use)
377       break;
378   }
379
380   if (i == ext_fb_list->num_external_frame_buffers)
381     return -1;
382
383   if (ext_fb_list->ext_fb[i].size < min_size) {
384     free(ext_fb_list->ext_fb[i].data);
385     ext_fb_list->ext_fb[i].data = (uint8_t *)calloc(min_size, sizeof(uint8_t));
386     if (!ext_fb_list->ext_fb[i].data)
387       return -1;
388
389     ext_fb_list->ext_fb[i].size = min_size;
390   }
391
392   fb->data = ext_fb_list->ext_fb[i].data;
393   fb->size = ext_fb_list->ext_fb[i].size;
394   ext_fb_list->ext_fb[i].in_use = 1;
395
396   // Set the frame buffer's private data to point at the external frame buffer.
397   fb->priv = &ext_fb_list->ext_fb[i];
398   return 0;
399 }
400
401 // Callback used by libvpx when there are no references to the frame buffer.
402 // |cb_priv| user private data passed into the set function. |fb| pointer
403 // to the frame buffer.
404 int release_vp9_frame_buffer(void *cb_priv,
405                              vpx_codec_frame_buffer_t *fb) {
406   struct ExternalFrameBuffer *const ext_fb =
407       (struct ExternalFrameBuffer *)fb->priv;
408   (void)cb_priv;
409   ext_fb->in_use = 0;
410   return 0;
411 }
412
413 void generate_filename(const char *pattern, char *out, size_t q_len,
414                        unsigned int d_w, unsigned int d_h,
415                        unsigned int frame_in) {
416   const char *p = pattern;
417   char *q = out;
418
419   do {
420     char *next_pat = strchr(p, '%');
421
422     if (p == next_pat) {
423       size_t pat_len;
424
425       /* parse the pattern */
426       q[q_len - 1] = '\0';
427       switch (p[1]) {
428         case 'w':
429           snprintf(q, q_len - 1, "%d", d_w);
430           break;
431         case 'h':
432           snprintf(q, q_len - 1, "%d", d_h);
433           break;
434         case '1':
435           snprintf(q, q_len - 1, "%d", frame_in);
436           break;
437         case '2':
438           snprintf(q, q_len - 1, "%02d", frame_in);
439           break;
440         case '3':
441           snprintf(q, q_len - 1, "%03d", frame_in);
442           break;
443         case '4':
444           snprintf(q, q_len - 1, "%04d", frame_in);
445           break;
446         case '5':
447           snprintf(q, q_len - 1, "%05d", frame_in);
448           break;
449         case '6':
450           snprintf(q, q_len - 1, "%06d", frame_in);
451           break;
452         case '7':
453           snprintf(q, q_len - 1, "%07d", frame_in);
454           break;
455         case '8':
456           snprintf(q, q_len - 1, "%08d", frame_in);
457           break;
458         case '9':
459           snprintf(q, q_len - 1, "%09d", frame_in);
460           break;
461         default:
462           die("Unrecognized pattern %%%c\n", p[1]);
463           break;
464       }
465
466       pat_len = strlen(q);
467       if (pat_len >= q_len - 1)
468         die("Output filename too long.\n");
469       q += pat_len;
470       p += 2;
471       q_len -= pat_len;
472     } else {
473       size_t copy_len;
474
475       /* copy the next segment */
476       if (!next_pat)
477         copy_len = strlen(p);
478       else
479         copy_len = next_pat - p;
480
481       if (copy_len >= q_len - 1)
482         die("Output filename too long.\n");
483
484       memcpy(q, p, copy_len);
485       q[copy_len] = '\0';
486       q += copy_len;
487       p += copy_len;
488       q_len -= copy_len;
489     }
490   } while (*p);
491 }
492
493 static int is_single_file(const char *outfile_pattern) {
494   const char *p = outfile_pattern;
495
496   do {
497     p = strchr(p, '%');
498     if (p && p[1] >= '1' && p[1] <= '9')
499       return 0;  // pattern contains sequence number, so it's not unique
500     if (p)
501       p++;
502   } while (p);
503
504   return 1;
505 }
506
507 static void print_md5(unsigned char digest[16], const char *filename) {
508   int i;
509
510   for (i = 0; i < 16; ++i)
511     printf("%02x", digest[i]);
512   printf("  %s\n", filename);
513 }
514
515 static FILE *open_outfile(const char *name) {
516   if (strcmp("-", name) == 0) {
517     set_binary_mode(stdout);
518     return stdout;
519   } else {
520     FILE *file = fopen(name, "wb");
521     if (!file)
522       fatal("Failed to open output file '%s'", name);
523     return file;
524   }
525 }
526
527 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
528 static int img_shifted_realloc_required(const vpx_image_t *img,
529                                         const vpx_image_t *shifted,
530                                         vpx_img_fmt_t required_fmt) {
531   return img->d_w != shifted->d_w ||
532          img->d_h != shifted->d_h ||
533          required_fmt != shifted->fmt;
534 }
535 #endif
536
537 int main_loop(int argc, const char **argv_) {
538   vpx_codec_ctx_t       decoder;
539   char                  *fn = NULL;
540   int                    i;
541   uint8_t               *buf = NULL;
542   size_t                 bytes_in_buffer = 0, buffer_size = 0;
543   FILE                  *infile;
544   int                    frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
545   int                    do_md5 = 0, progress = 0;
546   int                    stop_after = 0, postproc = 0, summary = 0, quiet = 1;
547   int                    arg_skip = 0;
548   int                    ec_enabled = 0;
549   int                    keep_going = 0;
550   const VpxInterface *interface = NULL;
551   const VpxInterface *fourcc_interface = NULL;
552   uint64_t dx_time = 0;
553   struct arg               arg;
554   char                   **argv, **argi, **argj;
555
556   int                     single_file;
557   int                     use_y4m = 1;
558   int                     opt_yv12 = 0;
559   int                     opt_i420 = 0;
560   vpx_codec_dec_cfg_t     cfg = {0, 0, 0};
561 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
562   int                     output_bit_depth = 0;
563 #endif
564 #if CONFIG_VP8_DECODER
565   vp8_postproc_cfg_t      vp8_pp_cfg = {0};
566   int                     vp8_dbg_color_ref_frame = 0;
567   int                     vp8_dbg_color_mb_modes = 0;
568   int                     vp8_dbg_color_b_modes = 0;
569   int                     vp8_dbg_display_mv = 0;
570 #endif
571   int                     frames_corrupted = 0;
572   int                     dec_flags = 0;
573   int                     do_scale = 0;
574   vpx_image_t             *scaled_img = NULL;
575 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
576   vpx_image_t             *img_shifted = NULL;
577 #endif
578   int                     frame_avail, got_data;
579   int                     num_external_frame_buffers = 0;
580   struct ExternalFrameBufferList ext_fb_list = {0, NULL};
581
582   const char *outfile_pattern = NULL;
583   char outfile_name[PATH_MAX] = {0};
584   FILE *outfile = NULL;
585
586   MD5Context md5_ctx;
587   unsigned char md5_digest[16];
588
589   struct VpxDecInputContext input = {NULL, NULL};
590   struct VpxInputContext vpx_input_ctx;
591 #if CONFIG_WEBM_IO
592   struct WebmInputContext webm_ctx;
593   memset(&(webm_ctx), 0, sizeof(webm_ctx));
594   input.webm_ctx = &webm_ctx;
595 #endif
596   input.vpx_input_ctx = &vpx_input_ctx;
597
598   /* Parse command line */
599   exec_name = argv_[0];
600   argv = argv_dup(argc - 1, argv_ + 1);
601
602   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
603     memset(&arg, 0, sizeof(arg));
604     arg.argv_step = 1;
605
606     if (arg_match(&arg, &codecarg, argi)) {
607       interface = get_vpx_decoder_by_name(arg.val);
608       if (!interface)
609         die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
610     } else if (arg_match(&arg, &looparg, argi)) {
611       // no-op
612     } else if (arg_match(&arg, &outputfile, argi))
613       outfile_pattern = arg.val;
614     else if (arg_match(&arg, &use_yv12, argi)) {
615       use_y4m = 0;
616       flipuv = 1;
617       opt_yv12 = 1;
618 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
619       output_bit_depth = 8;  // For yv12 8-bit depth output is assumed
620 #endif
621     } else if (arg_match(&arg, &use_i420, argi)) {
622       use_y4m = 0;
623       flipuv = 0;
624       opt_i420 = 1;
625     } else if (arg_match(&arg, &rawvideo, argi)) {
626       use_y4m = 0;
627     } else if (arg_match(&arg, &flipuvarg, argi))
628       flipuv = 1;
629     else if (arg_match(&arg, &noblitarg, argi))
630       noblit = 1;
631     else if (arg_match(&arg, &progressarg, argi))
632       progress = 1;
633     else if (arg_match(&arg, &limitarg, argi))
634       stop_after = arg_parse_uint(&arg);
635     else if (arg_match(&arg, &skiparg, argi))
636       arg_skip = arg_parse_uint(&arg);
637     else if (arg_match(&arg, &postprocarg, argi))
638       postproc = 1;
639     else if (arg_match(&arg, &md5arg, argi))
640       do_md5 = 1;
641     else if (arg_match(&arg, &summaryarg, argi))
642       summary = 1;
643     else if (arg_match(&arg, &threadsarg, argi))
644       cfg.threads = arg_parse_uint(&arg);
645     else if (arg_match(&arg, &verbosearg, argi))
646       quiet = 0;
647     else if (arg_match(&arg, &scalearg, argi))
648       do_scale = 1;
649     else if (arg_match(&arg, &fb_arg, argi))
650       num_external_frame_buffers = arg_parse_uint(&arg);
651     else if (arg_match(&arg, &continuearg, argi))
652       keep_going = 1;
653 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
654     else if (arg_match(&arg, &outbitdeptharg, argi)) {
655       output_bit_depth = arg_parse_uint(&arg);
656     }
657 #endif
658 #if CONFIG_VP8_DECODER
659     else if (arg_match(&arg, &addnoise_level, argi)) {
660       postproc = 1;
661       vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
662       vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
663     } else if (arg_match(&arg, &demacroblock_level, argi)) {
664       postproc = 1;
665       vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
666       vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
667     } else if (arg_match(&arg, &deblock, argi)) {
668       postproc = 1;
669       vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
670     } else if (arg_match(&arg, &mfqe, argi)) {
671       postproc = 1;
672       vp8_pp_cfg.post_proc_flag |= VP8_MFQE;
673     } else if (arg_match(&arg, &pp_debug_info, argi)) {
674       unsigned int level = arg_parse_uint(&arg);
675
676       postproc = 1;
677       vp8_pp_cfg.post_proc_flag &= ~0x7;
678
679       if (level)
680         vp8_pp_cfg.post_proc_flag |= level;
681     } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) {
682       unsigned int flags = arg_parse_int(&arg);
683       if (flags) {
684         postproc = 1;
685         vp8_dbg_color_ref_frame = flags;
686       }
687     } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) {
688       unsigned int flags = arg_parse_int(&arg);
689       if (flags) {
690         postproc = 1;
691         vp8_dbg_color_mb_modes = flags;
692       }
693     } else if (arg_match(&arg, &pp_disp_b_modes, argi)) {
694       unsigned int flags = arg_parse_int(&arg);
695       if (flags) {
696         postproc = 1;
697         vp8_dbg_color_b_modes = flags;
698       }
699     } else if (arg_match(&arg, &pp_disp_mvs, argi)) {
700       unsigned int flags = arg_parse_int(&arg);
701       if (flags) {
702         postproc = 1;
703         vp8_dbg_display_mv = flags;
704       }
705     } else if (arg_match(&arg, &error_concealment, argi)) {
706       ec_enabled = 1;
707     }
708 #endif  // CONFIG_VP8_DECODER
709     else
710       argj++;
711   }
712
713   /* Check for unrecognized options */
714   for (argi = argv; *argi; argi++)
715     if (argi[0][0] == '-' && strlen(argi[0]) > 1)
716       die("Error: Unrecognized option %s\n", *argi);
717
718   /* Handle non-option arguments */
719   fn = argv[0];
720
721   if (!fn) {
722     free(argv);
723     usage_exit();
724   }
725   /* Open file */
726   infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
727
728   if (!infile) {
729     fatal("Failed to open input file '%s'", strcmp(fn, "-") ? fn : "stdin");
730   }
731 #if CONFIG_OS_SUPPORT
732   /* Make sure we don't dump to the terminal, unless forced to with -o - */
733   if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) {
734     fprintf(stderr,
735             "Not dumping raw video to your terminal. Use '-o -' to "
736             "override.\n");
737     return EXIT_FAILURE;
738   }
739 #endif
740   input.vpx_input_ctx->file = infile;
741   if (file_is_ivf(input.vpx_input_ctx))
742     input.vpx_input_ctx->file_type = FILE_TYPE_IVF;
743 #if CONFIG_WEBM_IO
744   else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx))
745     input.vpx_input_ctx->file_type = FILE_TYPE_WEBM;
746 #endif
747   else if (file_is_raw(input.vpx_input_ctx))
748     input.vpx_input_ctx->file_type = FILE_TYPE_RAW;
749   else {
750     fprintf(stderr, "Unrecognized input file type.\n");
751 #if !CONFIG_WEBM_IO
752     fprintf(stderr, "vpxdec was built without WebM container support.\n");
753 #endif
754     return EXIT_FAILURE;
755   }
756
757   outfile_pattern = outfile_pattern ? outfile_pattern : "-";
758   single_file = is_single_file(outfile_pattern);
759
760   if (!noblit && single_file) {
761     generate_filename(outfile_pattern, outfile_name, PATH_MAX,
762                       vpx_input_ctx.width, vpx_input_ctx.height, 0);
763     if (do_md5)
764       MD5Init(&md5_ctx);
765     else
766       outfile = open_outfile(outfile_name);
767   }
768
769   if (use_y4m && !noblit) {
770     if (!single_file) {
771       fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
772               " try --i420 or --yv12 or --rawvideo.\n");
773       return EXIT_FAILURE;
774     }
775
776 #if CONFIG_WEBM_IO
777     if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) {
778       if (webm_guess_framerate(input.webm_ctx, input.vpx_input_ctx)) {
779         fprintf(stderr, "Failed to guess framerate -- error parsing "
780                 "webm file?\n");
781         return EXIT_FAILURE;
782       }
783     }
784 #endif
785   }
786
787   fourcc_interface = get_vpx_decoder_by_fourcc(vpx_input_ctx.fourcc);
788   if (interface && fourcc_interface && interface != fourcc_interface)
789     warn("Header indicates codec: %s\n", fourcc_interface->name);
790   else
791     interface = fourcc_interface;
792
793   if (!interface)
794     interface = get_vpx_decoder_by_index(0);
795
796   dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
797               (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
798   if (vpx_codec_dec_init(&decoder, interface->codec_interface(),
799                          &cfg, dec_flags)) {
800     fprintf(stderr, "Failed to initialize decoder: %s\n",
801             vpx_codec_error(&decoder));
802     return EXIT_FAILURE;
803   }
804
805   if (!quiet)
806     fprintf(stderr, "%s\n", decoder.name);
807
808 #if CONFIG_VP8_DECODER
809
810   if (vp8_pp_cfg.post_proc_flag
811       && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) {
812     fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
813     return EXIT_FAILURE;
814   }
815
816   if (vp8_dbg_color_ref_frame
817       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) {
818     fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder));
819     return EXIT_FAILURE;
820   }
821
822   if (vp8_dbg_color_mb_modes
823       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) {
824     fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder));
825     return EXIT_FAILURE;
826   }
827
828   if (vp8_dbg_color_b_modes
829       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) {
830     fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder));
831     return EXIT_FAILURE;
832   }
833
834   if (vp8_dbg_display_mv
835       && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) {
836     fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder));
837     return EXIT_FAILURE;
838   }
839 #endif
840
841
842   if (arg_skip)
843     fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
844   while (arg_skip) {
845     if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size))
846       break;
847     arg_skip--;
848   }
849
850   if (num_external_frame_buffers > 0) {
851     ext_fb_list.num_external_frame_buffers = num_external_frame_buffers;
852     ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc(
853         num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb));
854     if (vpx_codec_set_frame_buffer_functions(
855             &decoder, get_vp9_frame_buffer, release_vp9_frame_buffer,
856             &ext_fb_list)) {
857       fprintf(stderr, "Failed to configure external frame buffers: %s\n",
858               vpx_codec_error(&decoder));
859       return EXIT_FAILURE;
860     }
861   }
862
863   frame_avail = 1;
864   got_data = 0;
865
866   /* Decode file */
867   while (frame_avail || got_data) {
868     vpx_codec_iter_t  iter = NULL;
869     vpx_image_t    *img;
870     struct vpx_usec_timer timer;
871     int                   corrupted;
872
873     frame_avail = 0;
874     if (!stop_after || frame_in < stop_after) {
875       if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
876         frame_avail = 1;
877         frame_in++;
878
879         vpx_usec_timer_start(&timer);
880
881         if (vpx_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer,
882                              NULL, 0)) {
883           const char *detail = vpx_codec_error_detail(&decoder);
884           warn("Failed to decode frame %d: %s",
885                frame_in, vpx_codec_error(&decoder));
886
887           if (detail)
888             warn("Additional information: %s", detail);
889           if (!keep_going)
890             goto fail;
891         }
892
893         vpx_usec_timer_mark(&timer);
894         dx_time += vpx_usec_timer_elapsed(&timer);
895       }
896     }
897
898     vpx_usec_timer_start(&timer);
899
900     got_data = 0;
901     if ((img = vpx_codec_get_frame(&decoder, &iter))) {
902       ++frame_out;
903       got_data = 1;
904     }
905
906     vpx_usec_timer_mark(&timer);
907     dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
908
909     if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
910       warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder));
911       if (!keep_going)
912         goto fail;
913     }
914     frames_corrupted += corrupted;
915
916     if (progress)
917       show_progress(frame_in, frame_out, dx_time);
918
919     if (!noblit && img) {
920       const int PLANES_YUV[] = {VPX_PLANE_Y, VPX_PLANE_U, VPX_PLANE_V};
921       const int PLANES_YVU[] = {VPX_PLANE_Y, VPX_PLANE_V, VPX_PLANE_U};
922       const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;
923
924       if (do_scale) {
925         if (frame_out == 1) {
926           // If the output frames are to be scaled to a fixed display size then
927           // use the width and height specified in the container. If either of
928           // these is set to 0, use the display size set in the first frame
929           // header. If that is unavailable, use the raw decoded size of the
930           // first decoded frame.
931           int display_width = vpx_input_ctx.width;
932           int display_height = vpx_input_ctx.height;
933           if (!display_width || !display_height) {
934             int display_size[2];
935             if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE,
936                                   display_size)) {
937               // As last resort use size of first frame as display size.
938               display_width = img->d_w;
939               display_height = img->d_h;
940             } else {
941               display_width = display_size[0];
942               display_height = display_size[1];
943             }
944           }
945           scaled_img = vpx_img_alloc(NULL, img->fmt, display_width,
946                                      display_height, 16);
947           scaled_img->bit_depth = img->bit_depth;
948         }
949
950         if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
951 #if CONFIG_LIBYUV
952           libyuv_scale(img, scaled_img, kFilterBox);
953           img = scaled_img;
954 #else
955           fprintf(stderr, "Failed  to scale output frame: %s.\n"
956                   "Scaling is disabled in this configuration. "
957                   "To enable scaling, configure with --enable-libyuv\n",
958                   vpx_codec_error(&decoder));
959           return EXIT_FAILURE;
960 #endif
961         }
962       }
963 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
964       // Default to codec bit depth if output bit depth not set
965       if (!output_bit_depth) {
966         output_bit_depth = img->bit_depth;
967       }
968       // Shift up or down if necessary
969       if (output_bit_depth != img->bit_depth) {
970         const vpx_img_fmt_t shifted_fmt = output_bit_depth == 8 ?
971             img->fmt ^ (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) :
972             img->fmt | VPX_IMG_FMT_HIGHBITDEPTH;
973         if (img_shifted &&
974             img_shifted_realloc_required(img, img_shifted, shifted_fmt)) {
975           vpx_img_free(img_shifted);
976           img_shifted = NULL;
977         }
978         if (!img_shifted) {
979           img_shifted = vpx_img_alloc(NULL, shifted_fmt,
980                                       img->d_w, img->d_h, 16);
981           img_shifted->bit_depth = output_bit_depth;
982         }
983         if (output_bit_depth > img->bit_depth) {
984           vpx_img_upshift(img_shifted, img,
985                           output_bit_depth - img->bit_depth);
986         } else {
987           vpx_img_downshift(img_shifted, img,
988                             img->bit_depth - output_bit_depth);
989         }
990         img = img_shifted;
991       }
992 #endif
993
994       if (single_file) {
995         if (use_y4m) {
996           char buf[Y4M_BUFFER_SIZE] = {0};
997           size_t len = 0;
998           if (img->fmt == VPX_IMG_FMT_I440 || img->fmt == VPX_IMG_FMT_I44016) {
999             fprintf(stderr, "Cannot produce y4m output for 440 sampling.\n");
1000             goto fail;
1001           }
1002           if (frame_out == 1) {
1003             // Y4M file header
1004             len = y4m_write_file_header(buf, sizeof(buf),
1005                                         vpx_input_ctx.width,
1006                                         vpx_input_ctx.height,
1007                                         &vpx_input_ctx.framerate,
1008                                         img->fmt, img->bit_depth);
1009             if (do_md5) {
1010               MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
1011             } else {
1012               fputs(buf, outfile);
1013             }
1014           }
1015
1016           // Y4M frame header
1017           len = y4m_write_frame_header(buf, sizeof(buf));
1018           if (do_md5) {
1019             MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
1020           } else {
1021             fputs(buf, outfile);
1022           }
1023         } else {
1024           if (frame_out == 1) {
1025             // Check if --yv12 or --i420 options are consistent with the
1026             // bit-stream decoded
1027             if (opt_i420) {
1028               if (img->fmt != VPX_IMG_FMT_I420 &&
1029                   img->fmt != VPX_IMG_FMT_I42016) {
1030                 fprintf(stderr, "Cannot produce i420 output for bit-stream.\n");
1031                 goto fail;
1032               }
1033             }
1034             if (opt_yv12) {
1035               if ((img->fmt != VPX_IMG_FMT_I420 &&
1036                    img->fmt != VPX_IMG_FMT_YV12) || img->bit_depth != 8) {
1037                 fprintf(stderr, "Cannot produce yv12 output for bit-stream.\n");
1038                 goto fail;
1039               }
1040             }
1041           }
1042         }
1043
1044         if (do_md5) {
1045           update_image_md5(img, planes, &md5_ctx);
1046         } else {
1047           write_image_file(img, planes, outfile);
1048         }
1049       } else {
1050         generate_filename(outfile_pattern, outfile_name, PATH_MAX,
1051                           img->d_w, img->d_h, frame_in);
1052         if (do_md5) {
1053           MD5Init(&md5_ctx);
1054           update_image_md5(img, planes, &md5_ctx);
1055           MD5Final(md5_digest, &md5_ctx);
1056           print_md5(md5_digest, outfile_name);
1057         } else {
1058           outfile = open_outfile(outfile_name);
1059           write_image_file(img, planes, outfile);
1060           fclose(outfile);
1061         }
1062       }
1063     }
1064
1065     if (stop_after && frame_in >= stop_after)
1066       break;
1067   }
1068
1069   if (summary || progress) {
1070     show_progress(frame_in, frame_out, dx_time);
1071     fprintf(stderr, "\n");
1072   }
1073
1074   if (frames_corrupted)
1075     fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);
1076
1077 fail:
1078
1079   if (vpx_codec_destroy(&decoder)) {
1080     fprintf(stderr, "Failed to destroy decoder: %s\n",
1081             vpx_codec_error(&decoder));
1082     return EXIT_FAILURE;
1083   }
1084
1085   if (!noblit && single_file) {
1086     if (do_md5) {
1087       MD5Final(md5_digest, &md5_ctx);
1088       print_md5(md5_digest, outfile_name);
1089     } else {
1090       fclose(outfile);
1091     }
1092   }
1093
1094 #if CONFIG_WEBM_IO
1095   if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM)
1096     webm_free(input.webm_ctx);
1097 #endif
1098
1099   if (input.vpx_input_ctx->file_type != FILE_TYPE_WEBM)
1100     free(buf);
1101
1102   if (scaled_img) vpx_img_free(scaled_img);
1103 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
1104   if (img_shifted) vpx_img_free(img_shifted);
1105 #endif
1106
1107   for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) {
1108     free(ext_fb_list.ext_fb[i].data);
1109   }
1110   free(ext_fb_list.ext_fb);
1111
1112   fclose(infile);
1113   free(argv);
1114
1115   return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS;
1116 }
1117
1118 int main(int argc, const char **argv_) {
1119   unsigned int loops = 1, i;
1120   char **argv, **argi, **argj;
1121   struct arg arg;
1122   int error = 0;
1123
1124   argv = argv_dup(argc - 1, argv_ + 1);
1125   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
1126     memset(&arg, 0, sizeof(arg));
1127     arg.argv_step = 1;
1128
1129     if (arg_match(&arg, &looparg, argi)) {
1130       loops = arg_parse_uint(&arg);
1131       break;
1132     }
1133   }
1134   free(argv);
1135   for (i = 0; !error && i < loops; i++)
1136     error = main_loop(argc, argv_);
1137   return error;
1138 }