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