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

Generated on 13 May 2012 for WebM VP8 Codec SDK by  doxygen 1.6.1