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

Generated on 9 Sep 2013 for WebM VP8 Codec SDK by  doxygen 1.6.1