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