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