ivfdec

00001 /*
00002  *  Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
00003  *
00004  *  Use of this source code is governed by a BSD-style license and patent
00005  *  grant that can be found in the LICENSE file in the root of the source
00006  *  tree. All contributing project authors may be found in the AUTHORS
00007  *  file in the root of the source tree.
00008  */
00009 
00010 
00011 /* This is a simple program that reads ivf files and decodes them
00012  * using the new interface. Decoded frames are output as YV12 raw.
00013  */
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <stdarg.h>
00017 #include <string.h>
00018 #define VPX_CODEC_DISABLE_COMPAT 1
00019 #include "vpx_config.h"
00020 #include "vpx_decoder.h"
00021 #include "vpx_ports/vpx_timer.h"
00022 #if CONFIG_VP8_DECODER
00023 #include "vp8dx.h"
00024 #endif
00025 #if CONFIG_MD5
00026 #include "md5_utils.h"
00027 #endif
00028 
00029 static const char *exec_name;
00030 
00031 static const struct
00032 {
00033     char const *name;
00034     const vpx_codec_iface_t *iface;
00035     unsigned int             fourcc;
00036     unsigned int             fourcc_mask;
00037 } ifaces[] =
00038 {
00039 #if CONFIG_VP8_DECODER
00040     {"vp8",  &vpx_codec_vp8_dx_algo,   0x00385056, 0x00FFFFFF},
00041 #endif
00042 };
00043 
00044 #include "args.h"
00045 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1,
00046                                   "Codec to use");
00047 static const arg_def_t prefixarg = ARG_DEF("p", "prefix", 1,
00048                                    "Prefix to use when saving frames");
00049 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0,
00050                                   "Output file is YV12 ");
00051 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0,
00052                                   "Output file is I420 (default)");
00053 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0,
00054                                    "Synonym for --yv12");
00055 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0,
00056                                    "Don't process the decoded frames");
00057 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0,
00058                                      "Show progress after each frame decodes");
00059 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1,
00060                                   "Stop decoding after n frames");
00061 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0,
00062                                      "Postprocess decoded frames");
00063 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0,
00064                                     "Show timing summary");
00065 static const arg_def_t outputfile = ARG_DEF("o", "output-raw-file", 1,
00066                                     "Output raw yv12 file instead of images");
00067 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1,
00068                                     "Max threads to use");
00069 static const arg_def_t quietarg = ARG_DEF("q", "quiet", 0,
00070                                   "Suppress version string");
00071 
00072 #if CONFIG_MD5
00073 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0,
00074                                         "Compute the MD5 sum of the decoded frame");
00075 #endif
00076 static const arg_def_t *all_args[] =
00077 {
00078     &codecarg, &prefixarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg,
00079     &progressarg, &limitarg, &postprocarg, &summaryarg, &outputfile,
00080     &threadsarg, &quietarg,
00081 #if CONFIG_MD5
00082     &md5arg,
00083 #endif
00084     NULL
00085 };
00086 
00087 #if CONFIG_VP8_DECODER
00088 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1,
00089                                         "Enable VP8 postproc add noise");
00090 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0,
00091                                  "Enable VP8 deblocking");
00092 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1,
00093         "Enable VP8 demacroblocking, w/ level");
00094 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1,
00095                                        "Enable VP8 visible debug info");
00096 
00097 
00098 static const arg_def_t *vp8_pp_args[] =
00099 {
00100     &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info,
00101     NULL
00102 };
00103 #endif
00104 
00105 static void usage_exit()
00106 {
00107     int i;
00108 
00109     fprintf(stderr, "Usage: %s <options> filename\n\n"
00110             "Options:\n", exec_name);
00111     arg_show_usage(stderr, all_args);
00112 #if CONFIG_VP8_DECODER
00113     fprintf(stderr, "\nvp8 Postprocessing Options:\n");
00114     arg_show_usage(stderr, vp8_pp_args);
00115 #endif
00116     fprintf(stderr, "\nIncluded decoders:\n\n");
00117 
00118     for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
00119         fprintf(stderr, "    %-6s - %s\n",
00120                 ifaces[i].name,
00121                 vpx_codec_iface_name(ifaces[i].iface));
00122 
00123     exit(EXIT_FAILURE);
00124 }
00125 
00126 void die(const char *fmt, ...)
00127 {
00128     va_list ap;
00129     va_start(ap, fmt);
00130     vfprintf(stderr, fmt, ap);
00131     fprintf(stderr, "\n");
00132     usage_exit();
00133 }
00134 
00135 static unsigned int mem_get_le16(const void *vmem)
00136 {
00137     unsigned int  val;
00138     const unsigned char *mem = (const unsigned char *)vmem;
00139 
00140     val = mem[1] << 8;
00141     val |= mem[0];
00142     return val;
00143 }
00144 
00145 static unsigned int mem_get_le32(const void *vmem)
00146 {
00147     unsigned int  val;
00148     const unsigned char *mem = (const unsigned char *)vmem;
00149 
00150     val = mem[3] << 24;
00151     val |= mem[2] << 16;
00152     val |= mem[1] << 8;
00153     val |= mem[0];
00154     return val;
00155 }
00156 
00157 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t))
00158 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t))
00159 static int read_frame(FILE                  *infile,
00160                       uint8_t               **buf,
00161                       uint32_t              *buf_sz,
00162                       uint32_t              *buf_alloc_sz,
00163                       int                    is_ivf)
00164 {
00165     char     raw_hdr[IVF_FRAME_HDR_SZ];
00166     uint32_t new_buf_sz;
00167 
00168     /* For both the raw and ivf formats, the frame size is the first 4 bytes
00169      * of the frame header. We just need to special case on the header
00170      * size.
00171      */
00172     if (fread(raw_hdr, is_ivf ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1,
00173               infile) != 1)
00174     {
00175         if (!feof(infile))
00176             fprintf(stderr, "Failed to read frame size\n");
00177 
00178         new_buf_sz = 0;
00179     }
00180     else
00181     {
00182         new_buf_sz = mem_get_le32(raw_hdr);
00183 
00184         if (new_buf_sz > 256 * 1024 * 1024)
00185         {
00186             fprintf(stderr, "Error: Read invalid frame size (%u)\n",
00187                     new_buf_sz);
00188             new_buf_sz = 0;
00189         }
00190 
00191         if (!is_ivf && new_buf_sz > 256 * 1024)
00192             fprintf(stderr, "Warning: Read invalid frame size (%u)"
00193                     " - not a raw file?\n", new_buf_sz);
00194 
00195         if (new_buf_sz > *buf_alloc_sz)
00196         {
00197             uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz);
00198 
00199             if (new_buf)
00200             {
00201                 *buf = new_buf;
00202                 *buf_alloc_sz = 2 * new_buf_sz;
00203             }
00204             else
00205             {
00206                 fprintf(stderr, "Failed to allocate compressed data buffer\n");
00207                 new_buf_sz = 0;
00208             }
00209         }
00210     }
00211 
00212     *buf_sz = new_buf_sz;
00213 
00214     if (*buf_sz)
00215     {
00216         if (fread(*buf, 1, *buf_sz, infile) != *buf_sz)
00217         {
00218             fprintf(stderr, "Failed to read full frame\n");
00219             return 1;
00220         }
00221 
00222         return 0;
00223     }
00224 
00225     return 1;
00226 }
00227 
00228 void *out_open(const char *out_fn, int do_md5)
00229 {
00230     void *out = NULL;
00231 
00232     if (do_md5)
00233     {
00234 #if CONFIG_MD5
00235         md5_ctx_t *md5_ctx = out = malloc(sizeof(md5_ctx_t));
00236         (void)out_fn;
00237         md5_init(md5_ctx);
00238 #endif
00239     }
00240     else
00241     {
00242         FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") : stdout;
00243 
00244         if (!outfile)
00245         {
00246             fprintf(stderr, "Failed to output file");
00247             exit(EXIT_FAILURE);
00248         }
00249     }
00250 
00251     return out;
00252 }
00253 
00254 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5)
00255 {
00256     if (do_md5)
00257     {
00258 #if CONFIG_MD5
00259         md5_update(out, buf, len);
00260 #endif
00261     }
00262     else
00263     {
00264         fwrite(buf, 1, len, out);
00265     }
00266 }
00267 
00268 void out_close(void *out, const char *out_fn, int do_md5)
00269 {
00270     if (do_md5)
00271     {
00272 #if CONFIG_MD5
00273         uint8_t md5[16];
00274         int i;
00275 
00276         md5_finalize(out, md5);
00277         free(out);
00278 
00279         for (i = 0; i < 16; i++)
00280             printf("%02x", md5[i]);
00281 
00282         printf("  %s\n", out_fn);
00283 #endif
00284     }
00285     else
00286     {
00287         fclose(out);
00288     }
00289 }
00290 
00291 unsigned int file_is_ivf(FILE *infile, unsigned int *fourcc)
00292 {
00293     char raw_hdr[32];
00294     int is_ivf = 0;
00295 
00296     if (fread(raw_hdr, 1, 32, infile) == 32)
00297     {
00298         if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K'
00299             && raw_hdr[2] == 'I' && raw_hdr[3] == 'F')
00300         {
00301             is_ivf = 1;
00302 
00303             if (mem_get_le16(raw_hdr + 4) != 0)
00304                 fprintf(stderr, "Error: Unrecognized IVF version! This file may not"
00305                         " decode properly.");
00306 
00307             *fourcc = mem_get_le32(raw_hdr + 8);
00308         }
00309     }
00310 
00311     if (!is_ivf)
00312         rewind(infile);
00313 
00314     return is_ivf;
00315 }
00316 
00317 int main(int argc, const char **argv_)
00318 {
00319     vpx_codec_ctx_t          decoder;
00320     char                  *prefix = NULL, *fn = NULL;
00321     int                    i;
00322     uint8_t               *buf = NULL;
00323     uint32_t               buf_sz = 0, buf_alloc_sz = 0;
00324     FILE                  *infile;
00325     int                    frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0;
00326     int                    stop_after = 0, postproc = 0, summary = 0, quiet = 0;
00327     vpx_codec_iface_t       *iface = NULL;
00328     unsigned int           is_ivf, fourcc;
00329     unsigned long          dx_time = 0;
00330     struct arg               arg;
00331     char                   **argv, **argi, **argj;
00332     const char                   *fn2 = 0;
00333     void                   *out = NULL;
00334     vpx_codec_dec_cfg_t     cfg = {0};
00335 #if CONFIG_VP8_DECODER
00336     vp8_postproc_cfg_t      vp8_pp_cfg = {0};
00337 #endif
00338 
00339     /* Parse command line */
00340     exec_name = argv_[0];
00341     argv = argv_dup(argc - 1, argv_ + 1);
00342 
00343     for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step)
00344     {
00345         memset(&arg, 0, sizeof(arg));
00346         arg.argv_step = 1;
00347 
00348         if (arg_match(&arg, &codecarg, argi))
00349         {
00350             int j, k = -1;
00351 
00352             for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++)
00353                 if (!strcmp(ifaces[j].name, arg.val))
00354                     k = j;
00355 
00356             if (k >= 0)
00357                 iface = ifaces[k].iface;
00358             else
00359                 die("Error: Unrecognized argument (%s) to --codec\n",
00360                     arg.val);
00361         }
00362         else if (arg_match(&arg, &outputfile, argi))
00363             fn2 = arg.val;
00364         else if (arg_match(&arg, &prefixarg, argi))
00365             prefix = strdup(arg.val);
00366         else if (arg_match(&arg, &use_yv12, argi))
00367             flipuv = 1;
00368         else if (arg_match(&arg, &use_i420, argi))
00369             flipuv = 0;
00370         else if (arg_match(&arg, &flipuvarg, argi))
00371             flipuv = 1;
00372         else if (arg_match(&arg, &noblitarg, argi))
00373             noblit = 1;
00374         else if (arg_match(&arg, &progressarg, argi))
00375             progress = 1;
00376         else if (arg_match(&arg, &limitarg, argi))
00377             stop_after = arg_parse_uint(&arg);
00378         else if (arg_match(&arg, &postprocarg, argi))
00379             postproc = 1;
00380         else if (arg_match(&arg, &md5arg, argi))
00381             do_md5 = 1;
00382         else if (arg_match(&arg, &summaryarg, argi))
00383             summary = 1;
00384         else if (arg_match(&arg, &threadsarg, argi))
00385             cfg.threads = arg_parse_uint(&arg);
00386         else if (arg_match(&arg, &quietarg, argi))
00387             quiet = 1;
00388 
00389 #if CONFIG_VP8_DECODER
00390         else if (arg_match(&arg, &addnoise_level, argi))
00391         {
00392             postproc = 1;
00393             vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE;
00394             vp8_pp_cfg.noise_level = arg_parse_uint(&arg);
00395         }
00396         else if (arg_match(&arg, &demacroblock_level, argi))
00397         {
00398             postproc = 1;
00399             vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK;
00400             vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg);
00401         }
00402         else if (arg_match(&arg, &deblock, argi))
00403         {
00404             postproc = 1;
00405             vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK;
00406         }
00407         else if (arg_match(&arg, &pp_debug_info, argi))
00408         {
00409             unsigned int level = arg_parse_uint(&arg);
00410 
00411             postproc = 1;
00412             vp8_pp_cfg.post_proc_flag &= ~0x7;
00413 
00414             if (level)
00415                 vp8_pp_cfg.post_proc_flag |= 8 << (level - 1);
00416         }
00417 
00418 #endif
00419         else
00420             argj++;
00421     }
00422 
00423     /* Check for unrecognized options */
00424     for (argi = argv; *argi; argi++)
00425         if (argi[0][0] == '-' && strlen(argi[0]) > 1)
00426             die("Error: Unrecognized option %s\n", *argi);
00427 
00428     /* Handle non-option arguments */
00429     fn = argv[0];
00430 
00431     if (!fn)
00432         usage_exit();
00433 
00434     if (!prefix)
00435         prefix = strdup("img");
00436 
00437     /* Open file */
00438     infile = strcmp(fn, "-") ? fopen(fn, "rb") : stdin;
00439 
00440     if (!infile)
00441     {
00442         fprintf(stderr, "Failed to open file");
00443         return EXIT_FAILURE;
00444     }
00445 
00446     if (fn2)
00447         out = out_open(fn2, do_md5);
00448 
00449     is_ivf = file_is_ivf(infile, &fourcc);
00450 
00451     if (is_ivf)
00452     {
00453         /* Try to determine the codec from the fourcc. */
00454         for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++)
00455             if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc)
00456             {
00457                 vpx_codec_iface_t  *ivf_iface = ifaces[i].iface;
00458 
00459                 if (iface && iface != ivf_iface)
00460                     fprintf(stderr, "Notice -- IVF header indicates codec: %s\n",
00461                             ifaces[i].name);
00462                 else
00463                     iface = ivf_iface;
00464 
00465                 break;
00466             }
00467     }
00468 
00469     if (vpx_codec_dec_init(&decoder, iface ? iface :  ifaces[0].iface, &cfg,
00470                            postproc ? VPX_CODEC_USE_POSTPROC : 0))
00471     {
00472         fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder));
00473         return EXIT_FAILURE;
00474     }
00475 
00476     if (!quiet)
00477         fprintf(stderr, "%s\n", decoder.name);
00478 
00479 #if CONFIG_VP8_DECODER
00480 
00481     if (vp8_pp_cfg.post_proc_flag
00482         && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg))
00483     {
00484         fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder));
00485         return EXIT_FAILURE;
00486     }
00487 
00488 #endif
00489 
00490     /* Decode file */
00491     while (!read_frame(infile, &buf, &buf_sz, &buf_alloc_sz, is_ivf))
00492     {
00493         vpx_codec_iter_t  iter = NULL;
00494         vpx_image_t    *img;
00495         struct vpx_usec_timer timer;
00496 
00497         vpx_usec_timer_start(&timer);
00498 
00499         if (vpx_codec_decode(&decoder, buf, buf_sz, NULL, 0))
00500         {
00501             const char *detail = vpx_codec_error_detail(&decoder);
00502             fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder));
00503 
00504             if (detail)
00505                 fprintf(stderr, "  Additional information: %s\n", detail);
00506 
00507             goto fail;
00508         }
00509 
00510         vpx_usec_timer_mark(&timer);
00511         dx_time += vpx_usec_timer_elapsed(&timer);
00512 
00513         ++frame_in;
00514 
00515         if (progress)
00516             fprintf(stderr, "decoded frame %d.\n", frame_in);
00517 
00518         if ((img = vpx_codec_get_frame(&decoder, &iter)))
00519             ++frame_out;
00520 
00521         if (!noblit)
00522         {
00523             if (img)
00524             {
00525                 unsigned int y;
00526                 char out_fn[128+24];
00527                 uint8_t *buf;
00528                 const char *sfx = flipuv ? "yv12" : "i420";
00529 
00530                 if (!fn2)
00531                 {
00532                     sprintf(out_fn, "%s-%dx%d-%04d.%s",
00533                             prefix, img->d_w, img->d_h, frame_in, sfx);
00534                     out = out_open(out_fn, do_md5);
00535                 }
00536 
00537                 buf = img->planes[PLANE_Y];
00538 
00539                 for (y = 0; y < img->d_h; y++)
00540                 {
00541                     out_put(out, buf, img->d_w, do_md5);
00542                     buf += img->stride[PLANE_Y];
00543                 }
00544 
00545                 buf = img->planes[flipuv?PLANE_V:PLANE_U];
00546 
00547                 for (y = 0; y < (1 + img->d_h) / 2; y++)
00548                 {
00549                     out_put(out, buf, (1 + img->d_w) / 2, do_md5);
00550                     buf += img->stride[PLANE_U];
00551                 }
00552 
00553                 buf = img->planes[flipuv?PLANE_U:PLANE_V];
00554 
00555                 for (y = 0; y < (1 + img->d_h) / 2; y++)
00556                 {
00557                     out_put(out, buf, (1 + img->d_w) / 2, do_md5);
00558                     buf += img->stride[PLANE_V];
00559                 }
00560 
00561                 if (!fn2)
00562                     out_close(out, out_fn, do_md5);
00563             }
00564         }
00565 
00566         if (stop_after && frame_in >= stop_after)
00567             break;
00568     }
00569 
00570     if (summary)
00571     {
00572         fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\n",
00573                 frame_in, frame_out, dx_time, (float)frame_out * 1000000.0 / (float)dx_time);
00574     }
00575 
00576 fail:
00577 
00578     if (vpx_codec_destroy(&decoder))
00579     {
00580         fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder));
00581         return EXIT_FAILURE;
00582     }
00583 
00584     if (fn2)
00585         out_close(out, fn2, do_md5);
00586 
00587     free(buf);
00588     fclose(infile);
00589     free(prefix);
00590     free(argv);
00591 
00592     return EXIT_SUCCESS;
00593 }

Generated on 20 Dec 2010 for WebM VP8 Codec SDK by  doxygen 1.6.1