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