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

Generated on 4 Dec 2017 for WebM VP8 Codec SDK by  doxygen 1.6.1