WebM VP8 Codec SDK
vpxdec
00001 /*
00002  *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
00003  *
00004  *  Use of this source code is governed by a BSD-style license
00005  *  that can be found in the LICENSE file in the root of the source
00006  *  tree. An additional intellectual property rights grant can be found
00007  *  in the file PATENTS.  All contributing project authors may
00008  *  be found in the AUTHORS file in the root of the source tree.
00009  */
00010 
00011 
00012 /* This is a simple program that reads ivf files and decodes them
00013  * using the new interface. Decoded frames are output as YV12 raw.
00014  */
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <stdarg.h>
00018 #include <string.h>
00019 #include <limits.h>
00020 
00021 #define VPX_CODEC_DISABLE_COMPAT 1
00022 #include "vpx_config.h"
00023 #include "vpx/vpx_decoder.h"
00024 #include "vpx_ports/vpx_timer.h"
00025 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER
00026 #include "vpx/vp8dx.h"
00027 #endif
00028 #if CONFIG_MD5
00029 #include "md5_utils.h"
00030 #endif
00031 #include "tools_common.h"
00032 #include "nestegg/include/nestegg/nestegg.h"
00033 #include "third_party/libyuv/include/libyuv/scale.h"
00034 
00035 #if CONFIG_OS_SUPPORT
00036 #if defined(_MSC_VER)
00037 #include <io.h>
00038 #define snprintf _snprintf
00039 #define isatty   _isatty
00040 #define fileno   _fileno
00041 #else
00042 #include <unistd.h>
00043 #endif
00044 #endif
00045 
00046 #ifndef PATH_MAX
00047 #define PATH_MAX 256
00048 #endif
00049 
00050 static const char *exec_name;
00051 
00052 #define VP8_FOURCC (0x00385056)
00053 #define VP9_FOURCC (0x00395056)
00054 static const struct {
00055   char const *name;
00056   const vpx_codec_iface_t *(*iface)(void);
00057   unsigned int             fourcc;
00058   unsigned int             fourcc_mask;
00059 } ifaces[] = {
00060 #if CONFIG_VP8_DECODER
00061   {"vp8",  vpx_codec_vp8_dx,   VP8_FOURCC, 0x00FFFFFF},
00062 #endif
00063 #if CONFIG_VP9_DECODER
00064   {"vp9",  vpx_codec_vp9_dx,   VP9_FOURCC, 0x00FFFFFF},
00065 #endif
00066 };
00067 
00068 #include "args.h"
00069 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
00070                                           "Codec to use");
00071 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
00072                                           "Output raw YV12 frames");
00073 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
00074                                           "Output raw I420 frames");
00075 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0,
00076                                            "Flip the chroma planes in the output");
00077 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0,
00078                                            "Don't process the decoded frames");
00079 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0,
00080                                              "Show progress after each frame decodes");
00081 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1,
00082                                           "Stop decoding after n frames");
00083 static const arg_def_t skiparg = ARG_DEF(NULL, "skip", 1,
00084                                          "Skip the first n input frames");
00085 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0,
00086                                              "Postprocess decoded frames");
00087 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0,
00088                                             "Show timing summary");
00089 static const arg_def_t outputfile = ARG_DEF("o", "output", 1,
00090                                             "Output file name pattern (see below)");
00091 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1,
00092                                             "Max threads to use");
00093 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0,
00094                                             "Show version string");
00095 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0,
00096                                                    "Enable decoder error-concealment");
00097 static const arg_def_t scalearg = ARG_DEF("S", "scale", 0,
00098                                             "Scale output frames uniformly");
00099 
00100 
00101 #if CONFIG_MD5
00102 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0,
00103                                         "Compute the MD5 sum of the decoded frame");
00104 #endif
00105 static const arg_def_t *all_args[] = {
00106   &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg,
00107   &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile,
00108   &threadsarg, &verbosearg, &scalearg,
00109 #if CONFIG_MD5
00110   &md5arg,
00111 #endif
00112   &error_concealment,
00113   NULL
00114 };
00115 
00116 #if CONFIG_VP8_DECODER
00117 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1,
00118                                                 "Enable VP8 postproc add noise");
00119 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0,
00120                                          "Enable VP8 deblocking");
00121 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1,
00122                                                     "Enable VP8 demacroblocking, w/ level");
00123 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1,
00124                                                "Enable VP8 visible debug info");
00125 static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1,
00126                                                    "Display only selected reference frame per macro block");
00127 static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1,
00128                                                   "Display only selected macro block modes");
00129 static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1,
00130                                                  "Display only selected block modes");
00131 static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1,
00132                                              "Draw only selected motion vectors");
00133 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0,
00134                                       "Enable multiframe quality enhancement");
00135 
00136 static const arg_def_t *vp8_pp_args[] = {
00137   &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info,
00138   &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe,
00139   NULL
00140 };
00141 #endif
00142 
00143 static void usage_exit() {
00144   int i;
00145 
00146   fprintf(stderr, "Usage: %s <options> filename\n\n"
00147           "Options:\n", exec_name);
00148   arg_show_usage(stderr, all_args);
00149 #if CONFIG_VP8_DECODER
00150   fprintf(stderr, "\nVP8 Postprocessing Options:\n");
00151   arg_show_usage(stderr, vp8_pp_args);
00152 #endif
00153   fprintf(stderr,
00154           "\nOutput File Patterns:\n\n"
00155           "  The -o argument specifies the name of the file(s) to "
00156           "write to. If the\n  argument does not include any escape "
00157           "characters, the output will be\n  written to a single file. "
00158           "Otherwise, the filename will be calculated by\n  expanding "
00159           "the following escape characters:\n");
00160   fprintf(stderr,
00161           "\n\t%%w   - Frame width"
00162           "\n\t%%h   - Frame height"
00163           "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)"
00164           "\n\n  Pattern arguments are only supported in conjunction "
00165           "with the --yv12 and\n  --i420 options. If the -o option is "
00166           "not specified, the output will be\n  directed to stdout.\n"
00167          );
00168   fprintf(stderr, "\nIncluded decoders:\n\n");
00169 
00170   for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
00171     fprintf(stderr, "    %-6s - %s\n",
00172             ifaces[i].name,
00173             vpx_codec_iface_name(ifaces[i].iface()));
00174 
00175   exit(EXIT_FAILURE);
00176 }
00177 
00178 void die(const char *fmt, ...) {
00179   va_list ap;
00180   va_start(ap, fmt);
00181   vfprintf(stderr, fmt, ap);
00182   fprintf(stderr, "\n");
00183   usage_exit();
00184 }
00185 
00186 static unsigned int mem_get_le16(const void *vmem) {
00187   unsigned int  val;
00188   const unsigned char *mem = (const unsigned char *)vmem;
00189 
00190   val = mem[1] << 8;
00191   val |= mem[0];
00192   return val;
00193 }
00194 
00195 static unsigned int mem_get_le32(const void *vmem) {
00196   unsigned int  val;
00197   const unsigned char *mem = (const unsigned char *)vmem;
00198 
00199   val = mem[3] << 24;
00200   val |= mem[2] << 16;
00201   val |= mem[1] << 8;
00202   val |= mem[0];
00203   return val;
00204 }
00205 
00206 enum file_kind {
00207   RAW_FILE,
00208   IVF_FILE,
00209   WEBM_FILE
00210 };
00211 
00212 struct input_ctx {
00213   enum file_kind  kind;
00214   FILE           *infile;
00215   nestegg        *nestegg_ctx;
00216   nestegg_packet *pkt;
00217   unsigned int    chunk;
00218   unsigned int    chunks;
00219   unsigned int    video_track;
00220 };
00221 
00222 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t))
00223 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t))
00224 static int read_frame(struct input_ctx      *input,
00225                       uint8_t               **buf,
00226                       size_t                *buf_sz,
00227                       size_t                *buf_alloc_sz) {
00228   char            raw_hdr[IVF_FRAME_HDR_SZ];
00229   size_t          new_buf_sz;
00230   FILE           *infile = input->infile;
00231   enum file_kind  kind = input->kind;
00232   if (kind == WEBM_FILE) {
00233     if (input->chunk >= input->chunks) {
00234       unsigned int track;
00235 
00236       do {
00237         /* End of this packet, get another. */
00238         if (input->pkt)
00239           nestegg_free_packet(input->pkt);
00240 
00241         if (nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0
00242             || nestegg_packet_track(input->pkt, &track))
00243           return 1;
00244 
00245       } while (track != input->video_track);
00246 
00247       if (nestegg_packet_count(input->pkt, &input->chunks))
00248         return 1;
00249       input->chunk = 0;
00250     }
00251 
00252     if (nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz))
00253       return 1;
00254     input->chunk++;
00255 
00256     return 0;
00257   }
00258   /* For both the raw and ivf formats, the frame size is the first 4 bytes
00259    * of the frame header. We just need to special case on the header
00260    * size.
00261    */
00262   else if (fread(raw_hdr, kind == IVF_FILE
00263                  ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) {
00264     if (!feof(infile))
00265       fprintf(stderr, "Failed to read frame size\n");
00266 
00267     new_buf_sz = 0;
00268   } else {
00269     new_buf_sz = mem_get_le32(raw_hdr);
00270 
00271     if (new_buf_sz > 256 * 1024 * 1024) {
00272       fprintf(stderr, "Error: Read invalid frame size (%u)\n",
00273               (unsigned int)new_buf_sz);
00274       new_buf_sz = 0;
00275     }
00276 
00277     if (kind == RAW_FILE && new_buf_sz > 256 * 1024)
00278       fprintf(stderr, "Warning: Read invalid frame size (%u)"
00279               " - not a raw file?\n", (unsigned int)new_buf_sz);
00280 
00281     if (new_buf_sz > *buf_alloc_sz) {
00282       uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz);
00283 
00284       if (new_buf) {
00285         *buf = new_buf;
00286         *buf_alloc_sz = 2 * new_buf_sz;
00287       } else {
00288         fprintf(stderr, "Failed to allocate compressed data buffer\n");
00289         new_buf_sz = 0;
00290       }
00291     }
00292   }
00293 
00294   *buf_sz = new_buf_sz;
00295 
00296   if (!feof(infile)) {
00297     if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) {
00298       fprintf(stderr, "Failed to read full frame\n");
00299       return 1;
00300     }
00301 
00302     return 0;
00303   }
00304 
00305   return 1;
00306 }
00307 
00308 void *out_open(const char *out_fn, int do_md5) {
00309   void *out = NULL;
00310 
00311   if (do_md5) {
00312 #if CONFIG_MD5
00313     MD5Context *md5_ctx = out = malloc(sizeof(MD5Context));
00314     (void)out_fn;
00315     MD5Init(md5_ctx);
00316 #endif
00317   } else {
00318     FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb")
00319                           : set_binary_mode(stdout);
00320 
00321     if (!outfile) {
00322       fprintf(stderr, "Failed to output file");
00323       exit(EXIT_FAILURE);
00324     }
00325   }
00326 
00327   return out;
00328 }
00329 
00330 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) {
00331   if (do_md5) {
00332 #if CONFIG_MD5
00333     MD5Update(out, buf, len);
00334 #endif
00335   } else {
00336     (void) fwrite(buf, 1, len, out);
00337   }
00338 }
00339 
00340 void out_close(void *out, const char *out_fn, int do_md5) {
00341   if (do_md5) {
00342 #if CONFIG_MD5
00343     uint8_t md5[16];
00344     int i;
00345 
00346     MD5Final(md5, out);
00347     free(out);
00348 
00349     for (i = 0; i < 16; i++)
00350       printf("%02x", md5[i]);
00351 
00352     printf("  %s\n", out_fn);
00353 #endif
00354   } else {
00355     fclose(out);
00356   }
00357 }
00358 
00359 unsigned int file_is_ivf(FILE *infile,
00360                          unsigned int *fourcc,
00361                          unsigned int *width,
00362                          unsigned int *height,
00363                          unsigned int *fps_den,
00364                          unsigned int *fps_num) {
00365   char raw_hdr[32];
00366   int is_ivf = 0;
00367 
00368   if (fread(raw_hdr, 1, 32, infile) == 32) {
00369     if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K'
00370         && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') {
00371       is_ivf = 1;
00372 
00373       if (mem_get_le16(raw_hdr + 4) != 0)
00374         fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
00375                 " decode properly.");
00376 
00377       *fourcc = mem_get_le32(raw_hdr + 8);
00378       *width = mem_get_le16(raw_hdr + 12);
00379       *height = mem_get_le16(raw_hdr + 14);
00380       *fps_num = mem_get_le32(raw_hdr + 16);
00381       *fps_den = mem_get_le32(raw_hdr + 20);
00382 
00383       /* Some versions of vpxenc used 1/(2*fps) for the timebase, so
00384        * we can guess the framerate using only the timebase in this
00385        * case. Other files would require reading ahead to guess the
00386        * timebase, like we do for webm.
00387        */
00388       if (*fps_num < 1000) {
00389         /* Correct for the factor of 2 applied to the timebase in the
00390          * encoder.
00391          */
00392         if (*fps_num & 1)*fps_den <<= 1;
00393         else *fps_num >>= 1;
00394       } else {
00395         /* Don't know FPS for sure, and don't have readahead code
00396          * (yet?), so just default to 30fps.
00397          */
00398         *fps_num = 30;
00399         *fps_den = 1;
00400       }
00401     }
00402   }
00403 
00404   if (!is_ivf)
00405     rewind(infile);
00406 
00407   return is_ivf;
00408 }
00409 
00410 
00411 unsigned int file_is_raw(FILE *infile,
00412                          unsigned int *fourcc,
00413                          unsigned int *width,
00414                          unsigned int *height,
00415                          unsigned int *fps_den,
00416                          unsigned int *fps_num) {
00417   unsigned char buf[32];
00418   int is_raw = 0;
00419   vpx_codec_stream_info_t si;
00420 
00421   si.sz = sizeof(si);
00422 
00423   if (fread(buf, 1, 32, infile) == 32) {
00424     int i;
00425 
00426     if (mem_get_le32(buf) < 256 * 1024 * 1024)
00427       for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
00428         if (!vpx_codec_peek_stream_info(ifaces[i].iface(),
00429                                         buf + 4, 32 - 4, &si)) {
00430           is_raw = 1;
00431           *fourcc = ifaces[i].fourcc;
00432           *width = si.w;
00433           *height = si.h;
00434           *fps_num = 30;
00435           *fps_den = 1;
00436           break;
00437         }
00438   }
00439 
00440   rewind(infile);
00441   return is_raw;
00442 }
00443 
00444 
00445 static int
00446 nestegg_read_cb(void *buffer, size_t length, void *userdata) {
00447   FILE *f = userdata;
00448 
00449   if (fread(buffer, 1, length, f) < length) {
00450     if (ferror(f))
00451       return -1;
00452     if (feof(f))
00453       return 0;
00454   }
00455   return 1;
00456 }
00457 
00458 
00459 static int
00460 nestegg_seek_cb(int64_t offset, int whence, void *userdata) {
00461   switch (whence) {
00462     case NESTEGG_SEEK_SET:
00463       whence = SEEK_SET;
00464       break;
00465     case NESTEGG_SEEK_CUR:
00466       whence = SEEK_CUR;
00467       break;
00468     case NESTEGG_SEEK_END:
00469       whence = SEEK_END;
00470       break;
00471   };
00472   return fseek(userdata, (long)offset, whence) ? -1 : 0;
00473 }
00474 
00475 
00476 static int64_t
00477 nestegg_tell_cb(void *userdata) {
00478   return ftell(userdata);
00479 }
00480 
00481 
00482 static void
00483 nestegg_log_cb(nestegg *context, unsigned int severity, char const *format,
00484                ...) {
00485   va_list ap;
00486 
00487   va_start(ap, format);
00488   vfprintf(stderr, format, ap);
00489   fprintf(stderr, "\n");
00490   va_end(ap);
00491 }
00492 
00493 
00494 static int
00495 webm_guess_framerate(struct input_ctx *input,
00496                      unsigned int     *fps_den,
00497                      unsigned int     *fps_num) {
00498   unsigned int i;
00499   uint64_t     tstamp = 0;
00500 
00501   /* Guess the framerate. Read up to 1 second, or 50 video packets,
00502    * whichever comes first.
00503    */
00504   for (i = 0; tstamp < 1000000000 && i < 50;) {
00505     nestegg_packet *pkt;
00506     unsigned int track;
00507 
00508     if (nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0)
00509       break;
00510 
00511     nestegg_packet_track(pkt, &track);
00512     if (track == input->video_track) {
00513       nestegg_packet_tstamp(pkt, &tstamp);
00514       i++;
00515     }
00516 
00517     nestegg_free_packet(pkt);
00518   }
00519 
00520   if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0))
00521     goto fail;
00522 
00523   *fps_num = (i - 1) * 1000000;
00524   *fps_den = (unsigned int)(tstamp / 1000);
00525   return 0;
00526 fail:
00527   nestegg_destroy(input->nestegg_ctx);
00528   input->nestegg_ctx = NULL;
00529   rewind(input->infile);
00530   return 1;
00531 }
00532 
00533 
00534 static int
00535 file_is_webm(struct input_ctx *input,
00536              unsigned int     *fourcc,
00537              unsigned int     *width,
00538              unsigned int     *height,
00539              unsigned int     *fps_den,
00540              unsigned int     *fps_num) {
00541   unsigned int i, n;
00542   int          track_type = -1;
00543   int          codec_id;
00544 
00545   nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0};
00546   nestegg_video_params params;
00547 
00548   io.userdata = input->infile;
00549   if (nestegg_init(&input->nestegg_ctx, io, NULL))
00550     goto fail;
00551 
00552   if (nestegg_track_count(input->nestegg_ctx, &n))
00553     goto fail;
00554 
00555   for (i = 0; i < n; i++) {
00556     track_type = nestegg_track_type(input->nestegg_ctx, i);
00557 
00558     if (track_type == NESTEGG_TRACK_VIDEO)
00559       break;
00560     else if (track_type < 0)
00561       goto fail;
00562   }
00563 
00564   codec_id = nestegg_track_codec_id(input->nestegg_ctx, i);
00565   if (codec_id == NESTEGG_CODEC_VP8) {
00566     *fourcc = VP8_FOURCC;
00567   } else if (codec_id == NESTEGG_CODEC_VP9) {
00568     *fourcc = VP9_FOURCC;
00569   } else {
00570     fprintf(stderr, "Not VPx video, quitting.\n");
00571     exit(1);
00572   }
00573 
00574   input->video_track = i;
00575 
00576   if (nestegg_track_video_params(input->nestegg_ctx, i, &params))
00577     goto fail;
00578 
00579   *fps_den = 0;
00580   *fps_num = 0;
00581   *width = params.width;
00582   *height = params.height;
00583   return 1;
00584 fail:
00585   input->nestegg_ctx = NULL;
00586   rewind(input->infile);
00587   return 0;
00588 }
00589 
00590 
00591 void show_progress(int frame_in, int frame_out, unsigned long dx_time) {
00592   fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r",
00593           frame_in, frame_out, dx_time,
00594           (float)frame_out * 1000000.0 / (float)dx_time);
00595 }
00596 
00597 
00598 void generate_filename(const char *pattern, char *out, size_t q_len,
00599                        unsigned int d_w, unsigned int d_h,
00600                        unsigned int frame_in) {
00601   const char *p = pattern;
00602   char *q = out;
00603 
00604   do {
00605     char *next_pat = strchr(p, '%');
00606 
00607     if (p == next_pat) {
00608       size_t pat_len;
00609 
00610       /* parse the pattern */
00611       q[q_len - 1] = '\0';
00612       switch (p[1]) {
00613         case 'w':
00614           snprintf(q, q_len - 1, "%d", d_w);
00615           break;
00616         case 'h':
00617           snprintf(q, q_len - 1, "%d", d_h);
00618           break;
00619         case '1':
00620           snprintf(q, q_len - 1, "%d", frame_in);
00621           break;
00622         case '2':
00623           snprintf(q, q_len - 1, "%02d", frame_in);
00624           break;
00625         case '3':
00626           snprintf(q, q_len - 1, "%03d", frame_in);
00627           break;
00628         case '4':
00629           snprintf(q, q_len - 1, "%04d", frame_in);
00630           break;
00631         case '5':
00632           snprintf(q, q_len - 1, "%05d", frame_in);
00633           break;
00634         case '6':
00635           snprintf(q, q_len - 1, "%06d", frame_in);
00636           break;
00637         case '7':
00638           snprintf(q, q_len - 1, "%07d", frame_in);
00639           break;
00640         case '8':
00641           snprintf(q, q_len - 1, "%08d", frame_in);
00642           break;
00643         case '9':
00644           snprintf(q, q_len - 1, "%09d", frame_in);
00645           break;
00646         default:
00647           die("Unrecognized pattern %%%c\n", p[1]);
00648       }
00649 
00650       pat_len = strlen(q);
00651       if (pat_len >= q_len - 1)
00652         die("Output filename too long.\n");
00653       q += pat_len;
00654       p += 2;
00655       q_len -= pat_len;
00656     } else {
00657       size_t copy_len;
00658 
00659       /* copy the next segment */
00660       if (!next_pat)
00661         copy_len = strlen(p);
00662       else
00663         copy_len = next_pat - p;
00664 
00665       if (copy_len >= q_len - 1)
00666         die("Output filename too long.\n");
00667 
00668       memcpy(q, p, copy_len);
00669       q[copy_len] = '\0';
00670       q += copy_len;
00671       p += copy_len;
00672       q_len -= copy_len;
00673     }
00674   } while (*p);
00675 }
00676 
00677 
00678 int main(int argc, const char **argv_) {
00679   vpx_codec_ctx_t          decoder;
00680   char                  *fn = NULL;
00681   int                    i;
00682   uint8_t               *buf = NULL;
00683   size_t                 buf_sz = 0, buf_alloc_sz = 0;
00684   FILE                  *infile;
00685   int                    frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0;
00686   int                    stop_after = 0, postproc = 0, summary = 0, quiet = 1;
00687   int                    arg_skip = 0;
00688   int                    ec_enabled = 0;
00689   vpx_codec_iface_t       *iface = NULL;
00690   unsigned int           fourcc;
00691   unsigned long          dx_time = 0;
00692   struct arg               arg;
00693   char                   **argv, **argi, **argj;
00694   const char             *outfile_pattern = 0;
00695   char                    outfile[PATH_MAX];
00696   int                     single_file;
00697   int                     use_y4m = 1;
00698   unsigned int            width;
00699   unsigned int            height;
00700   unsigned int            fps_den;
00701   unsigned int            fps_num;
00702   void                   *out = NULL;
00703   vpx_codec_dec_cfg_t     cfg = {0};
00704 #if CONFIG_VP8_DECODER
00705   vp8_postproc_cfg_t      vp8_pp_cfg = {0};
00706   int                     vp8_dbg_color_ref_frame = 0;
00707   int                     vp8_dbg_color_mb_modes = 0;
00708   int                     vp8_dbg_color_b_modes = 0;
00709   int                     vp8_dbg_display_mv = 0;
00710 #endif
00711   struct input_ctx        input = {0};
00712   int                     frames_corrupted = 0;
00713   int                     dec_flags = 0;
00714   int                     do_scale = 0;
00715   int                     stream_w = 0, stream_h = 0;
00716   vpx_image_t             *scaled_img = NULL;
00717 
00718   /* Parse command line */
00719   exec_name = argv_[0];
00720   argv = argv_dup(argc - 1, argv_ + 1);
00721 
00722   for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
00723     memset(&arg, 0, sizeof(arg));
00724     arg.argv_step = 1;
00725 
00726     if (arg_match(&arg, &codecarg, argi)) {
00727       int j, k = -1;
00728 
00729       for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++)
00730         if (!strcmp(ifaces[j].name, arg.val))
00731           k = j;
00732 
00733       if (k >= 0)
00734         iface = ifaces[k].iface();
00735       else
00736         die("Error: Unrecognized argument (%s) to --codec\n",
00737             arg.val);
00738     } else if (arg_match(&arg, &outputfile, argi))
00739       outfile_pattern = arg.val;
00740     else if (arg_match(&arg, &use_yv12, argi)) {
00741       use_y4m = 0;
00742       flipuv = 1;
00743     } else if (arg_match(&arg, &use_i420, argi)) {
00744       use_y4m = 0;
00745       flipuv = 0;
00746     } else if (arg_match(&arg, &flipuvarg, argi))
00747       flipuv = 1;
00748     else if (arg_match(&arg, &noblitarg, argi))
00749       noblit = 1;
00750     else if (arg_match(&arg, &progressarg, argi))
00751       progress = 1;
00752     else if (arg_match(&arg, &limitarg, argi))
00753       stop_after = arg_parse_uint(&arg);
00754     else if (arg_match(&arg, &skiparg, argi))
00755       arg_skip = arg_parse_uint(&arg);
00756     else if (arg_match(&arg, &postprocarg, argi))
00757       postproc = 1;
00758     else if (arg_match(&arg, &md5arg, argi))
00759       do_md5 = 1;
00760     else if (arg_match(&arg, &summaryarg, argi))
00761       summary = 1;
00762     else if (arg_match(&arg, &threadsarg, argi))
00763       cfg.threads = arg_parse_uint(&arg);
00764     else if (arg_match(&arg, &verbosearg, argi))
00765       quiet = 0;
00766     else if (arg_match(&arg, &scalearg, argi))
00767       do_scale = 1;
00768 
00769 #if CONFIG_VP8_DECODER
00770     else if (arg_match(&arg, &addnoise_level, argi)) {
00771       postproc = 1;
00772       vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
00773       vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
00774     } else if (arg_match(&arg, &demacroblock_level, argi)) {
00775       postproc = 1;
00776       vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
00777       vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
00778     } else if (arg_match(&arg, &deblock, argi)) {
00779       postproc = 1;
00780       vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
00781     } else if (arg_match(&arg, &mfqe, argi)) {
00782       postproc = 1;
00783       vp8_pp_cfg.post_proc_flag |= VP8_MFQE;
00784     } else if (arg_match(&arg, &pp_debug_info, argi)) {
00785       unsigned int level = arg_parse_uint(&arg);
00786 
00787       postproc = 1;
00788       vp8_pp_cfg.post_proc_flag &= ~0x7;
00789 
00790       if (level)
00791         vp8_pp_cfg.post_proc_flag |= level;
00792     } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) {
00793       unsigned int flags = arg_parse_int(&arg);
00794       if (flags) {
00795         postproc = 1;
00796         vp8_dbg_color_ref_frame = flags;
00797       }
00798     } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) {
00799       unsigned int flags = arg_parse_int(&arg);
00800       if (flags) {
00801         postproc = 1;
00802         vp8_dbg_color_mb_modes = flags;
00803       }
00804     } else if (arg_match(&arg, &pp_disp_b_modes, argi)) {
00805       unsigned int flags = arg_parse_int(&arg);
00806       if (flags) {
00807         postproc = 1;
00808         vp8_dbg_color_b_modes = flags;
00809       }
00810     } else if (arg_match(&arg, &pp_disp_mvs, argi)) {
00811       unsigned int flags = arg_parse_int(&arg);
00812       if (flags) {
00813         postproc = 1;
00814         vp8_dbg_display_mv = flags;
00815       }
00816     } else if (arg_match(&arg, &error_concealment, argi)) {
00817       ec_enabled = 1;
00818     }
00819 
00820 #endif
00821     else
00822       argj++;
00823   }
00824 
00825   /* Check for unrecognized options */
00826   for (argi = argv; *argi; argi++)
00827     if (argi[0][0] == '-' && strlen(argi[0]) > 1)
00828       die("Error: Unrecognized option %s\n", *argi);
00829 
00830   /* Handle non-option arguments */
00831   fn = argv[0];
00832 
00833   if (!fn)
00834     usage_exit();
00835 
00836   /* Open file */
00837   infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin);
00838 
00839   if (!infile) {
00840     fprintf(stderr, "Failed to open file '%s'",
00841             strcmp(fn, "-") ? fn : "stdin");
00842     return EXIT_FAILURE;
00843   }
00844 #if CONFIG_OS_SUPPORT
00845   /* Make sure we don't dump to the terminal, unless forced to with -o - */
00846   if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) {
00847     fprintf(stderr,
00848             "Not dumping raw video to your terminal. Use '-o -' to "
00849             "override.\n");
00850     return EXIT_FAILURE;
00851   }
00852 #endif
00853   input.infile = infile;
00854   if (file_is_ivf(infile, &fourcc, &width, &height, &fps_den,
00855                   &fps_num))
00856     input.kind = IVF_FILE;
00857   else if (file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num))
00858     input.kind = WEBM_FILE;
00859   else if (file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num))
00860     input.kind = RAW_FILE;
00861   else {
00862     fprintf(stderr, "Unrecognized input file type.\n");
00863     return EXIT_FAILURE;
00864   }
00865 
00866   /* If the output file is not set or doesn't have a sequence number in
00867    * it, then we only open it once.
00868    */
00869   outfile_pattern = outfile_pattern ? outfile_pattern : "-";
00870   single_file = 1;
00871   {
00872     const char *p = outfile_pattern;
00873     do {
00874       p = strchr(p, '%');
00875       if (p && p[1] >= '1' && p[1] <= '9') {
00876         /* pattern contains sequence number, so it's not unique. */
00877         single_file = 0;
00878         break;
00879       }
00880       if (p)
00881         p++;
00882     } while (p);
00883   }
00884 
00885   if (single_file && !noblit) {
00886     generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1,
00887                       width, height, 0);
00888     out = out_open(outfile, do_md5);
00889   }
00890 
00891   if (use_y4m && !noblit) {
00892     char buffer[128];
00893     if (!single_file) {
00894       fprintf(stderr, "YUV4MPEG2 not supported with output patterns,"
00895               " try --i420 or --yv12.\n");
00896       return EXIT_FAILURE;
00897     }
00898 
00899     if (input.kind == WEBM_FILE)
00900       if (webm_guess_framerate(&input, &fps_den, &fps_num)) {
00901         fprintf(stderr, "Failed to guess framerate -- error parsing "
00902                 "webm file?\n");
00903         return EXIT_FAILURE;
00904       }
00905 
00906 
00907     /*Note: We can't output an aspect ratio here because IVF doesn't
00908        store one, and neither does VP8.
00909       That will have to wait until these tools support WebM natively.*/
00910     sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n",
00911             "420jpeg", width, height, fps_num, fps_den, 'p');
00912     out_put(out, (unsigned char *)buffer,
00913             (unsigned int)strlen(buffer), do_md5);
00914   }
00915 
00916   /* Try to determine the codec from the fourcc. */
00917   for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
00918     if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) {
00919       vpx_codec_iface_t  *ivf_iface = ifaces[i].iface();
00920 
00921       if (iface && iface != ivf_iface)
00922         fprintf(stderr, "Notice -- IVF header indicates codec: %s\n",
00923                 ifaces[i].name);
00924       else
00925         iface = ivf_iface;
00926 
00927       break;
00928     }
00929 
00930   dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) |
00931               (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0);
00932   if (vpx_codec_dec_init(&decoder, iface ? iface :  ifaces[0].iface(), &cfg,
00933                          dec_flags)) {
00934     fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder));
00935     return EXIT_FAILURE;
00936   }
00937 
00938   if (!quiet)
00939     fprintf(stderr, "%s\n", decoder.name);
00940 
00941 #if CONFIG_VP8_DECODER
00942 
00943   if (vp8_pp_cfg.post_proc_flag
00944       && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) {
00945     fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
00946     return EXIT_FAILURE;
00947   }
00948 
00949   if (vp8_dbg_color_ref_frame
00950       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) {
00951     fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder));
00952     return EXIT_FAILURE;
00953   }
00954 
00955   if (vp8_dbg_color_mb_modes
00956       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) {
00957     fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder));
00958     return EXIT_FAILURE;
00959   }
00960 
00961   if (vp8_dbg_color_b_modes
00962       && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) {
00963     fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder));
00964     return EXIT_FAILURE;
00965   }
00966 
00967   if (vp8_dbg_display_mv
00968       && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) {
00969     fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder));
00970     return EXIT_FAILURE;
00971   }
00972 #endif
00973 
00974 
00975   if(arg_skip)
00976     fprintf(stderr, "Skiping first %d frames.\n", arg_skip);
00977   while (arg_skip) {
00978     if (read_frame(&input, &buf, &buf_sz, &buf_alloc_sz))
00979       break;
00980     arg_skip--;
00981   }
00982 
00983   /* Decode file */
00984   while (!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) {
00985     vpx_codec_iter_t  iter = NULL;
00986     vpx_image_t    *img;
00987     struct vpx_usec_timer timer;
00988     int                   corrupted;
00989 
00990     vpx_usec_timer_start(&timer);
00991 
00992     if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) {
00993       const char *detail = vpx_codec_error_detail(&decoder);
00994       fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder));
00995 
00996       if (detail)
00997         fprintf(stderr, "  Additional information: %s\n", detail);
00998 
00999       goto fail;
01000     }
01001 
01002     vpx_usec_timer_mark(&timer);
01003     dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
01004 
01005     ++frame_in;
01006 
01007     if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
01008       fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n",
01009               vpx_codec_error(&decoder));
01010       goto fail;
01011     }
01012     frames_corrupted += corrupted;
01013 
01014     vpx_usec_timer_start(&timer);
01015 
01016     if ((img = vpx_codec_get_frame(&decoder, &iter)))
01017       ++frame_out;
01018 
01019     vpx_usec_timer_mark(&timer);
01020     dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer);
01021 
01022     if (progress)
01023       show_progress(frame_in, frame_out, dx_time);
01024 
01025     if (!noblit) {
01026       if (do_scale) {
01027         if (img && frame_out == 1) {
01028           stream_w = img->d_w;
01029           stream_h = img->d_h;
01030           scaled_img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420,
01031                                      stream_w, stream_h, 16);
01032         }
01033         if (img && (img->d_w != stream_w || img->d_h != stream_h)) {
01034           I420Scale(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
01035                     img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
01036                     img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
01037                     img->d_w, img->d_h,
01038                     scaled_img->planes[VPX_PLANE_Y],
01039                     scaled_img->stride[VPX_PLANE_Y],
01040                     scaled_img->planes[VPX_PLANE_U],
01041                     scaled_img->stride[VPX_PLANE_U],
01042                     scaled_img->planes[VPX_PLANE_V],
01043                     scaled_img->stride[VPX_PLANE_V],
01044                     stream_w, stream_h,
01045                     kFilterBox);
01046           img = scaled_img;
01047         }
01048       }
01049 
01050       if (img) {
01051         unsigned int y;
01052         char out_fn[PATH_MAX];
01053         uint8_t *buf;
01054 
01055         if (!single_file) {
01056           size_t len = sizeof(out_fn) - 1;
01057 
01058           out_fn[len] = '\0';
01059           generate_filename(outfile_pattern, out_fn, len - 1,
01060                             img->d_w, img->d_h, frame_in);
01061           out = out_open(out_fn, do_md5);
01062         } else if (use_y4m)
01063           out_put(out, (unsigned char *)"FRAME\n", 6, do_md5);
01064 
01065         buf = img->planes[VPX_PLANE_Y];
01066 
01067         for (y = 0; y < img->d_h; y++) {
01068           out_put(out, buf, img->d_w, do_md5);
01069           buf += img->stride[VPX_PLANE_Y];
01070         }
01071 
01072         buf = img->planes[flipuv ? VPX_PLANE_V : VPX_PLANE_U];
01073 
01074         for (y = 0; y < (1 + img->d_h) / 2; y++) {
01075           out_put(out, buf, (1 + img->d_w) / 2, do_md5);
01076           buf += img->stride[VPX_PLANE_U];
01077         }
01078 
01079         buf = img->planes[flipuv ? VPX_PLANE_U : VPX_PLANE_V];
01080 
01081         for (y = 0; y < (1 + img->d_h) / 2; y++) {
01082           out_put(out, buf, (1 + img->d_w) / 2, do_md5);
01083           buf += img->stride[VPX_PLANE_V];
01084         }
01085 
01086         if (!single_file)
01087           out_close(out, out_fn, do_md5);
01088       }
01089     }
01090 
01091     if (stop_after && frame_in >= stop_after)
01092       break;
01093   }
01094 
01095   if (summary || progress) {
01096     show_progress(frame_in, frame_out, dx_time);
01097     fprintf(stderr, "\n");
01098   }
01099 
01100   if (frames_corrupted)
01101     fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted);
01102 
01103 fail:
01104 
01105   if (vpx_codec_destroy(&decoder)) {
01106     fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder));
01107     return EXIT_FAILURE;
01108   }
01109 
01110   if (single_file && !noblit)
01111     out_close(out, outfile, do_md5);
01112 
01113   if (input.nestegg_ctx)
01114     nestegg_destroy(input.nestegg_ctx);
01115   if (input.kind != WEBM_FILE)
01116     free(buf);
01117   fclose(infile);
01118   free(argv);
01119 
01120   return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS;
01121 }