Rough merge of master into experimental
[platform/upstream/libvpx.git] / 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
12 /* This is a simple program that reads ivf files and decodes them
13  * using the new interface. Decoded frames are output as YV12 raw.
14  */
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <stdarg.h>
18 #include <string.h>
19 #include <limits.h>
20
21 #define VPX_CODEC_DISABLE_COMPAT 1
22 #include "vpx_config.h"
23 #include "vpx/vpx_decoder.h"
24 #include "vpx_ports/vpx_timer.h"
25 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
26 #include "vpx/vp8dx.h"
27 #endif
28 #if CONFIG_MD5
29 #include "md5_utils.h"
30 #endif
31 #include "tools_common.h"
32 #include "nestegg/include/nestegg/nestegg.h"
33
34 #if CONFIG_OS_SUPPORT
35 #if defined(_MSC_VER)
36 #include <io.h>
37 #define snprintf _snprintf
38 #define isatty   _isatty
39 #define fileno   _fileno
40 #else
41 #include <unistd.h>
42 #endif
43 #endif
44
45 #ifndef PATH_MAX
46 #define PATH_MAX 256
47 #endif
48
49 static const char *exec_name;
50
51 #define VP8_FOURCC (0x00385056)
52 static const struct {
53   char const *name;
54   const vpx_codec_iface_t *(*iface)(void);
55   unsigned int             fourcc;
56   unsigned int             fourcc_mask;
57 } ifaces[] = {
58 #if CONFIG_VP8_DECODER
59   {"vp8",  vpx_codec_vp8_dx,   VP8_FOURCC, 0x00FFFFFF},
60 #endif
61 #if CONFIG_VP9_DECODER
62   {"vp9",  vpx_codec_vp8_dx,   VP8_FOURCC, 0x00FFFFFF},
63 #endif
64 };
65
66 #include "args.h"
67 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
68                                           "Codec to use");
69 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
70                                           "Output raw YV12 frames");
71 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
72                                           "Output raw I420 frames");
73 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0,
74                                            "Flip the chroma planes in the output");
75 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0,
76                                            "Don't process the decoded frames");
77 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0,
78                                              "Show progress after each frame decodes");
79 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1,
80                                           "Stop decoding after n frames");
81 static const arg_def_t skiparg = ARG_DEF(NULL, "skip", 1,
82                                          "Skip the first n input frames");
83 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0,
84                                              "Postprocess decoded frames");
85 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0,
86                                             "Show timing summary");
87 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
88                                             "Output file name pattern (see below)");
89 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1,
90                                             "Max threads to use");
91 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0,
92                                             "Show version string");
93 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0,
94                                                    "Enable decoder error-concealment");
95
96
97 #if CONFIG_MD5
98 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0,
99                                         "Compute the MD5 sum of the decoded frame");
100 #endif
101 static const arg_def_t *all_args[] = {
102   &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg,
103   &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile,
104   &threadsarg, &verbosearg,
105 #if CONFIG_MD5
106   &md5arg,
107 #endif
108   &error_concealment,
109   NULL
110 };
111
112 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
113 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1,
114                                                 "Enable VP8 postproc add noise");
115 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0,
116                                          "Enable VP8 deblocking");
117 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1,
118                                                     "Enable VP8 demacroblocking, w/ level");
119 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1,
120                                                "Enable VP8 visible debug info");
121 static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1,
122                                                    "Display only selected reference frame per macro block");
123 static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1,
124                                                   "Display only selected macro block modes");
125 static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1,
126                                                  "Display only selected block modes");
127 static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1,
128                                              "Draw only selected motion vectors");
129 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0,
130                                       "Enable multiframe quality enhancement");
131
132 static const arg_def_t *vp8_pp_args[] = {
133   &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info,
134   &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe,
135   NULL
136 };
137 #endif
138
139 static void usage_exit() {
140   int i;
141
142   fprintf(stderr, "Usage: %s <options> filename\n\n"
143           "Options:\n", exec_name);
144   arg_show_usage(stderr, all_args);
145 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
146   fprintf(stderr, "\nVP8 Postprocessing Options:\n");
147   arg_show_usage(stderr, vp8_pp_args);
148 #endif
149   fprintf(stderr,
150           "\nOutput File Patterns:\n\n"
151           "  The -o argument specifies the name of the file(s) to "
152           "write to. If the\n  argument does not include any escape "
153           "characters, the output will be\n  written to a single file. "
154           "Otherwise, the filename will be calculated by\n  expanding "
155           "the following escape characters:\n");
156   fprintf(stderr,
157           "\n\t%%w   - Frame width"
158           "\n\t%%h   - Frame height"
159           "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)"
160           "\n\n  Pattern arguments are only supported in conjunction "
161           "with the --yv12 and\n  --i420 options. If the -o option is "
162           "not specified, the output will be\n  directed to stdout.\n"
163          );
164   fprintf(stderr, "\nIncluded decoders:\n\n");
165
166   for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
167     fprintf(stderr, "    %-6s - %s\n",
168             ifaces[i].name,
169             vpx_codec_iface_name(ifaces[i].iface()));
170
171   exit(EXIT_FAILURE);
172 }
173
174 void die(const char *fmt, ...) {
175   va_list ap;
176   va_start(ap, fmt);
177   vfprintf(stderr, fmt, ap);
178   fprintf(stderr, "\n");
179   usage_exit();
180 }
181
182 static unsigned int mem_get_le16(const void *vmem) {
183   unsigned int  val;
184   const unsigned char *mem = (const unsigned char *)vmem;
185
186   val = mem[1] << 8;
187   val |= mem[0];
188   return val;
189 }
190
191 static unsigned int mem_get_le32(const void *vmem) {
192   unsigned int  val;
193   const unsigned char *mem = (const unsigned char *)vmem;
194
195   val = mem[3] << 24;
196   val |= mem[2] << 16;
197   val |= mem[1] << 8;
198   val |= mem[0];
199   return val;
200 }
201
202 enum file_kind {
203   RAW_FILE,
204   IVF_FILE,
205   WEBM_FILE
206 };
207
208 struct input_ctx {
209   enum file_kind  kind;
210   FILE           *infile;
211   nestegg        *nestegg_ctx;
212   nestegg_packet *pkt;
213   unsigned int    chunk;
214   unsigned int    chunks;
215   unsigned int    video_track;
216 };
217
218 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t))
219 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t))
220 static int read_frame(struct input_ctx      *input,
221                       uint8_t               **buf,
222                       size_t                *buf_sz,
223                       size_t                *buf_alloc_sz) {
224   char            raw_hdr[IVF_FRAME_HDR_SZ];
225   size_t          new_buf_sz;
226   FILE           *infile = input->infile;
227   enum file_kind  kind = input->kind;
228   if (kind == WEBM_FILE) {
229     if (input->chunk >= input->chunks) {
230       unsigned int track;
231
232       do {
233         /* End of this packet, get another. */
234         if (input->pkt)
235           nestegg_free_packet(input->pkt);
236
237         if (nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0
238             || nestegg_packet_track(input->pkt, &track))
239           return 1;
240
241       } while (track != input->video_track);
242
243       if (nestegg_packet_count(input->pkt, &input->chunks))
244         return 1;
245       input->chunk = 0;
246     }
247
248     if (nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz))
249       return 1;
250     input->chunk++;
251
252     return 0;
253   }
254   /* For both the raw and ivf formats, the frame size is the first 4 bytes
255    * of the frame header. We just need to special case on the header
256    * size.
257    */
258   else if (fread(raw_hdr, kind == IVF_FILE
259                  ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) {
260     if (!feof(infile))
261       fprintf(stderr, "Failed to read frame size\n");
262
263     new_buf_sz = 0;
264   } else {
265     new_buf_sz = mem_get_le32(raw_hdr);
266
267     if (new_buf_sz > 256 * 1024 * 1024) {
268       fprintf(stderr, "Error: Read invalid frame size (%u)\n",
269               (unsigned int)new_buf_sz);
270       new_buf_sz = 0;
271     }
272
273     if (kind == RAW_FILE && new_buf_sz > 256 * 1024)
274       fprintf(stderr, "Warning: Read invalid frame size (%u)"
275               " - not a raw file?\n", (unsigned int)new_buf_sz);
276
277     if (new_buf_sz > *buf_alloc_sz) {
278       uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz);
279
280       if (new_buf) {
281         *buf = new_buf;
282         *buf_alloc_sz = 2 * new_buf_sz;
283       } else {
284         fprintf(stderr, "Failed to allocate compressed data buffer\n");
285         new_buf_sz = 0;
286       }
287     }
288   }
289
290   *buf_sz = new_buf_sz;
291
292   if (!feof(infile)) {
293     if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) {
294       fprintf(stderr, "Failed to read full frame\n");
295       return 1;
296     }
297
298     return 0;
299   }
300
301   return 1;
302 }
303
304 void *out_open(const char *out_fn, int do_md5) {
305   void *out = NULL;
306
307   if (do_md5) {
308 #if CONFIG_MD5
309     MD5Context *md5_ctx = out = malloc(sizeof(MD5Context));
310     (void)out_fn;
311     MD5Init(md5_ctx);
312 #endif
313   } else {
314     FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb")
315                           : set_binary_mode(stdout);
316
317     if (!outfile) {
318       fprintf(stderr, "Failed to output file");
319       exit(EXIT_FAILURE);
320     }
321   }
322
323   return out;
324 }
325
326 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) {
327   if (do_md5) {
328 #if CONFIG_MD5
329     MD5Update(out, buf, len);
330 #endif
331   } else {
332     (void) fwrite(buf, 1, len, out);
333   }
334 }
335
336 void out_close(void *out, const char *out_fn, int do_md5) {
337   if (do_md5) {
338 #if CONFIG_MD5
339     uint8_t md5[16];
340     int i;
341
342     MD5Final(md5, out);
343     free(out);
344
345     for (i = 0; i < 16; i++)
346       printf("%02x", md5[i]);
347
348     printf("  %s\n", out_fn);
349 #endif
350   } else {
351     fclose(out);
352   }
353 }
354
355 unsigned int file_is_ivf(FILE *infile,
356                          unsigned int *fourcc,
357                          unsigned int *width,
358                          unsigned int *height,
359                          unsigned int *fps_den,
360                          unsigned int *fps_num) {
361   char raw_hdr[32];
362   int is_ivf = 0;
363
364   if (fread(raw_hdr, 1, 32, infile) == 32) {
365     if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K'
366         && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') {
367       is_ivf = 1;
368
369       if (mem_get_le16(raw_hdr + 4) != 0)
370         fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
371                 " decode properly.");
372
373       *fourcc = mem_get_le32(raw_hdr + 8);
374       *width = mem_get_le16(raw_hdr + 12);
375       *height = mem_get_le16(raw_hdr + 14);
376       *fps_num = mem_get_le32(raw_hdr + 16);
377       *fps_den = mem_get_le32(raw_hdr + 20);
378
379       /* Some versions of vpxenc used 1/(2*fps) for the timebase, so
380        * we can guess the framerate using only the timebase in this
381        * case. Other files would require reading ahead to guess the
382        * timebase, like we do for webm.
383        */
384       if (*fps_num < 1000) {
385         /* Correct for the factor of 2 applied to the timebase in the
386          * encoder.
387          */
388         if (*fps_num & 1)*fps_den <<= 1;
389         else *fps_num >>= 1;
390       } else {
391         /* Don't know FPS for sure, and don't have readahead code
392          * (yet?), so just default to 30fps.
393          */
394         *fps_num = 30;
395         *fps_den = 1;
396       }
397     }
398   }
399
400   if (!is_ivf)
401     rewind(infile);
402
403   return is_ivf;
404 }
405
406
407 unsigned int file_is_raw(FILE *infile,
408                          unsigned int *fourcc,
409                          unsigned int *width,
410                          unsigned int *height,
411                          unsigned int *fps_den,
412                          unsigned int *fps_num) {
413   unsigned char buf[32];
414   int is_raw = 0;
415   vpx_codec_stream_info_t si;
416
417   si.sz = sizeof(si);
418
419   if (fread(buf, 1, 32, infile) == 32) {
420     int i;
421
422     if (mem_get_le32(buf) < 256 * 1024 * 1024)
423       for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
424         if (!vpx_codec_peek_stream_info(ifaces[i].iface(),
425                                         buf + 4, 32 - 4, &si)) {
426           is_raw = 1;
427           *fourcc = ifaces[i].fourcc;
428           *width = si.w;
429           *height = si.h;
430           *fps_num = 30;
431           *fps_den = 1;
432           break;
433         }
434   }
435
436   rewind(infile);
437   return is_raw;
438 }
439
440
441 static int
442 nestegg_read_cb(void *buffer, size_t length, void *userdata) {
443   FILE *f = userdata;
444
445   if (fread(buffer, 1, length, f) < length) {
446     if (ferror(f))
447       return -1;
448     if (feof(f))
449       return 0;
450   }
451   return 1;
452 }
453
454
455 static int
456 nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
457   switch (whence) {
458     case NESTEGG_SEEK_SET:
459       whence = SEEK_SET;
460       break;
461     case NESTEGG_SEEK_CUR:
462       whence = SEEK_CUR;
463       break;
464     case NESTEGG_SEEK_END:
465       whence = SEEK_END;
466       break;
467   };
468   return fseek(userdata, (long)offset, whence) ? -1 : 0;
469 }
470
471
472 static int64_t
473 nestegg_tell_cb(void *userdata) {
474   return ftell(userdata);
475 }
476
477
478 static void
479 nestegg_log_cb(nestegg *context, unsigned int severity, char const *format,
480                ...) {
481   va_list ap;
482
483   va_start(ap, format);
484   vfprintf(stderr, format, ap);
485   fprintf(stderr, "\n");
486   va_end(ap);
487 }
488
489
490 static int
491 webm_guess_framerate(struct input_ctx *input,
492                      unsigned int     *fps_den,
493                      unsigned int     *fps_num) {
494   unsigned int i;
495   uint64_t     tstamp = 0;
496
497   /* Guess the framerate. Read up to 1 second, or 50 video packets,
498    * whichever comes first.
499    */
500   for (i = 0; tstamp < 1000000000 && i < 50;) {
501     nestegg_packet *pkt;
502     unsigned int track;
503
504     if (nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0)
505       break;
506
507     nestegg_packet_track(pkt, &track);
508     if (track == input->video_track) {
509       nestegg_packet_tstamp(pkt, &tstamp);
510       i++;
511     }
512
513     nestegg_free_packet(pkt);
514   }
515
516   if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0))
517     goto fail;
518
519   *fps_num = (i - 1) * 1000000;
520   *fps_den = (unsigned int)(tstamp / 1000);
521   return 0;
522 fail:
523   nestegg_destroy(input->nestegg_ctx);
524   input->nestegg_ctx = NULL;
525   rewind(input->infile);
526   return 1;
527 }
528
529
530 static int
531 file_is_webm(struct input_ctx *input,
532              unsigned int     *fourcc,
533              unsigned int     *width,
534              unsigned int     *height,
535              unsigned int     *fps_den,
536              unsigned int     *fps_num) {
537   unsigned int i, n;
538   int          track_type = -1;
539
540   nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
541   nestegg_video_params params;
542
543   io.userdata = input->infile;
544   if (nestegg_init(&input->nestegg_ctx, io, NULL))
545     goto fail;
546
547   if (nestegg_track_count(input->nestegg_ctx, &n))
548     goto fail;
549
550   for (i = 0; i < n; i++) {
551     track_type = nestegg_track_type(input->nestegg_ctx, i);
552
553     if (track_type == NESTEGG_TRACK_VIDEO)
554       break;
555     else if (track_type < 0)
556       goto fail;
557   }
558
559   if (nestegg_track_codec_id(input->nestegg_ctx, i) != NESTEGG_CODEC_VP8) {
560     fprintf(stderr, "Not VP8 video, quitting.\n");
561     exit(1);
562   }
563
564   input->video_track = i;
565
566   if (nestegg_track_video_params(input->nestegg_ctx, i, &params))
567     goto fail;
568
569   *fps_den = 0;
570   *fps_num = 0;
571   *fourcc = VP8_FOURCC;
572   *width = params.width;
573   *height = params.height;
574   return 1;
575 fail:
576   input->nestegg_ctx = NULL;
577   rewind(input->infile);
578   return 0;
579 }
580
581
582 void show_progress(int frame_in, int frame_out, unsigned long dx_time) {
583   fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r",
584           frame_in, frame_out, dx_time,
585           (float)frame_out * 1000000.0 / (float)dx_time);
586 }
587
588
589 void generate_filename(const char *pattern, char *out, size_t q_len,
590                        unsigned int d_w, unsigned int d_h,
591                        unsigned int frame_in) {
592   const char *p = pattern;
593   char *q = out;
594
595   do {
596     char *next_pat = strchr(p, '%');
597
598     if (p == next_pat) {
599       size_t pat_len;
600
601       /* parse the pattern */
602       q[q_len - 1] = '\0';
603       switch (p[1]) {
604         case 'w':
605           snprintf(q, q_len - 1, "%d", d_w);
606           break;
607         case 'h':
608           snprintf(q, q_len - 1, "%d", d_h);
609           break;
610         case '1':
611           snprintf(q, q_len - 1, "%d", frame_in);
612           break;
613         case '2':
614           snprintf(q, q_len - 1, "%02d", frame_in);
615           break;
616         case '3':
617           snprintf(q, q_len - 1, "%03d", frame_in);
618           break;
619         case '4':
620           snprintf(q, q_len - 1, "%04d", frame_in);
621           break;
622         case '5':
623           snprintf(q, q_len - 1, "%05d", frame_in);
624           break;
625         case '6':
626           snprintf(q, q_len - 1, "%06d", frame_in);
627           break;
628         case '7':
629           snprintf(q, q_len - 1, "%07d", frame_in);
630           break;
631         case '8':
632           snprintf(q, q_len - 1, "%08d", frame_in);
633           break;
634         case '9':
635           snprintf(q, q_len - 1, "%09d", frame_in);
636           break;
637         default:
638           die("Unrecognized pattern %%%c\n", p[1]);
639       }
640
641       pat_len = strlen(q);
642       if (pat_len >= q_len - 1)
643         die("Output filename too long.\n");
644       q += pat_len;
645       p += 2;
646       q_len -= pat_len;
647     } else {
648       size_t copy_len;
649
650       /* copy the next segment */
651       if (!next_pat)
652         copy_len = strlen(p);
653       else
654         copy_len = next_pat - p;
655
656       if (copy_len >= q_len - 1)
657         die("Output filename too long.\n");
658
659       memcpy(q, p, copy_len);
660       q[copy_len] = '\0';
661       q += copy_len;
662       p += copy_len;
663       q_len -= copy_len;
664     }
665   } while (*p);
666 }
667
668
669 int main(int argc, const char **argv_) {
670   vpx_codec_ctx_t          decoder;
671   char                  *fn = NULL;
672   int                    i;
673   uint8_t               *buf = NULL;
674   size_t                 buf_sz = 0, buf_alloc_sz = 0;
675   FILE                  *infile;
676   int                    frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0;
677   int                    stop_after = 0, postproc = 0, summary = 0, quiet = 1;
678   int                    arg_skip = 0;
679   int                    ec_enabled = 0;
680   vpx_codec_iface_t       *iface = NULL;
681   unsigned int           fourcc;
682   unsigned long          dx_time = 0;
683   struct arg               arg;
684   char                   **argv, **argi, **argj;
685   const char             *outfile_pattern = 0;
686   char                    outfile[PATH_MAX];
687   int                     single_file;
688   int                     use_y4m = 1;
689   unsigned int            width;
690   unsigned int            height;
691   unsigned int            fps_den;
692   unsigned int            fps_num;
693   void                   *out = NULL;
694   vpx_codec_dec_cfg_t     cfg = {0};
695 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
696   vp8_postproc_cfg_t      vp8_pp_cfg = {0};
697   int                     vp8_dbg_color_ref_frame = 0;
698   int                     vp8_dbg_color_mb_modes = 0;
699   int                     vp8_dbg_color_b_modes = 0;
700   int                     vp8_dbg_display_mv = 0;
701 #endif
702   struct input_ctx        input = {0};
703   int                     frames_corrupted = 0;
704   int                     dec_flags = 0;
705
706   /* Parse command line */
707   exec_name = argv_[0];
708   argv = argv_dup(argc - 1, argv_ + 1);
709
710   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
711     memset(&arg, 0, sizeof(arg));
712     arg.argv_step = 1;
713
714     if (arg_match(&arg, &codecarg, argi)) {
715       int j, k = -1;
716
717       for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++)
718         if (!strcmp(ifaces[j].name, arg.val))
719           k = j;
720
721       if (k >= 0)
722         iface = ifaces[k].iface();
723       else
724         die("Error: Unrecognized argument (%s) to --codec\n",
725             arg.val);
726     } else if (arg_match(&arg, &outputfile, argi))
727       outfile_pattern = arg.val;
728     else if (arg_match(&arg, &use_yv12, argi)) {
729       use_y4m = 0;
730       flipuv = 1;
731     } else if (arg_match(&arg, &use_i420, argi)) {
732       use_y4m = 0;
733       flipuv = 0;
734     } else if (arg_match(&arg, &flipuvarg, argi))
735       flipuv = 1;
736     else if (arg_match(&arg, &noblitarg, argi))
737       noblit = 1;
738     else if (arg_match(&arg, &progressarg, argi))
739       progress = 1;
740     else if (arg_match(&arg, &limitarg, argi))
741       stop_after = arg_parse_uint(&arg);
742     else if (arg_match(&arg, &skiparg, argi))
743       arg_skip = arg_parse_uint(&arg);
744     else if (arg_match(&arg, &postprocarg, argi))
745       postproc = 1;
746     else if (arg_match(&arg, &md5arg, argi))
747       do_md5 = 1;
748     else if (arg_match(&arg, &summaryarg, argi))
749       summary = 1;
750     else if (arg_match(&arg, &threadsarg, argi))
751       cfg.threads = arg_parse_uint(&arg);
752     else if (arg_match(&arg, &verbosearg, argi))
753       quiet = 0;
754
755 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
756     else if (arg_match(&arg, &addnoise_level, argi)) {
757       postproc = 1;
758       vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
759       vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
760     } else if (arg_match(&arg, &demacroblock_level, argi)) {
761       postproc = 1;
762       vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
763       vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
764     } else if (arg_match(&arg, &deblock, argi)) {
765       postproc = 1;
766       vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
767     } else if (arg_match(&arg, &mfqe, argi)) {
768       postproc = 1;
769       vp8_pp_cfg.post_proc_flag |= VP8_MFQE;
770     } else if (arg_match(&arg, &pp_debug_info, argi)) {
771       unsigned int level = arg_parse_uint(&arg);
772
773       postproc = 1;
774       vp8_pp_cfg.post_proc_flag &= ~0x7;
775
776       if (level)
777         vp8_pp_cfg.post_proc_flag |= level;
778     } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) {
779       unsigned int flags = arg_parse_int(&arg);
780       if (flags) {
781         postproc = 1;
782         vp8_dbg_color_ref_frame = flags;
783       }
784     } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) {
785       unsigned int flags = arg_parse_int(&arg);
786       if (flags) {
787         postproc = 1;
788         vp8_dbg_color_mb_modes = flags;
789       }
790     } else if (arg_match(&arg, &pp_disp_b_modes, argi)) {
791       unsigned int flags = arg_parse_int(&arg);
792       if (flags) {
793         postproc = 1;
794         vp8_dbg_color_b_modes = flags;
795       }
796     } else if (arg_match(&arg, &pp_disp_mvs, argi)) {
797       unsigned int flags = arg_parse_int(&arg);
798       if (flags) {
799         postproc = 1;
800         vp8_dbg_display_mv = flags;
801       }
802     } else if (arg_match(&arg, &error_concealment, argi)) {
803       ec_enabled = 1;
804     }
805
806 #endif
807     else
808       argj++;
809   }
810
811   /* Check for unrecognized options */
812   for (argi = argv; *argi; argi++)
813     if (argi[0][0] == '-' && strlen(argi[0]) > 1)
814       die("Error: Unrecognized option %s\n", *argi);
815
816   /* Handle non-option arguments */
817   fn = argv[0];
818
819   if (!fn)
820     usage_exit();
821
822   /* Open file */
823   infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
824
825   if (!infile) {
826     fprintf(stderr, "Failed to open file '%s'",
827             strcmp(fn, "-") ? fn : "stdin");
828     return EXIT_FAILURE;
829   }
830 #if CONFIG_OS_SUPPORT
831   /* Make sure we don't dump to the terminal, unless forced to with -o - */
832   if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) {
833     fprintf(stderr,
834             "Not dumping raw video to your terminal. Use '-o -' to "
835             "override.\n");
836     return EXIT_FAILURE;
837   }
838 #endif
839   input.infile = infile;
840   if (file_is_ivf(infile, &fourcc, &width, &height, &fps_den,
841                   &fps_num))
842     input.kind = IVF_FILE;
843   else if (file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num))
844     input.kind = WEBM_FILE;
845   else if (file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num))
846     input.kind = RAW_FILE;
847   else {
848     fprintf(stderr, "Unrecognized input file type.\n");
849     return EXIT_FAILURE;
850   }
851
852   /* If the output file is not set or doesn't have a sequence number in
853    * it, then we only open it once.
854    */
855   outfile_pattern = outfile_pattern ? outfile_pattern : "-";
856   single_file = 1;
857   {
858     const char *p = outfile_pattern;
859     do {
860       p = strchr(p, '%');
861       if (p && p[1] >= '1' && p[1] <= '9') {
862         /* pattern contains sequence number, so it's not unique. */
863         single_file = 0;
864         break;
865       }
866       if (p)
867         p++;
868     } while (p);
869   }
870
871   if (single_file && !noblit) {
872     generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1,
873                       width, height, 0);
874     out = out_open(outfile, do_md5);
875   }
876
877   if (use_y4m && !noblit) {
878     char buffer[128];
879     if (!single_file) {
880       fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
881               " try --i420 or --yv12.\n");
882       return EXIT_FAILURE;
883     }
884
885     if (input.kind == WEBM_FILE)
886       if (webm_guess_framerate(&input, &fps_den, &fps_num)) {
887         fprintf(stderr, "Failed to guess framerate -- error parsing "
888                 "webm file?\n");
889         return EXIT_FAILURE;
890       }
891
892
893     /*Note: We can't output an aspect ratio here because IVF doesn't
894        store one, and neither does VP8.
895       That will have to wait until these tools support WebM natively.*/
896     sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n",
897             "420jpeg", width, height, fps_num, fps_den, 'p');
898     out_put(out, (unsigned char *)buffer,
899             (unsigned int)strlen(buffer), do_md5);
900   }
901
902   /* Try to determine the codec from the fourcc. */
903   for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
904     if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) {
905       vpx_codec_iface_t  *ivf_iface = ifaces[i].iface();
906
907       if (iface && iface != ivf_iface)
908         fprintf(stderr, "Notice -- IVF header indicates codec: %s\n",
909                 ifaces[i].name);
910       else
911         iface = ivf_iface;
912
913       break;
914     }
915
916   dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
917               (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
918   if (vpx_codec_dec_init(&decoder, iface ? iface :  ifaces[0].iface(), &cfg,
919                          dec_flags)) {
920     fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder));
921     return EXIT_FAILURE;
922   }
923
924   if (!quiet)
925     fprintf(stderr, "%s\n", decoder.name);
926
927 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
928
929   if (vp8_pp_cfg.post_proc_flag
930       && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) {
931     fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
932     return EXIT_FAILURE;
933   }
934
935   if (vp8_dbg_color_ref_frame
936       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) {
937     fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder));
938     return EXIT_FAILURE;
939   }
940
941   if (vp8_dbg_color_mb_modes
942       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) {
943     fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder));
944     return EXIT_FAILURE;
945   }
946
947   if (vp8_dbg_color_b_modes
948       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) {
949     fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder));
950     return EXIT_FAILURE;
951   }
952
953   if (vp8_dbg_display_mv
954       && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) {
955     fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder));
956     return EXIT_FAILURE;
957   }
958 #endif
959
960
961   if(arg_skip)
962     fprintf(stderr, "Skiping first %d frames.\n", arg_skip);
963   while (arg_skip) {
964     if (read_frame(&input, &buf, &buf_sz, &buf_alloc_sz))
965       break;
966     arg_skip--;
967   }
968
969   /* Decode file */
970   while (!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) {
971     vpx_codec_iter_t  iter = NULL;
972     vpx_image_t    *img;
973     struct vpx_usec_timer timer;
974     int                   corrupted;
975
976     vpx_usec_timer_start(&timer);
977
978     if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) {
979       const char *detail = vpx_codec_error_detail(&decoder);
980       fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder));
981
982       if (detail)
983         fprintf(stderr, "  Additional information: %s\n", detail);
984
985       goto fail;
986     }
987
988     vpx_usec_timer_mark(&timer);
989     dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
990
991     ++frame_in;
992
993     if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
994       fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n",
995               vpx_codec_error(&decoder));
996       goto fail;
997     }
998     frames_corrupted += corrupted;
999
1000     vpx_usec_timer_start(&timer);
1001
1002     if ((img = vpx_codec_get_frame(&decoder, &iter)))
1003       ++frame_out;
1004
1005     vpx_usec_timer_mark(&timer);
1006     dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
1007
1008     if (progress)
1009       show_progress(frame_in, frame_out, dx_time);
1010
1011     if (!noblit) {
1012       if (img) {
1013         unsigned int y;
1014         char out_fn[PATH_MAX];
1015         uint8_t *buf;
1016
1017         if (!single_file) {
1018           size_t len = sizeof(out_fn) - 1;
1019
1020           out_fn[len] = '\0';
1021           generate_filename(outfile_pattern, out_fn, len - 1,
1022                             img->d_w, img->d_h, frame_in);
1023           out = out_open(out_fn, do_md5);
1024         } else if (use_y4m)
1025           out_put(out, (unsigned char *)"FRAME\n", 6, do_md5);
1026
1027         buf = img->planes[VPX_PLANE_Y];
1028
1029         for (y = 0; y < img->d_h; y++) {
1030           out_put(out, buf, img->d_w, do_md5);
1031           buf += img->stride[VPX_PLANE_Y];
1032         }
1033
1034         buf = img->planes[flipuv ? VPX_PLANE_V : VPX_PLANE_U];
1035
1036         for (y = 0; y < (1 + img->d_h) / 2; y++) {
1037           out_put(out, buf, (1 + img->d_w) / 2, do_md5);
1038           buf += img->stride[VPX_PLANE_U];
1039         }
1040
1041         buf = img->planes[flipuv ? VPX_PLANE_U : VPX_PLANE_V];
1042
1043         for (y = 0; y < (1 + img->d_h) / 2; y++) {
1044           out_put(out, buf, (1 + img->d_w) / 2, do_md5);
1045           buf += img->stride[VPX_PLANE_V];
1046         }
1047
1048         if (!single_file)
1049           out_close(out, out_fn, do_md5);
1050       }
1051     }
1052
1053     if (stop_after && frame_in >= stop_after)
1054       break;
1055   }
1056
1057   if (summary || progress) {
1058     show_progress(frame_in, frame_out, dx_time);
1059     fprintf(stderr, "\n");
1060   }
1061
1062   if (frames_corrupted)
1063     fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);
1064
1065 fail:
1066
1067   if (vpx_codec_destroy(&decoder)) {
1068     fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder));
1069     return EXIT_FAILURE;
1070   }
1071
1072   if (single_file && !noblit)
1073     out_close(out, outfile, do_md5);
1074
1075   if (input.nestegg_ctx)
1076     nestegg_destroy(input.nestegg_ctx);
1077   if (input.kind != WEBM_FILE)
1078     free(buf);
1079   fclose(infile);
1080   free(argv);
1081
1082   return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS;
1083 }