Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / third_party / libvpx / source / 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 vpx_image_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     const int h = vpx_img_plane_height(img, plane);
281
282     for (y = 0; y < h; ++y) {
283       MD5Update(md5, buf, w);
284       buf += stride;
285     }
286   }
287 }
288
289 static void write_image_file(const vpx_image_t *img, const int planes[3],
290                              FILE *file) {
291   int i, y;
292 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
293   const int bytes_per_sample = ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) ? 2 : 1);
294 #else
295   const int bytes_per_sample = 1;
296 #endif
297
298   for (i = 0; i < 3; ++i) {
299     const int plane = planes[i];
300     const unsigned char *buf = img->planes[plane];
301     const int stride = img->stride[plane];
302     const int w = vpx_img_plane_width(img, plane);
303     const int h = vpx_img_plane_height(img, plane);
304
305     for (y = 0; y < h; ++y) {
306       fwrite(buf, bytes_per_sample, w, file);
307       buf += stride;
308     }
309   }
310 }
311
312 int file_is_raw(struct VpxInputContext *input) {
313   uint8_t buf[32];
314   int is_raw = 0;
315   vpx_codec_stream_info_t si;
316
317   si.sz = sizeof(si);
318
319   if (fread(buf, 1, 32, input->file) == 32) {
320     int i;
321
322     if (mem_get_le32(buf) < 256 * 1024 * 1024) {
323       for (i = 0; i < get_vpx_decoder_count(); ++i) {
324         const VpxInterface *const decoder = get_vpx_decoder_by_index(i);
325         if (!vpx_codec_peek_stream_info(decoder->codec_interface(),
326                                         buf + 4, 32 - 4, &si)) {
327           is_raw = 1;
328           input->fourcc = decoder->fourcc;
329           input->width = si.w;
330           input->height = si.h;
331           input->framerate.numerator = 30;
332           input->framerate.denominator = 1;
333           break;
334         }
335       }
336     }
337   }
338
339   rewind(input->file);
340   return is_raw;
341 }
342
343 void show_progress(int frame_in, int frame_out, uint64_t dx_time) {
344   fprintf(stderr,
345           "%d decoded frames/%d showed frames in %"PRId64" us (%.2f fps)\r",
346           frame_in, frame_out, dx_time,
347           (double)frame_out * 1000000.0 / (double)dx_time);
348 }
349
350 struct ExternalFrameBuffer {
351   uint8_t* data;
352   size_t size;
353   int in_use;
354 };
355
356 struct ExternalFrameBufferList {
357   int num_external_frame_buffers;
358   struct ExternalFrameBuffer *ext_fb;
359 };
360
361 // Callback used by libvpx to request an external frame buffer. |cb_priv|
362 // Application private data passed into the set function. |min_size| is the
363 // minimum size in bytes needed to decode the next frame. |fb| pointer to the
364 // frame buffer.
365 int get_vp9_frame_buffer(void *cb_priv, size_t min_size,
366                          vpx_codec_frame_buffer_t *fb) {
367   int i;
368   struct ExternalFrameBufferList *const ext_fb_list =
369       (struct ExternalFrameBufferList *)cb_priv;
370   if (ext_fb_list == NULL)
371     return -1;
372
373   // Find a free frame buffer.
374   for (i = 0; i < ext_fb_list->num_external_frame_buffers; ++i) {
375     if (!ext_fb_list->ext_fb[i].in_use)
376       break;
377   }
378
379   if (i == ext_fb_list->num_external_frame_buffers)
380     return -1;
381
382   if (ext_fb_list->ext_fb[i].size < min_size) {
383     free(ext_fb_list->ext_fb[i].data);
384     ext_fb_list->ext_fb[i].data = (uint8_t *)calloc(min_size, sizeof(uint8_t));
385     if (!ext_fb_list->ext_fb[i].data)
386       return -1;
387
388     ext_fb_list->ext_fb[i].size = min_size;
389   }
390
391   fb->data = ext_fb_list->ext_fb[i].data;
392   fb->size = ext_fb_list->ext_fb[i].size;
393   ext_fb_list->ext_fb[i].in_use = 1;
394
395   // Set the frame buffer's private data to point at the external frame buffer.
396   fb->priv = &ext_fb_list->ext_fb[i];
397   return 0;
398 }
399
400 // Callback used by libvpx when there are no references to the frame buffer.
401 // |cb_priv| user private data passed into the set function. |fb| pointer
402 // to the frame buffer.
403 int release_vp9_frame_buffer(void *cb_priv,
404                              vpx_codec_frame_buffer_t *fb) {
405   struct ExternalFrameBuffer *const ext_fb =
406       (struct ExternalFrameBuffer *)fb->priv;
407   (void)cb_priv;
408   ext_fb->in_use = 0;
409   return 0;
410 }
411
412 void generate_filename(const char *pattern, char *out, size_t q_len,
413                        unsigned int d_w, unsigned int d_h,
414                        unsigned int frame_in) {
415   const char *p = pattern;
416   char *q = out;
417
418   do {
419     char *next_pat = strchr(p, '%');
420
421     if (p == next_pat) {
422       size_t pat_len;
423
424       /* parse the pattern */
425       q[q_len - 1] = '\0';
426       switch (p[1]) {
427         case 'w':
428           snprintf(q, q_len - 1, "%d", d_w);
429           break;
430         case 'h':
431           snprintf(q, q_len - 1, "%d", d_h);
432           break;
433         case '1':
434           snprintf(q, q_len - 1, "%d", frame_in);
435           break;
436         case '2':
437           snprintf(q, q_len - 1, "%02d", frame_in);
438           break;
439         case '3':
440           snprintf(q, q_len - 1, "%03d", frame_in);
441           break;
442         case '4':
443           snprintf(q, q_len - 1, "%04d", frame_in);
444           break;
445         case '5':
446           snprintf(q, q_len - 1, "%05d", frame_in);
447           break;
448         case '6':
449           snprintf(q, q_len - 1, "%06d", frame_in);
450           break;
451         case '7':
452           snprintf(q, q_len - 1, "%07d", frame_in);
453           break;
454         case '8':
455           snprintf(q, q_len - 1, "%08d", frame_in);
456           break;
457         case '9':
458           snprintf(q, q_len - 1, "%09d", frame_in);
459           break;
460         default:
461           die("Unrecognized pattern %%%c\n", p[1]);
462           break;
463       }
464
465       pat_len = strlen(q);
466       if (pat_len >= q_len - 1)
467         die("Output filename too long.\n");
468       q += pat_len;
469       p += 2;
470       q_len -= pat_len;
471     } else {
472       size_t copy_len;
473
474       /* copy the next segment */
475       if (!next_pat)
476         copy_len = strlen(p);
477       else
478         copy_len = next_pat - p;
479
480       if (copy_len >= q_len - 1)
481         die("Output filename too long.\n");
482
483       memcpy(q, p, copy_len);
484       q[copy_len] = '\0';
485       q += copy_len;
486       p += copy_len;
487       q_len -= copy_len;
488     }
489   } while (*p);
490 }
491
492 static int is_single_file(const char *outfile_pattern) {
493   const char *p = outfile_pattern;
494
495   do {
496     p = strchr(p, '%');
497     if (p && p[1] >= '1' && p[1] <= '9')
498       return 0;  // pattern contains sequence number, so it's not unique
499     if (p)
500       p++;
501   } while (p);
502
503   return 1;
504 }
505
506 static void print_md5(unsigned char digest[16], const char *filename) {
507   int i;
508
509   for (i = 0; i < 16; ++i)
510     printf("%02x", digest[i]);
511   printf("  %s\n", filename);
512 }
513
514 static FILE *open_outfile(const char *name) {
515   if (strcmp("-", name) == 0) {
516     set_binary_mode(stdout);
517     return stdout;
518   } else {
519     FILE *file = fopen(name, "wb");
520     if (!file)
521       fatal("Failed to output file %s", name);
522     return file;
523   }
524 }
525
526 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
527 static int img_shifted_realloc_required(const vpx_image_t *img,
528                                         const vpx_image_t *shifted,
529                                         vpx_img_fmt_t required_fmt) {
530   return img->d_w != shifted->d_w ||
531          img->d_h != shifted->d_h ||
532          required_fmt != shifted->fmt;
533 }
534 #endif
535
536 int main_loop(int argc, const char **argv_) {
537   vpx_codec_ctx_t       decoder;
538   char                  *fn = NULL;
539   int                    i;
540   uint8_t               *buf = NULL;
541   size_t                 bytes_in_buffer = 0, buffer_size = 0;
542   FILE                  *infile;
543   int                    frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0;
544   int                    do_md5 = 0, progress = 0;
545   int                    stop_after = 0, postproc = 0, summary = 0, quiet = 1;
546   int                    arg_skip = 0;
547   int                    ec_enabled = 0;
548   int                    keep_going = 0;
549   const VpxInterface *interface = NULL;
550   const VpxInterface *fourcc_interface = NULL;
551   uint64_t dx_time = 0;
552   struct arg               arg;
553   char                   **argv, **argi, **argj;
554
555   int                     single_file;
556   int                     use_y4m = 1;
557   int                     opt_yv12 = 0;
558   int                     opt_i420 = 0;
559   vpx_codec_dec_cfg_t     cfg = {0, 0, 0};
560 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
561   int                     output_bit_depth = 0;
562 #endif
563 #if CONFIG_VP8_DECODER
564   vp8_postproc_cfg_t      vp8_pp_cfg = {0};
565   int                     vp8_dbg_color_ref_frame = 0;
566   int                     vp8_dbg_color_mb_modes = 0;
567   int                     vp8_dbg_color_b_modes = 0;
568   int                     vp8_dbg_display_mv = 0;
569 #endif
570   int                     frames_corrupted = 0;
571   int                     dec_flags = 0;
572   int                     do_scale = 0;
573   vpx_image_t             *scaled_img = NULL;
574 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
575   vpx_image_t             *img_shifted = NULL;
576 #endif
577   int                     frame_avail, got_data;
578   int                     num_external_frame_buffers = 0;
579   struct ExternalFrameBufferList ext_fb_list = {0, NULL};
580
581   const char *outfile_pattern = NULL;
582   char outfile_name[PATH_MAX] = {0};
583   FILE *outfile = NULL;
584
585   MD5Context md5_ctx;
586   unsigned char md5_digest[16];
587
588   struct VpxDecInputContext input = {NULL, NULL};
589   struct VpxInputContext vpx_input_ctx;
590 #if CONFIG_WEBM_IO
591   struct WebmInputContext webm_ctx;
592   memset(&(webm_ctx), 0, sizeof(webm_ctx));
593   input.webm_ctx = &webm_ctx;
594 #endif
595   input.vpx_input_ctx = &vpx_input_ctx;
596
597   /* Parse command line */
598   exec_name = argv_[0];
599   argv = argv_dup(argc - 1, argv_ + 1);
600
601   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
602     memset(&arg, 0, sizeof(arg));
603     arg.argv_step = 1;
604
605     if (arg_match(&arg, &codecarg, argi)) {
606       interface = get_vpx_decoder_by_name(arg.val);
607       if (!interface)
608         die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
609     } else if (arg_match(&arg, &looparg, argi)) {
610       // no-op
611     } else if (arg_match(&arg, &outputfile, argi))
612       outfile_pattern = arg.val;
613     else if (arg_match(&arg, &use_yv12, argi)) {
614       use_y4m = 0;
615       flipuv = 1;
616       opt_yv12 = 1;
617 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
618       output_bit_depth = 8;  // For yv12 8-bit depth output is assumed
619 #endif
620     } else if (arg_match(&arg, &use_i420, argi)) {
621       use_y4m = 0;
622       flipuv = 0;
623       opt_i420 = 1;
624     } else if (arg_match(&arg, &rawvideo, argi)) {
625       use_y4m = 0;
626     } else if (arg_match(&arg, &flipuvarg, argi))
627       flipuv = 1;
628     else if (arg_match(&arg, &noblitarg, argi))
629       noblit = 1;
630     else if (arg_match(&arg, &progressarg, argi))
631       progress = 1;
632     else if (arg_match(&arg, &limitarg, argi))
633       stop_after = arg_parse_uint(&arg);
634     else if (arg_match(&arg, &skiparg, argi))
635       arg_skip = arg_parse_uint(&arg);
636     else if (arg_match(&arg, &postprocarg, argi))
637       postproc = 1;
638     else if (arg_match(&arg, &md5arg, argi))
639       do_md5 = 1;
640     else if (arg_match(&arg, &summaryarg, argi))
641       summary = 1;
642     else if (arg_match(&arg, &threadsarg, argi))
643       cfg.threads = arg_parse_uint(&arg);
644     else if (arg_match(&arg, &verbosearg, argi))
645       quiet = 0;
646     else if (arg_match(&arg, &scalearg, argi))
647       do_scale = 1;
648     else if (arg_match(&arg, &fb_arg, argi))
649       num_external_frame_buffers = arg_parse_uint(&arg);
650     else if (arg_match(&arg, &continuearg, argi))
651       keep_going = 1;
652 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
653     else if (arg_match(&arg, &outbitdeptharg, argi)) {
654       output_bit_depth = arg_parse_uint(&arg);
655     }
656 #endif
657 #if CONFIG_VP8_DECODER
658     else if (arg_match(&arg, &addnoise_level, argi)) {
659       postproc = 1;
660       vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
661       vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
662     } else if (arg_match(&arg, &demacroblock_level, argi)) {
663       postproc = 1;
664       vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
665       vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
666     } else if (arg_match(&arg, &deblock, argi)) {
667       postproc = 1;
668       vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
669     } else if (arg_match(&arg, &mfqe, argi)) {
670       postproc = 1;
671       vp8_pp_cfg.post_proc_flag |= VP8_MFQE;
672     } else if (arg_match(&arg, &pp_debug_info, argi)) {
673       unsigned int level = arg_parse_uint(&arg);
674
675       postproc = 1;
676       vp8_pp_cfg.post_proc_flag &= ~0x7;
677
678       if (level)
679         vp8_pp_cfg.post_proc_flag |= level;
680     } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) {
681       unsigned int flags = arg_parse_int(&arg);
682       if (flags) {
683         postproc = 1;
684         vp8_dbg_color_ref_frame = flags;
685       }
686     } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) {
687       unsigned int flags = arg_parse_int(&arg);
688       if (flags) {
689         postproc = 1;
690         vp8_dbg_color_mb_modes = flags;
691       }
692     } else if (arg_match(&arg, &pp_disp_b_modes, argi)) {
693       unsigned int flags = arg_parse_int(&arg);
694       if (flags) {
695         postproc = 1;
696         vp8_dbg_color_b_modes = flags;
697       }
698     } else if (arg_match(&arg, &pp_disp_mvs, argi)) {
699       unsigned int flags = arg_parse_int(&arg);
700       if (flags) {
701         postproc = 1;
702         vp8_dbg_display_mv = flags;
703       }
704     } else if (arg_match(&arg, &error_concealment, argi)) {
705       ec_enabled = 1;
706     }
707 #endif  // CONFIG_VP8_DECODER
708     else
709       argj++;
710   }
711
712   /* Check for unrecognized options */
713   for (argi = argv; *argi; argi++)
714     if (argi[0][0] == '-' && strlen(argi[0]) > 1)
715       die("Error: Unrecognized option %s\n", *argi);
716
717   /* Handle non-option arguments */
718   fn = argv[0];
719
720   if (!fn)
721     usage_exit();
722
723   /* Open file */
724   infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
725
726   if (!infile) {
727     fprintf(stderr, "Failed to open file '%s'", strcmp(fn, "-") ? fn : "stdin");
728     return EXIT_FAILURE;
729   }
730 #if CONFIG_OS_SUPPORT
731   /* Make sure we don't dump to the terminal, unless forced to with -o - */
732   if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) {
733     fprintf(stderr,
734             "Not dumping raw video to your terminal. Use '-o -' to "
735             "override.\n");
736     return EXIT_FAILURE;
737   }
738 #endif
739   input.vpx_input_ctx->file = infile;
740   if (file_is_ivf(input.vpx_input_ctx))
741     input.vpx_input_ctx->file_type = FILE_TYPE_IVF;
742 #if CONFIG_WEBM_IO
743   else if (file_is_webm(input.webm_ctx, input.vpx_input_ctx))
744     input.vpx_input_ctx->file_type = FILE_TYPE_WEBM;
745 #endif
746   else if (file_is_raw(input.vpx_input_ctx))
747     input.vpx_input_ctx->file_type = FILE_TYPE_RAW;
748   else {
749     fprintf(stderr, "Unrecognized input file type.\n");
750 #if !CONFIG_WEBM_IO
751     fprintf(stderr, "vpxdec was built without WebM container support.\n");
752 #endif
753     return EXIT_FAILURE;
754   }
755
756   outfile_pattern = outfile_pattern ? outfile_pattern : "-";
757   single_file = is_single_file(outfile_pattern);
758
759   if (!noblit && single_file) {
760     generate_filename(outfile_pattern, outfile_name, PATH_MAX,
761                       vpx_input_ctx.width, vpx_input_ctx.height, 0);
762     if (do_md5)
763       MD5Init(&md5_ctx);
764     else
765       outfile = open_outfile(outfile_name);
766   }
767
768   if (use_y4m && !noblit) {
769     if (!single_file) {
770       fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
771               " try --i420 or --yv12 or --rawvideo.\n");
772       return EXIT_FAILURE;
773     }
774
775 #if CONFIG_WEBM_IO
776     if (vpx_input_ctx.file_type == FILE_TYPE_WEBM) {
777       if (webm_guess_framerate(input.webm_ctx, input.vpx_input_ctx)) {
778         fprintf(stderr, "Failed to guess framerate -- error parsing "
779                 "webm file?\n");
780         return EXIT_FAILURE;
781       }
782     }
783 #endif
784   }
785
786   fourcc_interface = get_vpx_decoder_by_fourcc(vpx_input_ctx.fourcc);
787   if (interface && fourcc_interface && interface != fourcc_interface)
788     warn("Header indicates codec: %s\n", fourcc_interface->name);
789   else
790     interface = fourcc_interface;
791
792   if (!interface)
793     interface = get_vpx_decoder_by_index(0);
794
795   dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
796               (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
797   if (vpx_codec_dec_init(&decoder, interface->codec_interface(),
798                          &cfg, dec_flags)) {
799     fprintf(stderr, "Failed to initialize decoder: %s\n",
800             vpx_codec_error(&decoder));
801     return EXIT_FAILURE;
802   }
803
804   if (!quiet)
805     fprintf(stderr, "%s\n", decoder.name);
806
807 #if CONFIG_VP8_DECODER
808
809   if (vp8_pp_cfg.post_proc_flag
810       && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) {
811     fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
812     return EXIT_FAILURE;
813   }
814
815   if (vp8_dbg_color_ref_frame
816       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) {
817     fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder));
818     return EXIT_FAILURE;
819   }
820
821   if (vp8_dbg_color_mb_modes
822       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) {
823     fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder));
824     return EXIT_FAILURE;
825   }
826
827   if (vp8_dbg_color_b_modes
828       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) {
829     fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder));
830     return EXIT_FAILURE;
831   }
832
833   if (vp8_dbg_display_mv
834       && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) {
835     fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder));
836     return EXIT_FAILURE;
837   }
838 #endif
839
840
841   if (arg_skip)
842     fprintf(stderr, "Skipping first %d frames.\n", arg_skip);
843   while (arg_skip) {
844     if (read_frame(&input, &buf, &bytes_in_buffer, &buffer_size))
845       break;
846     arg_skip--;
847   }
848
849   if (num_external_frame_buffers > 0) {
850     ext_fb_list.num_external_frame_buffers = num_external_frame_buffers;
851     ext_fb_list.ext_fb = (struct ExternalFrameBuffer *)calloc(
852         num_external_frame_buffers, sizeof(*ext_fb_list.ext_fb));
853     if (vpx_codec_set_frame_buffer_functions(
854             &decoder, get_vp9_frame_buffer, release_vp9_frame_buffer,
855             &ext_fb_list)) {
856       fprintf(stderr, "Failed to configure external frame buffers: %s\n",
857               vpx_codec_error(&decoder));
858       return EXIT_FAILURE;
859     }
860   }
861
862   frame_avail = 1;
863   got_data = 0;
864
865   /* Decode file */
866   while (frame_avail || got_data) {
867     vpx_codec_iter_t  iter = NULL;
868     vpx_image_t    *img;
869     struct vpx_usec_timer timer;
870     int                   corrupted;
871
872     frame_avail = 0;
873     if (!stop_after || frame_in < stop_after) {
874       if (!read_frame(&input, &buf, &bytes_in_buffer, &buffer_size)) {
875         frame_avail = 1;
876         frame_in++;
877
878         vpx_usec_timer_start(&timer);
879
880         if (vpx_codec_decode(&decoder, buf, (unsigned int)bytes_in_buffer,
881                              NULL, 0)) {
882           const char *detail = vpx_codec_error_detail(&decoder);
883           warn("Failed to decode frame %d: %s",
884                frame_in, vpx_codec_error(&decoder));
885
886           if (detail)
887             warn("Additional information: %s", detail);
888           if (!keep_going)
889             goto fail;
890         }
891
892         vpx_usec_timer_mark(&timer);
893         dx_time += vpx_usec_timer_elapsed(&timer);
894       }
895     }
896
897     vpx_usec_timer_start(&timer);
898
899     got_data = 0;
900     if ((img = vpx_codec_get_frame(&decoder, &iter))) {
901       ++frame_out;
902       got_data = 1;
903     }
904
905     vpx_usec_timer_mark(&timer);
906     dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
907
908     if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
909       warn("Failed VP8_GET_FRAME_CORRUPTED: %s", vpx_codec_error(&decoder));
910       goto fail;
911     }
912     frames_corrupted += corrupted;
913
914     if (progress)
915       show_progress(frame_in, frame_out, dx_time);
916
917     if (!noblit && img) {
918       const int PLANES_YUV[] = {VPX_PLANE_Y, VPX_PLANE_U, VPX_PLANE_V};
919       const int PLANES_YVU[] = {VPX_PLANE_Y, VPX_PLANE_V, VPX_PLANE_U};
920       const int *planes = flipuv ? PLANES_YVU : PLANES_YUV;
921
922       if (do_scale) {
923         if (frame_out == 1) {
924           // If the output frames are to be scaled to a fixed display size then
925           // use the width and height specified in the container. If either of
926           // these is set to 0, use the display size set in the first frame
927           // header. If that is unavailable, use the raw decoded size of the
928           // first decoded frame.
929           int display_width = vpx_input_ctx.width;
930           int display_height = vpx_input_ctx.height;
931           if (!display_width || !display_height) {
932             int display_size[2];
933             if (vpx_codec_control(&decoder, VP9D_GET_DISPLAY_SIZE,
934                                   display_size)) {
935               // As last resort use size of first frame as display size.
936               display_width = img->d_w;
937               display_height = img->d_h;
938             } else {
939               display_width = display_size[0];
940               display_height = display_size[1];
941             }
942           }
943           scaled_img = vpx_img_alloc(NULL, img->fmt, display_width,
944                                      display_height, 16);
945           scaled_img->bit_depth = img->bit_depth;
946         }
947
948         if (img->d_w != scaled_img->d_w || img->d_h != scaled_img->d_h) {
949 #if CONFIG_LIBYUV
950           vpx_image_scale(img, scaled_img, kFilterBox);
951           img = scaled_img;
952 #else
953           fprintf(stderr, "Failed  to scale output frame: %s.\n"
954                   "Scaling is disabled in this configuration. "
955                   "To enable scaling, configure with --enable-libyuv\n",
956                   vpx_codec_error(&decoder));
957           return EXIT_FAILURE;
958 #endif
959         }
960       }
961 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
962       // Default to codec bit depth if output bit depth not set
963       if (!output_bit_depth) {
964         output_bit_depth = img->bit_depth;
965       }
966       // Shift up or down if necessary
967       if (output_bit_depth != img->bit_depth) {
968         const vpx_img_fmt_t shifted_fmt = output_bit_depth == 8 ?
969             img->fmt ^ (img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) :
970             img->fmt | VPX_IMG_FMT_HIGHBITDEPTH;
971         if (img_shifted &&
972             img_shifted_realloc_required(img, img_shifted, shifted_fmt)) {
973           vpx_img_free(img_shifted);
974           img_shifted = NULL;
975         }
976         if (!img_shifted) {
977           img_shifted = vpx_img_alloc(NULL, shifted_fmt,
978                                       img->d_w, img->d_h, 16);
979           img_shifted->bit_depth = output_bit_depth;
980         }
981         if (output_bit_depth > img->bit_depth) {
982           vpx_img_upshift(img_shifted, img,
983                           output_bit_depth - img->bit_depth);
984         } else {
985           vpx_img_downshift(img_shifted, img,
986                             img->bit_depth - output_bit_depth);
987         }
988         img = img_shifted;
989       }
990 #endif
991
992       if (single_file) {
993         if (use_y4m) {
994           char buf[Y4M_BUFFER_SIZE] = {0};
995           size_t len = 0;
996           if (img->fmt == VPX_IMG_FMT_I440 || img->fmt == VPX_IMG_FMT_I44016) {
997             fprintf(stderr, "Cannot produce y4m output for 440 sampling.\n");
998             goto fail;
999           }
1000           if (frame_out == 1) {
1001             // Y4M file header
1002             len = y4m_write_file_header(buf, sizeof(buf),
1003                                         vpx_input_ctx.width,
1004                                         vpx_input_ctx.height,
1005                                         &vpx_input_ctx.framerate,
1006                                         img->fmt, img->bit_depth);
1007             if (do_md5) {
1008               MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
1009             } else {
1010               fputs(buf, outfile);
1011             }
1012           }
1013
1014           // Y4M frame header
1015           len = y4m_write_frame_header(buf, sizeof(buf));
1016           if (do_md5) {
1017             MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
1018           } else {
1019             fputs(buf, outfile);
1020           }
1021         } else {
1022           if (frame_out == 1) {
1023             // Check if --yv12 or --i420 options are consistent with the
1024             // bit-stream decoded
1025             if (opt_i420) {
1026               if (img->fmt != VPX_IMG_FMT_I420 &&
1027                   img->fmt != VPX_IMG_FMT_I42016) {
1028                 fprintf(stderr, "Cannot produce i420 output for bit-stream.\n");
1029                 goto fail;
1030               }
1031             }
1032             if (opt_yv12) {
1033               if ((img->fmt != VPX_IMG_FMT_I420 &&
1034                    img->fmt != VPX_IMG_FMT_YV12) || img->bit_depth != 8) {
1035                 fprintf(stderr, "Cannot produce yv12 output for bit-stream.\n");
1036                 goto fail;
1037               }
1038             }
1039           }
1040         }
1041
1042         if (do_md5) {
1043           update_image_md5(img, planes, &md5_ctx);
1044         } else {
1045           write_image_file(img, planes, outfile);
1046         }
1047       } else {
1048         generate_filename(outfile_pattern, outfile_name, PATH_MAX,
1049                           img->d_w, img->d_h, frame_in);
1050         if (do_md5) {
1051           MD5Init(&md5_ctx);
1052           update_image_md5(img, planes, &md5_ctx);
1053           MD5Final(md5_digest, &md5_ctx);
1054           print_md5(md5_digest, outfile_name);
1055         } else {
1056           outfile = open_outfile(outfile_name);
1057           write_image_file(img, planes, outfile);
1058           fclose(outfile);
1059         }
1060       }
1061     }
1062
1063     if (stop_after && frame_in >= stop_after)
1064       break;
1065   }
1066
1067   if (summary || progress) {
1068     show_progress(frame_in, frame_out, dx_time);
1069     fprintf(stderr, "\n");
1070   }
1071
1072   if (frames_corrupted)
1073     fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);
1074
1075 fail:
1076
1077   if (vpx_codec_destroy(&decoder)) {
1078     fprintf(stderr, "Failed to destroy decoder: %s\n",
1079             vpx_codec_error(&decoder));
1080     return EXIT_FAILURE;
1081   }
1082
1083   if (!noblit && single_file) {
1084     if (do_md5) {
1085       MD5Final(md5_digest, &md5_ctx);
1086       print_md5(md5_digest, outfile_name);
1087     } else {
1088       fclose(outfile);
1089     }
1090   }
1091
1092 #if CONFIG_WEBM_IO
1093   if (input.vpx_input_ctx->file_type == FILE_TYPE_WEBM)
1094     webm_free(input.webm_ctx);
1095 #endif
1096
1097   if (input.vpx_input_ctx->file_type != FILE_TYPE_WEBM)
1098     free(buf);
1099
1100   if (scaled_img) vpx_img_free(scaled_img);
1101 #if CONFIG_VP9 && CONFIG_VP9_HIGHBITDEPTH
1102   if (img_shifted) vpx_img_free(img_shifted);
1103 #endif
1104
1105   for (i = 0; i < ext_fb_list.num_external_frame_buffers; ++i) {
1106     free(ext_fb_list.ext_fb[i].data);
1107   }
1108   free(ext_fb_list.ext_fb);
1109
1110   fclose(infile);
1111   free(argv);
1112
1113   return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS;
1114 }
1115
1116 int main(int argc, const char **argv_) {
1117   unsigned int loops = 1, i;
1118   char **argv, **argi, **argj;
1119   struct arg arg;
1120   int error = 0;
1121
1122   argv = argv_dup(argc - 1, argv_ + 1);
1123   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
1124     memset(&arg, 0, sizeof(arg));
1125     arg.argv_step = 1;
1126
1127     if (arg_match(&arg, &looparg, argi)) {
1128       loops = arg_parse_uint(&arg);
1129       break;
1130     }
1131   }
1132   free(argv);
1133   for (i = 0; !error && i < loops; i++)
1134     error = main_loop(argc, argv_);
1135   return error;
1136 }