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 #include "./vpxenc.h" 12 #include "./vpx_config.h" 13 14 #include <assert.h> 15 #include <limits.h> 16 #include <math.h> 17 #include <stdarg.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <string.h> 21 22 #include "vpx/vpx_encoder.h" 23 #if CONFIG_DECODERS 24 #include "vpx/vpx_decoder.h" 25 #endif 26 27 #include "third_party/libyuv/include/libyuv/scale.h" 28 #include "./args.h" 29 #include "./ivfenc.h" 30 #include "./tools_common.h" 31 32 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER 33 #include "vpx/vp8cx.h" 34 #endif 35 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER 36 #include "vpx/vp8dx.h" 37 #endif 38 39 #include "vpx/vpx_integer.h" 40 #include "vpx_ports/mem_ops.h" 41 #include "vpx_ports/vpx_timer.h" 42 #include "./rate_hist.h" 43 #include "./vpxstats.h" 44 #include "./warnings.h" 45 #include "./webmenc.h" 46 #include "./y4minput.h" 47 48 /* Swallow warnings about unused results of fread/fwrite */ 49 static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, 50 FILE *stream) { 51 return fread(ptr, size, nmemb, stream); 52 } 53 #define fread wrap_fread 54 55 static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb, 56 FILE *stream) { 57 return fwrite(ptr, size, nmemb, stream); 58 } 59 #define fwrite wrap_fwrite 60 61 62 static const char *exec_name; 63 64 static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal, 65 const char *s, va_list ap) { 66 if (ctx->err) { 67 const char *detail = vpx_codec_error_detail(ctx); 68 69 vfprintf(stderr, s, ap); 70 fprintf(stderr, ": %s\n", vpx_codec_error(ctx)); 71 72 if (detail) 73 fprintf(stderr, " %s\n", detail); 74 75 if (fatal) 76 exit(EXIT_FAILURE); 77 } 78 } 79 80 static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) { 81 va_list ap; 82 83 va_start(ap, s); 84 warn_or_exit_on_errorv(ctx, 1, s, ap); 85 va_end(ap); 86 } 87 88 static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal, 89 const char *s, ...) { 90 va_list ap; 91 92 va_start(ap, s); 93 warn_or_exit_on_errorv(ctx, fatal, s, ap); 94 va_end(ap); 95 } 96 97 int read_frame(struct VpxInputContext *input_ctx, vpx_image_t *img) { 98 FILE *f = input_ctx->file; 99 y4m_input *y4m = &input_ctx->y4m; 100 int shortread = 0; 101 102 if (input_ctx->file_type == FILE_TYPE_Y4M) { 103 if (y4m_input_fetch_frame(y4m, f, img) < 1) 104 return 0; 105 } else { 106 shortread = read_yuv_frame(input_ctx, img); 107 } 108 109 return !shortread; 110 } 111 112 int file_is_y4m(const char detect[4]) { 113 if (memcmp(detect, "YUV4", 4) == 0) { 114 return 1; 115 } 116 return 0; 117 } 118 119 int fourcc_is_ivf(const char detect[4]) { 120 if (memcmp(detect, "DKIF", 4) == 0) { 121 return 1; 122 } 123 return 0; 124 } 125 126 #if CONFIG_WEBM_IO 127 /* Murmur hash derived from public domain reference implementation at 128 * http:// sites.google.com/site/murmurhash/ 129 */ 130 static unsigned int murmur(const void *key, int len, unsigned int seed) { 131 const unsigned int m = 0x5bd1e995; 132 const int r = 24; 133 134 unsigned int h = seed ^ len; 135 136 const unsigned char *data = (const unsigned char *)key; 137 138 while (len >= 4) { 139 unsigned int k; 140 141 k = (unsigned int)data[0]; 142 k |= (unsigned int)data[1] << 8; 143 k |= (unsigned int)data[2] << 16; 144 k |= (unsigned int)data[3] << 24; 145 146 k *= m; 147 k ^= k >> r; 148 k *= m; 149 150 h *= m; 151 h ^= k; 152 153 data += 4; 154 len -= 4; 155 } 156 157 switch (len) { 158 case 3: 159 h ^= data[2] << 16; 160 case 2: 161 h ^= data[1] << 8; 162 case 1: 163 h ^= data[0]; 164 h *= m; 165 }; 166 167 h ^= h >> 13; 168 h *= m; 169 h ^= h >> 15; 170 171 return h; 172 } 173 #endif // CONFIG_WEBM_IO 174 175 static const arg_def_t debugmode = ARG_DEF("D", "debug", 0, 176 "Debug mode (makes output deterministic)"); 177 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, 178 "Output filename"); 179 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, 180 "Input file is YV12 "); 181 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, 182 "Input file is I420 (default)"); 183 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, 184 "Codec to use"); 185 static const arg_def_t passes = ARG_DEF("p", "passes", 1, 186 "Number of passes (1/2)"); 187 static const arg_def_t pass_arg = ARG_DEF(NULL, "pass", 1, 188 "Pass to execute (1/2)"); 189 static const arg_def_t fpf_name = ARG_DEF(NULL, "fpf", 1, 190 "First pass statistics file name"); 191 static const arg_def_t limit = ARG_DEF(NULL, "limit", 1, 192 "Stop encoding after n input frames"); 193 static const arg_def_t skip = ARG_DEF(NULL, "skip", 1, 194 "Skip the first n input frames"); 195 static const arg_def_t deadline = ARG_DEF("d", "deadline", 1, 196 "Deadline per frame (usec)"); 197 static const arg_def_t best_dl = ARG_DEF(NULL, "best", 0, 198 "Use Best Quality Deadline"); 199 static const arg_def_t good_dl = ARG_DEF(NULL, "good", 0, 200 "Use Good Quality Deadline"); 201 static const arg_def_t rt_dl = ARG_DEF(NULL, "rt", 0, 202 "Use Realtime Quality Deadline"); 203 static const arg_def_t quietarg = ARG_DEF("q", "quiet", 0, 204 "Do not print encode progress"); 205 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, 206 "Show encoder parameters"); 207 static const arg_def_t psnrarg = ARG_DEF(NULL, "psnr", 0, 208 "Show PSNR in status line"); 209 210 static const struct arg_enum_list test_decode_enum[] = { 211 {"off", TEST_DECODE_OFF}, 212 {"fatal", TEST_DECODE_FATAL}, 213 {"warn", TEST_DECODE_WARN}, 214 {NULL, 0} 215 }; 216 static const arg_def_t recontest = ARG_DEF_ENUM(NULL, "test-decode", 1, 217 "Test encode/decode mismatch", 218 test_decode_enum); 219 static const arg_def_t framerate = ARG_DEF(NULL, "fps", 1, 220 "Stream frame rate (rate/scale)"); 221 static const arg_def_t use_ivf = ARG_DEF(NULL, "ivf", 0, 222 "Output IVF (default is WebM if WebM IO is enabled)"); 223 static const arg_def_t out_part = ARG_DEF("P", "output-partitions", 0, 224 "Makes encoder output partitions. Requires IVF output!"); 225 static const arg_def_t q_hist_n = ARG_DEF(NULL, "q-hist", 1, 226 "Show quantizer histogram (n-buckets)"); 227 static const arg_def_t rate_hist_n = ARG_DEF(NULL, "rate-hist", 1, 228 "Show rate histogram (n-buckets)"); 229 static const arg_def_t disable_warnings = 230 ARG_DEF(NULL, "disable-warnings", 0, 231 "Disable warnings about potentially incorrect encode settings."); 232 static const arg_def_t disable_warning_prompt = 233 ARG_DEF("y", "disable-warning-prompt", 0, 234 "Display warnings, but do not prompt user to continue."); 235 static const arg_def_t experimental_bitstream = 236 ARG_DEF(NULL, "experimental-bitstream", 0, 237 "Allow experimental bitstream features."); 238 239 240 static const arg_def_t *main_args[] = { 241 &debugmode, 242 &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &skip, 243 &deadline, &best_dl, &good_dl, &rt_dl, 244 &quietarg, &verbosearg, &psnrarg, &use_ivf, &out_part, &q_hist_n, 245 &rate_hist_n, &disable_warnings, &disable_warning_prompt, 246 NULL 247 }; 248 249 static const arg_def_t usage = ARG_DEF("u", "usage", 1, 250 "Usage profile number to use"); 251 static const arg_def_t threads = ARG_DEF("t", "threads", 1, 252 "Max number of threads to use"); 253 static const arg_def_t profile = ARG_DEF(NULL, "profile", 1, 254 "Bitstream profile number to use"); 255 static const arg_def_t width = ARG_DEF("w", "width", 1, 256 "Frame width"); 257 static const arg_def_t height = ARG_DEF("h", "height", 1, 258 "Frame height"); 259 static const struct arg_enum_list stereo_mode_enum[] = { 260 {"mono", STEREO_FORMAT_MONO}, 261 {"left-right", STEREO_FORMAT_LEFT_RIGHT}, 262 {"bottom-top", STEREO_FORMAT_BOTTOM_TOP}, 263 {"top-bottom", STEREO_FORMAT_TOP_BOTTOM}, 264 {"right-left", STEREO_FORMAT_RIGHT_LEFT}, 265 {NULL, 0} 266 }; 267 static const arg_def_t stereo_mode = ARG_DEF_ENUM(NULL, "stereo-mode", 1, 268 "Stereo 3D video format", stereo_mode_enum); 269 static const arg_def_t timebase = ARG_DEF(NULL, "timebase", 1, 270 "Output timestamp precision (fractional seconds)"); 271 static const arg_def_t error_resilient = ARG_DEF(NULL, "error-resilient", 1, 272 "Enable error resiliency features"); 273 static const arg_def_t lag_in_frames = ARG_DEF(NULL, "lag-in-frames", 1, 274 "Max number of frames to lag"); 275 276 static const arg_def_t *global_args[] = { 277 &use_yv12, &use_i420, &usage, &threads, &profile, 278 &width, &height, &stereo_mode, &timebase, &framerate, 279 &error_resilient, 280 &lag_in_frames, NULL 281 }; 282 283 static const arg_def_t dropframe_thresh = ARG_DEF(NULL, "drop-frame", 1, 284 "Temporal resampling threshold (buf %)"); 285 static const arg_def_t resize_allowed = ARG_DEF(NULL, "resize-allowed", 1, 286 "Spatial resampling enabled (bool)"); 287 static const arg_def_t resize_up_thresh = ARG_DEF(NULL, "resize-up", 1, 288 "Upscale threshold (buf %)"); 289 static const arg_def_t resize_down_thresh = ARG_DEF(NULL, "resize-down", 1, 290 "Downscale threshold (buf %)"); 291 static const struct arg_enum_list end_usage_enum[] = { 292 {"vbr", VPX_VBR}, 293 {"cbr", VPX_CBR}, 294 {"cq", VPX_CQ}, 295 {"q", VPX_Q}, 296 {NULL, 0} 297 }; 298 static const arg_def_t end_usage = ARG_DEF_ENUM(NULL, "end-usage", 1, 299 "Rate control mode", end_usage_enum); 300 static const arg_def_t target_bitrate = ARG_DEF(NULL, "target-bitrate", 1, 301 "Bitrate (kbps)"); 302 static const arg_def_t min_quantizer = ARG_DEF(NULL, "min-q", 1, 303 "Minimum (best) quantizer"); 304 static const arg_def_t max_quantizer = ARG_DEF(NULL, "max-q", 1, 305 "Maximum (worst) quantizer"); 306 static const arg_def_t undershoot_pct = ARG_DEF(NULL, "undershoot-pct", 1, 307 "Datarate undershoot (min) target (%)"); 308 static const arg_def_t overshoot_pct = ARG_DEF(NULL, "overshoot-pct", 1, 309 "Datarate overshoot (max) target (%)"); 310 static const arg_def_t buf_sz = ARG_DEF(NULL, "buf-sz", 1, 311 "Client buffer size (ms)"); 312 static const arg_def_t buf_initial_sz = ARG_DEF(NULL, "buf-initial-sz", 1, 313 "Client initial buffer size (ms)"); 314 static const arg_def_t buf_optimal_sz = ARG_DEF(NULL, "buf-optimal-sz", 1, 315 "Client optimal buffer size (ms)"); 316 static const arg_def_t *rc_args[] = { 317 &dropframe_thresh, &resize_allowed, &resize_up_thresh, &resize_down_thresh, 318 &end_usage, &target_bitrate, &min_quantizer, &max_quantizer, 319 &undershoot_pct, &overshoot_pct, &buf_sz, &buf_initial_sz, &buf_optimal_sz, 320 NULL 321 }; 322 323 324 static const arg_def_t bias_pct = ARG_DEF(NULL, "bias-pct", 1, 325 "CBR/VBR bias (0=CBR, 100=VBR)"); 326 static const arg_def_t minsection_pct = ARG_DEF(NULL, "minsection-pct", 1, 327 "GOP min bitrate (% of target)"); 328 static const arg_def_t maxsection_pct = ARG_DEF(NULL, "maxsection-pct", 1, 329 "GOP max bitrate (% of target)"); 330 static const arg_def_t *rc_twopass_args[] = { 331 &bias_pct, &minsection_pct, &maxsection_pct, NULL 332 }; 333 334 335 static const arg_def_t kf_min_dist = ARG_DEF(NULL, "kf-min-dist", 1, 336 "Minimum keyframe interval (frames)"); 337 static const arg_def_t kf_max_dist = ARG_DEF(NULL, "kf-max-dist", 1, 338 "Maximum keyframe interval (frames)"); 339 static const arg_def_t kf_disabled = ARG_DEF(NULL, "disable-kf", 0, 340 "Disable keyframe placement"); 341 static const arg_def_t *kf_args[] = { 342 &kf_min_dist, &kf_max_dist, &kf_disabled, NULL 343 }; 344 345 346 static const arg_def_t noise_sens = ARG_DEF(NULL, "noise-sensitivity", 1, 347 "Noise sensitivity (frames to blur)"); 348 static const arg_def_t sharpness = ARG_DEF(NULL, "sharpness", 1, 349 "Filter sharpness (0-7)"); 350 static const arg_def_t static_thresh = ARG_DEF(NULL, "static-thresh", 1, 351 "Motion detection threshold"); 352 static const arg_def_t cpu_used = ARG_DEF(NULL, "cpu-used", 1, 353 "CPU Used (-16..16)"); 354 static const arg_def_t auto_altref = ARG_DEF(NULL, "auto-alt-ref", 1, 355 "Enable automatic alt reference frames"); 356 static const arg_def_t arnr_maxframes = ARG_DEF(NULL, "arnr-maxframes", 1, 357 "AltRef Max Frames"); 358 static const arg_def_t arnr_strength = ARG_DEF(NULL, "arnr-strength", 1, 359 "AltRef Strength"); 360 static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1, 361 "AltRef Type"); 362 static const struct arg_enum_list tuning_enum[] = { 363 {"psnr", VP8_TUNE_PSNR}, 364 {"ssim", VP8_TUNE_SSIM}, 365 {NULL, 0} 366 }; 367 static const arg_def_t tune_ssim = ARG_DEF_ENUM(NULL, "tune", 1, 368 "Material to favor", tuning_enum); 369 static const arg_def_t cq_level = ARG_DEF(NULL, "cq-level", 1, 370 "Constant/Constrained Quality level"); 371 static const arg_def_t max_intra_rate_pct = ARG_DEF(NULL, "max-intra-rate", 1, 372 "Max I-frame bitrate (pct)"); 373 374 #if CONFIG_VP8_ENCODER 375 static const arg_def_t token_parts = 376 ARG_DEF(NULL, "token-parts", 1, "Number of token partitions to use, log2"); 377 static const arg_def_t *vp8_args[] = { 378 &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, 379 &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type, 380 &tune_ssim, &cq_level, &max_intra_rate_pct, 381 NULL 382 }; 383 static const int vp8_arg_ctrl_map[] = { 384 VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, 385 VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, 386 VP8E_SET_TOKEN_PARTITIONS, 387 VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE, 388 VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, 389 0 390 }; 391 #endif 392 393 #if CONFIG_VP9_ENCODER 394 static const arg_def_t tile_cols = 395 ARG_DEF(NULL, "tile-columns", 1, "Number of tile columns to use, log2"); 396 static const arg_def_t tile_rows = 397 ARG_DEF(NULL, "tile-rows", 1, "Number of tile rows to use, log2"); 398 static const arg_def_t lossless = ARG_DEF(NULL, "lossless", 1, "Lossless mode"); 399 static const arg_def_t frame_parallel_decoding = ARG_DEF( 400 NULL, "frame-parallel", 1, "Enable frame parallel decodability features"); 401 static const arg_def_t aq_mode = ARG_DEF( 402 NULL, "aq-mode", 1, 403 "Adaptive q mode (0: off (by default), 1: variance 2: complexity, " 404 "3: cyclic refresh)"); 405 static const arg_def_t frame_periodic_boost = ARG_DEF( 406 NULL, "frame_boost", 1, 407 "Enable frame periodic boost (0: off (by default), 1: on)"); 408 409 static const arg_def_t *vp9_args[] = { 410 &cpu_used, &auto_altref, &noise_sens, &sharpness, &static_thresh, 411 &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type, 412 &tune_ssim, &cq_level, &max_intra_rate_pct, &lossless, 413 &frame_parallel_decoding, &aq_mode, &frame_periodic_boost, 414 NULL 415 }; 416 static const int vp9_arg_ctrl_map[] = { 417 VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF, 418 VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD, 419 VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS, 420 VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE, 421 VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT, 422 VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING, VP9E_SET_AQ_MODE, 423 VP9E_SET_FRAME_PERIODIC_BOOST, 424 0 425 }; 426 #endif 427 428 static const arg_def_t *no_args[] = { NULL }; 429 430 void usage_exit() { 431 int i; 432 433 fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n", 434 exec_name); 435 436 fprintf(stderr, "\nOptions:\n"); 437 arg_show_usage(stderr, main_args); 438 fprintf(stderr, "\nEncoder Global Options:\n"); 439 arg_show_usage(stderr, global_args); 440 fprintf(stderr, "\nRate Control Options:\n"); 441 arg_show_usage(stderr, rc_args); 442 fprintf(stderr, "\nTwopass Rate Control Options:\n"); 443 arg_show_usage(stderr, rc_twopass_args); 444 fprintf(stderr, "\nKeyframe Placement Options:\n"); 445 arg_show_usage(stderr, kf_args); 446 #if CONFIG_VP8_ENCODER 447 fprintf(stderr, "\nVP8 Specific Options:\n"); 448 arg_show_usage(stderr, vp8_args); 449 #endif 450 #if CONFIG_VP9_ENCODER 451 fprintf(stderr, "\nVP9 Specific Options:\n"); 452 arg_show_usage(stderr, vp9_args); 453 #endif 454 fprintf(stderr, "\nStream timebase (--timebase):\n" 455 " The desired precision of timestamps in the output, expressed\n" 456 " in fractional seconds. Default is 1/1000.\n"); 457 fprintf(stderr, "\nIncluded encoders:\n\n"); 458 459 for (i = 0; i < get_vpx_encoder_count(); ++i) { 460 const VpxInterface *const encoder = get_vpx_encoder_by_index(i); 461 fprintf(stderr, " %-6s - %s\n", 462 encoder->name, vpx_codec_iface_name(encoder->interface())); 463 } 464 465 exit(EXIT_FAILURE); 466 } 467 468 #define mmin(a, b) ((a) < (b) ? (a) : (b)) 469 static void find_mismatch(const vpx_image_t *const img1, 470 const vpx_image_t *const img2, 471 int yloc[4], int uloc[4], int vloc[4]) { 472 const uint32_t bsize = 64; 473 const uint32_t bsizey = bsize >> img1->y_chroma_shift; 474 const uint32_t bsizex = bsize >> img1->x_chroma_shift; 475 const uint32_t c_w = 476 (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; 477 const uint32_t c_h = 478 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; 479 int match = 1; 480 uint32_t i, j; 481 yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1; 482 for (i = 0, match = 1; match && i < img1->d_h; i += bsize) { 483 for (j = 0; match && j < img1->d_w; j += bsize) { 484 int k, l; 485 const int si = mmin(i + bsize, img1->d_h) - i; 486 const int sj = mmin(j + bsize, img1->d_w) - j; 487 for (k = 0; match && k < si; ++k) { 488 for (l = 0; match && l < sj; ++l) { 489 if (*(img1->planes[VPX_PLANE_Y] + 490 (i + k) * img1->stride[VPX_PLANE_Y] + j + l) != 491 *(img2->planes[VPX_PLANE_Y] + 492 (i + k) * img2->stride[VPX_PLANE_Y] + j + l)) { 493 yloc[0] = i + k; 494 yloc[1] = j + l; 495 yloc[2] = *(img1->planes[VPX_PLANE_Y] + 496 (i + k) * img1->stride[VPX_PLANE_Y] + j + l); 497 yloc[3] = *(img2->planes[VPX_PLANE_Y] + 498 (i + k) * img2->stride[VPX_PLANE_Y] + j + l); 499 match = 0; 500 break; 501 } 502 } 503 } 504 } 505 } 506 507 uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1; 508 for (i = 0, match = 1; match && i < c_h; i += bsizey) { 509 for (j = 0; match && j < c_w; j += bsizex) { 510 int k, l; 511 const int si = mmin(i + bsizey, c_h - i); 512 const int sj = mmin(j + bsizex, c_w - j); 513 for (k = 0; match && k < si; ++k) { 514 for (l = 0; match && l < sj; ++l) { 515 if (*(img1->planes[VPX_PLANE_U] + 516 (i + k) * img1->stride[VPX_PLANE_U] + j + l) != 517 *(img2->planes[VPX_PLANE_U] + 518 (i + k) * img2->stride[VPX_PLANE_U] + j + l)) { 519 uloc[0] = i + k; 520 uloc[1] = j + l; 521 uloc[2] = *(img1->planes[VPX_PLANE_U] + 522 (i + k) * img1->stride[VPX_PLANE_U] + j + l); 523 uloc[3] = *(img2->planes[VPX_PLANE_U] + 524 (i + k) * img2->stride[VPX_PLANE_U] + j + l); 525 match = 0; 526 break; 527 } 528 } 529 } 530 } 531 } 532 vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1; 533 for (i = 0, match = 1; match && i < c_h; i += bsizey) { 534 for (j = 0; match && j < c_w; j += bsizex) { 535 int k, l; 536 const int si = mmin(i + bsizey, c_h - i); 537 const int sj = mmin(j + bsizex, c_w - j); 538 for (k = 0; match && k < si; ++k) { 539 for (l = 0; match && l < sj; ++l) { 540 if (*(img1->planes[VPX_PLANE_V] + 541 (i + k) * img1->stride[VPX_PLANE_V] + j + l) != 542 *(img2->planes[VPX_PLANE_V] + 543 (i + k) * img2->stride[VPX_PLANE_V] + j + l)) { 544 vloc[0] = i + k; 545 vloc[1] = j + l; 546 vloc[2] = *(img1->planes[VPX_PLANE_V] + 547 (i + k) * img1->stride[VPX_PLANE_V] + j + l); 548 vloc[3] = *(img2->planes[VPX_PLANE_V] + 549 (i + k) * img2->stride[VPX_PLANE_V] + j + l); 550 match = 0; 551 break; 552 } 553 } 554 } 555 } 556 } 557 } 558 559 static int compare_img(const vpx_image_t *const img1, 560 const vpx_image_t *const img2) { 561 const uint32_t c_w = 562 (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; 563 const uint32_t c_h = 564 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; 565 uint32_t i; 566 int match = 1; 567 568 match &= (img1->fmt == img2->fmt); 569 match &= (img1->d_w == img2->d_w); 570 match &= (img1->d_h == img2->d_h); 571 572 for (i = 0; i < img1->d_h; ++i) 573 match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y], 574 img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y], 575 img1->d_w) == 0); 576 577 for (i = 0; i < c_h; ++i) 578 match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U], 579 img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U], 580 c_w) == 0); 581 582 for (i = 0; i < c_h; ++i) 583 match &= (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V], 584 img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V], 585 c_w) == 0); 586 587 return match; 588 } 589 590 591 #define NELEMENTS(x) (sizeof(x)/sizeof(x[0])) 592 #define MAX(x,y) ((x)>(y)?(x):(y)) 593 #if CONFIG_VP8_ENCODER && !CONFIG_VP9_ENCODER 594 #define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map) 595 #elif !CONFIG_VP8_ENCODER && CONFIG_VP9_ENCODER 596 #define ARG_CTRL_CNT_MAX NELEMENTS(vp9_arg_ctrl_map) 597 #else 598 #define ARG_CTRL_CNT_MAX MAX(NELEMENTS(vp8_arg_ctrl_map), \ 599 NELEMENTS(vp9_arg_ctrl_map)) 600 #endif 601 602 /* Per-stream configuration */ 603 struct stream_config { 604 struct vpx_codec_enc_cfg cfg; 605 const char *out_fn; 606 const char *stats_fn; 607 stereo_format_t stereo_fmt; 608 int arg_ctrls[ARG_CTRL_CNT_MAX][2]; 609 int arg_ctrl_cnt; 610 int write_webm; 611 int have_kf_max_dist; 612 }; 613 614 615 struct stream_state { 616 int index; 617 struct stream_state *next; 618 struct stream_config config; 619 FILE *file; 620 struct rate_hist *rate_hist; 621 struct EbmlGlobal ebml; 622 uint32_t hash; 623 uint64_t psnr_sse_total; 624 uint64_t psnr_samples_total; 625 double psnr_totals[4]; 626 int psnr_count; 627 int counts[64]; 628 vpx_codec_ctx_t encoder; 629 unsigned int frames_out; 630 uint64_t cx_time; 631 size_t nbytes; 632 stats_io_t stats; 633 struct vpx_image *img; 634 vpx_codec_ctx_t decoder; 635 int mismatch_seen; 636 }; 637 638 639 void validate_positive_rational(const char *msg, 640 struct vpx_rational *rat) { 641 if (rat->den < 0) { 642 rat->num *= -1; 643 rat->den *= -1; 644 } 645 646 if (rat->num < 0) 647 die("Error: %s must be positive\n", msg); 648 649 if (!rat->den) 650 die("Error: %s has zero denominator\n", msg); 651 } 652 653 654 static void parse_global_config(struct VpxEncoderConfig *global, char **argv) { 655 char **argi, **argj; 656 struct arg arg; 657 658 /* Initialize default parameters */ 659 memset(global, 0, sizeof(*global)); 660 global->codec = get_vpx_encoder_by_index(0); 661 global->passes = 0; 662 global->use_i420 = 1; 663 /* Assign default deadline to good quality */ 664 global->deadline = VPX_DL_GOOD_QUALITY; 665 666 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { 667 arg.argv_step = 1; 668 669 if (arg_match(&arg, &codecarg, argi)) { 670 global->codec = get_vpx_encoder_by_name(arg.val); 671 if (!global->codec) 672 die("Error: Unrecognized argument (%s) to --codec\n", arg.val); 673 } else if (arg_match(&arg, &passes, argi)) { 674 global->passes = arg_parse_uint(&arg); 675 676 if (global->passes < 1 || global->passes > 2) 677 die("Error: Invalid number of passes (%d)\n", global->passes); 678 } else if (arg_match(&arg, &pass_arg, argi)) { 679 global->pass = arg_parse_uint(&arg); 680 681 if (global->pass < 1 || global->pass > 2) 682 die("Error: Invalid pass selected (%d)\n", 683 global->pass); 684 } else if (arg_match(&arg, &usage, argi)) 685 global->usage = arg_parse_uint(&arg); 686 else if (arg_match(&arg, &deadline, argi)) 687 global->deadline = arg_parse_uint(&arg); 688 else if (arg_match(&arg, &best_dl, argi)) 689 global->deadline = VPX_DL_BEST_QUALITY; 690 else if (arg_match(&arg, &good_dl, argi)) 691 global->deadline = VPX_DL_GOOD_QUALITY; 692 else if (arg_match(&arg, &rt_dl, argi)) 693 global->deadline = VPX_DL_REALTIME; 694 else if (arg_match(&arg, &use_yv12, argi)) 695 global->use_i420 = 0; 696 else if (arg_match(&arg, &use_i420, argi)) 697 global->use_i420 = 1; 698 else if (arg_match(&arg, &quietarg, argi)) 699 global->quiet = 1; 700 else if (arg_match(&arg, &verbosearg, argi)) 701 global->verbose = 1; 702 else if (arg_match(&arg, &limit, argi)) 703 global->limit = arg_parse_uint(&arg); 704 else if (arg_match(&arg, &skip, argi)) 705 global->skip_frames = arg_parse_uint(&arg); 706 else if (arg_match(&arg, &psnrarg, argi)) 707 global->show_psnr = 1; 708 else if (arg_match(&arg, &recontest, argi)) 709 global->test_decode = arg_parse_enum_or_int(&arg); 710 else if (arg_match(&arg, &framerate, argi)) { 711 global->framerate = arg_parse_rational(&arg); 712 validate_positive_rational(arg.name, &global->framerate); 713 global->have_framerate = 1; 714 } else if (arg_match(&arg, &out_part, argi)) 715 global->out_part = 1; 716 else if (arg_match(&arg, &debugmode, argi)) 717 global->debug = 1; 718 else if (arg_match(&arg, &q_hist_n, argi)) 719 global->show_q_hist_buckets = arg_parse_uint(&arg); 720 else if (arg_match(&arg, &rate_hist_n, argi)) 721 global->show_rate_hist_buckets = arg_parse_uint(&arg); 722 else if (arg_match(&arg, &disable_warnings, argi)) 723 global->disable_warnings = 1; 724 else if (arg_match(&arg, &disable_warning_prompt, argi)) 725 global->disable_warning_prompt = 1; 726 else if (arg_match(&arg, &experimental_bitstream, argi)) 727 global->experimental_bitstream = 1; 728 else 729 argj++; 730 } 731 732 if (global->pass) { 733 /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ 734 if (global->pass > global->passes) { 735 warn("Assuming --pass=%d implies --passes=%d\n", 736 global->pass, global->pass); 737 global->passes = global->pass; 738 } 739 } 740 /* Validate global config */ 741 if (global->passes == 0) { 742 #if CONFIG_VP9_ENCODER 743 // Make default VP9 passes = 2 until there is a better quality 1-pass 744 // encoder 745 global->passes = (strcmp(global->codec->name, "vp9") == 0 && 746 global->deadline != VPX_DL_REALTIME) ? 2 : 1; 747 #else 748 global->passes = 1; 749 #endif 750 } 751 752 if (global->deadline == VPX_DL_REALTIME && 753 global->passes > 1) { 754 warn("Enforcing one-pass encoding in realtime mode\n"); 755 global->passes = 1; 756 } 757 } 758 759 760 void open_input_file(struct VpxInputContext *input) { 761 /* Parse certain options from the input file, if possible */ 762 input->file = strcmp(input->filename, "-") 763 ? fopen(input->filename, "rb") : set_binary_mode(stdin); 764 765 if (!input->file) 766 fatal("Failed to open input file"); 767 768 if (!fseeko(input->file, 0, SEEK_END)) { 769 /* Input file is seekable. Figure out how long it is, so we can get 770 * progress info. 771 */ 772 input->length = ftello(input->file); 773 rewind(input->file); 774 } 775 776 /* For RAW input sources, these bytes will applied on the first frame 777 * in read_frame(). 778 */ 779 input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file); 780 input->detect.position = 0; 781 782 if (input->detect.buf_read == 4 783 && file_is_y4m(input->detect.buf)) { 784 if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4, 785 input->only_i420) >= 0) { 786 input->file_type = FILE_TYPE_Y4M; 787 input->width = input->y4m.pic_w; 788 input->height = input->y4m.pic_h; 789 input->framerate.numerator = input->y4m.fps_n; 790 input->framerate.denominator = input->y4m.fps_d; 791 input->use_i420 = 0; 792 } else 793 fatal("Unsupported Y4M stream."); 794 } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) { 795 fatal("IVF is not supported as input."); 796 } else { 797 input->file_type = FILE_TYPE_RAW; 798 } 799 } 800 801 802 static void close_input_file(struct VpxInputContext *input) { 803 fclose(input->file); 804 if (input->file_type == FILE_TYPE_Y4M) 805 y4m_input_close(&input->y4m); 806 } 807 808 static struct stream_state *new_stream(struct VpxEncoderConfig *global, 809 struct stream_state *prev) { 810 struct stream_state *stream; 811 812 stream = calloc(1, sizeof(*stream)); 813 if (!stream) 814 fatal("Failed to allocate new stream."); 815 if (prev) { 816 memcpy(stream, prev, sizeof(*stream)); 817 stream->index++; 818 prev->next = stream; 819 } else { 820 vpx_codec_err_t res; 821 822 /* Populate encoder configuration */ 823 res = vpx_codec_enc_config_default(global->codec->interface(), 824 &stream->config.cfg, 825 global->usage); 826 if (res) 827 fatal("Failed to get config: %s\n", vpx_codec_err_to_string(res)); 828 829 /* Change the default timebase to a high enough value so that the 830 * encoder will always create strictly increasing timestamps. 831 */ 832 stream->config.cfg.g_timebase.den = 1000; 833 834 /* Never use the library's default resolution, require it be parsed 835 * from the file or set on the command line. 836 */ 837 stream->config.cfg.g_w = 0; 838 stream->config.cfg.g_h = 0; 839 840 /* Initialize remaining stream parameters */ 841 stream->config.stereo_fmt = STEREO_FORMAT_MONO; 842 stream->config.write_webm = 1; 843 #if CONFIG_WEBM_IO 844 stream->ebml.last_pts_ms = -1; 845 #endif 846 847 /* Allows removal of the application version from the EBML tags */ 848 stream->ebml.debug = global->debug; 849 850 /* Default lag_in_frames is 0 in realtime mode */ 851 if (global->deadline == VPX_DL_REALTIME) 852 stream->config.cfg.g_lag_in_frames = 0; 853 } 854 855 /* Output files must be specified for each stream */ 856 stream->config.out_fn = NULL; 857 858 stream->next = NULL; 859 return stream; 860 } 861 862 863 static int parse_stream_params(struct VpxEncoderConfig *global, 864 struct stream_state *stream, 865 char **argv) { 866 char **argi, **argj; 867 struct arg arg; 868 static const arg_def_t **ctrl_args = no_args; 869 static const int *ctrl_args_map = NULL; 870 struct stream_config *config = &stream->config; 871 int eos_mark_found = 0; 872 873 // Handle codec specific options 874 if (0) { 875 #if CONFIG_VP8_ENCODER 876 } else if (strcmp(global->codec->name, "vp8") == 0) { 877 ctrl_args = vp8_args; 878 ctrl_args_map = vp8_arg_ctrl_map; 879 #endif 880 #if CONFIG_VP9_ENCODER 881 } else if (strcmp(global->codec->name, "vp9") == 0) { 882 ctrl_args = vp9_args; 883 ctrl_args_map = vp9_arg_ctrl_map; 884 #endif 885 } 886 887 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { 888 arg.argv_step = 1; 889 890 /* Once we've found an end-of-stream marker (--) we want to continue 891 * shifting arguments but not consuming them. 892 */ 893 if (eos_mark_found) { 894 argj++; 895 continue; 896 } else if (!strcmp(*argj, "--")) { 897 eos_mark_found = 1; 898 continue; 899 } 900 901 if (0) { 902 } else if (arg_match(&arg, &outputfile, argi)) { 903 config->out_fn = arg.val; 904 } else if (arg_match(&arg, &fpf_name, argi)) { 905 config->stats_fn = arg.val; 906 } else if (arg_match(&arg, &use_ivf, argi)) { 907 config->write_webm = 0; 908 } else if (arg_match(&arg, &threads, argi)) { 909 config->cfg.g_threads = arg_parse_uint(&arg); 910 } else if (arg_match(&arg, &profile, argi)) { 911 config->cfg.g_profile = arg_parse_uint(&arg); 912 } else if (arg_match(&arg, &width, argi)) { 913 config->cfg.g_w = arg_parse_uint(&arg); 914 } else if (arg_match(&arg, &height, argi)) { 915 config->cfg.g_h = arg_parse_uint(&arg); 916 } else if (arg_match(&arg, &stereo_mode, argi)) { 917 config->stereo_fmt = arg_parse_enum_or_int(&arg); 918 } else if (arg_match(&arg, &timebase, argi)) { 919 config->cfg.g_timebase = arg_parse_rational(&arg); 920 validate_positive_rational(arg.name, &config->cfg.g_timebase); 921 } else if (arg_match(&arg, &error_resilient, argi)) { 922 config->cfg.g_error_resilient = arg_parse_uint(&arg); 923 } else if (arg_match(&arg, &lag_in_frames, argi)) { 924 config->cfg.g_lag_in_frames = arg_parse_uint(&arg); 925 if (global->deadline == VPX_DL_REALTIME && 926 config->cfg.g_lag_in_frames != 0) { 927 warn("non-zero %s option ignored in realtime mode.\n", arg.name); 928 config->cfg.g_lag_in_frames = 0; 929 } 930 } else if (arg_match(&arg, &dropframe_thresh, argi)) { 931 config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg); 932 } else if (arg_match(&arg, &resize_allowed, argi)) { 933 config->cfg.rc_resize_allowed = arg_parse_uint(&arg); 934 } else if (arg_match(&arg, &resize_up_thresh, argi)) { 935 config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg); 936 } else if (arg_match(&arg, &resize_down_thresh, argi)) { 937 config->cfg.rc_resize_down_thresh = arg_parse_uint(&arg); 938 } else if (arg_match(&arg, &end_usage, argi)) { 939 config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg); 940 } else if (arg_match(&arg, &target_bitrate, argi)) { 941 config->cfg.rc_target_bitrate = arg_parse_uint(&arg); 942 } else if (arg_match(&arg, &min_quantizer, argi)) { 943 config->cfg.rc_min_quantizer = arg_parse_uint(&arg); 944 } else if (arg_match(&arg, &max_quantizer, argi)) { 945 config->cfg.rc_max_quantizer = arg_parse_uint(&arg); 946 } else if (arg_match(&arg, &undershoot_pct, argi)) { 947 config->cfg.rc_undershoot_pct = arg_parse_uint(&arg); 948 } else if (arg_match(&arg, &overshoot_pct, argi)) { 949 config->cfg.rc_overshoot_pct = arg_parse_uint(&arg); 950 } else if (arg_match(&arg, &buf_sz, argi)) { 951 config->cfg.rc_buf_sz = arg_parse_uint(&arg); 952 } else if (arg_match(&arg, &buf_initial_sz, argi)) { 953 config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg); 954 } else if (arg_match(&arg, &buf_optimal_sz, argi)) { 955 config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg); 956 } else if (arg_match(&arg, &bias_pct, argi)) { 957 config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg); 958 if (global->passes < 2) 959 warn("option %s ignored in one-pass mode.\n", arg.name); 960 } else if (arg_match(&arg, &minsection_pct, argi)) { 961 config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg); 962 963 if (global->passes < 2) 964 warn("option %s ignored in one-pass mode.\n", arg.name); 965 } else if (arg_match(&arg, &maxsection_pct, argi)) { 966 config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg); 967 968 if (global->passes < 2) 969 warn("option %s ignored in one-pass mode.\n", arg.name); 970 } else if (arg_match(&arg, &kf_min_dist, argi)) { 971 config->cfg.kf_min_dist = arg_parse_uint(&arg); 972 } else if (arg_match(&arg, &kf_max_dist, argi)) { 973 config->cfg.kf_max_dist = arg_parse_uint(&arg); 974 config->have_kf_max_dist = 1; 975 } else if (arg_match(&arg, &kf_disabled, argi)) { 976 config->cfg.kf_mode = VPX_KF_DISABLED; 977 } else { 978 int i, match = 0; 979 for (i = 0; ctrl_args[i]; i++) { 980 if (arg_match(&arg, ctrl_args[i], argi)) { 981 int j; 982 match = 1; 983 984 /* Point either to the next free element or the first 985 * instance of this control. 986 */ 987 for (j = 0; j < config->arg_ctrl_cnt; j++) 988 if (config->arg_ctrls[j][0] == ctrl_args_map[i]) 989 break; 990 991 /* Update/insert */ 992 assert(j < ARG_CTRL_CNT_MAX); 993 if (j < ARG_CTRL_CNT_MAX) { 994 config->arg_ctrls[j][0] = ctrl_args_map[i]; 995 config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg); 996 if (j == config->arg_ctrl_cnt) 997 config->arg_ctrl_cnt++; 998 } 999 1000 } 1001 } 1002 if (!match) 1003 argj++; 1004 } 1005 } 1006 return eos_mark_found; 1007 } 1008 1009 1010 #define FOREACH_STREAM(func) \ 1011 do { \ 1012 struct stream_state *stream; \ 1013 for (stream = streams; stream; stream = stream->next) { \ 1014 func; \ 1015 } \ 1016 } while (0) 1017 1018 1019 static void validate_stream_config(const struct stream_state *stream, 1020 const struct VpxEncoderConfig *global) { 1021 const struct stream_state *streami; 1022 1023 if (!stream->config.cfg.g_w || !stream->config.cfg.g_h) 1024 fatal("Stream %d: Specify stream dimensions with --width (-w) " 1025 " and --height (-h)", stream->index); 1026 1027 if (stream->config.cfg.g_profile != 0 && !global->experimental_bitstream) { 1028 fatal("Stream %d: profile %d is experimental and requires the --%s flag", 1029 stream->index, stream->config.cfg.g_profile, 1030 experimental_bitstream.long_name); 1031 } 1032 1033 for (streami = stream; streami; streami = streami->next) { 1034 /* All streams require output files */ 1035 if (!streami->config.out_fn) 1036 fatal("Stream %d: Output file is required (specify with -o)", 1037 streami->index); 1038 1039 /* Check for two streams outputting to the same file */ 1040 if (streami != stream) { 1041 const char *a = stream->config.out_fn; 1042 const char *b = streami->config.out_fn; 1043 if (!strcmp(a, b) && strcmp(a, "/dev/null") && strcmp(a, ":nul")) 1044 fatal("Stream %d: duplicate output file (from stream %d)", 1045 streami->index, stream->index); 1046 } 1047 1048 /* Check for two streams sharing a stats file. */ 1049 if (streami != stream) { 1050 const char *a = stream->config.stats_fn; 1051 const char *b = streami->config.stats_fn; 1052 if (a && b && !strcmp(a, b)) 1053 fatal("Stream %d: duplicate stats file (from stream %d)", 1054 streami->index, stream->index); 1055 } 1056 } 1057 } 1058 1059 1060 static void set_stream_dimensions(struct stream_state *stream, 1061 unsigned int w, 1062 unsigned int h) { 1063 if (!stream->config.cfg.g_w) { 1064 if (!stream->config.cfg.g_h) 1065 stream->config.cfg.g_w = w; 1066 else 1067 stream->config.cfg.g_w = w * stream->config.cfg.g_h / h; 1068 } 1069 if (!stream->config.cfg.g_h) { 1070 stream->config.cfg.g_h = h * stream->config.cfg.g_w / w; 1071 } 1072 } 1073 1074 1075 static void set_default_kf_interval(struct stream_state *stream, 1076 struct VpxEncoderConfig *global) { 1077 /* Use a max keyframe interval of 5 seconds, if none was 1078 * specified on the command line. 1079 */ 1080 if (!stream->config.have_kf_max_dist) { 1081 double framerate = (double)global->framerate.num / global->framerate.den; 1082 if (framerate > 0.0) 1083 stream->config.cfg.kf_max_dist = (unsigned int)(5.0 * framerate); 1084 } 1085 } 1086 1087 1088 static void show_stream_config(struct stream_state *stream, 1089 struct VpxEncoderConfig *global, 1090 struct VpxInputContext *input) { 1091 1092 #define SHOW(field) \ 1093 fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) 1094 1095 if (stream->index == 0) { 1096 fprintf(stderr, "Codec: %s\n", 1097 vpx_codec_iface_name(global->codec->interface())); 1098 fprintf(stderr, "Source file: %s Format: %s\n", input->filename, 1099 input->use_i420 ? "I420" : "YV12"); 1100 } 1101 if (stream->next || stream->index) 1102 fprintf(stderr, "\nStream Index: %d\n", stream->index); 1103 fprintf(stderr, "Destination file: %s\n", stream->config.out_fn); 1104 fprintf(stderr, "Encoder parameters:\n"); 1105 1106 SHOW(g_usage); 1107 SHOW(g_threads); 1108 SHOW(g_profile); 1109 SHOW(g_w); 1110 SHOW(g_h); 1111 SHOW(g_timebase.num); 1112 SHOW(g_timebase.den); 1113 SHOW(g_error_resilient); 1114 SHOW(g_pass); 1115 SHOW(g_lag_in_frames); 1116 SHOW(rc_dropframe_thresh); 1117 SHOW(rc_resize_allowed); 1118 SHOW(rc_resize_up_thresh); 1119 SHOW(rc_resize_down_thresh); 1120 SHOW(rc_end_usage); 1121 SHOW(rc_target_bitrate); 1122 SHOW(rc_min_quantizer); 1123 SHOW(rc_max_quantizer); 1124 SHOW(rc_undershoot_pct); 1125 SHOW(rc_overshoot_pct); 1126 SHOW(rc_buf_sz); 1127 SHOW(rc_buf_initial_sz); 1128 SHOW(rc_buf_optimal_sz); 1129 SHOW(rc_2pass_vbr_bias_pct); 1130 SHOW(rc_2pass_vbr_minsection_pct); 1131 SHOW(rc_2pass_vbr_maxsection_pct); 1132 SHOW(kf_mode); 1133 SHOW(kf_min_dist); 1134 SHOW(kf_max_dist); 1135 } 1136 1137 1138 static void open_output_file(struct stream_state *stream, 1139 struct VpxEncoderConfig *global) { 1140 const char *fn = stream->config.out_fn; 1141 const struct vpx_codec_enc_cfg *const cfg = &stream->config.cfg; 1142 1143 if (cfg->g_pass == VPX_RC_FIRST_PASS) 1144 return; 1145 1146 stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout); 1147 1148 if (!stream->file) 1149 fatal("Failed to open output file"); 1150 1151 if (stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR)) 1152 fatal("WebM output to pipes not supported."); 1153 1154 #if CONFIG_WEBM_IO 1155 if (stream->config.write_webm) { 1156 stream->ebml.stream = stream->file; 1157 write_webm_file_header(&stream->ebml, cfg, 1158 &global->framerate, 1159 stream->config.stereo_fmt, 1160 global->codec->fourcc); 1161 } 1162 #endif 1163 1164 if (!stream->config.write_webm) { 1165 ivf_write_file_header(stream->file, cfg, global->codec->fourcc, 0); 1166 } 1167 } 1168 1169 1170 static void close_output_file(struct stream_state *stream, 1171 unsigned int fourcc) { 1172 const struct vpx_codec_enc_cfg *const cfg = &stream->config.cfg; 1173 1174 if (cfg->g_pass == VPX_RC_FIRST_PASS) 1175 return; 1176 1177 #if CONFIG_WEBM_IO 1178 if (stream->config.write_webm) { 1179 write_webm_file_footer(&stream->ebml, stream->hash); 1180 free(stream->ebml.cue_list); 1181 stream->ebml.cue_list = NULL; 1182 } 1183 #endif 1184 1185 if (!stream->config.write_webm) { 1186 if (!fseek(stream->file, 0, SEEK_SET)) 1187 ivf_write_file_header(stream->file, &stream->config.cfg, 1188 fourcc, 1189 stream->frames_out); 1190 } 1191 1192 fclose(stream->file); 1193 } 1194 1195 1196 static void setup_pass(struct stream_state *stream, 1197 struct VpxEncoderConfig *global, 1198 int pass) { 1199 if (stream->config.stats_fn) { 1200 if (!stats_open_file(&stream->stats, stream->config.stats_fn, 1201 pass)) 1202 fatal("Failed to open statistics store"); 1203 } else { 1204 if (!stats_open_mem(&stream->stats, pass)) 1205 fatal("Failed to open statistics store"); 1206 } 1207 1208 stream->config.cfg.g_pass = global->passes == 2 1209 ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS 1210 : VPX_RC_ONE_PASS; 1211 if (pass) 1212 stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); 1213 1214 stream->cx_time = 0; 1215 stream->nbytes = 0; 1216 stream->frames_out = 0; 1217 } 1218 1219 1220 static void initialize_encoder(struct stream_state *stream, 1221 struct VpxEncoderConfig *global) { 1222 int i; 1223 int flags = 0; 1224 1225 flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0; 1226 flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0; 1227 1228 /* Construct Encoder Context */ 1229 vpx_codec_enc_init(&stream->encoder, global->codec->interface(), 1230 &stream->config.cfg, flags); 1231 ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder"); 1232 1233 /* Note that we bypass the vpx_codec_control wrapper macro because 1234 * we're being clever to store the control IDs in an array. Real 1235 * applications will want to make use of the enumerations directly 1236 */ 1237 for (i = 0; i < stream->config.arg_ctrl_cnt; i++) { 1238 int ctrl = stream->config.arg_ctrls[i][0]; 1239 int value = stream->config.arg_ctrls[i][1]; 1240 if (vpx_codec_control_(&stream->encoder, ctrl, value)) 1241 fprintf(stderr, "Error: Tried to set control %d = %d\n", 1242 ctrl, value); 1243 1244 ctx_exit_on_error(&stream->encoder, "Failed to control codec"); 1245 } 1246 1247 #if CONFIG_DECODERS 1248 if (global->test_decode != TEST_DECODE_OFF) { 1249 const VpxInterface *decoder = get_vpx_decoder_by_name(global->codec->name); 1250 vpx_codec_dec_init(&stream->decoder, decoder->interface(), NULL, 0); 1251 } 1252 #endif 1253 } 1254 1255 1256 static void encode_frame(struct stream_state *stream, 1257 struct VpxEncoderConfig *global, 1258 struct vpx_image *img, 1259 unsigned int frames_in) { 1260 vpx_codec_pts_t frame_start, next_frame_start; 1261 struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; 1262 struct vpx_usec_timer timer; 1263 1264 frame_start = (cfg->g_timebase.den * (int64_t)(frames_in - 1) 1265 * global->framerate.den) 1266 / cfg->g_timebase.num / global->framerate.num; 1267 next_frame_start = (cfg->g_timebase.den * (int64_t)(frames_in) 1268 * global->framerate.den) 1269 / cfg->g_timebase.num / global->framerate.num; 1270 1271 /* Scale if necessary */ 1272 if (img && (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) { 1273 if (!stream->img) 1274 stream->img = vpx_img_alloc(NULL, VPX_IMG_FMT_I420, 1275 cfg->g_w, cfg->g_h, 16); 1276 I420Scale(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y], 1277 img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U], 1278 img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], 1279 img->d_w, img->d_h, 1280 stream->img->planes[VPX_PLANE_Y], 1281 stream->img->stride[VPX_PLANE_Y], 1282 stream->img->planes[VPX_PLANE_U], 1283 stream->img->stride[VPX_PLANE_U], 1284 stream->img->planes[VPX_PLANE_V], 1285 stream->img->stride[VPX_PLANE_V], 1286 stream->img->d_w, stream->img->d_h, 1287 kFilterBox); 1288 1289 img = stream->img; 1290 } 1291 1292 vpx_usec_timer_start(&timer); 1293 vpx_codec_encode(&stream->encoder, img, frame_start, 1294 (unsigned long)(next_frame_start - frame_start), 1295 0, global->deadline); 1296 vpx_usec_timer_mark(&timer); 1297 stream->cx_time += vpx_usec_timer_elapsed(&timer); 1298 ctx_exit_on_error(&stream->encoder, "Stream %d: Failed to encode frame", 1299 stream->index); 1300 } 1301 1302 1303 static void update_quantizer_histogram(struct stream_state *stream) { 1304 if (stream->config.cfg.g_pass != VPX_RC_FIRST_PASS) { 1305 int q; 1306 1307 vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q); 1308 ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); 1309 stream->counts[q]++; 1310 } 1311 } 1312 1313 1314 static void get_cx_data(struct stream_state *stream, 1315 struct VpxEncoderConfig *global, 1316 int *got_data) { 1317 const vpx_codec_cx_pkt_t *pkt; 1318 const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; 1319 vpx_codec_iter_t iter = NULL; 1320 1321 *got_data = 0; 1322 while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) { 1323 static size_t fsize = 0; 1324 static off_t ivf_header_pos = 0; 1325 1326 switch (pkt->kind) { 1327 case VPX_CODEC_CX_FRAME_PKT: 1328 if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) { 1329 stream->frames_out++; 1330 } 1331 if (!global->quiet) 1332 fprintf(stderr, " %6luF", (unsigned long)pkt->data.frame.sz); 1333 1334 update_rate_histogram(stream->rate_hist, cfg, pkt); 1335 #if CONFIG_WEBM_IO 1336 if (stream->config.write_webm) { 1337 /* Update the hash */ 1338 if (!stream->ebml.debug) 1339 stream->hash = murmur(pkt->data.frame.buf, 1340 (int)pkt->data.frame.sz, 1341 stream->hash); 1342 1343 write_webm_block(&stream->ebml, cfg, pkt); 1344 } 1345 #endif 1346 if (!stream->config.write_webm) { 1347 if (pkt->data.frame.partition_id <= 0) { 1348 ivf_header_pos = ftello(stream->file); 1349 fsize = pkt->data.frame.sz; 1350 1351 ivf_write_frame_header(stream->file, pkt->data.frame.pts, fsize); 1352 } else { 1353 fsize += pkt->data.frame.sz; 1354 1355 if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) { 1356 off_t currpos = ftello(stream->file); 1357 fseeko(stream->file, ivf_header_pos, SEEK_SET); 1358 ivf_write_frame_size(stream->file, fsize); 1359 fseeko(stream->file, currpos, SEEK_SET); 1360 } 1361 } 1362 1363 (void) fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, 1364 stream->file); 1365 } 1366 stream->nbytes += pkt->data.raw.sz; 1367 1368 *got_data = 1; 1369 #if CONFIG_DECODERS 1370 if (global->test_decode != TEST_DECODE_OFF && !stream->mismatch_seen) { 1371 vpx_codec_decode(&stream->decoder, pkt->data.frame.buf, 1372 (unsigned int)pkt->data.frame.sz, NULL, 0); 1373 if (stream->decoder.err) { 1374 warn_or_exit_on_error(&stream->decoder, 1375 global->test_decode == TEST_DECODE_FATAL, 1376 "Failed to decode frame %d in stream %d", 1377 stream->frames_out + 1, stream->index); 1378 stream->mismatch_seen = stream->frames_out + 1; 1379 } 1380 } 1381 #endif 1382 break; 1383 case VPX_CODEC_STATS_PKT: 1384 stream->frames_out++; 1385 stats_write(&stream->stats, 1386 pkt->data.twopass_stats.buf, 1387 pkt->data.twopass_stats.sz); 1388 stream->nbytes += pkt->data.raw.sz; 1389 break; 1390 case VPX_CODEC_PSNR_PKT: 1391 1392 if (global->show_psnr) { 1393 int i; 1394 1395 stream->psnr_sse_total += pkt->data.psnr.sse[0]; 1396 stream->psnr_samples_total += pkt->data.psnr.samples[0]; 1397 for (i = 0; i < 4; i++) { 1398 if (!global->quiet) 1399 fprintf(stderr, "%.3f ", pkt->data.psnr.psnr[i]); 1400 stream->psnr_totals[i] += pkt->data.psnr.psnr[i]; 1401 } 1402 stream->psnr_count++; 1403 } 1404 1405 break; 1406 default: 1407 break; 1408 } 1409 } 1410 } 1411 1412 1413 static void show_psnr(struct stream_state *stream) { 1414 int i; 1415 double ovpsnr; 1416 1417 if (!stream->psnr_count) 1418 return; 1419 1420 fprintf(stderr, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream->index); 1421 ovpsnr = sse_to_psnr((double)stream->psnr_samples_total, 255.0, 1422 (double)stream->psnr_sse_total); 1423 fprintf(stderr, " %.3f", ovpsnr); 1424 1425 for (i = 0; i < 4; i++) { 1426 fprintf(stderr, " %.3f", stream->psnr_totals[i] / stream->psnr_count); 1427 } 1428 fprintf(stderr, "\n"); 1429 } 1430 1431 1432 static float usec_to_fps(uint64_t usec, unsigned int frames) { 1433 return (float)(usec > 0 ? frames * 1000000.0 / (float)usec : 0); 1434 } 1435 1436 1437 static void test_decode(struct stream_state *stream, 1438 enum TestDecodeFatality fatal, 1439 const VpxInterface *codec) { 1440 vpx_image_t enc_img, dec_img; 1441 1442 if (stream->mismatch_seen) 1443 return; 1444 1445 /* Get the internal reference frame */ 1446 if (strcmp(codec->name, "vp8") == 0) { 1447 struct vpx_ref_frame ref_enc, ref_dec; 1448 int width, height; 1449 1450 width = (stream->config.cfg.g_w + 15) & ~15; 1451 height = (stream->config.cfg.g_h + 15) & ~15; 1452 vpx_img_alloc(&ref_enc.img, VPX_IMG_FMT_I420, width, height, 1); 1453 enc_img = ref_enc.img; 1454 vpx_img_alloc(&ref_dec.img, VPX_IMG_FMT_I420, width, height, 1); 1455 dec_img = ref_dec.img; 1456 1457 ref_enc.frame_type = VP8_LAST_FRAME; 1458 ref_dec.frame_type = VP8_LAST_FRAME; 1459 vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &ref_enc); 1460 vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &ref_dec); 1461 } else { 1462 struct vp9_ref_frame ref; 1463 1464 ref.idx = 0; 1465 vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref); 1466 enc_img = ref.img; 1467 vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref); 1468 dec_img = ref.img; 1469 } 1470 ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame"); 1471 ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame"); 1472 1473 if (!compare_img(&enc_img, &dec_img)) { 1474 int y[4], u[4], v[4]; 1475 find_mismatch(&enc_img, &dec_img, y, u, v); 1476 stream->decoder.err = 1; 1477 warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL, 1478 "Stream %d: Encode/decode mismatch on frame %d at" 1479 " Y[%d, %d] {%d/%d}," 1480 " U[%d, %d] {%d/%d}," 1481 " V[%d, %d] {%d/%d}", 1482 stream->index, stream->frames_out, 1483 y[0], y[1], y[2], y[3], 1484 u[0], u[1], u[2], u[3], 1485 v[0], v[1], v[2], v[3]); 1486 stream->mismatch_seen = stream->frames_out; 1487 } 1488 1489 vpx_img_free(&enc_img); 1490 vpx_img_free(&dec_img); 1491 } 1492 1493 1494 static void print_time(const char *label, int64_t etl) { 1495 int64_t hours; 1496 int64_t mins; 1497 int64_t secs; 1498 1499 if (etl >= 0) { 1500 hours = etl / 3600; 1501 etl -= hours * 3600; 1502 mins = etl / 60; 1503 etl -= mins * 60; 1504 secs = etl; 1505 1506 fprintf(stderr, "[%3s %2"PRId64":%02"PRId64": % 02"PRId64"] ", 1507 label, hours, mins, secs); 1508 } else { 1509 fprintf(stderr, "[%3s unknown] ", label); 1510 } 1511 } 1512 1513 1514 int main(int argc, const char **argv_) { 1515 int pass; 1516 vpx_image_t raw; 1517 int frame_avail, got_data; 1518 1519 struct VpxInputContext input = {0}; 1520 struct VpxEncoderConfig global; 1521 struct stream_state *streams = NULL; 1522 char **argv, **argi; 1523 uint64_t cx_time = 0; 1524 int stream_cnt = 0; 1525 int res = 0; 1526 1527 exec_name = argv_[0]; 1528 1529 if (argc < 3) 1530 usage_exit(); 1531 1532 /* Setup default input stream settings */ 1533 input.framerate.numerator = 30; 1534 input.framerate.denominator = 1; 1535 input.use_i420 = 1; 1536 input.only_i420 = 1; 1537 1538 /* First parse the global configuration values, because we want to apply 1539 * other parameters on top of the default configuration provided by the 1540 * codec. 1541 */ 1542 argv = argv_dup(argc - 1, argv_ + 1); 1543 parse_global_config(&global, argv); 1544 1545 1546 { 1547 /* Now parse each stream's parameters. Using a local scope here 1548 * due to the use of 'stream' as loop variable in FOREACH_STREAM 1549 * loops 1550 */ 1551 struct stream_state *stream = NULL; 1552 1553 do { 1554 stream = new_stream(&global, stream); 1555 stream_cnt++; 1556 if (!streams) 1557 streams = stream; 1558 } while (parse_stream_params(&global, stream, argv)); 1559 } 1560 1561 /* Check for unrecognized options */ 1562 for (argi = argv; *argi; argi++) 1563 if (argi[0][0] == '-' && argi[0][1]) 1564 die("Error: Unrecognized option %s\n", *argi); 1565 1566 FOREACH_STREAM(check_encoder_config(global.disable_warning_prompt, 1567 &global, &stream->config.cfg);); 1568 1569 /* Handle non-option arguments */ 1570 input.filename = argv[0]; 1571 1572 if (!input.filename) 1573 usage_exit(); 1574 1575 /* Decide if other chroma subsamplings than 4:2:0 are supported */ 1576 if (global.codec->fourcc == VP9_FOURCC) 1577 input.only_i420 = 0; 1578 1579 for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) { 1580 int frames_in = 0, seen_frames = 0; 1581 int64_t estimated_time_left = -1; 1582 int64_t average_rate = -1; 1583 off_t lagged_count = 0; 1584 1585 open_input_file(&input); 1586 1587 /* If the input file doesn't specify its w/h (raw files), try to get 1588 * the data from the first stream's configuration. 1589 */ 1590 if (!input.width || !input.height) 1591 FOREACH_STREAM( { 1592 if (stream->config.cfg.g_w && stream->config.cfg.g_h) { 1593 input.width = stream->config.cfg.g_w; 1594 input.height = stream->config.cfg.g_h; 1595 break; 1596 } 1597 }); 1598 1599 /* Update stream configurations from the input file's parameters */ 1600 if (!input.width || !input.height) 1601 fatal("Specify stream dimensions with --width (-w) " 1602 " and --height (-h)"); 1603 FOREACH_STREAM(set_stream_dimensions(stream, input.width, input.height)); 1604 FOREACH_STREAM(validate_stream_config(stream, &global)); 1605 1606 /* Ensure that --passes and --pass are consistent. If --pass is set and 1607 * --passes=2, ensure --fpf was set. 1608 */ 1609 if (global.pass && global.passes == 2) 1610 FOREACH_STREAM( { 1611 if (!stream->config.stats_fn) 1612 die("Stream %d: Must specify --fpf when --pass=%d" 1613 " and --passes=2\n", stream->index, global.pass); 1614 }); 1615 1616 #if !CONFIG_WEBM_IO 1617 FOREACH_STREAM({ 1618 stream->config.write_webm = 0; 1619 warn("vpxenc was compiled without WebM container support." 1620 "Producing IVF output"); 1621 }); 1622 #endif 1623 1624 /* Use the frame rate from the file only if none was specified 1625 * on the command-line. 1626 */ 1627 if (!global.have_framerate) { 1628 global.framerate.num = input.framerate.numerator; 1629 global.framerate.den = input.framerate.denominator; 1630 } 1631 1632 FOREACH_STREAM(set_default_kf_interval(stream, &global)); 1633 1634 /* Show configuration */ 1635 if (global.verbose && pass == 0) 1636 FOREACH_STREAM(show_stream_config(stream, &global, &input)); 1637 1638 if (pass == (global.pass ? global.pass - 1 : 0)) { 1639 if (input.file_type == FILE_TYPE_Y4M) 1640 /*The Y4M reader does its own allocation. 1641 Just initialize this here to avoid problems if we never read any 1642 frames.*/ 1643 memset(&raw, 0, sizeof(raw)); 1644 else 1645 vpx_img_alloc(&raw, 1646 input.use_i420 ? VPX_IMG_FMT_I420 1647 : VPX_IMG_FMT_YV12, 1648 input.width, input.height, 32); 1649 1650 FOREACH_STREAM(stream->rate_hist = 1651 init_rate_histogram(&stream->config.cfg, 1652 &global.framerate)); 1653 } 1654 1655 FOREACH_STREAM(setup_pass(stream, &global, pass)); 1656 FOREACH_STREAM(open_output_file(stream, &global)); 1657 FOREACH_STREAM(initialize_encoder(stream, &global)); 1658 1659 frame_avail = 1; 1660 got_data = 0; 1661 1662 while (frame_avail || got_data) { 1663 struct vpx_usec_timer timer; 1664 1665 if (!global.limit || frames_in < global.limit) { 1666 frame_avail = read_frame(&input, &raw); 1667 1668 if (frame_avail) 1669 frames_in++; 1670 seen_frames = frames_in > global.skip_frames ? 1671 frames_in - global.skip_frames : 0; 1672 1673 if (!global.quiet) { 1674 float fps = usec_to_fps(cx_time, seen_frames); 1675 fprintf(stderr, "\rPass %d/%d ", pass + 1, global.passes); 1676 1677 if (stream_cnt == 1) 1678 fprintf(stderr, 1679 "frame %4d/%-4d %7"PRId64"B ", 1680 frames_in, streams->frames_out, (int64_t)streams->nbytes); 1681 else 1682 fprintf(stderr, "frame %4d ", frames_in); 1683 1684 fprintf(stderr, "%7"PRId64" %s %.2f %s ", 1685 cx_time > 9999999 ? cx_time / 1000 : cx_time, 1686 cx_time > 9999999 ? "ms" : "us", 1687 fps >= 1.0 ? fps : fps * 60, 1688 fps >= 1.0 ? "fps" : "fpm"); 1689 print_time("ETA", estimated_time_left); 1690 fprintf(stderr, "\033[K"); 1691 } 1692 1693 } else 1694 frame_avail = 0; 1695 1696 if (frames_in > global.skip_frames) { 1697 vpx_usec_timer_start(&timer); 1698 FOREACH_STREAM(encode_frame(stream, &global, 1699 frame_avail ? &raw : NULL, 1700 frames_in)); 1701 vpx_usec_timer_mark(&timer); 1702 cx_time += vpx_usec_timer_elapsed(&timer); 1703 1704 FOREACH_STREAM(update_quantizer_histogram(stream)); 1705 1706 got_data = 0; 1707 FOREACH_STREAM(get_cx_data(stream, &global, &got_data)); 1708 1709 if (!got_data && input.length && !streams->frames_out) { 1710 lagged_count = global.limit ? seen_frames : ftello(input.file); 1711 } else if (input.length) { 1712 int64_t remaining; 1713 int64_t rate; 1714 1715 if (global.limit) { 1716 off_t frame_in_lagged = (seen_frames - lagged_count) * 1000; 1717 1718 rate = cx_time ? frame_in_lagged * (int64_t)1000000 / cx_time : 0; 1719 remaining = 1000 * (global.limit - global.skip_frames 1720 - seen_frames + lagged_count); 1721 } else { 1722 off_t input_pos = ftello(input.file); 1723 off_t input_pos_lagged = input_pos - lagged_count; 1724 int64_t limit = input.length; 1725 1726 rate = cx_time ? input_pos_lagged * (int64_t)1000000 / cx_time : 0; 1727 remaining = limit - input_pos + lagged_count; 1728 } 1729 1730 average_rate = (average_rate <= 0) 1731 ? rate 1732 : (average_rate * 7 + rate) / 8; 1733 estimated_time_left = average_rate ? remaining / average_rate : -1; 1734 } 1735 1736 if (got_data && global.test_decode != TEST_DECODE_OFF) 1737 FOREACH_STREAM(test_decode(stream, global.test_decode, global.codec)); 1738 } 1739 1740 fflush(stdout); 1741 } 1742 1743 if (stream_cnt > 1) 1744 fprintf(stderr, "\n"); 1745 1746 if (!global.quiet) 1747 FOREACH_STREAM(fprintf( 1748 stderr, 1749 "\rPass %d/%d frame %4d/%-4d %7"PRId64"B %7lub/f %7"PRId64"b/s" 1750 " %7"PRId64" %s (%.2f fps)\033[K\n", pass + 1, 1751 global.passes, frames_in, stream->frames_out, (int64_t)stream->nbytes, 1752 seen_frames ? (unsigned long)(stream->nbytes * 8 / seen_frames) : 0, 1753 seen_frames ? (int64_t)stream->nbytes * 8 1754 * (int64_t)global.framerate.num / global.framerate.den 1755 / seen_frames 1756 : 0, 1757 stream->cx_time > 9999999 ? stream->cx_time / 1000 : stream->cx_time, 1758 stream->cx_time > 9999999 ? "ms" : "us", 1759 usec_to_fps(stream->cx_time, seen_frames)); 1760 ); 1761 1762 if (global.show_psnr) 1763 FOREACH_STREAM(show_psnr(stream)); 1764 1765 FOREACH_STREAM(vpx_codec_destroy(&stream->encoder)); 1766 1767 if (global.test_decode != TEST_DECODE_OFF) { 1768 FOREACH_STREAM(vpx_codec_destroy(&stream->decoder)); 1769 } 1770 1771 close_input_file(&input); 1772 1773 if (global.test_decode == TEST_DECODE_FATAL) { 1774 FOREACH_STREAM(res |= stream->mismatch_seen); 1775 } 1776 FOREACH_STREAM(close_output_file(stream, global.codec->fourcc)); 1777 1778 FOREACH_STREAM(stats_close(&stream->stats, global.passes - 1)); 1779 1780 if (global.pass) 1781 break; 1782 } 1783 1784 if (global.show_q_hist_buckets) 1785 FOREACH_STREAM(show_q_histogram(stream->counts, 1786 global.show_q_hist_buckets)); 1787 1788 if (global.show_rate_hist_buckets) 1789 FOREACH_STREAM(show_rate_histogram(stream->rate_hist, 1790 &stream->config.cfg, 1791 global.show_rate_hist_buckets)); 1792 FOREACH_STREAM(destroy_rate_histogram(stream->rate_hist)); 1793 1794 #if CONFIG_INTERNAL_STATS 1795 /* TODO(jkoleszar): This doesn't belong in this executable. Do it for now, 1796 * to match some existing utilities. 1797 */ 1798 if (!(global.pass == 1 && global.passes == 2)) 1799 FOREACH_STREAM({ 1800 FILE *f = fopen("opsnr.stt", "a"); 1801 if (stream->mismatch_seen) { 1802 fprintf(f, "First mismatch occurred in frame %d\n", 1803 stream->mismatch_seen); 1804 } else { 1805 fprintf(f, "No mismatch detected in recon buffers\n"); 1806 } 1807 fclose(f); 1808 }); 1809 #endif 1810 1811 vpx_img_free(&raw); 1812 free(argv); 1813 free(streams); 1814 return res ? EXIT_FAILURE : EXIT_SUCCESS; 1815 } 1816