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 #if CONFIG_LIBYUV 23 #include "third_party/libyuv/include/libyuv/scale.h" 24 #endif 25 26 #include "vpx/vpx_encoder.h" 27 #if CONFIG_DECODERS 28 #include "vpx/vpx_decoder.h" 29 #endif 30 31 #include "./args.h" 32 #include "./ivfenc.h" 33 #include "./tools_common.h" 34 35 #if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER 36 #include "vpx/vp8cx.h" 37 #endif 38 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER 39 #include "vpx/vp8dx.h" 40 #endif 41 42 #include "vpx/vpx_integer.h" 43 #include "vpx_ports/mem_ops.h" 44 #include "vpx_ports/vpx_timer.h" 45 #include "./rate_hist.h" 46 #include "./vpxstats.h" 47 #include "./warnings.h" 48 #if CONFIG_WEBM_IO 49 #include "./webmenc.h" 50 #endif 51 #include "./y4minput.h" 52 53 /* Swallow warnings about unused results of fread/fwrite */ 54 static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) { 55 return fread(ptr, size, nmemb, stream); 56 } 57 #define fread wrap_fread 58 59 static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb, 60 FILE *stream) { 61 return fwrite(ptr, size, nmemb, stream); 62 } 63 #define fwrite wrap_fwrite 64 65 static const char *exec_name; 66 67 static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal, 68 const char *s, va_list ap) { 69 if (ctx->err) { 70 const char *detail = vpx_codec_error_detail(ctx); 71 72 vfprintf(stderr, s, ap); 73 fprintf(stderr, ": %s\n", vpx_codec_error(ctx)); 74 75 if (detail) fprintf(stderr, " %s\n", detail); 76 77 if (fatal) exit(EXIT_FAILURE); 78 } 79 } 80 81 static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) { 82 va_list ap; 83 84 va_start(ap, s); 85 warn_or_exit_on_errorv(ctx, 1, s, ap); 86 va_end(ap); 87 } 88 89 static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal, 90 const char *s, ...) { 91 va_list ap; 92 93 va_start(ap, s); 94 warn_or_exit_on_errorv(ctx, fatal, s, ap); 95 va_end(ap); 96 } 97 98 static int read_frame(struct VpxInputContext *input_ctx, vpx_image_t *img) { 99 FILE *f = input_ctx->file; 100 y4m_input *y4m = &input_ctx->y4m; 101 int shortread = 0; 102 103 if (input_ctx->file_type == FILE_TYPE_Y4M) { 104 if (y4m_input_fetch_frame(y4m, f, img) < 1) return 0; 105 } else { 106 shortread = read_yuv_frame(input_ctx, img); 107 } 108 109 return !shortread; 110 } 111 112 static 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 static 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 static const arg_def_t debugmode = 127 ARG_DEF("D", "debug", 0, "Debug mode (makes output deterministic)"); 128 static const arg_def_t outputfile = 129 ARG_DEF("o", "output", 1, "Output filename"); 130 static const arg_def_t use_yv12 = 131 ARG_DEF(NULL, "yv12", 0, "Input file is YV12 "); 132 static const arg_def_t use_i420 = 133 ARG_DEF(NULL, "i420", 0, "Input file is I420 (default)"); 134 static const arg_def_t use_i422 = 135 ARG_DEF(NULL, "i422", 0, "Input file is I422"); 136 static const arg_def_t use_i444 = 137 ARG_DEF(NULL, "i444", 0, "Input file is I444"); 138 static const arg_def_t use_i440 = 139 ARG_DEF(NULL, "i440", 0, "Input file is I440"); 140 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, "Codec to use"); 141 static const arg_def_t passes = 142 ARG_DEF("p", "passes", 1, "Number of passes (1/2)"); 143 static const arg_def_t pass_arg = 144 ARG_DEF(NULL, "pass", 1, "Pass to execute (1/2)"); 145 static const arg_def_t fpf_name = 146 ARG_DEF(NULL, "fpf", 1, "First pass statistics file name"); 147 #if CONFIG_FP_MB_STATS 148 static const arg_def_t fpmbf_name = 149 ARG_DEF(NULL, "fpmbf", 1, "First pass block statistics file name"); 150 #endif 151 static const arg_def_t limit = 152 ARG_DEF(NULL, "limit", 1, "Stop encoding after n input frames"); 153 static const arg_def_t skip = 154 ARG_DEF(NULL, "skip", 1, "Skip the first n input frames"); 155 static const arg_def_t deadline = 156 ARG_DEF("d", "deadline", 1, "Deadline per frame (usec)"); 157 static const arg_def_t best_dl = 158 ARG_DEF(NULL, "best", 0, "Use Best Quality Deadline"); 159 static const arg_def_t good_dl = 160 ARG_DEF(NULL, "good", 0, "Use Good Quality Deadline"); 161 static const arg_def_t rt_dl = 162 ARG_DEF(NULL, "rt", 0, "Use Realtime Quality Deadline"); 163 static const arg_def_t quietarg = 164 ARG_DEF("q", "quiet", 0, "Do not print encode progress"); 165 static const arg_def_t verbosearg = 166 ARG_DEF("v", "verbose", 0, "Show encoder parameters"); 167 static const arg_def_t psnrarg = 168 ARG_DEF(NULL, "psnr", 0, "Show PSNR in status line"); 169 170 static const struct arg_enum_list test_decode_enum[] = { 171 { "off", TEST_DECODE_OFF }, 172 { "fatal", TEST_DECODE_FATAL }, 173 { "warn", TEST_DECODE_WARN }, 174 { NULL, 0 } 175 }; 176 static const arg_def_t recontest = ARG_DEF_ENUM( 177 NULL, "test-decode", 1, "Test encode/decode mismatch", test_decode_enum); 178 static const arg_def_t framerate = 179 ARG_DEF(NULL, "fps", 1, "Stream frame rate (rate/scale)"); 180 static const arg_def_t use_webm = 181 ARG_DEF(NULL, "webm", 0, "Output WebM (default when WebM IO is enabled)"); 182 static const arg_def_t use_ivf = ARG_DEF(NULL, "ivf", 0, "Output IVF"); 183 static const arg_def_t out_part = 184 ARG_DEF("P", "output-partitions", 0, 185 "Makes encoder output partitions. Requires IVF output!"); 186 static const arg_def_t q_hist_n = 187 ARG_DEF(NULL, "q-hist", 1, "Show quantizer histogram (n-buckets)"); 188 static const arg_def_t rate_hist_n = 189 ARG_DEF(NULL, "rate-hist", 1, "Show rate histogram (n-buckets)"); 190 static const arg_def_t disable_warnings = 191 ARG_DEF(NULL, "disable-warnings", 0, 192 "Disable warnings about potentially incorrect encode settings."); 193 static const arg_def_t disable_warning_prompt = 194 ARG_DEF("y", "disable-warning-prompt", 0, 195 "Display warnings, but do not prompt user to continue."); 196 197 #if CONFIG_VP9_HIGHBITDEPTH 198 static const arg_def_t test16bitinternalarg = ARG_DEF( 199 NULL, "test-16bit-internal", 0, "Force use of 16 bit internal buffer"); 200 #endif 201 202 static const arg_def_t *main_args[] = { &debugmode, 203 &outputfile, 204 &codecarg, 205 &passes, 206 &pass_arg, 207 &fpf_name, 208 &limit, 209 &skip, 210 &deadline, 211 &best_dl, 212 &good_dl, 213 &rt_dl, 214 &quietarg, 215 &verbosearg, 216 &psnrarg, 217 &use_webm, 218 &use_ivf, 219 &out_part, 220 &q_hist_n, 221 &rate_hist_n, 222 &disable_warnings, 223 &disable_warning_prompt, 224 &recontest, 225 NULL }; 226 227 static const arg_def_t usage = 228 ARG_DEF("u", "usage", 1, "Usage profile number to use"); 229 static const arg_def_t threads = 230 ARG_DEF("t", "threads", 1, "Max number of threads to use"); 231 static const arg_def_t profile = 232 ARG_DEF(NULL, "profile", 1, "Bitstream profile number to use"); 233 static const arg_def_t width = ARG_DEF("w", "width", 1, "Frame width"); 234 static const arg_def_t height = ARG_DEF("h", "height", 1, "Frame height"); 235 #if CONFIG_WEBM_IO 236 static const struct arg_enum_list stereo_mode_enum[] = { 237 { "mono", STEREO_FORMAT_MONO }, 238 { "left-right", STEREO_FORMAT_LEFT_RIGHT }, 239 { "bottom-top", STEREO_FORMAT_BOTTOM_TOP }, 240 { "top-bottom", STEREO_FORMAT_TOP_BOTTOM }, 241 { "right-left", STEREO_FORMAT_RIGHT_LEFT }, 242 { NULL, 0 } 243 }; 244 static const arg_def_t stereo_mode = ARG_DEF_ENUM( 245 NULL, "stereo-mode", 1, "Stereo 3D video format", stereo_mode_enum); 246 #endif 247 static const arg_def_t timebase = ARG_DEF( 248 NULL, "timebase", 1, "Output timestamp precision (fractional seconds)"); 249 static const arg_def_t error_resilient = 250 ARG_DEF(NULL, "error-resilient", 1, "Enable error resiliency features"); 251 static const arg_def_t lag_in_frames = 252 ARG_DEF(NULL, "lag-in-frames", 1, "Max number of frames to lag"); 253 254 static const arg_def_t *global_args[] = { &use_yv12, 255 &use_i420, 256 &use_i422, 257 &use_i444, 258 &use_i440, 259 &usage, 260 &threads, 261 &profile, 262 &width, 263 &height, 264 #if CONFIG_WEBM_IO 265 &stereo_mode, 266 #endif 267 &timebase, 268 &framerate, 269 &error_resilient, 270 #if CONFIG_VP9_HIGHBITDEPTH 271 &test16bitinternalarg, 272 #endif 273 &lag_in_frames, 274 NULL }; 275 276 static const arg_def_t dropframe_thresh = 277 ARG_DEF(NULL, "drop-frame", 1, "Temporal resampling threshold (buf %)"); 278 static const arg_def_t resize_allowed = 279 ARG_DEF(NULL, "resize-allowed", 1, "Spatial resampling enabled (bool)"); 280 static const arg_def_t resize_width = 281 ARG_DEF(NULL, "resize-width", 1, "Width of encoded frame"); 282 static const arg_def_t resize_height = 283 ARG_DEF(NULL, "resize-height", 1, "Height of encoded frame"); 284 static const arg_def_t resize_up_thresh = 285 ARG_DEF(NULL, "resize-up", 1, "Upscale threshold (buf %)"); 286 static const arg_def_t resize_down_thresh = 287 ARG_DEF(NULL, "resize-down", 1, "Downscale threshold (buf %)"); 288 static const struct arg_enum_list end_usage_enum[] = { { "vbr", VPX_VBR }, 289 { "cbr", VPX_CBR }, 290 { "cq", VPX_CQ }, 291 { "q", VPX_Q }, 292 { NULL, 0 } }; 293 static const arg_def_t end_usage = 294 ARG_DEF_ENUM(NULL, "end-usage", 1, "Rate control mode", end_usage_enum); 295 static const arg_def_t target_bitrate = 296 ARG_DEF(NULL, "target-bitrate", 1, "Bitrate (kbps)"); 297 static const arg_def_t min_quantizer = 298 ARG_DEF(NULL, "min-q", 1, "Minimum (best) quantizer"); 299 static const arg_def_t max_quantizer = 300 ARG_DEF(NULL, "max-q", 1, "Maximum (worst) quantizer"); 301 static const arg_def_t undershoot_pct = 302 ARG_DEF(NULL, "undershoot-pct", 1, "Datarate undershoot (min) target (%)"); 303 static const arg_def_t overshoot_pct = 304 ARG_DEF(NULL, "overshoot-pct", 1, "Datarate overshoot (max) target (%)"); 305 static const arg_def_t buf_sz = 306 ARG_DEF(NULL, "buf-sz", 1, "Client buffer size (ms)"); 307 static const arg_def_t buf_initial_sz = 308 ARG_DEF(NULL, "buf-initial-sz", 1, "Client initial buffer size (ms)"); 309 static const arg_def_t buf_optimal_sz = 310 ARG_DEF(NULL, "buf-optimal-sz", 1, "Client optimal buffer size (ms)"); 311 static const arg_def_t *rc_args[] = { 312 &dropframe_thresh, &resize_allowed, &resize_width, &resize_height, 313 &resize_up_thresh, &resize_down_thresh, &end_usage, &target_bitrate, 314 &min_quantizer, &max_quantizer, &undershoot_pct, &overshoot_pct, 315 &buf_sz, &buf_initial_sz, &buf_optimal_sz, NULL 316 }; 317 318 static const arg_def_t bias_pct = 319 ARG_DEF(NULL, "bias-pct", 1, "CBR/VBR bias (0=CBR, 100=VBR)"); 320 static const arg_def_t minsection_pct = 321 ARG_DEF(NULL, "minsection-pct", 1, "GOP min bitrate (% of target)"); 322 static const arg_def_t maxsection_pct = 323 ARG_DEF(NULL, "maxsection-pct", 1, "GOP max bitrate (% of target)"); 324 static const arg_def_t *rc_twopass_args[] = { &bias_pct, &minsection_pct, 325 &maxsection_pct, NULL }; 326 327 static const arg_def_t kf_min_dist = 328 ARG_DEF(NULL, "kf-min-dist", 1, "Minimum keyframe interval (frames)"); 329 static const arg_def_t kf_max_dist = 330 ARG_DEF(NULL, "kf-max-dist", 1, "Maximum keyframe interval (frames)"); 331 static const arg_def_t kf_disabled = 332 ARG_DEF(NULL, "disable-kf", 0, "Disable keyframe placement"); 333 static const arg_def_t *kf_args[] = { &kf_min_dist, &kf_max_dist, &kf_disabled, 334 NULL }; 335 336 static const arg_def_t noise_sens = 337 ARG_DEF(NULL, "noise-sensitivity", 1, "Noise sensitivity (frames to blur)"); 338 static const arg_def_t sharpness = 339 ARG_DEF(NULL, "sharpness", 1, "Loop filter sharpness (0..7)"); 340 static const arg_def_t static_thresh = 341 ARG_DEF(NULL, "static-thresh", 1, "Motion detection threshold"); 342 static const arg_def_t auto_altref = 343 ARG_DEF(NULL, "auto-alt-ref", 1, "Enable automatic alt reference frames"); 344 static const arg_def_t arnr_maxframes = 345 ARG_DEF(NULL, "arnr-maxframes", 1, "AltRef max frames (0..15)"); 346 static const arg_def_t arnr_strength = 347 ARG_DEF(NULL, "arnr-strength", 1, "AltRef filter strength (0..6)"); 348 static const arg_def_t arnr_type = ARG_DEF(NULL, "arnr-type", 1, "AltRef type"); 349 static const struct arg_enum_list tuning_enum[] = { 350 { "psnr", VP8_TUNE_PSNR }, { "ssim", VP8_TUNE_SSIM }, { NULL, 0 } 351 }; 352 static const arg_def_t tune_ssim = 353 ARG_DEF_ENUM(NULL, "tune", 1, "Material to favor", tuning_enum); 354 static const arg_def_t cq_level = 355 ARG_DEF(NULL, "cq-level", 1, "Constant/Constrained Quality level"); 356 static const arg_def_t max_intra_rate_pct = 357 ARG_DEF(NULL, "max-intra-rate", 1, "Max I-frame bitrate (pct)"); 358 static const arg_def_t gf_cbr_boost_pct = ARG_DEF( 359 NULL, "gf-cbr-boost", 1, "Boost for Golden Frame in CBR mode (pct)"); 360 361 #if CONFIG_VP8_ENCODER 362 static const arg_def_t cpu_used_vp8 = 363 ARG_DEF(NULL, "cpu-used", 1, "CPU Used (-16..16)"); 364 static const arg_def_t token_parts = 365 ARG_DEF(NULL, "token-parts", 1, "Number of token partitions to use, log2"); 366 static const arg_def_t screen_content_mode = 367 ARG_DEF(NULL, "screen-content-mode", 1, "Screen content mode"); 368 static const arg_def_t *vp8_args[] = { &cpu_used_vp8, 369 &auto_altref, 370 &noise_sens, 371 &sharpness, 372 &static_thresh, 373 &token_parts, 374 &arnr_maxframes, 375 &arnr_strength, 376 &arnr_type, 377 &tune_ssim, 378 &cq_level, 379 &max_intra_rate_pct, 380 &gf_cbr_boost_pct, 381 &screen_content_mode, 382 NULL }; 383 static const int vp8_arg_ctrl_map[] = { VP8E_SET_CPUUSED, 384 VP8E_SET_ENABLEAUTOALTREF, 385 VP8E_SET_NOISE_SENSITIVITY, 386 VP8E_SET_SHARPNESS, 387 VP8E_SET_STATIC_THRESHOLD, 388 VP8E_SET_TOKEN_PARTITIONS, 389 VP8E_SET_ARNR_MAXFRAMES, 390 VP8E_SET_ARNR_STRENGTH, 391 VP8E_SET_ARNR_TYPE, 392 VP8E_SET_TUNING, 393 VP8E_SET_CQ_LEVEL, 394 VP8E_SET_MAX_INTRA_BITRATE_PCT, 395 VP8E_SET_GF_CBR_BOOST_PCT, 396 VP8E_SET_SCREEN_CONTENT_MODE, 397 0 }; 398 #endif 399 400 #if CONFIG_VP9_ENCODER 401 static const arg_def_t cpu_used_vp9 = 402 ARG_DEF(NULL, "cpu-used", 1, "CPU Used (-8..8)"); 403 static const arg_def_t tile_cols = 404 ARG_DEF(NULL, "tile-columns", 1, "Number of tile columns to use, log2"); 405 static const arg_def_t tile_rows = 406 ARG_DEF(NULL, "tile-rows", 1, 407 "Number of tile rows to use, log2 (set to 0 while threads > 1)"); 408 static const arg_def_t lossless = 409 ARG_DEF(NULL, "lossless", 1, "Lossless mode (0: false (default), 1: true)"); 410 static const arg_def_t frame_parallel_decoding = ARG_DEF( 411 NULL, "frame-parallel", 1, "Enable frame parallel decodability features"); 412 static const arg_def_t aq_mode = ARG_DEF( 413 NULL, "aq-mode", 1, 414 "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, " 415 "3: cyclic refresh, 4: equator360)"); 416 static const arg_def_t alt_ref_aq = ARG_DEF(NULL, "alt-ref-aq", 1, 417 "Special adaptive quantization for " 418 "the alternate reference frames."); 419 static const arg_def_t frame_periodic_boost = 420 ARG_DEF(NULL, "frame-boost", 1, 421 "Enable frame periodic boost (0: off (default), 1: on)"); 422 static const arg_def_t max_inter_rate_pct = 423 ARG_DEF(NULL, "max-inter-rate", 1, "Max P-frame bitrate (pct)"); 424 static const arg_def_t min_gf_interval = ARG_DEF( 425 NULL, "min-gf-interval", 1, 426 "min gf/arf frame interval (default 0, indicating in-built behavior)"); 427 static const arg_def_t max_gf_interval = ARG_DEF( 428 NULL, "max-gf-interval", 1, 429 "max gf/arf frame interval (default 0, indicating in-built behavior)"); 430 431 static const struct arg_enum_list color_space_enum[] = { 432 { "unknown", VPX_CS_UNKNOWN }, 433 { "bt601", VPX_CS_BT_601 }, 434 { "bt709", VPX_CS_BT_709 }, 435 { "smpte170", VPX_CS_SMPTE_170 }, 436 { "smpte240", VPX_CS_SMPTE_240 }, 437 { "bt2020", VPX_CS_BT_2020 }, 438 { "reserved", VPX_CS_RESERVED }, 439 { "sRGB", VPX_CS_SRGB }, 440 { NULL, 0 } 441 }; 442 443 static const arg_def_t input_color_space = 444 ARG_DEF_ENUM(NULL, "color-space", 1, "The color space of input content:", 445 color_space_enum); 446 447 #if CONFIG_VP9_HIGHBITDEPTH 448 static const struct arg_enum_list bitdepth_enum[] = { 449 { "8", VPX_BITS_8 }, { "10", VPX_BITS_10 }, { "12", VPX_BITS_12 }, { NULL, 0 } 450 }; 451 452 static const arg_def_t bitdeptharg = ARG_DEF_ENUM( 453 "b", "bit-depth", 1, 454 "Bit depth for codec (8 for version <=1, 10 or 12 for version 2)", 455 bitdepth_enum); 456 static const arg_def_t inbitdeptharg = 457 ARG_DEF(NULL, "input-bit-depth", 1, "Bit depth of input"); 458 #endif 459 460 static const struct arg_enum_list tune_content_enum[] = { 461 { "default", VP9E_CONTENT_DEFAULT }, 462 { "screen", VP9E_CONTENT_SCREEN }, 463 { NULL, 0 } 464 }; 465 466 static const arg_def_t tune_content = ARG_DEF_ENUM( 467 NULL, "tune-content", 1, "Tune content type", tune_content_enum); 468 469 static const arg_def_t target_level = ARG_DEF( 470 NULL, "target-level", 1, 471 "Target level (255: off (default); 0: only keep level stats; 10: level 1.0;" 472 " 11: level 1.1; ... 62: level 6.2)"); 473 474 static const arg_def_t row_mt = 475 ARG_DEF(NULL, "row-mt", 1, 476 "Enable row based non-deterministic multi-threading in VP9"); 477 #endif 478 479 #if CONFIG_VP9_ENCODER 480 static const arg_def_t *vp9_args[] = { &cpu_used_vp9, 481 &auto_altref, 482 &sharpness, 483 &static_thresh, 484 &tile_cols, 485 &tile_rows, 486 &arnr_maxframes, 487 &arnr_strength, 488 &arnr_type, 489 &tune_ssim, 490 &cq_level, 491 &max_intra_rate_pct, 492 &max_inter_rate_pct, 493 &gf_cbr_boost_pct, 494 &lossless, 495 &frame_parallel_decoding, 496 &aq_mode, 497 &alt_ref_aq, 498 &frame_periodic_boost, 499 &noise_sens, 500 &tune_content, 501 &input_color_space, 502 &min_gf_interval, 503 &max_gf_interval, 504 &target_level, 505 &row_mt, 506 #if CONFIG_VP9_HIGHBITDEPTH 507 &bitdeptharg, 508 &inbitdeptharg, 509 #endif // CONFIG_VP9_HIGHBITDEPTH 510 NULL }; 511 static const int vp9_arg_ctrl_map[] = { VP8E_SET_CPUUSED, 512 VP8E_SET_ENABLEAUTOALTREF, 513 VP8E_SET_SHARPNESS, 514 VP8E_SET_STATIC_THRESHOLD, 515 VP9E_SET_TILE_COLUMNS, 516 VP9E_SET_TILE_ROWS, 517 VP8E_SET_ARNR_MAXFRAMES, 518 VP8E_SET_ARNR_STRENGTH, 519 VP8E_SET_ARNR_TYPE, 520 VP8E_SET_TUNING, 521 VP8E_SET_CQ_LEVEL, 522 VP8E_SET_MAX_INTRA_BITRATE_PCT, 523 VP9E_SET_MAX_INTER_BITRATE_PCT, 524 VP9E_SET_GF_CBR_BOOST_PCT, 525 VP9E_SET_LOSSLESS, 526 VP9E_SET_FRAME_PARALLEL_DECODING, 527 VP9E_SET_AQ_MODE, 528 VP9E_SET_ALT_REF_AQ, 529 VP9E_SET_FRAME_PERIODIC_BOOST, 530 VP9E_SET_NOISE_SENSITIVITY, 531 VP9E_SET_TUNE_CONTENT, 532 VP9E_SET_COLOR_SPACE, 533 VP9E_SET_MIN_GF_INTERVAL, 534 VP9E_SET_MAX_GF_INTERVAL, 535 VP9E_SET_TARGET_LEVEL, 536 VP9E_SET_ROW_MT, 537 0 }; 538 #endif 539 540 static const arg_def_t *no_args[] = { NULL }; 541 542 void usage_exit(void) { 543 int i; 544 const int num_encoder = get_vpx_encoder_count(); 545 546 fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n", 547 exec_name); 548 549 fprintf(stderr, "\nOptions:\n"); 550 arg_show_usage(stderr, main_args); 551 fprintf(stderr, "\nEncoder Global Options:\n"); 552 arg_show_usage(stderr, global_args); 553 fprintf(stderr, "\nRate Control Options:\n"); 554 arg_show_usage(stderr, rc_args); 555 fprintf(stderr, "\nTwopass Rate Control Options:\n"); 556 arg_show_usage(stderr, rc_twopass_args); 557 fprintf(stderr, "\nKeyframe Placement Options:\n"); 558 arg_show_usage(stderr, kf_args); 559 #if CONFIG_VP8_ENCODER 560 fprintf(stderr, "\nVP8 Specific Options:\n"); 561 arg_show_usage(stderr, vp8_args); 562 #endif 563 #if CONFIG_VP9_ENCODER 564 fprintf(stderr, "\nVP9 Specific Options:\n"); 565 arg_show_usage(stderr, vp9_args); 566 #endif 567 fprintf(stderr, 568 "\nStream timebase (--timebase):\n" 569 " The desired precision of timestamps in the output, expressed\n" 570 " in fractional seconds. Default is 1/1000.\n"); 571 fprintf(stderr, "\nIncluded encoders:\n\n"); 572 573 for (i = 0; i < num_encoder; ++i) { 574 const VpxInterface *const encoder = get_vpx_encoder_by_index(i); 575 const char *defstr = (i == (num_encoder - 1)) ? "(default)" : ""; 576 fprintf(stderr, " %-6s - %s %s\n", encoder->name, 577 vpx_codec_iface_name(encoder->codec_interface()), defstr); 578 } 579 fprintf(stderr, "\n "); 580 fprintf(stderr, "Use --codec to switch to a non-default encoder.\n\n"); 581 582 exit(EXIT_FAILURE); 583 } 584 585 #define mmin(a, b) ((a) < (b) ? (a) : (b)) 586 587 #if CONFIG_VP9_HIGHBITDEPTH 588 static void find_mismatch_high(const vpx_image_t *const img1, 589 const vpx_image_t *const img2, int yloc[4], 590 int uloc[4], int vloc[4]) { 591 uint16_t *plane1, *plane2; 592 uint32_t stride1, stride2; 593 const uint32_t bsize = 64; 594 const uint32_t bsizey = bsize >> img1->y_chroma_shift; 595 const uint32_t bsizex = bsize >> img1->x_chroma_shift; 596 const uint32_t c_w = 597 (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; 598 const uint32_t c_h = 599 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; 600 int match = 1; 601 uint32_t i, j; 602 yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1; 603 plane1 = (uint16_t *)img1->planes[VPX_PLANE_Y]; 604 plane2 = (uint16_t *)img2->planes[VPX_PLANE_Y]; 605 stride1 = img1->stride[VPX_PLANE_Y] / 2; 606 stride2 = img2->stride[VPX_PLANE_Y] / 2; 607 for (i = 0, match = 1; match && i < img1->d_h; i += bsize) { 608 for (j = 0; match && j < img1->d_w; j += bsize) { 609 int k, l; 610 const int si = mmin(i + bsize, img1->d_h) - i; 611 const int sj = mmin(j + bsize, img1->d_w) - j; 612 for (k = 0; match && k < si; ++k) { 613 for (l = 0; match && l < sj; ++l) { 614 if (*(plane1 + (i + k) * stride1 + j + l) != 615 *(plane2 + (i + k) * stride2 + j + l)) { 616 yloc[0] = i + k; 617 yloc[1] = j + l; 618 yloc[2] = *(plane1 + (i + k) * stride1 + j + l); 619 yloc[3] = *(plane2 + (i + k) * stride2 + j + l); 620 match = 0; 621 break; 622 } 623 } 624 } 625 } 626 } 627 628 uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1; 629 plane1 = (uint16_t *)img1->planes[VPX_PLANE_U]; 630 plane2 = (uint16_t *)img2->planes[VPX_PLANE_U]; 631 stride1 = img1->stride[VPX_PLANE_U] / 2; 632 stride2 = img2->stride[VPX_PLANE_U] / 2; 633 for (i = 0, match = 1; match && i < c_h; i += bsizey) { 634 for (j = 0; match && j < c_w; j += bsizex) { 635 int k, l; 636 const int si = mmin(i + bsizey, c_h - i); 637 const int sj = mmin(j + bsizex, c_w - j); 638 for (k = 0; match && k < si; ++k) { 639 for (l = 0; match && l < sj; ++l) { 640 if (*(plane1 + (i + k) * stride1 + j + l) != 641 *(plane2 + (i + k) * stride2 + j + l)) { 642 uloc[0] = i + k; 643 uloc[1] = j + l; 644 uloc[2] = *(plane1 + (i + k) * stride1 + j + l); 645 uloc[3] = *(plane2 + (i + k) * stride2 + j + l); 646 match = 0; 647 break; 648 } 649 } 650 } 651 } 652 } 653 654 vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1; 655 plane1 = (uint16_t *)img1->planes[VPX_PLANE_V]; 656 plane2 = (uint16_t *)img2->planes[VPX_PLANE_V]; 657 stride1 = img1->stride[VPX_PLANE_V] / 2; 658 stride2 = img2->stride[VPX_PLANE_V] / 2; 659 for (i = 0, match = 1; match && i < c_h; i += bsizey) { 660 for (j = 0; match && j < c_w; j += bsizex) { 661 int k, l; 662 const int si = mmin(i + bsizey, c_h - i); 663 const int sj = mmin(j + bsizex, c_w - j); 664 for (k = 0; match && k < si; ++k) { 665 for (l = 0; match && l < sj; ++l) { 666 if (*(plane1 + (i + k) * stride1 + j + l) != 667 *(plane2 + (i + k) * stride2 + j + l)) { 668 vloc[0] = i + k; 669 vloc[1] = j + l; 670 vloc[2] = *(plane1 + (i + k) * stride1 + j + l); 671 vloc[3] = *(plane2 + (i + k) * stride2 + j + l); 672 match = 0; 673 break; 674 } 675 } 676 } 677 } 678 } 679 } 680 #endif 681 682 static void find_mismatch(const vpx_image_t *const img1, 683 const vpx_image_t *const img2, int yloc[4], 684 int uloc[4], int vloc[4]) { 685 const uint32_t bsize = 64; 686 const uint32_t bsizey = bsize >> img1->y_chroma_shift; 687 const uint32_t bsizex = bsize >> img1->x_chroma_shift; 688 const uint32_t c_w = 689 (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; 690 const uint32_t c_h = 691 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; 692 int match = 1; 693 uint32_t i, j; 694 yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1; 695 for (i = 0, match = 1; match && i < img1->d_h; i += bsize) { 696 for (j = 0; match && j < img1->d_w; j += bsize) { 697 int k, l; 698 const int si = mmin(i + bsize, img1->d_h) - i; 699 const int sj = mmin(j + bsize, img1->d_w) - j; 700 for (k = 0; match && k < si; ++k) { 701 for (l = 0; match && l < sj; ++l) { 702 if (*(img1->planes[VPX_PLANE_Y] + 703 (i + k) * img1->stride[VPX_PLANE_Y] + j + l) != 704 *(img2->planes[VPX_PLANE_Y] + 705 (i + k) * img2->stride[VPX_PLANE_Y] + j + l)) { 706 yloc[0] = i + k; 707 yloc[1] = j + l; 708 yloc[2] = *(img1->planes[VPX_PLANE_Y] + 709 (i + k) * img1->stride[VPX_PLANE_Y] + j + l); 710 yloc[3] = *(img2->planes[VPX_PLANE_Y] + 711 (i + k) * img2->stride[VPX_PLANE_Y] + j + l); 712 match = 0; 713 break; 714 } 715 } 716 } 717 } 718 } 719 720 uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1; 721 for (i = 0, match = 1; match && i < c_h; i += bsizey) { 722 for (j = 0; match && j < c_w; j += bsizex) { 723 int k, l; 724 const int si = mmin(i + bsizey, c_h - i); 725 const int sj = mmin(j + bsizex, c_w - j); 726 for (k = 0; match && k < si; ++k) { 727 for (l = 0; match && l < sj; ++l) { 728 if (*(img1->planes[VPX_PLANE_U] + 729 (i + k) * img1->stride[VPX_PLANE_U] + j + l) != 730 *(img2->planes[VPX_PLANE_U] + 731 (i + k) * img2->stride[VPX_PLANE_U] + j + l)) { 732 uloc[0] = i + k; 733 uloc[1] = j + l; 734 uloc[2] = *(img1->planes[VPX_PLANE_U] + 735 (i + k) * img1->stride[VPX_PLANE_U] + j + l); 736 uloc[3] = *(img2->planes[VPX_PLANE_U] + 737 (i + k) * img2->stride[VPX_PLANE_U] + j + l); 738 match = 0; 739 break; 740 } 741 } 742 } 743 } 744 } 745 vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1; 746 for (i = 0, match = 1; match && i < c_h; i += bsizey) { 747 for (j = 0; match && j < c_w; j += bsizex) { 748 int k, l; 749 const int si = mmin(i + bsizey, c_h - i); 750 const int sj = mmin(j + bsizex, c_w - j); 751 for (k = 0; match && k < si; ++k) { 752 for (l = 0; match && l < sj; ++l) { 753 if (*(img1->planes[VPX_PLANE_V] + 754 (i + k) * img1->stride[VPX_PLANE_V] + j + l) != 755 *(img2->planes[VPX_PLANE_V] + 756 (i + k) * img2->stride[VPX_PLANE_V] + j + l)) { 757 vloc[0] = i + k; 758 vloc[1] = j + l; 759 vloc[2] = *(img1->planes[VPX_PLANE_V] + 760 (i + k) * img1->stride[VPX_PLANE_V] + j + l); 761 vloc[3] = *(img2->planes[VPX_PLANE_V] + 762 (i + k) * img2->stride[VPX_PLANE_V] + j + l); 763 match = 0; 764 break; 765 } 766 } 767 } 768 } 769 } 770 } 771 772 static int compare_img(const vpx_image_t *const img1, 773 const vpx_image_t *const img2) { 774 uint32_t l_w = img1->d_w; 775 uint32_t c_w = (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift; 776 const uint32_t c_h = 777 (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift; 778 uint32_t i; 779 int match = 1; 780 781 match &= (img1->fmt == img2->fmt); 782 match &= (img1->d_w == img2->d_w); 783 match &= (img1->d_h == img2->d_h); 784 #if CONFIG_VP9_HIGHBITDEPTH 785 if (img1->fmt & VPX_IMG_FMT_HIGHBITDEPTH) { 786 l_w *= 2; 787 c_w *= 2; 788 } 789 #endif 790 791 for (i = 0; i < img1->d_h; ++i) 792 match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y], 793 img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y], 794 l_w) == 0); 795 796 for (i = 0; i < c_h; ++i) 797 match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U], 798 img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U], 799 c_w) == 0); 800 801 for (i = 0; i < c_h; ++i) 802 match &= (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V], 803 img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V], 804 c_w) == 0); 805 806 return match; 807 } 808 809 #define NELEMENTS(x) (sizeof(x) / sizeof(x[0])) 810 #if CONFIG_VP9_ENCODER 811 #define ARG_CTRL_CNT_MAX NELEMENTS(vp9_arg_ctrl_map) 812 #else 813 #define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map) 814 #endif 815 816 #if !CONFIG_WEBM_IO 817 typedef int stereo_format_t; 818 struct WebmOutputContext { 819 int debug; 820 }; 821 #endif 822 823 /* Per-stream configuration */ 824 struct stream_config { 825 struct vpx_codec_enc_cfg cfg; 826 const char *out_fn; 827 const char *stats_fn; 828 #if CONFIG_FP_MB_STATS 829 const char *fpmb_stats_fn; 830 #endif 831 stereo_format_t stereo_fmt; 832 int arg_ctrls[ARG_CTRL_CNT_MAX][2]; 833 int arg_ctrl_cnt; 834 int write_webm; 835 #if CONFIG_VP9_HIGHBITDEPTH 836 // whether to use 16bit internal buffers 837 int use_16bit_internal; 838 #endif 839 }; 840 841 struct stream_state { 842 int index; 843 struct stream_state *next; 844 struct stream_config config; 845 FILE *file; 846 struct rate_hist *rate_hist; 847 struct WebmOutputContext webm_ctx; 848 uint64_t psnr_sse_total; 849 uint64_t psnr_samples_total; 850 double psnr_totals[4]; 851 int psnr_count; 852 int counts[64]; 853 vpx_codec_ctx_t encoder; 854 unsigned int frames_out; 855 uint64_t cx_time; 856 size_t nbytes; 857 stats_io_t stats; 858 #if CONFIG_FP_MB_STATS 859 stats_io_t fpmb_stats; 860 #endif 861 struct vpx_image *img; 862 vpx_codec_ctx_t decoder; 863 int mismatch_seen; 864 }; 865 866 static void validate_positive_rational(const char *msg, 867 struct vpx_rational *rat) { 868 if (rat->den < 0) { 869 rat->num *= -1; 870 rat->den *= -1; 871 } 872 873 if (rat->num < 0) die("Error: %s must be positive\n", msg); 874 875 if (!rat->den) die("Error: %s has zero denominator\n", msg); 876 } 877 878 static void parse_global_config(struct VpxEncoderConfig *global, char **argv) { 879 char **argi, **argj; 880 struct arg arg; 881 const int num_encoder = get_vpx_encoder_count(); 882 883 if (num_encoder < 1) die("Error: no valid encoder available\n"); 884 885 /* Initialize default parameters */ 886 memset(global, 0, sizeof(*global)); 887 global->codec = get_vpx_encoder_by_index(num_encoder - 1); 888 global->passes = 0; 889 global->color_type = I420; 890 /* Assign default deadline to good quality */ 891 global->deadline = VPX_DL_GOOD_QUALITY; 892 893 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { 894 arg.argv_step = 1; 895 896 if (arg_match(&arg, &codecarg, argi)) { 897 global->codec = get_vpx_encoder_by_name(arg.val); 898 if (!global->codec) 899 die("Error: Unrecognized argument (%s) to --codec\n", arg.val); 900 } else if (arg_match(&arg, &passes, argi)) { 901 global->passes = arg_parse_uint(&arg); 902 903 if (global->passes < 1 || global->passes > 2) 904 die("Error: Invalid number of passes (%d)\n", global->passes); 905 } else if (arg_match(&arg, &pass_arg, argi)) { 906 global->pass = arg_parse_uint(&arg); 907 908 if (global->pass < 1 || global->pass > 2) 909 die("Error: Invalid pass selected (%d)\n", global->pass); 910 } else if (arg_match(&arg, &usage, argi)) 911 global->usage = arg_parse_uint(&arg); 912 else if (arg_match(&arg, &deadline, argi)) 913 global->deadline = arg_parse_uint(&arg); 914 else if (arg_match(&arg, &best_dl, argi)) 915 global->deadline = VPX_DL_BEST_QUALITY; 916 else if (arg_match(&arg, &good_dl, argi)) 917 global->deadline = VPX_DL_GOOD_QUALITY; 918 else if (arg_match(&arg, &rt_dl, argi)) 919 global->deadline = VPX_DL_REALTIME; 920 else if (arg_match(&arg, &use_yv12, argi)) 921 global->color_type = YV12; 922 else if (arg_match(&arg, &use_i420, argi)) 923 global->color_type = I420; 924 else if (arg_match(&arg, &use_i422, argi)) 925 global->color_type = I422; 926 else if (arg_match(&arg, &use_i444, argi)) 927 global->color_type = I444; 928 else if (arg_match(&arg, &use_i440, argi)) 929 global->color_type = I440; 930 else if (arg_match(&arg, &quietarg, argi)) 931 global->quiet = 1; 932 else if (arg_match(&arg, &verbosearg, argi)) 933 global->verbose = 1; 934 else if (arg_match(&arg, &limit, argi)) 935 global->limit = arg_parse_uint(&arg); 936 else if (arg_match(&arg, &skip, argi)) 937 global->skip_frames = arg_parse_uint(&arg); 938 else if (arg_match(&arg, &psnrarg, argi)) 939 global->show_psnr = 1; 940 else if (arg_match(&arg, &recontest, argi)) 941 global->test_decode = arg_parse_enum_or_int(&arg); 942 else if (arg_match(&arg, &framerate, argi)) { 943 global->framerate = arg_parse_rational(&arg); 944 validate_positive_rational(arg.name, &global->framerate); 945 global->have_framerate = 1; 946 } else if (arg_match(&arg, &out_part, argi)) 947 global->out_part = 1; 948 else if (arg_match(&arg, &debugmode, argi)) 949 global->debug = 1; 950 else if (arg_match(&arg, &q_hist_n, argi)) 951 global->show_q_hist_buckets = arg_parse_uint(&arg); 952 else if (arg_match(&arg, &rate_hist_n, argi)) 953 global->show_rate_hist_buckets = arg_parse_uint(&arg); 954 else if (arg_match(&arg, &disable_warnings, argi)) 955 global->disable_warnings = 1; 956 else if (arg_match(&arg, &disable_warning_prompt, argi)) 957 global->disable_warning_prompt = 1; 958 else 959 argj++; 960 } 961 962 if (global->pass) { 963 /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ 964 if (global->pass > global->passes) { 965 warn("Assuming --pass=%d implies --passes=%d\n", global->pass, 966 global->pass); 967 global->passes = global->pass; 968 } 969 } 970 /* Validate global config */ 971 if (global->passes == 0) { 972 #if CONFIG_VP9_ENCODER 973 // Make default VP9 passes = 2 until there is a better quality 1-pass 974 // encoder 975 if (global->codec != NULL && global->codec->name != NULL) 976 global->passes = (strcmp(global->codec->name, "vp9") == 0 && 977 global->deadline != VPX_DL_REALTIME) 978 ? 2 979 : 1; 980 #else 981 global->passes = 1; 982 #endif 983 } 984 985 if (global->deadline == VPX_DL_REALTIME && global->passes > 1) { 986 warn("Enforcing one-pass encoding in realtime mode\n"); 987 global->passes = 1; 988 } 989 } 990 991 static void open_input_file(struct VpxInputContext *input) { 992 /* Parse certain options from the input file, if possible */ 993 input->file = strcmp(input->filename, "-") ? fopen(input->filename, "rb") 994 : set_binary_mode(stdin); 995 996 if (!input->file) fatal("Failed to open input file"); 997 998 if (!fseeko(input->file, 0, SEEK_END)) { 999 /* Input file is seekable. Figure out how long it is, so we can get 1000 * progress info. 1001 */ 1002 input->length = ftello(input->file); 1003 rewind(input->file); 1004 } 1005 1006 /* Default to 1:1 pixel aspect ratio. */ 1007 input->pixel_aspect_ratio.numerator = 1; 1008 input->pixel_aspect_ratio.denominator = 1; 1009 1010 /* For RAW input sources, these bytes will applied on the first frame 1011 * in read_frame(). 1012 */ 1013 input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file); 1014 input->detect.position = 0; 1015 1016 if (input->detect.buf_read == 4 && file_is_y4m(input->detect.buf)) { 1017 if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4, 1018 input->only_i420) >= 0) { 1019 input->file_type = FILE_TYPE_Y4M; 1020 input->width = input->y4m.pic_w; 1021 input->height = input->y4m.pic_h; 1022 input->pixel_aspect_ratio.numerator = input->y4m.par_n; 1023 input->pixel_aspect_ratio.denominator = input->y4m.par_d; 1024 input->framerate.numerator = input->y4m.fps_n; 1025 input->framerate.denominator = input->y4m.fps_d; 1026 input->fmt = input->y4m.vpx_fmt; 1027 input->bit_depth = input->y4m.bit_depth; 1028 } else 1029 fatal("Unsupported Y4M stream."); 1030 } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) { 1031 fatal("IVF is not supported as input."); 1032 } else { 1033 input->file_type = FILE_TYPE_RAW; 1034 } 1035 } 1036 1037 static void close_input_file(struct VpxInputContext *input) { 1038 fclose(input->file); 1039 if (input->file_type == FILE_TYPE_Y4M) y4m_input_close(&input->y4m); 1040 } 1041 1042 static struct stream_state *new_stream(struct VpxEncoderConfig *global, 1043 struct stream_state *prev) { 1044 struct stream_state *stream; 1045 1046 stream = calloc(1, sizeof(*stream)); 1047 if (stream == NULL) { 1048 fatal("Failed to allocate new stream."); 1049 } 1050 1051 if (prev) { 1052 memcpy(stream, prev, sizeof(*stream)); 1053 stream->index++; 1054 prev->next = stream; 1055 } else { 1056 vpx_codec_err_t res; 1057 1058 /* Populate encoder configuration */ 1059 res = vpx_codec_enc_config_default(global->codec->codec_interface(), 1060 &stream->config.cfg, global->usage); 1061 if (res) fatal("Failed to get config: %s\n", vpx_codec_err_to_string(res)); 1062 1063 /* Change the default timebase to a high enough value so that the 1064 * encoder will always create strictly increasing timestamps. 1065 */ 1066 stream->config.cfg.g_timebase.den = 1000; 1067 1068 /* Never use the library's default resolution, require it be parsed 1069 * from the file or set on the command line. 1070 */ 1071 stream->config.cfg.g_w = 0; 1072 stream->config.cfg.g_h = 0; 1073 1074 /* Initialize remaining stream parameters */ 1075 stream->config.write_webm = 1; 1076 #if CONFIG_WEBM_IO 1077 stream->config.stereo_fmt = STEREO_FORMAT_MONO; 1078 stream->webm_ctx.last_pts_ns = -1; 1079 stream->webm_ctx.writer = NULL; 1080 stream->webm_ctx.segment = NULL; 1081 #endif 1082 1083 /* Allows removal of the application version from the EBML tags */ 1084 stream->webm_ctx.debug = global->debug; 1085 1086 /* Default lag_in_frames is 0 in realtime mode CBR mode*/ 1087 if (global->deadline == VPX_DL_REALTIME && 1088 stream->config.cfg.rc_end_usage == 1) 1089 stream->config.cfg.g_lag_in_frames = 0; 1090 } 1091 1092 /* Output files must be specified for each stream */ 1093 stream->config.out_fn = NULL; 1094 1095 stream->next = NULL; 1096 return stream; 1097 } 1098 1099 static int parse_stream_params(struct VpxEncoderConfig *global, 1100 struct stream_state *stream, char **argv) { 1101 char **argi, **argj; 1102 struct arg arg; 1103 static const arg_def_t **ctrl_args = no_args; 1104 static const int *ctrl_args_map = NULL; 1105 struct stream_config *config = &stream->config; 1106 int eos_mark_found = 0; 1107 #if CONFIG_VP9_HIGHBITDEPTH 1108 int test_16bit_internal = 0; 1109 #endif 1110 1111 // Handle codec specific options 1112 if (0) { 1113 #if CONFIG_VP8_ENCODER 1114 } else if (strcmp(global->codec->name, "vp8") == 0) { 1115 ctrl_args = vp8_args; 1116 ctrl_args_map = vp8_arg_ctrl_map; 1117 #endif 1118 #if CONFIG_VP9_ENCODER 1119 } else if (strcmp(global->codec->name, "vp9") == 0) { 1120 ctrl_args = vp9_args; 1121 ctrl_args_map = vp9_arg_ctrl_map; 1122 #endif 1123 } 1124 1125 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { 1126 arg.argv_step = 1; 1127 1128 /* Once we've found an end-of-stream marker (--) we want to continue 1129 * shifting arguments but not consuming them. 1130 */ 1131 if (eos_mark_found) { 1132 argj++; 1133 continue; 1134 } else if (!strcmp(*argj, "--")) { 1135 eos_mark_found = 1; 1136 continue; 1137 } 1138 1139 if (arg_match(&arg, &outputfile, argi)) { 1140 config->out_fn = arg.val; 1141 } else if (arg_match(&arg, &fpf_name, argi)) { 1142 config->stats_fn = arg.val; 1143 #if CONFIG_FP_MB_STATS 1144 } else if (arg_match(&arg, &fpmbf_name, argi)) { 1145 config->fpmb_stats_fn = arg.val; 1146 #endif 1147 } else if (arg_match(&arg, &use_webm, argi)) { 1148 #if CONFIG_WEBM_IO 1149 config->write_webm = 1; 1150 #else 1151 die("Error: --webm specified but webm is disabled."); 1152 #endif 1153 } else if (arg_match(&arg, &use_ivf, argi)) { 1154 config->write_webm = 0; 1155 } else if (arg_match(&arg, &threads, argi)) { 1156 config->cfg.g_threads = arg_parse_uint(&arg); 1157 } else if (arg_match(&arg, &profile, argi)) { 1158 config->cfg.g_profile = arg_parse_uint(&arg); 1159 } else if (arg_match(&arg, &width, argi)) { 1160 config->cfg.g_w = arg_parse_uint(&arg); 1161 } else if (arg_match(&arg, &height, argi)) { 1162 config->cfg.g_h = arg_parse_uint(&arg); 1163 #if CONFIG_VP9_HIGHBITDEPTH 1164 } else if (arg_match(&arg, &bitdeptharg, argi)) { 1165 config->cfg.g_bit_depth = arg_parse_enum_or_int(&arg); 1166 } else if (arg_match(&arg, &inbitdeptharg, argi)) { 1167 config->cfg.g_input_bit_depth = arg_parse_uint(&arg); 1168 #endif 1169 #if CONFIG_WEBM_IO 1170 } else if (arg_match(&arg, &stereo_mode, argi)) { 1171 config->stereo_fmt = arg_parse_enum_or_int(&arg); 1172 #endif 1173 } else if (arg_match(&arg, &timebase, argi)) { 1174 config->cfg.g_timebase = arg_parse_rational(&arg); 1175 validate_positive_rational(arg.name, &config->cfg.g_timebase); 1176 } else if (arg_match(&arg, &error_resilient, argi)) { 1177 config->cfg.g_error_resilient = arg_parse_uint(&arg); 1178 } else if (arg_match(&arg, &end_usage, argi)) { 1179 config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg); 1180 } else if (arg_match(&arg, &lag_in_frames, argi)) { 1181 config->cfg.g_lag_in_frames = arg_parse_uint(&arg); 1182 if (global->deadline == VPX_DL_REALTIME && 1183 config->cfg.rc_end_usage == VPX_CBR && 1184 config->cfg.g_lag_in_frames != 0) { 1185 warn("non-zero %s option ignored in realtime CBR mode.\n", arg.name); 1186 config->cfg.g_lag_in_frames = 0; 1187 } 1188 } else if (arg_match(&arg, &dropframe_thresh, argi)) { 1189 config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg); 1190 } else if (arg_match(&arg, &resize_allowed, argi)) { 1191 config->cfg.rc_resize_allowed = arg_parse_uint(&arg); 1192 } else if (arg_match(&arg, &resize_width, argi)) { 1193 config->cfg.rc_scaled_width = arg_parse_uint(&arg); 1194 } else if (arg_match(&arg, &resize_height, argi)) { 1195 config->cfg.rc_scaled_height = arg_parse_uint(&arg); 1196 } else if (arg_match(&arg, &resize_up_thresh, argi)) { 1197 config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg); 1198 } else if (arg_match(&arg, &resize_down_thresh, argi)) { 1199 config->cfg.rc_resize_down_thresh = arg_parse_uint(&arg); 1200 } else if (arg_match(&arg, &end_usage, argi)) { 1201 config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg); 1202 } else if (arg_match(&arg, &target_bitrate, argi)) { 1203 config->cfg.rc_target_bitrate = arg_parse_uint(&arg); 1204 } else if (arg_match(&arg, &min_quantizer, argi)) { 1205 config->cfg.rc_min_quantizer = arg_parse_uint(&arg); 1206 } else if (arg_match(&arg, &max_quantizer, argi)) { 1207 config->cfg.rc_max_quantizer = arg_parse_uint(&arg); 1208 } else if (arg_match(&arg, &undershoot_pct, argi)) { 1209 config->cfg.rc_undershoot_pct = arg_parse_uint(&arg); 1210 } else if (arg_match(&arg, &overshoot_pct, argi)) { 1211 config->cfg.rc_overshoot_pct = arg_parse_uint(&arg); 1212 } else if (arg_match(&arg, &buf_sz, argi)) { 1213 config->cfg.rc_buf_sz = arg_parse_uint(&arg); 1214 } else if (arg_match(&arg, &buf_initial_sz, argi)) { 1215 config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg); 1216 } else if (arg_match(&arg, &buf_optimal_sz, argi)) { 1217 config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg); 1218 } else if (arg_match(&arg, &bias_pct, argi)) { 1219 config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg); 1220 if (global->passes < 2) 1221 warn("option %s ignored in one-pass mode.\n", arg.name); 1222 } else if (arg_match(&arg, &minsection_pct, argi)) { 1223 config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg); 1224 1225 if (global->passes < 2) 1226 warn("option %s ignored in one-pass mode.\n", arg.name); 1227 } else if (arg_match(&arg, &maxsection_pct, argi)) { 1228 config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg); 1229 1230 if (global->passes < 2) 1231 warn("option %s ignored in one-pass mode.\n", arg.name); 1232 } else if (arg_match(&arg, &kf_min_dist, argi)) { 1233 config->cfg.kf_min_dist = arg_parse_uint(&arg); 1234 } else if (arg_match(&arg, &kf_max_dist, argi)) { 1235 config->cfg.kf_max_dist = arg_parse_uint(&arg); 1236 } else if (arg_match(&arg, &kf_disabled, argi)) { 1237 config->cfg.kf_mode = VPX_KF_DISABLED; 1238 #if CONFIG_VP9_HIGHBITDEPTH 1239 } else if (arg_match(&arg, &test16bitinternalarg, argi)) { 1240 if (strcmp(global->codec->name, "vp9") == 0) { 1241 test_16bit_internal = 1; 1242 } 1243 #endif 1244 } else { 1245 int i, match = 0; 1246 for (i = 0; ctrl_args[i]; i++) { 1247 if (arg_match(&arg, ctrl_args[i], argi)) { 1248 int j; 1249 match = 1; 1250 1251 /* Point either to the next free element or the first 1252 * instance of this control. 1253 */ 1254 for (j = 0; j < config->arg_ctrl_cnt; j++) 1255 if (ctrl_args_map != NULL && 1256 config->arg_ctrls[j][0] == ctrl_args_map[i]) 1257 break; 1258 1259 /* Update/insert */ 1260 assert(j < (int)ARG_CTRL_CNT_MAX); 1261 if (ctrl_args_map != NULL && j < (int)ARG_CTRL_CNT_MAX) { 1262 config->arg_ctrls[j][0] = ctrl_args_map[i]; 1263 config->arg_ctrls[j][1] = arg_parse_enum_or_int(&arg); 1264 if (j == config->arg_ctrl_cnt) config->arg_ctrl_cnt++; 1265 } 1266 } 1267 } 1268 if (!match) argj++; 1269 } 1270 } 1271 #if CONFIG_VP9_HIGHBITDEPTH 1272 if (strcmp(global->codec->name, "vp9") == 0) { 1273 config->use_16bit_internal = 1274 test_16bit_internal | (config->cfg.g_profile > 1); 1275 } 1276 #endif 1277 return eos_mark_found; 1278 } 1279 1280 #define FOREACH_STREAM(func) \ 1281 do { \ 1282 struct stream_state *stream; \ 1283 for (stream = streams; stream; stream = stream->next) { \ 1284 func; \ 1285 } \ 1286 } while (0) 1287 1288 static void validate_stream_config(const struct stream_state *stream, 1289 const struct VpxEncoderConfig *global) { 1290 const struct stream_state *streami; 1291 (void)global; 1292 1293 if (!stream->config.cfg.g_w || !stream->config.cfg.g_h) 1294 fatal( 1295 "Stream %d: Specify stream dimensions with --width (-w) " 1296 " and --height (-h)", 1297 stream->index); 1298 1299 // Check that the codec bit depth is greater than the input bit depth. 1300 if (stream->config.cfg.g_input_bit_depth > 1301 (unsigned int)stream->config.cfg.g_bit_depth) { 1302 fatal("Stream %d: codec bit depth (%d) less than input bit depth (%d)", 1303 stream->index, (int)stream->config.cfg.g_bit_depth, 1304 stream->config.cfg.g_input_bit_depth); 1305 } 1306 1307 for (streami = stream; streami; streami = streami->next) { 1308 /* All streams require output files */ 1309 if (!streami->config.out_fn) 1310 fatal("Stream %d: Output file is required (specify with -o)", 1311 streami->index); 1312 1313 /* Check for two streams outputting to the same file */ 1314 if (streami != stream) { 1315 const char *a = stream->config.out_fn; 1316 const char *b = streami->config.out_fn; 1317 if (!strcmp(a, b) && strcmp(a, "/dev/null") && strcmp(a, ":nul")) 1318 fatal("Stream %d: duplicate output file (from stream %d)", 1319 streami->index, stream->index); 1320 } 1321 1322 /* Check for two streams sharing a stats file. */ 1323 if (streami != stream) { 1324 const char *a = stream->config.stats_fn; 1325 const char *b = streami->config.stats_fn; 1326 if (a && b && !strcmp(a, b)) 1327 fatal("Stream %d: duplicate stats file (from stream %d)", 1328 streami->index, stream->index); 1329 } 1330 1331 #if CONFIG_FP_MB_STATS 1332 /* Check for two streams sharing a mb stats file. */ 1333 if (streami != stream) { 1334 const char *a = stream->config.fpmb_stats_fn; 1335 const char *b = streami->config.fpmb_stats_fn; 1336 if (a && b && !strcmp(a, b)) 1337 fatal("Stream %d: duplicate mb stats file (from stream %d)", 1338 streami->index, stream->index); 1339 } 1340 #endif 1341 } 1342 } 1343 1344 static void set_stream_dimensions(struct stream_state *stream, unsigned int w, 1345 unsigned int h) { 1346 if (!stream->config.cfg.g_w) { 1347 if (!stream->config.cfg.g_h) 1348 stream->config.cfg.g_w = w; 1349 else 1350 stream->config.cfg.g_w = w * stream->config.cfg.g_h / h; 1351 } 1352 if (!stream->config.cfg.g_h) { 1353 stream->config.cfg.g_h = h * stream->config.cfg.g_w / w; 1354 } 1355 } 1356 1357 static const char *file_type_to_string(enum VideoFileType t) { 1358 switch (t) { 1359 case FILE_TYPE_RAW: return "RAW"; 1360 case FILE_TYPE_Y4M: return "Y4M"; 1361 default: return "Other"; 1362 } 1363 } 1364 1365 static const char *image_format_to_string(vpx_img_fmt_t f) { 1366 switch (f) { 1367 case VPX_IMG_FMT_I420: return "I420"; 1368 case VPX_IMG_FMT_I422: return "I422"; 1369 case VPX_IMG_FMT_I444: return "I444"; 1370 case VPX_IMG_FMT_I440: return "I440"; 1371 case VPX_IMG_FMT_YV12: return "YV12"; 1372 case VPX_IMG_FMT_I42016: return "I42016"; 1373 case VPX_IMG_FMT_I42216: return "I42216"; 1374 case VPX_IMG_FMT_I44416: return "I44416"; 1375 case VPX_IMG_FMT_I44016: return "I44016"; 1376 default: return "Other"; 1377 } 1378 } 1379 1380 static void show_stream_config(struct stream_state *stream, 1381 struct VpxEncoderConfig *global, 1382 struct VpxInputContext *input) { 1383 #define SHOW(field) \ 1384 fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field) 1385 1386 if (stream->index == 0) { 1387 fprintf(stderr, "Codec: %s\n", 1388 vpx_codec_iface_name(global->codec->codec_interface())); 1389 fprintf(stderr, "Source file: %s File Type: %s Format: %s\n", 1390 input->filename, file_type_to_string(input->file_type), 1391 image_format_to_string(input->fmt)); 1392 } 1393 if (stream->next || stream->index) 1394 fprintf(stderr, "\nStream Index: %d\n", stream->index); 1395 fprintf(stderr, "Destination file: %s\n", stream->config.out_fn); 1396 fprintf(stderr, "Encoder parameters:\n"); 1397 1398 SHOW(g_usage); 1399 SHOW(g_threads); 1400 SHOW(g_profile); 1401 SHOW(g_w); 1402 SHOW(g_h); 1403 SHOW(g_bit_depth); 1404 SHOW(g_input_bit_depth); 1405 SHOW(g_timebase.num); 1406 SHOW(g_timebase.den); 1407 SHOW(g_error_resilient); 1408 SHOW(g_pass); 1409 SHOW(g_lag_in_frames); 1410 SHOW(rc_dropframe_thresh); 1411 SHOW(rc_resize_allowed); 1412 SHOW(rc_scaled_width); 1413 SHOW(rc_scaled_height); 1414 SHOW(rc_resize_up_thresh); 1415 SHOW(rc_resize_down_thresh); 1416 SHOW(rc_end_usage); 1417 SHOW(rc_target_bitrate); 1418 SHOW(rc_min_quantizer); 1419 SHOW(rc_max_quantizer); 1420 SHOW(rc_undershoot_pct); 1421 SHOW(rc_overshoot_pct); 1422 SHOW(rc_buf_sz); 1423 SHOW(rc_buf_initial_sz); 1424 SHOW(rc_buf_optimal_sz); 1425 SHOW(rc_2pass_vbr_bias_pct); 1426 SHOW(rc_2pass_vbr_minsection_pct); 1427 SHOW(rc_2pass_vbr_maxsection_pct); 1428 SHOW(kf_mode); 1429 SHOW(kf_min_dist); 1430 SHOW(kf_max_dist); 1431 } 1432 1433 static void open_output_file(struct stream_state *stream, 1434 struct VpxEncoderConfig *global, 1435 const struct VpxRational *pixel_aspect_ratio) { 1436 const char *fn = stream->config.out_fn; 1437 const struct vpx_codec_enc_cfg *const cfg = &stream->config.cfg; 1438 1439 if (cfg->g_pass == VPX_RC_FIRST_PASS) return; 1440 1441 stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout); 1442 1443 if (!stream->file) fatal("Failed to open output file"); 1444 1445 if (stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR)) 1446 fatal("WebM output to pipes not supported."); 1447 1448 #if CONFIG_WEBM_IO 1449 if (stream->config.write_webm) { 1450 stream->webm_ctx.stream = stream->file; 1451 write_webm_file_header(&stream->webm_ctx, cfg, stream->config.stereo_fmt, 1452 global->codec->fourcc, pixel_aspect_ratio); 1453 } 1454 #else 1455 (void)pixel_aspect_ratio; 1456 #endif 1457 1458 if (!stream->config.write_webm) { 1459 ivf_write_file_header(stream->file, cfg, global->codec->fourcc, 0); 1460 } 1461 } 1462 1463 static void close_output_file(struct stream_state *stream, 1464 unsigned int fourcc) { 1465 const struct vpx_codec_enc_cfg *const cfg = &stream->config.cfg; 1466 1467 if (cfg->g_pass == VPX_RC_FIRST_PASS) return; 1468 1469 #if CONFIG_WEBM_IO 1470 if (stream->config.write_webm) { 1471 write_webm_file_footer(&stream->webm_ctx); 1472 } 1473 #endif 1474 1475 if (!stream->config.write_webm) { 1476 if (!fseek(stream->file, 0, SEEK_SET)) 1477 ivf_write_file_header(stream->file, &stream->config.cfg, fourcc, 1478 stream->frames_out); 1479 } 1480 1481 fclose(stream->file); 1482 } 1483 1484 static void setup_pass(struct stream_state *stream, 1485 struct VpxEncoderConfig *global, int pass) { 1486 if (stream->config.stats_fn) { 1487 if (!stats_open_file(&stream->stats, stream->config.stats_fn, pass)) 1488 fatal("Failed to open statistics store"); 1489 } else { 1490 if (!stats_open_mem(&stream->stats, pass)) 1491 fatal("Failed to open statistics store"); 1492 } 1493 1494 #if CONFIG_FP_MB_STATS 1495 if (stream->config.fpmb_stats_fn) { 1496 if (!stats_open_file(&stream->fpmb_stats, stream->config.fpmb_stats_fn, 1497 pass)) 1498 fatal("Failed to open mb statistics store"); 1499 } else { 1500 if (!stats_open_mem(&stream->fpmb_stats, pass)) 1501 fatal("Failed to open mb statistics store"); 1502 } 1503 #endif 1504 1505 stream->config.cfg.g_pass = global->passes == 2 1506 ? pass ? VPX_RC_LAST_PASS : VPX_RC_FIRST_PASS 1507 : VPX_RC_ONE_PASS; 1508 if (pass) { 1509 stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats); 1510 #if CONFIG_FP_MB_STATS 1511 stream->config.cfg.rc_firstpass_mb_stats_in = 1512 stats_get(&stream->fpmb_stats); 1513 #endif 1514 } 1515 1516 stream->cx_time = 0; 1517 stream->nbytes = 0; 1518 stream->frames_out = 0; 1519 } 1520 1521 static void initialize_encoder(struct stream_state *stream, 1522 struct VpxEncoderConfig *global) { 1523 int i; 1524 int flags = 0; 1525 1526 flags |= global->show_psnr ? VPX_CODEC_USE_PSNR : 0; 1527 flags |= global->out_part ? VPX_CODEC_USE_OUTPUT_PARTITION : 0; 1528 #if CONFIG_VP9_HIGHBITDEPTH 1529 flags |= stream->config.use_16bit_internal ? VPX_CODEC_USE_HIGHBITDEPTH : 0; 1530 #endif 1531 1532 /* Construct Encoder Context */ 1533 vpx_codec_enc_init(&stream->encoder, global->codec->codec_interface(), 1534 &stream->config.cfg, flags); 1535 ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder"); 1536 1537 /* Note that we bypass the vpx_codec_control wrapper macro because 1538 * we're being clever to store the control IDs in an array. Real 1539 * applications will want to make use of the enumerations directly 1540 */ 1541 for (i = 0; i < stream->config.arg_ctrl_cnt; i++) { 1542 int ctrl = stream->config.arg_ctrls[i][0]; 1543 int value = stream->config.arg_ctrls[i][1]; 1544 if (vpx_codec_control_(&stream->encoder, ctrl, value)) 1545 fprintf(stderr, "Error: Tried to set control %d = %d\n", ctrl, value); 1546 1547 ctx_exit_on_error(&stream->encoder, "Failed to control codec"); 1548 } 1549 1550 #if CONFIG_DECODERS 1551 if (global->test_decode != TEST_DECODE_OFF) { 1552 const VpxInterface *decoder = get_vpx_decoder_by_name(global->codec->name); 1553 vpx_codec_dec_init(&stream->decoder, decoder->codec_interface(), NULL, 0); 1554 } 1555 #endif 1556 } 1557 1558 static void encode_frame(struct stream_state *stream, 1559 struct VpxEncoderConfig *global, struct vpx_image *img, 1560 unsigned int frames_in) { 1561 vpx_codec_pts_t frame_start, next_frame_start; 1562 struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; 1563 struct vpx_usec_timer timer; 1564 1565 frame_start = 1566 (cfg->g_timebase.den * (int64_t)(frames_in - 1) * global->framerate.den) / 1567 cfg->g_timebase.num / global->framerate.num; 1568 next_frame_start = 1569 (cfg->g_timebase.den * (int64_t)(frames_in)*global->framerate.den) / 1570 cfg->g_timebase.num / global->framerate.num; 1571 1572 /* Scale if necessary */ 1573 #if CONFIG_VP9_HIGHBITDEPTH 1574 if (img) { 1575 if ((img->fmt & VPX_IMG_FMT_HIGHBITDEPTH) && 1576 (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) { 1577 if (img->fmt != VPX_IMG_FMT_I42016) { 1578 fprintf(stderr, "%s can only scale 4:2:0 inputs\n", exec_name); 1579 exit(EXIT_FAILURE); 1580 } 1581 #if CONFIG_LIBYUV 1582 if (!stream->img) { 1583 stream->img = 1584 vpx_img_alloc(NULL, VPX_IMG_FMT_I42016, cfg->g_w, cfg->g_h, 16); 1585 } 1586 I420Scale_16( 1587 (uint16 *)img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y] / 2, 1588 (uint16 *)img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U] / 2, 1589 (uint16 *)img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V] / 2, 1590 img->d_w, img->d_h, (uint16 *)stream->img->planes[VPX_PLANE_Y], 1591 stream->img->stride[VPX_PLANE_Y] / 2, 1592 (uint16 *)stream->img->planes[VPX_PLANE_U], 1593 stream->img->stride[VPX_PLANE_U] / 2, 1594 (uint16 *)stream->img->planes[VPX_PLANE_V], 1595 stream->img->stride[VPX_PLANE_V] / 2, stream->img->d_w, 1596 stream->img->d_h, kFilterBox); 1597 img = stream->img; 1598 #else 1599 stream->encoder.err = 1; 1600 ctx_exit_on_error(&stream->encoder, 1601 "Stream %d: Failed to encode frame.\n" 1602 "Scaling disabled in this configuration. \n" 1603 "To enable, configure with --enable-libyuv\n", 1604 stream->index); 1605 #endif 1606 } 1607 } 1608 #endif 1609 if (img && (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) { 1610 if (img->fmt != VPX_IMG_FMT_I420 && img->fmt != VPX_IMG_FMT_YV12) { 1611 fprintf(stderr, "%s can only scale 4:2:0 8bpp inputs\n", exec_name); 1612 exit(EXIT_FAILURE); 1613 } 1614 #if CONFIG_LIBYUV 1615 if (!stream->img) 1616 stream->img = 1617 vpx_img_alloc(NULL, VPX_IMG_FMT_I420, cfg->g_w, cfg->g_h, 16); 1618 I420Scale( 1619 img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y], 1620 img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U], 1621 img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], img->d_w, img->d_h, 1622 stream->img->planes[VPX_PLANE_Y], stream->img->stride[VPX_PLANE_Y], 1623 stream->img->planes[VPX_PLANE_U], stream->img->stride[VPX_PLANE_U], 1624 stream->img->planes[VPX_PLANE_V], stream->img->stride[VPX_PLANE_V], 1625 stream->img->d_w, stream->img->d_h, kFilterBox); 1626 img = stream->img; 1627 #else 1628 stream->encoder.err = 1; 1629 ctx_exit_on_error(&stream->encoder, 1630 "Stream %d: Failed to encode frame.\n" 1631 "Scaling disabled in this configuration. \n" 1632 "To enable, configure with --enable-libyuv\n", 1633 stream->index); 1634 #endif 1635 } 1636 1637 vpx_usec_timer_start(&timer); 1638 vpx_codec_encode(&stream->encoder, img, frame_start, 1639 (unsigned long)(next_frame_start - frame_start), 0, 1640 global->deadline); 1641 vpx_usec_timer_mark(&timer); 1642 stream->cx_time += vpx_usec_timer_elapsed(&timer); 1643 ctx_exit_on_error(&stream->encoder, "Stream %d: Failed to encode frame", 1644 stream->index); 1645 } 1646 1647 static void update_quantizer_histogram(struct stream_state *stream) { 1648 if (stream->config.cfg.g_pass != VPX_RC_FIRST_PASS) { 1649 int q; 1650 1651 vpx_codec_control(&stream->encoder, VP8E_GET_LAST_QUANTIZER_64, &q); 1652 ctx_exit_on_error(&stream->encoder, "Failed to read quantizer"); 1653 stream->counts[q]++; 1654 } 1655 } 1656 1657 static void get_cx_data(struct stream_state *stream, 1658 struct VpxEncoderConfig *global, int *got_data) { 1659 const vpx_codec_cx_pkt_t *pkt; 1660 const struct vpx_codec_enc_cfg *cfg = &stream->config.cfg; 1661 vpx_codec_iter_t iter = NULL; 1662 1663 *got_data = 0; 1664 while ((pkt = vpx_codec_get_cx_data(&stream->encoder, &iter))) { 1665 static size_t fsize = 0; 1666 static FileOffset ivf_header_pos = 0; 1667 1668 switch (pkt->kind) { 1669 case VPX_CODEC_CX_FRAME_PKT: 1670 if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) { 1671 stream->frames_out++; 1672 } 1673 if (!global->quiet) 1674 fprintf(stderr, " %6luF", (unsigned long)pkt->data.frame.sz); 1675 1676 update_rate_histogram(stream->rate_hist, cfg, pkt); 1677 #if CONFIG_WEBM_IO 1678 if (stream->config.write_webm) { 1679 write_webm_block(&stream->webm_ctx, cfg, pkt); 1680 } 1681 #endif 1682 if (!stream->config.write_webm) { 1683 if (pkt->data.frame.partition_id <= 0) { 1684 ivf_header_pos = ftello(stream->file); 1685 fsize = pkt->data.frame.sz; 1686 1687 ivf_write_frame_header(stream->file, pkt->data.frame.pts, fsize); 1688 } else { 1689 fsize += pkt->data.frame.sz; 1690 1691 if (!(pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT)) { 1692 const FileOffset currpos = ftello(stream->file); 1693 fseeko(stream->file, ivf_header_pos, SEEK_SET); 1694 ivf_write_frame_size(stream->file, fsize); 1695 fseeko(stream->file, currpos, SEEK_SET); 1696 } 1697 } 1698 1699 (void)fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, 1700 stream->file); 1701 } 1702 stream->nbytes += pkt->data.raw.sz; 1703 1704 *got_data = 1; 1705 #if CONFIG_DECODERS 1706 if (global->test_decode != TEST_DECODE_OFF && !stream->mismatch_seen) { 1707 vpx_codec_decode(&stream->decoder, pkt->data.frame.buf, 1708 (unsigned int)pkt->data.frame.sz, NULL, 0); 1709 if (stream->decoder.err) { 1710 warn_or_exit_on_error(&stream->decoder, 1711 global->test_decode == TEST_DECODE_FATAL, 1712 "Failed to decode frame %d in stream %d", 1713 stream->frames_out + 1, stream->index); 1714 stream->mismatch_seen = stream->frames_out + 1; 1715 } 1716 } 1717 #endif 1718 break; 1719 case VPX_CODEC_STATS_PKT: 1720 stream->frames_out++; 1721 stats_write(&stream->stats, pkt->data.twopass_stats.buf, 1722 pkt->data.twopass_stats.sz); 1723 stream->nbytes += pkt->data.raw.sz; 1724 break; 1725 #if CONFIG_FP_MB_STATS 1726 case VPX_CODEC_FPMB_STATS_PKT: 1727 stats_write(&stream->fpmb_stats, pkt->data.firstpass_mb_stats.buf, 1728 pkt->data.firstpass_mb_stats.sz); 1729 stream->nbytes += pkt->data.raw.sz; 1730 break; 1731 #endif 1732 case VPX_CODEC_PSNR_PKT: 1733 1734 if (global->show_psnr) { 1735 int i; 1736 1737 stream->psnr_sse_total += pkt->data.psnr.sse[0]; 1738 stream->psnr_samples_total += pkt->data.psnr.samples[0]; 1739 for (i = 0; i < 4; i++) { 1740 if (!global->quiet) 1741 fprintf(stderr, "%.3f ", pkt->data.psnr.psnr[i]); 1742 stream->psnr_totals[i] += pkt->data.psnr.psnr[i]; 1743 } 1744 stream->psnr_count++; 1745 } 1746 1747 break; 1748 default: break; 1749 } 1750 } 1751 } 1752 1753 static void show_psnr(struct stream_state *stream, double peak) { 1754 int i; 1755 double ovpsnr; 1756 1757 if (!stream->psnr_count) return; 1758 1759 fprintf(stderr, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream->index); 1760 ovpsnr = sse_to_psnr((double)stream->psnr_samples_total, peak, 1761 (double)stream->psnr_sse_total); 1762 fprintf(stderr, " %.3f", ovpsnr); 1763 1764 for (i = 0; i < 4; i++) { 1765 fprintf(stderr, " %.3f", stream->psnr_totals[i] / stream->psnr_count); 1766 } 1767 fprintf(stderr, "\n"); 1768 } 1769 1770 static float usec_to_fps(uint64_t usec, unsigned int frames) { 1771 return (float)(usec > 0 ? frames * 1000000.0 / (float)usec : 0); 1772 } 1773 1774 static void test_decode(struct stream_state *stream, 1775 enum TestDecodeFatality fatal, 1776 const VpxInterface *codec) { 1777 vpx_image_t enc_img, dec_img; 1778 1779 if (stream->mismatch_seen) return; 1780 1781 /* Get the internal reference frame */ 1782 if (strcmp(codec->name, "vp8") == 0) { 1783 struct vpx_ref_frame ref_enc, ref_dec; 1784 int width, height; 1785 1786 width = (stream->config.cfg.g_w + 15) & ~15; 1787 height = (stream->config.cfg.g_h + 15) & ~15; 1788 vpx_img_alloc(&ref_enc.img, VPX_IMG_FMT_I420, width, height, 1); 1789 enc_img = ref_enc.img; 1790 vpx_img_alloc(&ref_dec.img, VPX_IMG_FMT_I420, width, height, 1); 1791 dec_img = ref_dec.img; 1792 1793 ref_enc.frame_type = VP8_LAST_FRAME; 1794 ref_dec.frame_type = VP8_LAST_FRAME; 1795 vpx_codec_control(&stream->encoder, VP8_COPY_REFERENCE, &ref_enc); 1796 vpx_codec_control(&stream->decoder, VP8_COPY_REFERENCE, &ref_dec); 1797 } else { 1798 struct vp9_ref_frame ref_enc, ref_dec; 1799 1800 ref_enc.idx = 0; 1801 ref_dec.idx = 0; 1802 vpx_codec_control(&stream->encoder, VP9_GET_REFERENCE, &ref_enc); 1803 enc_img = ref_enc.img; 1804 vpx_codec_control(&stream->decoder, VP9_GET_REFERENCE, &ref_dec); 1805 dec_img = ref_dec.img; 1806 #if CONFIG_VP9_HIGHBITDEPTH 1807 if ((enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) != 1808 (dec_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH)) { 1809 if (enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) { 1810 vpx_img_alloc(&enc_img, enc_img.fmt - VPX_IMG_FMT_HIGHBITDEPTH, 1811 enc_img.d_w, enc_img.d_h, 16); 1812 vpx_img_truncate_16_to_8(&enc_img, &ref_enc.img); 1813 } 1814 if (dec_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) { 1815 vpx_img_alloc(&dec_img, dec_img.fmt - VPX_IMG_FMT_HIGHBITDEPTH, 1816 dec_img.d_w, dec_img.d_h, 16); 1817 vpx_img_truncate_16_to_8(&dec_img, &ref_dec.img); 1818 } 1819 } 1820 #endif 1821 } 1822 ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame"); 1823 ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame"); 1824 1825 if (!compare_img(&enc_img, &dec_img)) { 1826 int y[4], u[4], v[4]; 1827 #if CONFIG_VP9_HIGHBITDEPTH 1828 if (enc_img.fmt & VPX_IMG_FMT_HIGHBITDEPTH) { 1829 find_mismatch_high(&enc_img, &dec_img, y, u, v); 1830 } else { 1831 find_mismatch(&enc_img, &dec_img, y, u, v); 1832 } 1833 #else 1834 find_mismatch(&enc_img, &dec_img, y, u, v); 1835 #endif 1836 stream->decoder.err = 1; 1837 warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL, 1838 "Stream %d: Encode/decode mismatch on frame %d at" 1839 " Y[%d, %d] {%d/%d}," 1840 " U[%d, %d] {%d/%d}," 1841 " V[%d, %d] {%d/%d}", 1842 stream->index, stream->frames_out, y[0], y[1], y[2], 1843 y[3], u[0], u[1], u[2], u[3], v[0], v[1], v[2], v[3]); 1844 stream->mismatch_seen = stream->frames_out; 1845 } 1846 1847 vpx_img_free(&enc_img); 1848 vpx_img_free(&dec_img); 1849 } 1850 1851 static void print_time(const char *label, int64_t etl) { 1852 int64_t hours; 1853 int64_t mins; 1854 int64_t secs; 1855 1856 if (etl >= 0) { 1857 hours = etl / 3600; 1858 etl -= hours * 3600; 1859 mins = etl / 60; 1860 etl -= mins * 60; 1861 secs = etl; 1862 1863 fprintf(stderr, "[%3s %2" PRId64 ":%02" PRId64 ":%02" PRId64 "] ", label, 1864 hours, mins, secs); 1865 } else { 1866 fprintf(stderr, "[%3s unknown] ", label); 1867 } 1868 } 1869 1870 int main(int argc, const char **argv_) { 1871 int pass; 1872 vpx_image_t raw; 1873 #if CONFIG_VP9_HIGHBITDEPTH 1874 vpx_image_t raw_shift; 1875 int allocated_raw_shift = 0; 1876 int use_16bit_internal = 0; 1877 int input_shift = 0; 1878 #endif 1879 int frame_avail, got_data; 1880 1881 struct VpxInputContext input; 1882 struct VpxEncoderConfig global; 1883 struct stream_state *streams = NULL; 1884 char **argv, **argi; 1885 uint64_t cx_time = 0; 1886 int stream_cnt = 0; 1887 int res = 0; 1888 1889 memset(&input, 0, sizeof(input)); 1890 exec_name = argv_[0]; 1891 1892 if (argc < 3) usage_exit(); 1893 1894 /* Setup default input stream settings */ 1895 input.framerate.numerator = 30; 1896 input.framerate.denominator = 1; 1897 input.only_i420 = 1; 1898 input.bit_depth = 0; 1899 1900 /* First parse the global configuration values, because we want to apply 1901 * other parameters on top of the default configuration provided by the 1902 * codec. 1903 */ 1904 argv = argv_dup(argc - 1, argv_ + 1); 1905 parse_global_config(&global, argv); 1906 1907 switch (global.color_type) { 1908 case I420: input.fmt = VPX_IMG_FMT_I420; break; 1909 case I422: input.fmt = VPX_IMG_FMT_I422; break; 1910 case I444: input.fmt = VPX_IMG_FMT_I444; break; 1911 case I440: input.fmt = VPX_IMG_FMT_I440; break; 1912 case YV12: input.fmt = VPX_IMG_FMT_YV12; break; 1913 } 1914 1915 { 1916 /* Now parse each stream's parameters. Using a local scope here 1917 * due to the use of 'stream' as loop variable in FOREACH_STREAM 1918 * loops 1919 */ 1920 struct stream_state *stream = NULL; 1921 1922 do { 1923 stream = new_stream(&global, stream); 1924 stream_cnt++; 1925 if (!streams) streams = stream; 1926 } while (parse_stream_params(&global, stream, argv)); 1927 } 1928 1929 /* Check for unrecognized options */ 1930 for (argi = argv; *argi; argi++) 1931 if (argi[0][0] == '-' && argi[0][1]) 1932 die("Error: Unrecognized option %s\n", *argi); 1933 1934 FOREACH_STREAM(check_encoder_config(global.disable_warning_prompt, &global, 1935 &stream->config.cfg);); 1936 1937 /* Handle non-option arguments */ 1938 input.filename = argv[0]; 1939 1940 if (!input.filename) usage_exit(); 1941 1942 /* Decide if other chroma subsamplings than 4:2:0 are supported */ 1943 if (global.codec->fourcc == VP9_FOURCC) input.only_i420 = 0; 1944 1945 for (pass = global.pass ? global.pass - 1 : 0; pass < global.passes; pass++) { 1946 int frames_in = 0, seen_frames = 0; 1947 int64_t estimated_time_left = -1; 1948 int64_t average_rate = -1; 1949 int64_t lagged_count = 0; 1950 1951 open_input_file(&input); 1952 1953 /* If the input file doesn't specify its w/h (raw files), try to get 1954 * the data from the first stream's configuration. 1955 */ 1956 if (!input.width || !input.height) { 1957 FOREACH_STREAM({ 1958 if (stream->config.cfg.g_w && stream->config.cfg.g_h) { 1959 input.width = stream->config.cfg.g_w; 1960 input.height = stream->config.cfg.g_h; 1961 break; 1962 } 1963 }); 1964 } 1965 1966 /* Update stream configurations from the input file's parameters */ 1967 if (!input.width || !input.height) 1968 fatal( 1969 "Specify stream dimensions with --width (-w) " 1970 " and --height (-h)"); 1971 1972 /* If input file does not specify bit-depth but input-bit-depth parameter 1973 * exists, assume that to be the input bit-depth. However, if the 1974 * input-bit-depth paramter does not exist, assume the input bit-depth 1975 * to be the same as the codec bit-depth. 1976 */ 1977 if (!input.bit_depth) { 1978 FOREACH_STREAM({ 1979 if (stream->config.cfg.g_input_bit_depth) 1980 input.bit_depth = stream->config.cfg.g_input_bit_depth; 1981 else 1982 input.bit_depth = stream->config.cfg.g_input_bit_depth = 1983 (int)stream->config.cfg.g_bit_depth; 1984 }); 1985 if (input.bit_depth > 8) input.fmt |= VPX_IMG_FMT_HIGHBITDEPTH; 1986 } else { 1987 FOREACH_STREAM( 1988 { stream->config.cfg.g_input_bit_depth = input.bit_depth; }); 1989 } 1990 1991 FOREACH_STREAM(set_stream_dimensions(stream, input.width, input.height)); 1992 FOREACH_STREAM(validate_stream_config(stream, &global)); 1993 1994 /* Ensure that --passes and --pass are consistent. If --pass is set and 1995 * --passes=2, ensure --fpf was set. 1996 */ 1997 if (global.pass && global.passes == 2) 1998 FOREACH_STREAM({ 1999 if (!stream->config.stats_fn) 2000 die("Stream %d: Must specify --fpf when --pass=%d" 2001 " and --passes=2\n", 2002 stream->index, global.pass); 2003 }); 2004 2005 #if !CONFIG_WEBM_IO 2006 FOREACH_STREAM({ 2007 if (stream->config.write_webm) { 2008 stream->config.write_webm = 0; 2009 warn( 2010 "vpxenc was compiled without WebM container support." 2011 "Producing IVF output"); 2012 } 2013 }); 2014 #endif 2015 2016 /* Use the frame rate from the file only if none was specified 2017 * on the command-line. 2018 */ 2019 if (!global.have_framerate) { 2020 global.framerate.num = input.framerate.numerator; 2021 global.framerate.den = input.framerate.denominator; 2022 FOREACH_STREAM(stream->config.cfg.g_timebase.den = global.framerate.num; 2023 stream->config.cfg.g_timebase.num = global.framerate.den); 2024 } 2025 2026 /* Show configuration */ 2027 if (global.verbose && pass == 0) 2028 FOREACH_STREAM(show_stream_config(stream, &global, &input)); 2029 2030 if (pass == (global.pass ? global.pass - 1 : 0)) { 2031 if (input.file_type == FILE_TYPE_Y4M) 2032 /*The Y4M reader does its own allocation. 2033 Just initialize this here to avoid problems if we never read any 2034 frames.*/ 2035 memset(&raw, 0, sizeof(raw)); 2036 else 2037 vpx_img_alloc(&raw, input.fmt, input.width, input.height, 32); 2038 2039 FOREACH_STREAM(stream->rate_hist = init_rate_histogram( 2040 &stream->config.cfg, &global.framerate)); 2041 } 2042 2043 FOREACH_STREAM(setup_pass(stream, &global, pass)); 2044 FOREACH_STREAM( 2045 open_output_file(stream, &global, &input.pixel_aspect_ratio)); 2046 FOREACH_STREAM(initialize_encoder(stream, &global)); 2047 2048 #if CONFIG_VP9_HIGHBITDEPTH 2049 if (strcmp(global.codec->name, "vp9") == 0) { 2050 // Check to see if at least one stream uses 16 bit internal. 2051 // Currently assume that the bit_depths for all streams using 2052 // highbitdepth are the same. 2053 FOREACH_STREAM({ 2054 if (stream->config.use_16bit_internal) { 2055 use_16bit_internal = 1; 2056 } 2057 if (stream->config.cfg.g_profile == 0) { 2058 input_shift = 0; 2059 } else { 2060 input_shift = (int)stream->config.cfg.g_bit_depth - 2061 stream->config.cfg.g_input_bit_depth; 2062 } 2063 }); 2064 } 2065 #endif 2066 2067 frame_avail = 1; 2068 got_data = 0; 2069 2070 while (frame_avail || got_data) { 2071 struct vpx_usec_timer timer; 2072 2073 if (!global.limit || frames_in < global.limit) { 2074 frame_avail = read_frame(&input, &raw); 2075 2076 if (frame_avail) frames_in++; 2077 seen_frames = 2078 frames_in > global.skip_frames ? frames_in - global.skip_frames : 0; 2079 2080 if (!global.quiet) { 2081 float fps = usec_to_fps(cx_time, seen_frames); 2082 fprintf(stderr, "\rPass %d/%d ", pass + 1, global.passes); 2083 2084 if (stream_cnt == 1) 2085 fprintf(stderr, "frame %4d/%-4d %7" PRId64 "B ", frames_in, 2086 streams->frames_out, (int64_t)streams->nbytes); 2087 else 2088 fprintf(stderr, "frame %4d ", frames_in); 2089 2090 fprintf(stderr, "%7" PRId64 " %s %.2f %s ", 2091 cx_time > 9999999 ? cx_time / 1000 : cx_time, 2092 cx_time > 9999999 ? "ms" : "us", fps >= 1.0 ? fps : fps * 60, 2093 fps >= 1.0 ? "fps" : "fpm"); 2094 print_time("ETA", estimated_time_left); 2095 } 2096 2097 } else 2098 frame_avail = 0; 2099 2100 if (frames_in > global.skip_frames) { 2101 #if CONFIG_VP9_HIGHBITDEPTH 2102 vpx_image_t *frame_to_encode; 2103 if (input_shift || (use_16bit_internal && input.bit_depth == 8)) { 2104 assert(use_16bit_internal); 2105 // Input bit depth and stream bit depth do not match, so up 2106 // shift frame to stream bit depth 2107 if (!allocated_raw_shift) { 2108 vpx_img_alloc(&raw_shift, raw.fmt | VPX_IMG_FMT_HIGHBITDEPTH, 2109 input.width, input.height, 32); 2110 allocated_raw_shift = 1; 2111 } 2112 vpx_img_upshift(&raw_shift, &raw, input_shift); 2113 frame_to_encode = &raw_shift; 2114 } else { 2115 frame_to_encode = &raw; 2116 } 2117 vpx_usec_timer_start(&timer); 2118 if (use_16bit_internal) { 2119 assert(frame_to_encode->fmt & VPX_IMG_FMT_HIGHBITDEPTH); 2120 FOREACH_STREAM({ 2121 if (stream->config.use_16bit_internal) 2122 encode_frame(stream, &global, 2123 frame_avail ? frame_to_encode : NULL, frames_in); 2124 else 2125 assert(0); 2126 }); 2127 } else { 2128 assert((frame_to_encode->fmt & VPX_IMG_FMT_HIGHBITDEPTH) == 0); 2129 FOREACH_STREAM(encode_frame(stream, &global, 2130 frame_avail ? frame_to_encode : NULL, 2131 frames_in)); 2132 } 2133 #else 2134 vpx_usec_timer_start(&timer); 2135 FOREACH_STREAM(encode_frame(stream, &global, frame_avail ? &raw : NULL, 2136 frames_in)); 2137 #endif 2138 vpx_usec_timer_mark(&timer); 2139 cx_time += vpx_usec_timer_elapsed(&timer); 2140 2141 FOREACH_STREAM(update_quantizer_histogram(stream)); 2142 2143 got_data = 0; 2144 FOREACH_STREAM(get_cx_data(stream, &global, &got_data)); 2145 2146 if (!got_data && input.length && streams != NULL && 2147 !streams->frames_out) { 2148 lagged_count = global.limit ? seen_frames : ftello(input.file); 2149 } else if (input.length) { 2150 int64_t remaining; 2151 int64_t rate; 2152 2153 if (global.limit) { 2154 const int64_t frame_in_lagged = (seen_frames - lagged_count) * 1000; 2155 2156 rate = cx_time ? frame_in_lagged * (int64_t)1000000 / cx_time : 0; 2157 remaining = 1000 * (global.limit - global.skip_frames - 2158 seen_frames + lagged_count); 2159 } else { 2160 const int64_t input_pos = ftello(input.file); 2161 const int64_t input_pos_lagged = input_pos - lagged_count; 2162 const int64_t limit = input.length; 2163 2164 rate = cx_time ? input_pos_lagged * (int64_t)1000000 / cx_time : 0; 2165 remaining = limit - input_pos + lagged_count; 2166 } 2167 2168 average_rate = 2169 (average_rate <= 0) ? rate : (average_rate * 7 + rate) / 8; 2170 estimated_time_left = average_rate ? remaining / average_rate : -1; 2171 } 2172 2173 if (got_data && global.test_decode != TEST_DECODE_OFF) 2174 FOREACH_STREAM(test_decode(stream, global.test_decode, global.codec)); 2175 } 2176 2177 fflush(stdout); 2178 if (!global.quiet) fprintf(stderr, "\033[K"); 2179 } 2180 2181 if (stream_cnt > 1) fprintf(stderr, "\n"); 2182 2183 if (!global.quiet) { 2184 FOREACH_STREAM(fprintf( 2185 stderr, "\rPass %d/%d frame %4d/%-4d %7" PRId64 "B %7" PRId64 2186 "b/f %7" PRId64 "b/s" 2187 " %7" PRId64 " %s (%.2f fps)\033[K\n", 2188 pass + 1, global.passes, frames_in, stream->frames_out, 2189 (int64_t)stream->nbytes, 2190 seen_frames ? (int64_t)(stream->nbytes * 8 / seen_frames) : 0, 2191 seen_frames 2192 ? (int64_t)stream->nbytes * 8 * (int64_t)global.framerate.num / 2193 global.framerate.den / seen_frames 2194 : 0, 2195 stream->cx_time > 9999999 ? stream->cx_time / 1000 : stream->cx_time, 2196 stream->cx_time > 9999999 ? "ms" : "us", 2197 usec_to_fps(stream->cx_time, seen_frames))); 2198 } 2199 2200 if (global.show_psnr) { 2201 if (global.codec->fourcc == VP9_FOURCC) { 2202 FOREACH_STREAM( 2203 show_psnr(stream, (1 << stream->config.cfg.g_input_bit_depth) - 1)); 2204 } else { 2205 FOREACH_STREAM(show_psnr(stream, 255.0)); 2206 } 2207 } 2208 2209 FOREACH_STREAM(vpx_codec_destroy(&stream->encoder)); 2210 2211 if (global.test_decode != TEST_DECODE_OFF) { 2212 FOREACH_STREAM(vpx_codec_destroy(&stream->decoder)); 2213 } 2214 2215 close_input_file(&input); 2216 2217 if (global.test_decode == TEST_DECODE_FATAL) { 2218 FOREACH_STREAM(res |= stream->mismatch_seen); 2219 } 2220 FOREACH_STREAM(close_output_file(stream, global.codec->fourcc)); 2221 2222 FOREACH_STREAM(stats_close(&stream->stats, global.passes - 1)); 2223 2224 #if CONFIG_FP_MB_STATS 2225 FOREACH_STREAM(stats_close(&stream->fpmb_stats, global.passes - 1)); 2226 #endif 2227 2228 if (global.pass) break; 2229 } 2230 2231 if (global.show_q_hist_buckets) 2232 FOREACH_STREAM( 2233 show_q_histogram(stream->counts, global.show_q_hist_buckets)); 2234 2235 if (global.show_rate_hist_buckets) 2236 FOREACH_STREAM(show_rate_histogram(stream->rate_hist, &stream->config.cfg, 2237 global.show_rate_hist_buckets)); 2238 FOREACH_STREAM(destroy_rate_histogram(stream->rate_hist)); 2239 2240 #if CONFIG_INTERNAL_STATS 2241 /* TODO(jkoleszar): This doesn't belong in this executable. Do it for now, 2242 * to match some existing utilities. 2243 */ 2244 if (!(global.pass == 1 && global.passes == 2)) 2245 FOREACH_STREAM({ 2246 FILE *f = fopen("opsnr.stt", "a"); 2247 if (stream->mismatch_seen) { 2248 fprintf(f, "First mismatch occurred in frame %d\n", 2249 stream->mismatch_seen); 2250 } else { 2251 fprintf(f, "No mismatch detected in recon buffers\n"); 2252 } 2253 fclose(f); 2254 }); 2255 #endif 2256 2257 #if CONFIG_VP9_HIGHBITDEPTH 2258 if (allocated_raw_shift) vpx_img_free(&raw_shift); 2259 #endif 2260 vpx_img_free(&raw); 2261 free(argv); 2262 free(streams); 2263 return res ? EXIT_FAILURE : EXIT_SUCCESS; 2264 } 2265