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