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