1 /* 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 12 /* This is a simple program that reads ivf files and decodes them 13 * using the new interface. Decoded frames are output as YV12 raw. 14 */ 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <stdarg.h> 18 #include <string.h> 19 #include <limits.h> 20 21 #define VPX_CODEC_DISABLE_COMPAT 1 22 #include "vpx_config.h" 23 #include "vpx/vpx_decoder.h" 24 #include "vpx_ports/vpx_timer.h" 25 #if CONFIG_VP8_DECODER 26 #include "vpx/vp8dx.h" 27 #endif 28 #if CONFIG_MD5 29 #include "md5_utils.h" 30 #endif 31 #include "tools_common.h" 32 #include "nestegg/include/nestegg/nestegg.h" 33 34 #if CONFIG_OS_SUPPORT 35 #if defined(_MSC_VER) 36 #include <io.h> 37 #define snprintf _snprintf 38 #define isatty _isatty 39 #define fileno _fileno 40 #else 41 #include <unistd.h> 42 #endif 43 #endif 44 45 #ifndef PATH_MAX 46 #define PATH_MAX 256 47 #endif 48 49 static const char *exec_name; 50 51 #define VP8_FOURCC (0x00385056) 52 static const struct 53 { 54 char const *name; 55 vpx_codec_iface_t *iface; 56 unsigned int fourcc; 57 unsigned int fourcc_mask; 58 } ifaces[] = 59 { 60 #if CONFIG_VP8_DECODER 61 {"vp8", &vpx_codec_vp8_dx_algo, VP8_FOURCC, 0x00FFFFFF}, 62 #endif 63 }; 64 65 #include "args.h" 66 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, 67 "Codec to use"); 68 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, 69 "Output raw YV12 frames"); 70 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, 71 "Output raw I420 frames"); 72 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0, 73 "Flip the chroma planes in the output"); 74 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0, 75 "Don't process the decoded frames"); 76 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0, 77 "Show progress after each frame decodes"); 78 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1, 79 "Stop decoding after n frames"); 80 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0, 81 "Postprocess decoded frames"); 82 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0, 83 "Show timing summary"); 84 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, 85 "Output file name pattern (see below)"); 86 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1, 87 "Max threads to use"); 88 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, 89 "Show version string"); 90 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0, 91 "Enable decoder error-concealment"); 92 93 94 #if CONFIG_MD5 95 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, 96 "Compute the MD5 sum of the decoded frame"); 97 #endif 98 static const arg_def_t *all_args[] = 99 { 100 &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg, 101 &progressarg, &limitarg, &postprocarg, &summaryarg, &outputfile, 102 &threadsarg, &verbosearg, 103 #if CONFIG_MD5 104 &md5arg, 105 #endif 106 &error_concealment, 107 NULL 108 }; 109 110 #if CONFIG_VP8_DECODER 111 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1, 112 "Enable VP8 postproc add noise"); 113 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0, 114 "Enable VP8 deblocking"); 115 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level", 1, 116 "Enable VP8 demacroblocking, w/ level"); 117 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1, 118 "Enable VP8 visible debug info"); 119 static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1, 120 "Display only selected reference frame per macro block"); 121 static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1, 122 "Display only selected macro block modes"); 123 static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1, 124 "Display only selected block modes"); 125 static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1, 126 "Draw only selected motion vectors"); 127 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0, 128 "Enable multiframe quality enhancement"); 129 130 static const arg_def_t *vp8_pp_args[] = 131 { 132 &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info, 133 &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe, 134 NULL 135 }; 136 #endif 137 138 static void usage_exit() 139 { 140 int i; 141 142 fprintf(stderr, "Usage: %s <options> filename\n\n" 143 "Options:\n", exec_name); 144 arg_show_usage(stderr, all_args); 145 #if CONFIG_VP8_DECODER 146 fprintf(stderr, "\nVP8 Postprocessing Options:\n"); 147 arg_show_usage(stderr, vp8_pp_args); 148 #endif 149 fprintf(stderr, 150 "\nOutput File Patterns:\n\n" 151 " The -o argument specifies the name of the file(s) to " 152 "write to. If the\n argument does not include any escape " 153 "characters, the output will be\n written to a single file. " 154 "Otherwise, the filename will be calculated by\n expanding " 155 "the following escape characters:\n"); 156 fprintf(stderr, 157 "\n\t%%w - Frame width" 158 "\n\t%%h - Frame height" 159 "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)" 160 "\n\n Pattern arguments are only supported in conjunction " 161 "with the --yv12 and\n --i420 options. If the -o option is " 162 "not specified, the output will be\n directed to stdout.\n" 163 ); 164 fprintf(stderr, "\nIncluded decoders:\n\n"); 165 166 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) 167 fprintf(stderr, " %-6s - %s\n", 168 ifaces[i].name, 169 vpx_codec_iface_name(ifaces[i].iface)); 170 171 exit(EXIT_FAILURE); 172 } 173 174 void die(const char *fmt, ...) 175 { 176 va_list ap; 177 va_start(ap, fmt); 178 vfprintf(stderr, fmt, ap); 179 fprintf(stderr, "\n"); 180 usage_exit(); 181 } 182 183 static unsigned int mem_get_le16(const void *vmem) 184 { 185 unsigned int val; 186 const unsigned char *mem = (const unsigned char *)vmem; 187 188 val = mem[1] << 8; 189 val |= mem[0]; 190 return val; 191 } 192 193 static unsigned int mem_get_le32(const void *vmem) 194 { 195 unsigned int val; 196 const unsigned char *mem = (const unsigned char *)vmem; 197 198 val = mem[3] << 24; 199 val |= mem[2] << 16; 200 val |= mem[1] << 8; 201 val |= mem[0]; 202 return val; 203 } 204 205 enum file_kind 206 { 207 RAW_FILE, 208 IVF_FILE, 209 WEBM_FILE 210 }; 211 212 struct input_ctx 213 { 214 enum file_kind kind; 215 FILE *infile; 216 nestegg *nestegg_ctx; 217 nestegg_packet *pkt; 218 unsigned int chunk; 219 unsigned int chunks; 220 unsigned int video_track; 221 }; 222 223 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t)) 224 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t)) 225 static int read_frame(struct input_ctx *input, 226 uint8_t **buf, 227 size_t *buf_sz, 228 size_t *buf_alloc_sz) 229 { 230 char raw_hdr[IVF_FRAME_HDR_SZ]; 231 size_t new_buf_sz; 232 FILE *infile = input->infile; 233 enum file_kind kind = input->kind; 234 if(kind == WEBM_FILE) 235 { 236 if(input->chunk >= input->chunks) 237 { 238 unsigned int track; 239 240 do 241 { 242 /* End of this packet, get another. */ 243 if(input->pkt) 244 nestegg_free_packet(input->pkt); 245 246 if(nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0 247 || nestegg_packet_track(input->pkt, &track)) 248 return 1; 249 250 } while(track != input->video_track); 251 252 if(nestegg_packet_count(input->pkt, &input->chunks)) 253 return 1; 254 input->chunk = 0; 255 } 256 257 if(nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz)) 258 return 1; 259 input->chunk++; 260 261 return 0; 262 } 263 /* For both the raw and ivf formats, the frame size is the first 4 bytes 264 * of the frame header. We just need to special case on the header 265 * size. 266 */ 267 else if (fread(raw_hdr, kind==IVF_FILE 268 ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) 269 { 270 if (!feof(infile)) 271 fprintf(stderr, "Failed to read frame size\n"); 272 273 new_buf_sz = 0; 274 } 275 else 276 { 277 new_buf_sz = mem_get_le32(raw_hdr); 278 279 if (new_buf_sz > 256 * 1024 * 1024) 280 { 281 fprintf(stderr, "Error: Read invalid frame size (%u)\n", 282 (unsigned int)new_buf_sz); 283 new_buf_sz = 0; 284 } 285 286 if (kind == RAW_FILE && new_buf_sz > 256 * 1024) 287 fprintf(stderr, "Warning: Read invalid frame size (%u)" 288 " - not a raw file?\n", (unsigned int)new_buf_sz); 289 290 if (new_buf_sz > *buf_alloc_sz) 291 { 292 uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz); 293 294 if (new_buf) 295 { 296 *buf = new_buf; 297 *buf_alloc_sz = 2 * new_buf_sz; 298 } 299 else 300 { 301 fprintf(stderr, "Failed to allocate compressed data buffer\n"); 302 new_buf_sz = 0; 303 } 304 } 305 } 306 307 *buf_sz = new_buf_sz; 308 309 if (!feof(infile)) 310 { 311 if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) 312 { 313 fprintf(stderr, "Failed to read full frame\n"); 314 return 1; 315 } 316 317 return 0; 318 } 319 320 return 1; 321 } 322 323 void *out_open(const char *out_fn, int do_md5) 324 { 325 void *out = NULL; 326 327 if (do_md5) 328 { 329 #if CONFIG_MD5 330 MD5Context *md5_ctx = out = malloc(sizeof(MD5Context)); 331 (void)out_fn; 332 MD5Init(md5_ctx); 333 #endif 334 } 335 else 336 { 337 FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") 338 : set_binary_mode(stdout); 339 340 if (!outfile) 341 { 342 fprintf(stderr, "Failed to output file"); 343 exit(EXIT_FAILURE); 344 } 345 } 346 347 return out; 348 } 349 350 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) 351 { 352 if (do_md5) 353 { 354 #if CONFIG_MD5 355 MD5Update(out, buf, len); 356 #endif 357 } 358 else 359 { 360 (void) fwrite(buf, 1, len, out); 361 } 362 } 363 364 void out_close(void *out, const char *out_fn, int do_md5) 365 { 366 if (do_md5) 367 { 368 #if CONFIG_MD5 369 uint8_t md5[16]; 370 int i; 371 372 MD5Final(md5, out); 373 free(out); 374 375 for (i = 0; i < 16; i++) 376 printf("%02x", md5[i]); 377 378 printf(" %s\n", out_fn); 379 #endif 380 } 381 else 382 { 383 fclose(out); 384 } 385 } 386 387 unsigned int file_is_ivf(FILE *infile, 388 unsigned int *fourcc, 389 unsigned int *width, 390 unsigned int *height, 391 unsigned int *fps_den, 392 unsigned int *fps_num) 393 { 394 char raw_hdr[32]; 395 int is_ivf = 0; 396 397 if (fread(raw_hdr, 1, 32, infile) == 32) 398 { 399 if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' 400 && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') 401 { 402 is_ivf = 1; 403 404 if (mem_get_le16(raw_hdr + 4) != 0) 405 fprintf(stderr, "Error: Unrecognized IVF version! This file may not" 406 " decode properly."); 407 408 *fourcc = mem_get_le32(raw_hdr + 8); 409 *width = mem_get_le16(raw_hdr + 12); 410 *height = mem_get_le16(raw_hdr + 14); 411 *fps_num = mem_get_le32(raw_hdr + 16); 412 *fps_den = mem_get_le32(raw_hdr + 20); 413 414 /* Some versions of vpxenc used 1/(2*fps) for the timebase, so 415 * we can guess the framerate using only the timebase in this 416 * case. Other files would require reading ahead to guess the 417 * timebase, like we do for webm. 418 */ 419 if(*fps_num < 1000) 420 { 421 /* Correct for the factor of 2 applied to the timebase in the 422 * encoder. 423 */ 424 if(*fps_num&1)*fps_den<<=1; 425 else *fps_num>>=1; 426 } 427 else 428 { 429 /* Don't know FPS for sure, and don't have readahead code 430 * (yet?), so just default to 30fps. 431 */ 432 *fps_num = 30; 433 *fps_den = 1; 434 } 435 } 436 } 437 438 if (!is_ivf) 439 rewind(infile); 440 441 return is_ivf; 442 } 443 444 445 unsigned int file_is_raw(FILE *infile, 446 unsigned int *fourcc, 447 unsigned int *width, 448 unsigned int *height, 449 unsigned int *fps_den, 450 unsigned int *fps_num) 451 { 452 unsigned char buf[32]; 453 int is_raw = 0; 454 vpx_codec_stream_info_t si; 455 456 si.sz = sizeof(si); 457 458 if (fread(buf, 1, 32, infile) == 32) 459 { 460 int i; 461 462 if(mem_get_le32(buf) < 256 * 1024 * 1024) 463 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) 464 if(!vpx_codec_peek_stream_info(ifaces[i].iface, 465 buf + 4, 32 - 4, &si)) 466 { 467 is_raw = 1; 468 *fourcc = ifaces[i].fourcc; 469 *width = si.w; 470 *height = si.h; 471 *fps_num = 30; 472 *fps_den = 1; 473 break; 474 } 475 } 476 477 rewind(infile); 478 return is_raw; 479 } 480 481 482 static int 483 nestegg_read_cb(void *buffer, size_t length, void *userdata) 484 { 485 FILE *f = userdata; 486 487 if(fread(buffer, 1, length, f) < length) 488 { 489 if (ferror(f)) 490 return -1; 491 if (feof(f)) 492 return 0; 493 } 494 return 1; 495 } 496 497 498 static int 499 nestegg_seek_cb(int64_t offset, int whence, void * userdata) 500 { 501 switch(whence) { 502 case NESTEGG_SEEK_SET: whence = SEEK_SET; break; 503 case NESTEGG_SEEK_CUR: whence = SEEK_CUR; break; 504 case NESTEGG_SEEK_END: whence = SEEK_END; break; 505 }; 506 return fseek(userdata, (long)offset, whence)? -1 : 0; 507 } 508 509 510 static int64_t 511 nestegg_tell_cb(void * userdata) 512 { 513 return ftell(userdata); 514 } 515 516 517 static void 518 nestegg_log_cb(nestegg * context, unsigned int severity, char const * format, 519 ...) 520 { 521 va_list ap; 522 523 va_start(ap, format); 524 vfprintf(stderr, format, ap); 525 fprintf(stderr, "\n"); 526 va_end(ap); 527 } 528 529 530 static int 531 webm_guess_framerate(struct input_ctx *input, 532 unsigned int *fps_den, 533 unsigned int *fps_num) 534 { 535 unsigned int i; 536 uint64_t tstamp=0; 537 538 /* Guess the framerate. Read up to 1 second, or 50 video packets, 539 * whichever comes first. 540 */ 541 for(i=0; tstamp < 1000000000 && i < 50;) 542 { 543 nestegg_packet * pkt; 544 unsigned int track; 545 546 if(nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0) 547 break; 548 549 nestegg_packet_track(pkt, &track); 550 if(track == input->video_track) 551 { 552 nestegg_packet_tstamp(pkt, &tstamp); 553 i++; 554 } 555 556 nestegg_free_packet(pkt); 557 } 558 559 if(nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) 560 goto fail; 561 562 *fps_num = (i - 1) * 1000000; 563 *fps_den = (unsigned int)(tstamp / 1000); 564 return 0; 565 fail: 566 nestegg_destroy(input->nestegg_ctx); 567 input->nestegg_ctx = NULL; 568 rewind(input->infile); 569 return 1; 570 } 571 572 573 static int 574 file_is_webm(struct input_ctx *input, 575 unsigned int *fourcc, 576 unsigned int *width, 577 unsigned int *height, 578 unsigned int *fps_den, 579 unsigned int *fps_num) 580 { 581 unsigned int i, n; 582 int track_type = -1; 583 584 nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0}; 585 nestegg_video_params params; 586 587 io.userdata = input->infile; 588 if(nestegg_init(&input->nestegg_ctx, io, NULL)) 589 goto fail; 590 591 if(nestegg_track_count(input->nestegg_ctx, &n)) 592 goto fail; 593 594 for(i=0; i<n; i++) 595 { 596 track_type = nestegg_track_type(input->nestegg_ctx, i); 597 598 if(track_type == NESTEGG_TRACK_VIDEO) 599 break; 600 else if(track_type < 0) 601 goto fail; 602 } 603 604 if(nestegg_track_codec_id(input->nestegg_ctx, i) != NESTEGG_CODEC_VP8) 605 { 606 fprintf(stderr, "Not VP8 video, quitting.\n"); 607 exit(1); 608 } 609 610 input->video_track = i; 611 612 if(nestegg_track_video_params(input->nestegg_ctx, i, ¶ms)) 613 goto fail; 614 615 *fps_den = 0; 616 *fps_num = 0; 617 *fourcc = VP8_FOURCC; 618 *width = params.width; 619 *height = params.height; 620 return 1; 621 fail: 622 input->nestegg_ctx = NULL; 623 rewind(input->infile); 624 return 0; 625 } 626 627 628 void show_progress(int frame_in, int frame_out, unsigned long dx_time) 629 { 630 fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r", 631 frame_in, frame_out, dx_time, 632 (float)frame_out * 1000000.0 / (float)dx_time); 633 } 634 635 636 void generate_filename(const char *pattern, char *out, size_t q_len, 637 unsigned int d_w, unsigned int d_h, 638 unsigned int frame_in) 639 { 640 const char *p = pattern; 641 char *q = out; 642 643 do 644 { 645 char *next_pat = strchr(p, '%'); 646 647 if(p == next_pat) 648 { 649 size_t pat_len; 650 651 /* parse the pattern */ 652 q[q_len - 1] = '\0'; 653 switch(p[1]) 654 { 655 case 'w': snprintf(q, q_len - 1, "%d", d_w); break; 656 case 'h': snprintf(q, q_len - 1, "%d", d_h); break; 657 case '1': snprintf(q, q_len - 1, "%d", frame_in); break; 658 case '2': snprintf(q, q_len - 1, "%02d", frame_in); break; 659 case '3': snprintf(q, q_len - 1, "%03d", frame_in); break; 660 case '4': snprintf(q, q_len - 1, "%04d", frame_in); break; 661 case '5': snprintf(q, q_len - 1, "%05d", frame_in); break; 662 case '6': snprintf(q, q_len - 1, "%06d", frame_in); break; 663 case '7': snprintf(q, q_len - 1, "%07d", frame_in); break; 664 case '8': snprintf(q, q_len - 1, "%08d", frame_in); break; 665 case '9': snprintf(q, q_len - 1, "%09d", frame_in); break; 666 default: 667 die("Unrecognized pattern %%%c\n", p[1]); 668 } 669 670 pat_len = strlen(q); 671 if(pat_len >= q_len - 1) 672 die("Output filename too long.\n"); 673 q += pat_len; 674 p += 2; 675 q_len -= pat_len; 676 } 677 else 678 { 679 size_t copy_len; 680 681 /* copy the next segment */ 682 if(!next_pat) 683 copy_len = strlen(p); 684 else 685 copy_len = next_pat - p; 686 687 if(copy_len >= q_len - 1) 688 die("Output filename too long.\n"); 689 690 memcpy(q, p, copy_len); 691 q[copy_len] = '\0'; 692 q += copy_len; 693 p += copy_len; 694 q_len -= copy_len; 695 } 696 } while(*p); 697 } 698 699 700 int main(int argc, const char **argv_) 701 { 702 vpx_codec_ctx_t decoder; 703 char *fn = NULL; 704 int i; 705 uint8_t *buf = NULL; 706 size_t buf_sz = 0, buf_alloc_sz = 0; 707 FILE *infile; 708 int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do_md5 = 0, progress = 0; 709 int stop_after = 0, postproc = 0, summary = 0, quiet = 1; 710 int ec_enabled = 0; 711 vpx_codec_iface_t *iface = NULL; 712 unsigned int fourcc; 713 unsigned long dx_time = 0; 714 struct arg arg; 715 char **argv, **argi, **argj; 716 const char *outfile_pattern = 0; 717 char outfile[PATH_MAX]; 718 int single_file; 719 int use_y4m = 1; 720 unsigned int width; 721 unsigned int height; 722 unsigned int fps_den; 723 unsigned int fps_num; 724 void *out = NULL; 725 vpx_codec_dec_cfg_t cfg = {0}; 726 #if CONFIG_VP8_DECODER 727 vp8_postproc_cfg_t vp8_pp_cfg = {0}; 728 int vp8_dbg_color_ref_frame = 0; 729 int vp8_dbg_color_mb_modes = 0; 730 int vp8_dbg_color_b_modes = 0; 731 int vp8_dbg_display_mv = 0; 732 #endif 733 struct input_ctx input = {0}; 734 int frames_corrupted = 0; 735 int dec_flags = 0; 736 737 /* Parse command line */ 738 exec_name = argv_[0]; 739 argv = argv_dup(argc - 1, argv_ + 1); 740 741 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) 742 { 743 memset(&arg, 0, sizeof(arg)); 744 arg.argv_step = 1; 745 746 if (arg_match(&arg, &codecarg, argi)) 747 { 748 int j, k = -1; 749 750 for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++) 751 if (!strcmp(ifaces[j].name, arg.val)) 752 k = j; 753 754 if (k >= 0) 755 iface = ifaces[k].iface; 756 else 757 die("Error: Unrecognized argument (%s) to --codec\n", 758 arg.val); 759 } 760 else if (arg_match(&arg, &outputfile, argi)) 761 outfile_pattern = arg.val; 762 else if (arg_match(&arg, &use_yv12, argi)) 763 { 764 use_y4m = 0; 765 flipuv = 1; 766 } 767 else if (arg_match(&arg, &use_i420, argi)) 768 { 769 use_y4m = 0; 770 flipuv = 0; 771 } 772 else if (arg_match(&arg, &flipuvarg, argi)) 773 flipuv = 1; 774 else if (arg_match(&arg, &noblitarg, argi)) 775 noblit = 1; 776 else if (arg_match(&arg, &progressarg, argi)) 777 progress = 1; 778 else if (arg_match(&arg, &limitarg, argi)) 779 stop_after = arg_parse_uint(&arg); 780 else if (arg_match(&arg, &postprocarg, argi)) 781 postproc = 1; 782 else if (arg_match(&arg, &md5arg, argi)) 783 do_md5 = 1; 784 else if (arg_match(&arg, &summaryarg, argi)) 785 summary = 1; 786 else if (arg_match(&arg, &threadsarg, argi)) 787 cfg.threads = arg_parse_uint(&arg); 788 else if (arg_match(&arg, &verbosearg, argi)) 789 quiet = 0; 790 791 #if CONFIG_VP8_DECODER 792 else if (arg_match(&arg, &addnoise_level, argi)) 793 { 794 postproc = 1; 795 vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE; 796 vp8_pp_cfg.noise_level = arg_parse_uint(&arg); 797 } 798 else if (arg_match(&arg, &demacroblock_level, argi)) 799 { 800 postproc = 1; 801 vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK; 802 vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg); 803 } 804 else if (arg_match(&arg, &deblock, argi)) 805 { 806 postproc = 1; 807 vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK; 808 } 809 else if (arg_match(&arg, &mfqe, argi)) 810 { 811 postproc = 1; 812 vp8_pp_cfg.post_proc_flag |= VP8_MFQE; 813 } 814 else if (arg_match(&arg, &pp_debug_info, argi)) 815 { 816 unsigned int level = arg_parse_uint(&arg); 817 818 postproc = 1; 819 vp8_pp_cfg.post_proc_flag &= ~0x7; 820 821 if (level) 822 vp8_pp_cfg.post_proc_flag |= level; 823 } 824 else if (arg_match(&arg, &pp_disp_ref_frame, argi)) 825 { 826 unsigned int flags = arg_parse_int(&arg); 827 if (flags) 828 { 829 postproc = 1; 830 vp8_dbg_color_ref_frame = flags; 831 } 832 } 833 else if (arg_match(&arg, &pp_disp_mb_modes, argi)) 834 { 835 unsigned int flags = arg_parse_int(&arg); 836 if (flags) 837 { 838 postproc = 1; 839 vp8_dbg_color_mb_modes = flags; 840 } 841 } 842 else if (arg_match(&arg, &pp_disp_b_modes, argi)) 843 { 844 unsigned int flags = arg_parse_int(&arg); 845 if (flags) 846 { 847 postproc = 1; 848 vp8_dbg_color_b_modes = flags; 849 } 850 } 851 else if (arg_match(&arg, &pp_disp_mvs, argi)) 852 { 853 unsigned int flags = arg_parse_int(&arg); 854 if (flags) 855 { 856 postproc = 1; 857 vp8_dbg_display_mv = flags; 858 } 859 } 860 else if (arg_match(&arg, &error_concealment, argi)) 861 { 862 ec_enabled = 1; 863 } 864 865 #endif 866 else 867 argj++; 868 } 869 870 /* Check for unrecognized options */ 871 for (argi = argv; *argi; argi++) 872 if (argi[0][0] == '-' && strlen(argi[0]) > 1) 873 die("Error: Unrecognized option %s\n", *argi); 874 875 /* Handle non-option arguments */ 876 fn = argv[0]; 877 878 if (!fn) 879 usage_exit(); 880 881 /* Open file */ 882 infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin); 883 884 if (!infile) 885 { 886 fprintf(stderr, "Failed to open file '%s'", 887 strcmp(fn, "-") ? fn : "stdin"); 888 return EXIT_FAILURE; 889 } 890 #if CONFIG_OS_SUPPORT 891 /* Make sure we don't dump to the terminal, unless forced to with -o - */ 892 if(!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) 893 { 894 fprintf(stderr, 895 "Not dumping raw video to your terminal. Use '-o -' to " 896 "override.\n"); 897 return EXIT_FAILURE; 898 } 899 #endif 900 input.infile = infile; 901 if(file_is_ivf(infile, &fourcc, &width, &height, &fps_den, 902 &fps_num)) 903 input.kind = IVF_FILE; 904 else if(file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num)) 905 input.kind = WEBM_FILE; 906 else if(file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num)) 907 input.kind = RAW_FILE; 908 else 909 { 910 fprintf(stderr, "Unrecognized input file type.\n"); 911 return EXIT_FAILURE; 912 } 913 914 /* If the output file is not set or doesn't have a sequence number in 915 * it, then we only open it once. 916 */ 917 outfile_pattern = outfile_pattern ? outfile_pattern : "-"; 918 single_file = 1; 919 { 920 const char *p = outfile_pattern; 921 do 922 { 923 p = strchr(p, '%'); 924 if(p && p[1] >= '1' && p[1] <= '9') 925 { 926 /* pattern contains sequence number, so it's not unique. */ 927 single_file = 0; 928 break; 929 } 930 if(p) 931 p++; 932 } while(p); 933 } 934 935 if(single_file && !noblit) 936 { 937 generate_filename(outfile_pattern, outfile, sizeof(outfile)-1, 938 width, height, 0); 939 out = out_open(outfile, do_md5); 940 } 941 942 if (use_y4m && !noblit) 943 { 944 char buffer[128]; 945 if (!single_file) 946 { 947 fprintf(stderr, "YUV4MPEG2 not supported with output patterns," 948 " try --i420 or --yv12.\n"); 949 return EXIT_FAILURE; 950 } 951 952 if(input.kind == WEBM_FILE) 953 if(webm_guess_framerate(&input, &fps_den, &fps_num)) 954 { 955 fprintf(stderr, "Failed to guess framerate -- error parsing " 956 "webm file?\n"); 957 return EXIT_FAILURE; 958 } 959 960 961 /*Note: We can't output an aspect ratio here because IVF doesn't 962 store one, and neither does VP8. 963 That will have to wait until these tools support WebM natively.*/ 964 sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n", 965 "420jpeg", width, height, fps_num, fps_den, 'p'); 966 out_put(out, (unsigned char *)buffer, 967 (unsigned int)strlen(buffer), do_md5); 968 } 969 970 /* Try to determine the codec from the fourcc. */ 971 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) 972 if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) 973 { 974 vpx_codec_iface_t *ivf_iface = ifaces[i].iface; 975 976 if (iface && iface != ivf_iface) 977 fprintf(stderr, "Notice -- IVF header indicates codec: %s\n", 978 ifaces[i].name); 979 else 980 iface = ivf_iface; 981 982 break; 983 } 984 985 dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | 986 (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); 987 if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface, &cfg, 988 dec_flags)) 989 { 990 fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decoder)); 991 return EXIT_FAILURE; 992 } 993 994 if (!quiet) 995 fprintf(stderr, "%s\n", decoder.name); 996 997 #if CONFIG_VP8_DECODER 998 999 if (vp8_pp_cfg.post_proc_flag 1000 && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) 1001 { 1002 fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decoder)); 1003 return EXIT_FAILURE; 1004 } 1005 1006 if (vp8_dbg_color_ref_frame 1007 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_ref_frame)) 1008 { 1009 fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_codec_error(&decoder)); 1010 return EXIT_FAILURE; 1011 } 1012 1013 if (vp8_dbg_color_mb_modes 1014 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_mb_modes)) 1015 { 1016 fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_codec_error(&decoder)); 1017 return EXIT_FAILURE; 1018 } 1019 1020 if (vp8_dbg_color_b_modes 1021 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_modes)) 1022 { 1023 fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_error(&decoder)); 1024 return EXIT_FAILURE; 1025 } 1026 1027 if (vp8_dbg_display_mv 1028 && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)) 1029 { 1030 fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_codec_error(&decoder)); 1031 return EXIT_FAILURE; 1032 } 1033 #endif 1034 1035 /* Decode file */ 1036 while (!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) 1037 { 1038 vpx_codec_iter_t iter = NULL; 1039 vpx_image_t *img; 1040 struct vpx_usec_timer timer; 1041 int corrupted; 1042 1043 vpx_usec_timer_start(&timer); 1044 1045 if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) 1046 { 1047 const char *detail = vpx_codec_error_detail(&decoder); 1048 fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder)); 1049 1050 if (detail) 1051 fprintf(stderr, " Additional information: %s\n", detail); 1052 1053 goto fail; 1054 } 1055 1056 vpx_usec_timer_mark(&timer); 1057 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); 1058 1059 ++frame_in; 1060 1061 if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) 1062 { 1063 fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n", 1064 vpx_codec_error(&decoder)); 1065 goto fail; 1066 } 1067 frames_corrupted += corrupted; 1068 1069 vpx_usec_timer_start(&timer); 1070 1071 if ((img = vpx_codec_get_frame(&decoder, &iter))) 1072 ++frame_out; 1073 1074 vpx_usec_timer_mark(&timer); 1075 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); 1076 1077 if (progress) 1078 show_progress(frame_in, frame_out, dx_time); 1079 1080 if (!noblit) 1081 { 1082 if (img) 1083 { 1084 unsigned int y; 1085 char out_fn[PATH_MAX]; 1086 uint8_t *buf; 1087 1088 if (!single_file) 1089 { 1090 size_t len = sizeof(out_fn)-1; 1091 1092 out_fn[len] = '\0'; 1093 generate_filename(outfile_pattern, out_fn, len-1, 1094 img->d_w, img->d_h, frame_in); 1095 out = out_open(out_fn, do_md5); 1096 } 1097 else if(use_y4m) 1098 out_put(out, (unsigned char *)"FRAME\n", 6, do_md5); 1099 1100 buf = img->planes[VPX_PLANE_Y]; 1101 1102 for (y = 0; y < img->d_h; y++) 1103 { 1104 out_put(out, buf, img->d_w, do_md5); 1105 buf += img->stride[VPX_PLANE_Y]; 1106 } 1107 1108 buf = img->planes[flipuv?VPX_PLANE_V:VPX_PLANE_U]; 1109 1110 for (y = 0; y < (1 + img->d_h) / 2; y++) 1111 { 1112 out_put(out, buf, (1 + img->d_w) / 2, do_md5); 1113 buf += img->stride[VPX_PLANE_U]; 1114 } 1115 1116 buf = img->planes[flipuv?VPX_PLANE_U:VPX_PLANE_V]; 1117 1118 for (y = 0; y < (1 + img->d_h) / 2; y++) 1119 { 1120 out_put(out, buf, (1 + img->d_w) / 2, do_md5); 1121 buf += img->stride[VPX_PLANE_V]; 1122 } 1123 1124 if (!single_file) 1125 out_close(out, out_fn, do_md5); 1126 } 1127 } 1128 1129 if (stop_after && frame_in >= stop_after) 1130 break; 1131 } 1132 1133 if (summary || progress) 1134 { 1135 show_progress(frame_in, frame_out, dx_time); 1136 fprintf(stderr, "\n"); 1137 } 1138 1139 if (frames_corrupted) 1140 fprintf(stderr, "WARNING: %d frames corrupted.\n",frames_corrupted); 1141 1142 fail: 1143 1144 if (vpx_codec_destroy(&decoder)) 1145 { 1146 fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder)); 1147 return EXIT_FAILURE; 1148 } 1149 1150 if (single_file && !noblit) 1151 out_close(out, outfile, do_md5); 1152 1153 if(input.nestegg_ctx) 1154 nestegg_destroy(input.nestegg_ctx); 1155 if(input.kind != WEBM_FILE) 1156 free(buf); 1157 fclose(infile); 1158 free(argv); 1159 1160 return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS; 1161 } 1162