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