vpxenc.c 79.3 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5 6
 *  that can be found in the LICENSE file in the root of the source
 *  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.
John Koleszar's avatar
John Koleszar committed
9 10
 */

11
#include "./vpxenc.h"
12
#include "./vpx_config.h"
John Koleszar's avatar
John Koleszar committed
13

14 15
#include <assert.h>
#include <limits.h>
16
#include <math.h>
17
#include <stdarg.h>
John Koleszar's avatar
John Koleszar committed
18 19 20
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
21

22 23 24 25
#if CONFIG_LIBYUV
#include "third_party/libyuv/include/libyuv/scale.h"
#endif

26
#include "vpx/vpx_encoder.h"
27
#if CONFIG_DECODERS
28
#include "vpx/vpx_decoder.h"
29
#endif
30

31 32
#include "./args.h"
#include "./ivfenc.h"
33
#include "./tools_common.h"
34

35
#if CONFIG_VP8_ENCODER || CONFIG_VP9_ENCODER || CONFIG_VP10_ENCODER
36
#include "vpx/vp8cx.h"
37
#endif
James Zern's avatar
James Zern committed
38
#if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER || CONFIG_VP10_DECODER
39
#include "vpx/vp8dx.h"
40 41
#endif

42
#include "vpx/vpx_integer.h"
John Koleszar's avatar
John Koleszar committed
43 44
#include "vpx_ports/mem_ops.h"
#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 54
/* Swallow warnings about unused results of fread/fwrite */
static size_t wrap_fread(void *ptr, size_t size, size_t nmemb,
55 56
                         FILE *stream) {
  return fread(ptr, size, nmemb, stream);
57 58 59 60
}
#define fread wrap_fread

static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb,
61 62
                          FILE *stream) {
  return fwrite(ptr, size, nmemb, stream);
63 64 65 66
}
#define fwrite wrap_fwrite


John Koleszar's avatar
John Koleszar committed
67 68
static const char *exec_name;

69 70
static void warn_or_exit_on_errorv(vpx_codec_ctx_t *ctx, int fatal,
                                   const char *s, va_list ap) {
John Koleszar's avatar
John Koleszar committed
71 72
  if (ctx->err) {
    const char *detail = vpx_codec_error_detail(ctx);
John Koleszar's avatar
John Koleszar committed
73

74 75
    vfprintf(stderr, s, ap);
    fprintf(stderr, ": %s\n", vpx_codec_error(ctx));
John Koleszar's avatar
John Koleszar committed
76

John Koleszar's avatar
John Koleszar committed
77 78
    if (detail)
      fprintf(stderr, "    %s\n", detail);
John Koleszar's avatar
John Koleszar committed
79

80 81
    if (fatal)
      exit(EXIT_FAILURE);
John Koleszar's avatar
John Koleszar committed
82
  }
John Koleszar's avatar
John Koleszar committed
83 84
}

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s, ...) {
  va_list ap;

  va_start(ap, s);
  warn_or_exit_on_errorv(ctx, 1, s, ap);
  va_end(ap);
}

static void warn_or_exit_on_error(vpx_codec_ctx_t *ctx, int fatal,
                                  const char *s, ...) {
  va_list ap;

  va_start(ap, s);
  warn_or_exit_on_errorv(ctx, fatal, s, ap);
  va_end(ap);
}

102
static int read_frame(struct VpxInputContext *input_ctx, vpx_image_t *img) {
103 104
  FILE *f = input_ctx->file;
  y4m_input *y4m = &input_ctx->y4m;
John Koleszar's avatar
John Koleszar committed
105 106
  int shortread = 0;

107
  if (input_ctx->file_type == FILE_TYPE_Y4M) {
John Koleszar's avatar
John Koleszar committed
108 109 110
    if (y4m_input_fetch_frame(y4m, f, img) < 1)
      return 0;
  } else {
111
    shortread = read_yuv_frame(input_ctx, img);
John Koleszar's avatar
John Koleszar committed
112
  }
John Koleszar's avatar
John Koleszar committed
113

John Koleszar's avatar
John Koleszar committed
114
  return !shortread;
John Koleszar's avatar
John Koleszar committed
115 116
}

117
static int file_is_y4m(const char detect[4]) {
John Koleszar's avatar
John Koleszar committed
118 119 120 121
  if (memcmp(detect, "YUV4", 4) == 0) {
    return 1;
  }
  return 0;
122 123
}

124
static int fourcc_is_ivf(const char detect[4]) {
125 126 127 128 129
  if (memcmp(detect, "DKIF", 4) == 0) {
    return 1;
  }
  return 0;
}
130

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
static const arg_def_t debugmode = ARG_DEF(
    "D", "debug", 0, "Debug mode (makes output deterministic)");
static const arg_def_t outputfile = ARG_DEF(
    "o", "output", 1, "Output filename");
static const arg_def_t use_yv12 = ARG_DEF(
    NULL, "yv12", 0, "Input file is YV12 ");
static const arg_def_t use_i420 = ARG_DEF(
    NULL, "i420", 0, "Input file is I420 (default)");
static const arg_def_t use_i422 = ARG_DEF(
    NULL, "i422", 0, "Input file is I422");
static const arg_def_t use_i444 = ARG_DEF(
    NULL, "i444", 0, "Input file is I444");
static const arg_def_t use_i440 = ARG_DEF(
    NULL, "i440", 0, "Input file is I440");
static const arg_def_t codecarg = ARG_DEF(
    NULL, "codec", 1, "Codec to use");
static const arg_def_t passes = ARG_DEF(
    "p", "passes", 1, "Number of passes (1/2)");
static const arg_def_t pass_arg = ARG_DEF(
    NULL, "pass", 1, "Pass to execute (1/2)");
static const arg_def_t fpf_name = ARG_DEF(
    NULL, "fpf", 1, "First pass statistics file name");
153
#if CONFIG_FP_MB_STATS
154 155
static const arg_def_t fpmbf_name = ARG_DEF(
    NULL, "fpmbf", 1, "First pass block statistics file name");
156
#endif
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
static const arg_def_t limit = ARG_DEF(
    NULL, "limit", 1, "Stop encoding after n input frames");
static const arg_def_t skip = ARG_DEF(
    NULL, "skip", 1, "Skip the first n input frames");
static const arg_def_t deadline = ARG_DEF(
    "d", "deadline", 1, "Deadline per frame (usec)");
static const arg_def_t best_dl = ARG_DEF(
    NULL, "best", 0, "Use Best Quality Deadline");
static const arg_def_t good_dl = ARG_DEF(
    NULL, "good", 0, "Use Good Quality Deadline");
static const arg_def_t rt_dl = ARG_DEF(
    NULL, "rt", 0, "Use Realtime Quality Deadline");
static const arg_def_t quietarg = ARG_DEF(
    "q", "quiet", 0, "Do not print encode progress");
static const arg_def_t verbosearg = ARG_DEF(
    "v", "verbose", 0, "Show encoder parameters");
static const arg_def_t psnrarg = ARG_DEF(
    NULL, "psnr", 0, "Show PSNR in status line");
175

176 177 178 179 180 181
static const struct arg_enum_list test_decode_enum[] = {
  {"off",   TEST_DECODE_OFF},
  {"fatal", TEST_DECODE_FATAL},
  {"warn",  TEST_DECODE_WARN},
  {NULL, 0}
};
182 183 184 185
static const arg_def_t recontest = ARG_DEF_ENUM(
    NULL, "test-decode", 1, "Test encode/decode mismatch", test_decode_enum);
static const arg_def_t framerate = ARG_DEF(
    NULL, "fps", 1, "Stream frame rate (rate/scale)");
186 187
static const arg_def_t use_webm = ARG_DEF(
    NULL, "webm", 0, "Output WebM (default when WebM IO is enabled)");
188
static const arg_def_t use_ivf = ARG_DEF(
189
    NULL, "ivf", 0, "Output IVF");
190 191 192 193 194 195 196 197 198 199 200 201 202
static const arg_def_t out_part = ARG_DEF(
    "P", "output-partitions", 0,
    "Makes encoder output partitions. Requires IVF output!");
static const arg_def_t q_hist_n = ARG_DEF(
    NULL, "q-hist", 1, "Show quantizer histogram (n-buckets)");
static const arg_def_t rate_hist_n = ARG_DEF(
    NULL, "rate-hist", 1, "Show rate histogram (n-buckets)");
static const arg_def_t disable_warnings = ARG_DEF(
    NULL, "disable-warnings", 0,
    "Disable warnings about potentially incorrect encode settings.");
static const arg_def_t disable_warning_prompt = ARG_DEF(
    "y", "disable-warning-prompt", 0,
    "Display warnings, but do not prompt user to continue.");
203

204
#if CONFIG_VP9_HIGHBITDEPTH
205 206 207
static const arg_def_t test16bitinternalarg = ARG_DEF(
    NULL, "test-16bit-internal", 0, "Force use of 16 bit internal buffer");
#endif
208

John Koleszar's avatar
John Koleszar committed
209 210 211
static const arg_def_t *main_args[] = {
  &debugmode,
  &outputfile, &codecarg, &passes, &pass_arg, &fpf_name, &limit, &skip,
212
  &deadline, &best_dl, &good_dl, &rt_dl,
213
  &quietarg, &verbosearg, &psnrarg, &use_webm, &use_ivf, &out_part, &q_hist_n,
Yaowu Xu's avatar
Yaowu Xu committed
214
  &rate_hist_n, &disable_warnings, &disable_warning_prompt, &recontest,
John Koleszar's avatar
John Koleszar committed
215
  NULL
John Koleszar's avatar
John Koleszar committed
216 217
};

218 219 220 221 222 223 224 225
static const arg_def_t usage = ARG_DEF(
    "u", "usage", 1, "Usage profile number to use");
static const arg_def_t threads = ARG_DEF(
    "t", "threads", 1, "Max number of threads to use");
static const arg_def_t profile = ARG_DEF(
    NULL, "profile", 1, "Bitstream profile number to use");
static const arg_def_t width = ARG_DEF("w", "width", 1, "Frame width");
static const arg_def_t height = ARG_DEF("h", "height", 1, "Frame height");
226
#if CONFIG_WEBM_IO
227
static const struct arg_enum_list stereo_mode_enum[] = {
John Koleszar's avatar
John Koleszar committed
228 229 230 231 232 233
  {"mono", STEREO_FORMAT_MONO},
  {"left-right", STEREO_FORMAT_LEFT_RIGHT},
  {"bottom-top", STEREO_FORMAT_BOTTOM_TOP},
  {"top-bottom", STEREO_FORMAT_TOP_BOTTOM},
  {"right-left", STEREO_FORMAT_RIGHT_LEFT},
  {NULL, 0}
234
};
235 236
static const arg_def_t stereo_mode = ARG_DEF_ENUM(
    NULL, "stereo-mode", 1, "Stereo 3D video format", stereo_mode_enum);
237
#endif
238 239 240 241 242 243
static const arg_def_t timebase = ARG_DEF(
    NULL, "timebase", 1, "Output timestamp precision (fractional seconds)");
static const arg_def_t error_resilient = ARG_DEF(
    NULL, "error-resilient", 1, "Enable error resiliency features");
static const arg_def_t lag_in_frames = ARG_DEF(
    NULL, "lag-in-frames", 1, "Max number of frames to lag");
John Koleszar's avatar
John Koleszar committed
244

John Koleszar's avatar
John Koleszar committed
245
static const arg_def_t *global_args[] = {
246
  &use_yv12, &use_i420, &use_i422, &use_i444, &use_i440,
247
  &usage, &threads, &profile,
248 249 250 251 252
  &width, &height,
#if CONFIG_WEBM_IO
  &stereo_mode,
#endif
  &timebase, &framerate,
253
  &error_resilient,
254
#if CONFIG_VP9_HIGHBITDEPTH
255 256
  &test16bitinternalarg,
#endif
John Koleszar's avatar
John Koleszar committed
257
  &lag_in_frames, NULL
John Koleszar's avatar
John Koleszar committed
258 259
};

260 261 262 263 264 265 266 267 268 269 270 271
static const arg_def_t dropframe_thresh = ARG_DEF(
    NULL, "drop-frame", 1, "Temporal resampling threshold (buf %)");
static const arg_def_t resize_allowed = ARG_DEF(
    NULL, "resize-allowed", 1, "Spatial resampling enabled (bool)");
static const arg_def_t resize_width = ARG_DEF(
    NULL, "resize-width", 1, "Width of encoded frame");
static const arg_def_t resize_height = ARG_DEF(
    NULL, "resize-height", 1, "Height of encoded frame");
static const arg_def_t resize_up_thresh = ARG_DEF(
    NULL, "resize-up", 1, "Upscale threshold (buf %)");
static const arg_def_t resize_down_thresh = ARG_DEF(
    NULL, "resize-down", 1, "Downscale threshold (buf %)");
272
static const struct arg_enum_list end_usage_enum[] = {
John Koleszar's avatar
John Koleszar committed
273 274 275
  {"vbr", VPX_VBR},
  {"cbr", VPX_CBR},
  {"cq",  VPX_CQ},
276
  {"q",   VPX_Q},
John Koleszar's avatar
John Koleszar committed
277
  {NULL, 0}
278
};
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
static const arg_def_t end_usage = ARG_DEF_ENUM(
    NULL, "end-usage", 1, "Rate control mode", end_usage_enum);
static const arg_def_t target_bitrate = ARG_DEF(
    NULL, "target-bitrate", 1, "Bitrate (kbps)");
static const arg_def_t min_quantizer = ARG_DEF(
    NULL, "min-q", 1, "Minimum (best) quantizer");
static const arg_def_t max_quantizer = ARG_DEF(
    NULL, "max-q", 1, "Maximum (worst) quantizer");
static const arg_def_t undershoot_pct = ARG_DEF(
    NULL, "undershoot-pct", 1, "Datarate undershoot (min) target (%)");
static const arg_def_t overshoot_pct = ARG_DEF(
    NULL, "overshoot-pct", 1, "Datarate overshoot (max) target (%)");
static const arg_def_t buf_sz = ARG_DEF(
    NULL, "buf-sz", 1, "Client buffer size (ms)");
static const arg_def_t buf_initial_sz = ARG_DEF(
    NULL, "buf-initial-sz", 1, "Client initial buffer size (ms)");
static const arg_def_t buf_optimal_sz = ARG_DEF(
    NULL, "buf-optimal-sz", 1, "Client optimal buffer size (ms)");
John Koleszar's avatar
John Koleszar committed
297
static const arg_def_t *rc_args[] = {
298 299 300 301
  &dropframe_thresh, &resize_allowed, &resize_width, &resize_height,
  &resize_up_thresh, &resize_down_thresh, &end_usage, &target_bitrate,
  &min_quantizer, &max_quantizer, &undershoot_pct, &overshoot_pct, &buf_sz,
  &buf_initial_sz, &buf_optimal_sz, NULL
John Koleszar's avatar
John Koleszar committed
302 303 304
};


305 306 307 308 309 310
static const arg_def_t bias_pct = ARG_DEF(
    NULL, "bias-pct", 1, "CBR/VBR bias (0=CBR, 100=VBR)");
static const arg_def_t minsection_pct = ARG_DEF(
    NULL, "minsection-pct", 1, "GOP min bitrate (% of target)");
static const arg_def_t maxsection_pct = ARG_DEF(
    NULL, "maxsection-pct", 1, "GOP max bitrate (% of target)");
John Koleszar's avatar
John Koleszar committed
311 312
static const arg_def_t *rc_twopass_args[] = {
  &bias_pct, &minsection_pct, &maxsection_pct, NULL
John Koleszar's avatar
John Koleszar committed
313 314 315
};


316 317 318 319 320 321
static const arg_def_t kf_min_dist = ARG_DEF(
    NULL, "kf-min-dist", 1, "Minimum keyframe interval (frames)");
static const arg_def_t kf_max_dist = ARG_DEF(
    NULL, "kf-max-dist", 1, "Maximum keyframe interval (frames)");
static const arg_def_t kf_disabled = ARG_DEF(
    NULL, "disable-kf", 0, "Disable keyframe placement");
John Koleszar's avatar
John Koleszar committed
322 323
static const arg_def_t *kf_args[] = {
  &kf_min_dist, &kf_max_dist, &kf_disabled, NULL
John Koleszar's avatar
John Koleszar committed
324 325 326
};


327 328 329 330 331 332 333 334 335 336 337 338 339 340
static const arg_def_t noise_sens = ARG_DEF(
    NULL, "noise-sensitivity", 1, "Noise sensitivity (frames to blur)");
static const arg_def_t sharpness = ARG_DEF(
    NULL, "sharpness", 1, "Loop filter sharpness (0..7)");
static const arg_def_t static_thresh = ARG_DEF(
    NULL, "static-thresh", 1, "Motion detection threshold");
static const arg_def_t auto_altref = ARG_DEF(
    NULL, "auto-alt-ref", 1, "Enable automatic alt reference frames");
static const arg_def_t arnr_maxframes = ARG_DEF(
    NULL, "arnr-maxframes", 1, "AltRef max frames (0..15)");
static const arg_def_t arnr_strength = ARG_DEF(
    NULL, "arnr-strength", 1, "AltRef filter strength (0..6)");
static const arg_def_t arnr_type = ARG_DEF(
    NULL, "arnr-type", 1, "AltRef type");
341
static const struct arg_enum_list tuning_enum[] = {
John Koleszar's avatar
John Koleszar committed
342 343 344
  {"psnr", VP8_TUNE_PSNR},
  {"ssim", VP8_TUNE_SSIM},
  {NULL, 0}
345
};
346 347 348 349 350 351
static const arg_def_t tune_ssim = ARG_DEF_ENUM(
    NULL, "tune", 1, "Material to favor", tuning_enum);
static const arg_def_t cq_level = ARG_DEF(
    NULL, "cq-level", 1, "Constant/Constrained Quality level");
static const arg_def_t max_intra_rate_pct = ARG_DEF(
    NULL, "max-intra-rate", 1, "Max I-frame bitrate (pct)");
Marco's avatar
Marco committed
352

353
#if CONFIG_VP8_ENCODER
354 355
static const arg_def_t cpu_used_vp8 = ARG_DEF(
    NULL, "cpu-used", 1, "CPU Used (-16..16)");
356 357
static const arg_def_t token_parts = ARG_DEF(
    NULL, "token-parts", 1, "Number of token partitions to use, log2");
358 359
static const arg_def_t screen_content_mode = ARG_DEF(
    NULL, "screen-content-mode", 1, "Screen content mode");
John Koleszar's avatar
John Koleszar committed
360
static const arg_def_t *vp8_args[] = {
361
  &cpu_used_vp8, &auto_altref, &noise_sens, &sharpness, &static_thresh,
John Koleszar's avatar
John Koleszar committed
362
  &token_parts, &arnr_maxframes, &arnr_strength, &arnr_type,
Marco's avatar
Marco committed
363
  &tune_ssim, &cq_level, &max_intra_rate_pct, &screen_content_mode,
364
  NULL
John Koleszar's avatar
John Koleszar committed
365
};
366 367 368 369 370 371
static const int vp8_arg_ctrl_map[] = {
  VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
  VP8E_SET_NOISE_SENSITIVITY, VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
  VP8E_SET_TOKEN_PARTITIONS,
  VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
  VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
Marco's avatar
Marco committed
372
  VP8E_SET_SCREEN_CONTENT_MODE,
373 374 375 376
  0
};
#endif

377
#if CONFIG_VP9_ENCODER || CONFIG_VP10_ENCODER
378 379
static const arg_def_t cpu_used_vp9 = ARG_DEF(
    NULL, "cpu-used", 1, "CPU Used (-8..8)");
380 381 382 383 384
static const arg_def_t tile_cols = ARG_DEF(
    NULL, "tile-columns", 1, "Number of tile columns to use, log2");
static const arg_def_t tile_rows = ARG_DEF(
    NULL, "tile-rows", 1, "Number of tile rows to use, log2");
static const arg_def_t lossless = ARG_DEF(
385
    NULL, "lossless", 1, "Lossless mode (0: false (default), 1: true)");
386 387 388 389
static const arg_def_t frame_parallel_decoding = ARG_DEF(
    NULL, "frame-parallel", 1, "Enable frame parallel decodability features");
static const arg_def_t aq_mode = ARG_DEF(
    NULL, "aq-mode", 1,
390
    "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
391 392
    "3: cyclic refresh)");
static const arg_def_t frame_periodic_boost = ARG_DEF(
393
    NULL, "frame-boost", 1,
394
    "Enable frame periodic boost (0: off (default), 1: on)");
395 396 397 398
static const arg_def_t gf_cbr_boost_pct = ARG_DEF(
    NULL, "gf-cbr-boost", 1, "Boost for Golden Frame in CBR mode (pct)");
static const arg_def_t max_inter_rate_pct = ARG_DEF(
    NULL, "max-inter-rate", 1, "Max P-frame bitrate (pct)");
399 400 401 402 403 404
static const arg_def_t min_gf_interval = ARG_DEF(
    NULL, "min-gf-interval", 1,
    "min gf/arf frame interval (default 0, indicating in-built behavior)");
static const arg_def_t max_gf_interval = ARG_DEF(
    NULL, "max-gf-interval", 1,
    "max gf/arf frame interval (default 0, indicating in-built behavior)");
405

Yaowu Xu's avatar
Yaowu Xu committed
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
static const struct arg_enum_list color_space_enum[] = {
  { "unknown", VPX_CS_UNKNOWN },
  { "bt601", VPX_CS_BT_601 },
  { "bt709", VPX_CS_BT_709 },
  { "smpte170", VPX_CS_SMPTE_170 },
  { "smpte240", VPX_CS_SMPTE_240 },
  { "bt2020", VPX_CS_BT_2020 },
  { "reserved", VPX_CS_RESERVED },
  { "sRGB", VPX_CS_SRGB },
  { NULL, 0 }
};

static const arg_def_t input_color_space = ARG_DEF_ENUM(
    NULL, "color-space", 1,
    "The color space of input content:", color_space_enum);

422
#if CONFIG_VP9_HIGHBITDEPTH
423 424 425 426 427 428 429
static const struct arg_enum_list bitdepth_enum[] = {
  {"8",  VPX_BITS_8},
  {"10", VPX_BITS_10},
  {"12", VPX_BITS_12},
  {NULL, 0}
};

430 431 432 433 434 435
static const arg_def_t bitdeptharg = ARG_DEF_ENUM(
    "b", "bit-depth", 1,
    "Bit depth for codec (8 for version <=1, 10 or 12 for version 2)",
    bitdepth_enum);
static const arg_def_t inbitdeptharg = ARG_DEF(
    NULL, "input-bit-depth", 1, "Bit depth of input");
436 437
#endif

438 439 440 441 442 443 444 445
static const struct arg_enum_list tune_content_enum[] = {
  {"default", VP9E_CONTENT_DEFAULT},
  {"screen", VP9E_CONTENT_SCREEN},
  {NULL, 0}
};

static const arg_def_t tune_content = ARG_DEF_ENUM(
    NULL, "tune-content", 1, "Tune content type", tune_content_enum);
hui su's avatar
hui su committed
446
#endif
447

hui su's avatar
hui su committed
448
#if CONFIG_VP9_ENCODER
449
static const arg_def_t *vp9_args[] = {
450
  &cpu_used_vp9, &auto_altref, &sharpness, &static_thresh,
451
  &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type,
452 453
  &tune_ssim, &cq_level, &max_intra_rate_pct, &max_inter_rate_pct,
  &gf_cbr_boost_pct, &lossless,
454
  &frame_parallel_decoding, &aq_mode, &frame_periodic_boost,
Yaowu Xu's avatar
Yaowu Xu committed
455
  &noise_sens, &tune_content, &input_color_space,
456
  &min_gf_interval, &max_gf_interval,
John Koleszar's avatar
John Koleszar committed
457
  NULL
John Koleszar's avatar
John Koleszar committed
458
};
459
static const int vp9_arg_ctrl_map[] = {
John Koleszar's avatar
John Koleszar committed
460
  VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
461
  VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
462
  VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS,
463
  VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
John Koleszar's avatar
John Koleszar committed
464
  VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
465
  VP9E_SET_MAX_INTER_BITRATE_PCT, VP9E_SET_GF_CBR_BOOST_PCT,
466
  VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING, VP9E_SET_AQ_MODE,
467
  VP9E_SET_FRAME_PERIODIC_BOOST, VP9E_SET_NOISE_SENSITIVITY,
468
  VP9E_SET_TUNE_CONTENT, VP9E_SET_COLOR_SPACE,
469
  VP9E_SET_MIN_GF_INTERVAL, VP9E_SET_MAX_GF_INTERVAL,
John Koleszar's avatar
John Koleszar committed
470
  0
John Koleszar's avatar
John Koleszar committed
471 472 473
};
#endif

hui su's avatar
hui su committed
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
#if CONFIG_VP10_ENCODER
static const arg_def_t *vp10_args[] = {
  &cpu_used_vp9, &auto_altref, &sharpness, &static_thresh,
  &tile_cols, &tile_rows, &arnr_maxframes, &arnr_strength, &arnr_type,
  &tune_ssim, &cq_level, &max_intra_rate_pct, &max_inter_rate_pct,
  &gf_cbr_boost_pct, &lossless,
  &frame_parallel_decoding, &aq_mode, &frame_periodic_boost,
  &noise_sens, &tune_content, &input_color_space,
  &min_gf_interval, &max_gf_interval,
  NULL
};
static const int vp10_arg_ctrl_map[] = {
  VP8E_SET_CPUUSED, VP8E_SET_ENABLEAUTOALTREF,
  VP8E_SET_SHARPNESS, VP8E_SET_STATIC_THRESHOLD,
  VP9E_SET_TILE_COLUMNS, VP9E_SET_TILE_ROWS,
  VP8E_SET_ARNR_MAXFRAMES, VP8E_SET_ARNR_STRENGTH, VP8E_SET_ARNR_TYPE,
  VP8E_SET_TUNING, VP8E_SET_CQ_LEVEL, VP8E_SET_MAX_INTRA_BITRATE_PCT,
  VP9E_SET_MAX_INTER_BITRATE_PCT, VP9E_SET_GF_CBR_BOOST_PCT,
  VP9E_SET_LOSSLESS, VP9E_SET_FRAME_PARALLEL_DECODING, VP9E_SET_AQ_MODE,
  VP9E_SET_FRAME_PERIODIC_BOOST, VP9E_SET_NOISE_SENSITIVITY,
  VP9E_SET_TUNE_CONTENT, VP9E_SET_COLOR_SPACE,
  VP9E_SET_MIN_GF_INTERVAL, VP9E_SET_MAX_GF_INTERVAL,
  0
};
#endif

John Koleszar's avatar
John Koleszar committed
500 501
static const arg_def_t *no_args[] = { NULL };

502
void usage_exit(void) {
John Koleszar's avatar
John Koleszar committed
503
  int i;
504
  const int num_encoder = get_vpx_encoder_count();
John Koleszar's avatar
John Koleszar committed
505 506 507 508 509

  fprintf(stderr, "Usage: %s <options> -o dst_filename src_filename \n",
          exec_name);

  fprintf(stderr, "\nOptions:\n");
510
  arg_show_usage(stderr, main_args);
John Koleszar's avatar
John Koleszar committed
511
  fprintf(stderr, "\nEncoder Global Options:\n");
512
  arg_show_usage(stderr, global_args);
John Koleszar's avatar
John Koleszar committed
513
  fprintf(stderr, "\nRate Control Options:\n");
514
  arg_show_usage(stderr, rc_args);
John Koleszar's avatar
John Koleszar committed
515
  fprintf(stderr, "\nTwopass Rate Control Options:\n");
516
  arg_show_usage(stderr, rc_twopass_args);
John Koleszar's avatar
John Koleszar committed
517
  fprintf(stderr, "\nKeyframe Placement Options:\n");
518
  arg_show_usage(stderr, kf_args);
John Koleszar's avatar
John Koleszar committed
519
#if CONFIG_VP8_ENCODER
John Koleszar's avatar
John Koleszar committed
520
  fprintf(stderr, "\nVP8 Specific Options:\n");
521
  arg_show_usage(stderr, vp8_args);
John Koleszar's avatar
John Koleszar committed
522
#endif
hui su's avatar
hui su committed
523 524
#if CONFIG_VP9_ENCODER
  fprintf(stderr, "\nVP9 Specific Options:\n");
525
  arg_show_usage(stderr, vp9_args);
hui su's avatar
hui su committed
526 527 528 529
#endif
#if CONFIG_VP10_ENCODER
  fprintf(stderr, "\nVP10 Specific Options:\n");
  arg_show_usage(stderr, vp10_args);
John Koleszar's avatar
John Koleszar committed
530
#endif
John Koleszar's avatar
John Koleszar committed
531 532 533
  fprintf(stderr, "\nStream timebase (--timebase):\n"
          "  The desired precision of timestamps in the output, expressed\n"
          "  in fractional seconds. Default is 1/1000.\n");
534
  fprintf(stderr, "\nIncluded encoders:\n\n");
John Koleszar's avatar
John Koleszar committed
535

536
  for (i = 0; i < num_encoder; ++i) {
537
    const VpxInterface *const encoder = get_vpx_encoder_by_index(i);
538 539 540 541
    const char* defstr = (i == (num_encoder - 1)) ? "(default)" : "";
      fprintf(stderr, "    %-6s - %s %s\n",
              encoder->name, vpx_codec_iface_name(encoder->codec_interface()),
              defstr);
542
  }
543 544
  fprintf(stderr, "\n        ");
  fprintf(stderr, "Use --codec to switch to a non-default encoder.\n\n");
John Koleszar's avatar
John Koleszar committed
545 546

  exit(EXIT_FAILURE);
John Koleszar's avatar
John Koleszar committed
547 548
}

549
#define mmin(a, b)  ((a) < (b) ? (a) : (b))
550

551
#if CONFIG_VP9_HIGHBITDEPTH
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
static void find_mismatch_high(const vpx_image_t *const img1,
                               const vpx_image_t *const img2,
                               int yloc[4], int uloc[4], int vloc[4]) {
  uint16_t *plane1, *plane2;
  uint32_t stride1, stride2;
  const uint32_t bsize = 64;
  const uint32_t bsizey = bsize >> img1->y_chroma_shift;
  const uint32_t bsizex = bsize >> img1->x_chroma_shift;
  const uint32_t c_w =
      (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
  const uint32_t c_h =
      (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
  int match = 1;
  uint32_t i, j;
  yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
  plane1 = (uint16_t*)img1->planes[VPX_PLANE_Y];
  plane2 = (uint16_t*)img2->planes[VPX_PLANE_Y];
  stride1 = img1->stride[VPX_PLANE_Y]/2;
  stride2 = img2->stride[VPX_PLANE_Y]/2;
  for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
    for (j = 0; match && j < img1->d_w; j += bsize) {
      int k, l;
      const int si = mmin(i + bsize, img1->d_h) - i;
      const int sj = mmin(j + bsize, img1->d_w) - j;
      for (k = 0; match && k < si; ++k) {
        for (l = 0; match && l < sj; ++l) {
          if (*(plane1 + (i + k) * stride1 + j + l) !=
              *(plane2 + (i + k) * stride2 + j + l)) {
            yloc[0] = i + k;
            yloc[1] = j + l;
            yloc[2] = *(plane1 + (i + k) * stride1 + j + l);
            yloc[3] = *(plane2 + (i + k) * stride2 + j + l);
            match = 0;
            break;
          }
        }
      }
    }
  }

  uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
  plane1 = (uint16_t*)img1->planes[VPX_PLANE_U];
  plane2 = (uint16_t*)img2->planes[VPX_PLANE_U];
  stride1 = img1->stride[VPX_PLANE_U]/2;
  stride2 = img2->stride[VPX_PLANE_U]/2;
  for (i = 0, match = 1; match && i < c_h; i += bsizey) {
    for (j = 0; match && j < c_w; j += bsizex) {
      int k, l;
      const int si = mmin(i + bsizey, c_h - i);
      const int sj = mmin(j + bsizex, c_w - j);
      for (k = 0; match && k < si; ++k) {
        for (l = 0; match && l < sj; ++l) {
          if (*(plane1 + (i + k) * stride1 + j + l) !=
              *(plane2 + (i + k) * stride2 + j + l)) {
            uloc[0] = i + k;
            uloc[1] = j + l;
            uloc[2] = *(plane1 + (i + k) * stride1 + j + l);
            uloc[3] = *(plane2 + (i + k) * stride2 + j + l);
            match = 0;
            break;
          }
        }
      }
    }
  }

  vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
  plane1 = (uint16_t*)img1->planes[VPX_PLANE_V];
  plane2 = (uint16_t*)img2->planes[VPX_PLANE_V];
  stride1 = img1->stride[VPX_PLANE_V]/2;
  stride2 = img2->stride[VPX_PLANE_V]/2;
  for (i = 0, match = 1; match && i < c_h; i += bsizey) {
    for (j = 0; match && j < c_w; j += bsizex) {
      int k, l;
      const int si = mmin(i + bsizey, c_h - i);
      const int sj = mmin(j + bsizex, c_w - j);
      for (k = 0; match && k < si; ++k) {
        for (l = 0; match && l < sj; ++l) {
          if (*(plane1 + (i + k) * stride1 + j + l) !=
              *(plane2 + (i + k) * stride2 + j + l)) {
            vloc[0] = i + k;
            vloc[1] = j + l;
            vloc[2] = *(plane1 + (i + k) * stride1 + j + l);
            vloc[3] = *(plane2 + (i + k) * stride2 + j + l);
            match = 0;
            break;
          }
        }
      }
    }
  }
}
#endif

James Zern's avatar
James Zern committed
646 647
static void find_mismatch(const vpx_image_t *const img1,
                          const vpx_image_t *const img2,
648
                          int yloc[4], int uloc[4], int vloc[4]) {
649 650 651 652 653 654 655 656 657
  const uint32_t bsize = 64;
  const uint32_t bsizey = bsize >> img1->y_chroma_shift;
  const uint32_t bsizex = bsize >> img1->x_chroma_shift;
  const uint32_t c_w =
      (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
  const uint32_t c_h =
      (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
  int match = 1;
  uint32_t i, j;
658
  yloc[0] = yloc[1] = yloc[2] = yloc[3] = -1;
659 660
  for (i = 0, match = 1; match && i < img1->d_h; i += bsize) {
    for (j = 0; match && j < img1->d_w; j += bsize) {
661
      int k, l;
James Zern's avatar
James Zern committed
662 663 664 665
      const int si = mmin(i + bsize, img1->d_h) - i;
      const int sj = mmin(j + bsize, img1->d_w) - j;
      for (k = 0; match && k < si; ++k) {
        for (l = 0; match && l < sj; ++l) {
666 667 668 669 670 671
          if (*(img1->planes[VPX_PLANE_Y] +
                (i + k) * img1->stride[VPX_PLANE_Y] + j + l) !=
              *(img2->planes[VPX_PLANE_Y] +
                (i + k) * img2->stride[VPX_PLANE_Y] + j + l)) {
            yloc[0] = i + k;
            yloc[1] = j + l;
672 673 674 675
            yloc[2] = *(img1->planes[VPX_PLANE_Y] +
                        (i + k) * img1->stride[VPX_PLANE_Y] + j + l);
            yloc[3] = *(img2->planes[VPX_PLANE_Y] +
                        (i + k) * img2->stride[VPX_PLANE_Y] + j + l);
676
            match = 0;
677
            break;
678 679
          }
        }
James Zern's avatar
James Zern committed
680
      }
681
    }
682
  }
683

684
  uloc[0] = uloc[1] = uloc[2] = uloc[3] = -1;
685
  for (i = 0, match = 1; match && i < c_h; i += bsizey) {
686
    for (j = 0; match && j < c_w; j += bsizex) {
687
      int k, l;
James Zern's avatar
James Zern committed
688 689 690 691
      const int si = mmin(i + bsizey, c_h - i);
      const int sj = mmin(j + bsizex, c_w - j);
      for (k = 0; match && k < si; ++k) {
        for (l = 0; match && l < sj; ++l) {
692 693 694 695 696 697
          if (*(img1->planes[VPX_PLANE_U] +
                (i + k) * img1->stride[VPX_PLANE_U] + j + l) !=
              *(img2->planes[VPX_PLANE_U] +
                (i + k) * img2->stride[VPX_PLANE_U] + j + l)) {
            uloc[0] = i + k;
            uloc[1] = j + l;
698 699 700
            uloc[2] = *(img1->planes[VPX_PLANE_U] +
                        (i + k) * img1->stride[VPX_PLANE_U] + j + l);
            uloc[3] = *(img2->planes[VPX_PLANE_U] +
James Zern's avatar
James Zern committed
701
                        (i + k) * img2->stride[VPX_PLANE_U] + j + l);
702 703 704 705
            match = 0;
            break;
          }
        }
James Zern's avatar
James Zern committed
706
      }
707 708
    }
  }
709
  vloc[0] = vloc[1] = vloc[2] = vloc[3] = -1;
710
  for (i = 0, match = 1; match && i < c_h; i += bsizey) {
711
    for (j = 0; match && j < c_w; j += bsizex) {
712
      int k, l;
James Zern's avatar
James Zern committed
713 714 715 716
      const int si = mmin(i + bsizey, c_h - i);
      const int sj = mmin(j + bsizex, c_w - j);
      for (k = 0; match && k < si; ++k) {
        for (l = 0; match && l < sj; ++l) {
717 718 719 720 721 722
          if (*(img1->planes[VPX_PLANE_V] +
                (i + k) * img1->stride[VPX_PLANE_V] + j + l) !=
              *(img2->planes[VPX_PLANE_V] +
                (i + k) * img2->stride[VPX_PLANE_V] + j + l)) {
            vloc[0] = i + k;
            vloc[1] = j + l;
723 724 725 726
            vloc[2] = *(img1->planes[VPX_PLANE_V] +
                        (i + k) * img1->stride[VPX_PLANE_V] + j + l);
            vloc[3] = *(img2->planes[VPX_PLANE_V] +
                        (i + k) * img2->stride[VPX_PLANE_V] + j + l);
727 728 729 730
            match = 0;
            break;
          }
        }
James Zern's avatar
James Zern committed
731
      }
732 733
    }
  }
734 735
}

James Zern's avatar
James Zern committed
736 737
static int compare_img(const vpx_image_t *const img1,
                       const vpx_image_t *const img2) {
738 739
  uint32_t l_w = img1->d_w;
  uint32_t c_w =
740 741 742 743
      (img1->d_w + img1->x_chroma_shift) >> img1->x_chroma_shift;
  const uint32_t c_h =
      (img1->d_h + img1->y_chroma_shift) >> img1->y_chroma_shift;
  uint32_t i;
John Koleszar's avatar
John Koleszar committed
744
  int match = 1;
745

John Koleszar's avatar
John Koleszar committed
746
  match &= (img1->fmt == img2->fmt);
747 748
  match &= (img1->d_w == img2->d_w);
  match &= (img1->d_h == img2->d_h);
749
#if CONFIG_VP9_HIGHBITDEPTH
750 751 752 753 754
  if (img1->fmt & VPX_IMG_FMT_HIGHBITDEPTH) {
    l_w *= 2;
    c_w *= 2;
  }
#endif
755

James Zern's avatar
James Zern committed
756 757 758
  for (i = 0; i < img1->d_h; ++i)
    match &= (memcmp(img1->planes[VPX_PLANE_Y] + i * img1->stride[VPX_PLANE_Y],
                     img2->planes[VPX_PLANE_Y] + i * img2->stride[VPX_PLANE_Y],
759
                     l_w) == 0);
760

James Zern's avatar
James Zern committed
761 762 763
  for (i = 0; i < c_h; ++i)
    match &= (memcmp(img1->planes[VPX_PLANE_U] + i * img1->stride[VPX_PLANE_U],
                     img2->planes[VPX_PLANE_U] + i * img2->stride[VPX_PLANE_U],
764
                     c_w) == 0);
765

James Zern's avatar
James Zern committed
766 767 768
  for (i = 0; i < c_h; ++i)
    match &= (memcmp(img1->planes[VPX_PLANE_V] + i * img1->stride[VPX_PLANE_V],
                     img2->planes[VPX_PLANE_V] + i * img2->stride[VPX_PLANE_V],
769
                     c_w) == 0);
770

John Koleszar's avatar
John Koleszar committed
771
  return match;
772 773
}

774

775
#define NELEMENTS(x) (sizeof(x)/sizeof(x[0]))
hui su's avatar
hui su committed
776 777 778
#if CONFIG_VP10_ENCODER
#define ARG_CTRL_CNT_MAX NELEMENTS(vp10_arg_ctrl_map)
#elif CONFIG_VP9_ENCODER
779 780
#define ARG_CTRL_CNT_MAX NELEMENTS(vp9_arg_ctrl_map)
#else
hui su's avatar
hui su committed
781
#define ARG_CTRL_CNT_MAX NELEMENTS(vp8_arg_ctrl_map)
782
#endif
John Koleszar's avatar
John Koleszar committed
783

784 785 786 787 788
#if !CONFIG_WEBM_IO
typedef int stereo_format_t;
struct EbmlGlobal { int debug; };
#endif

789
/* Per-stream configuration */
790 791 792 793
struct stream_config {
  struct vpx_codec_enc_cfg  cfg;
  const char               *out_fn;
  const char               *stats_fn;
794 795 796
#if CONFIG_FP_MB_STATS
  const char               *fpmb_stats_fn;
#endif
797 798 799 800 801
  stereo_format_t           stereo_fmt;
  int                       arg_ctrls[ARG_CTRL_CNT_MAX][2];
  int                       arg_ctrl_cnt;
  int                       write_webm;
  int                       have_kf_max_dist;
802
#if CONFIG_VP9_HIGHBITDEPTH
803 804 805
  // whether to use 16bit internal buffers
  int                       use_16bit_internal;
#endif
806 807 808
};


809 810 811 812 813
struct stream_state {
  int                       index;
  struct stream_state      *next;
  struct stream_config      config;
  FILE                     *file;
814
  struct rate_hist         *rate_hist;
815
  struct EbmlGlobal         ebml;
816 817 818 819 820 821 822 823 824 825
  uint64_t                  psnr_sse_total;
  uint64_t                  psnr_samples_total;
  double                    psnr_totals[4];
  int                       psnr_count;
  int                       counts[64];
  vpx_codec_ctx_t           encoder;
  unsigned int              frames_out;
  uint64_t                  cx_time;
  size_t                    nbytes;
  stats_io_t                stats;
826 827 828
#if CONFIG_FP_MB_STATS
  stats_io_t                fpmb_stats;
#endif
829
  struct vpx_image         *img;
830 831
  vpx_codec_ctx_t           decoder;
  int                       mismatch_seen;
832 833 834
};


835 836
static void validate_positive_rational(const char          *msg,
                                       struct vpx_rational *rat) {
837 838 839 840
  if (rat->den < 0) {
    rat->num *= -1;
    rat->den *= -1;
  }
841

842 843
  if (rat->num < 0)
    die("Error: %s must be positive\n", msg);
844

845 846
  if (!rat->den)
    die("Error: %s has zero denominator\n", msg);
847 848 849
}


850
static void parse_global_config(struct VpxEncoderConfig *global, char **argv) {
851 852
  char       **argi, **argj;
  struct arg   arg;
853 854 855 856
  const int num_encoder = get_vpx_encoder_count();

  if (num_encoder < 1)
    die("Error: no valid encoder available\n");
857 858 859

  /* Initialize default parameters */
  memset(global, 0, sizeof(*global));
860
  global->codec = get_vpx_encoder_by_index(num_encoder - 1);
861
  global->passes = 0;
862
  global->color_type = I420;
863 864
  /* Assign default deadline to good quality */
  global->deadline = VPX_DL_GOOD_QUALITY;
John Koleszar's avatar
John Koleszar committed
865 866 867 868 869

  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
    arg.argv_step = 1;

    if (arg_match(&arg, &codecarg, argi)) {
870 871 872
      global->codec = get_vpx_encoder_by_name(arg.val);
      if (!global->codec)
        die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
John Koleszar's avatar
John Koleszar committed
873
    } else if (arg_match(&arg, &passes, argi)) {
874
      global->passes = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
875

876 877
      if (global->passes < 1 || global->passes > 2)
        die("Error: Invalid number of passes (%d)\n", global->passes);
John Koleszar's avatar
John Koleszar committed
878
    } else if (arg_match(&arg, &pass_arg, argi)) {
879 880 881 882 883 884 885
      global->pass = arg_parse_uint(&arg);

      if (global->pass < 1 || global->pass > 2)
        die("Error: Invalid pass selected (%d)\n",
            global->pass);
    } else if (arg_match(&arg, &usage, argi))
      global->usage = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
886
    else if (arg_match(&arg, &deadline, argi))
887
      global->deadline = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
888
    else if (arg_match(&arg, &best_dl, argi))
889
      global->deadline = VPX_DL_BEST_QUALITY;
John Koleszar's avatar
John Koleszar committed
890
    else if (arg_match(&arg, &good_dl, argi))
891
      global->deadline = VPX_DL_GOOD_QUALITY;
John Koleszar's avatar
John Koleszar committed
892
    else if (arg_match(&arg, &rt_dl, argi))
893 894
      global->deadline = VPX_DL_REALTIME;
    else if (arg_match(&arg, &use_yv12, argi))
895
      global->color_type = YV12;
896
    else if (arg_match(&arg, &use_i420, argi))
897 898 899 900 901
      global->color_type = I420;
    else if (arg_match(&arg, &use_i422, argi))
      global->color_type = I422;
    else if (arg_match(&arg, &use_i444, argi))
      global->color_type = I444;
902 903
    else if (arg_match(&arg, &use_i440, argi))
      global->color_type = I440;
904 905 906 907
    else if (arg_match(&arg, &quietarg, argi))
      global->quiet = 1;
    else if (arg_match(&arg, &verbosearg, argi))
      global->verbose = 1;
John Koleszar's avatar
John Koleszar committed
908
    else if (arg_match(&arg, &limit, argi))
909
      global->limit = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
910
    else if (arg_match(&arg, &skip, argi))
911
      global->skip_frames = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
912
    else if (arg_match(&arg, &psnrarg, argi))
913
      global->show_psnr = 1;
John Koleszar's avatar
John Koleszar committed
914
    else if (arg_match(&arg, &recontest, argi))
915
      global->test_decode = arg_parse_enum_or_int(&arg);
John Koleszar's avatar
John Koleszar committed
916
    else if (arg_match(&arg, &framerate, argi)) {
917 918 919 920 921
      global->framerate = arg_parse_rational(&arg);
      validate_positive_rational(arg.name, &global->framerate);
      global->have_framerate = 1;
    } else if (arg_match(&arg, &out_part, argi))
      global->out_part = 1;
John Koleszar's avatar
John Koleszar committed
922
    else if (arg_match(&arg, &debugmode, argi))
923
      global->debug = 1;
John Koleszar's avatar
John Koleszar committed
924
    else if (arg_match(&arg, &q_hist_n, argi))
925
      global->show_q_hist_buckets = arg_parse_uint(&arg);
John Koleszar's avatar
John Koleszar committed
926
    else if (arg_match(&arg, &rate_hist_n, argi))
927
      global->show_rate_hist_buckets = arg_parse_uint(&arg);
928 929 930 931
    else if (arg_match(&arg, &disable_warnings, argi))
      global->disable_warnings = 1;
    else if (arg_match(&arg, &disable_warning_prompt, argi))
      global->disable_warning_prompt = 1;
John Koleszar's avatar
John Koleszar committed
932 933 934
    else
      argj++;
  }
John Koleszar's avatar
John Koleszar committed
935

936 937 938 939 940 941 942 943
  if (global->pass) {
    /* DWIM: Assume the user meant passes=2 if pass=2 is specified */
    if (global->pass > global->passes) {
      warn("Assuming --pass=%d implies --passes=%d\n",
           global->pass, global->pass);
      global->passes = global->pass;
    }
  }
944
  /* Validate global config */
945
  if (global->passes == 0) {
946
#if CONFIG_VP9_ENCODER || CONFIG_VP10_ENCODER
947 948
    // Make default VP9 passes = 2 until there is a better quality 1-pass
    // encoder
949 950 951
    if (global->codec != NULL && global->codec->name != NULL)
      global->passes = (strcmp(global->codec->name, "vp9") == 0 &&
                        global->deadline != VPX_DL_REALTIME) ? 2 : 1;
James Zern's avatar
James Zern committed
952 953 954
#else
    global->passes = 1;
#endif
955
  }
956

957 958 959 960
  if (global->deadline == VPX_DL_REALTIME &&
      global->passes > 1) {
    warn("Enforcing one-pass encoding in realtime mode\n");
    global->passes = 1;
961
  }
962 963 964
}


965
static void open_input_file(struct VpxInputContext *input) {
966
  /* Parse certain options from the input file, if possible */
967 968
  input->file = strcmp(input->filename, "-")
      ? fopen(input->filename, "rb") : set_binary_mode(stdin);
969 970 971

  if (!input->file)
    fatal("Failed to open input file");
John Koleszar's avatar
John Koleszar committed
972

973 974 975 976 977 978 979 980
  if (!fseeko(input->file, 0, SEEK_END)) {
    /* Input file is seekable. Figure out how long it is, so we can get
     * progress info.
     */
    input->length = ftello(input->file);
    rewind(input->file);
  }

981 982 983 984
  /* Default to 1:1 pixel aspect ratio. */
  input->pixel_aspect_ratio.numerator = 1;
  input->pixel_aspect_ratio.denominator = 1;

985 986 987 988 989 990 991
  /* For RAW input sources, these bytes will applied on the first frame
   *  in read_frame().
   */
  input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file);
  input->detect.position = 0;

  if (input->detect.buf_read == 4
992
      && file_is_y4m(input->detect.buf)) {
993 994
    if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4,
                       input->only_i420) >= 0) {
995
      input->file_type = FILE_TYPE_Y4M;
996 997
      input->width = input->y4m.pic_w;
      input->height = input->y4m.pic_h;
998 999
      input->pixel_aspect_ratio.numerator = input->y4m.par_n;
      input->pixel_aspect_ratio.denominator = input->y4m.par_d;
1000 1001
      input->framerate.numerator = input->y4m.fps_n;
      input->framerate.denominator = input->y4m.fps_d;
1002
      input->fmt = input->y4m.vpx_fmt;
1003
      input->bit_depth = input->y4m.bit_depth;
1004 1005
    } else
      fatal("Unsupported Y4M stream.");
1006
  } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) {
1007
    fatal("IVF is not supported as input.");
1008 1009
  } else {
    input->file_type = FILE_TYPE_RAW;
John Koleszar's avatar
John Koleszar committed
1010
  }
1011 1012 1013
}


1014
static void close_input_file(struct VpxInputContext *input) {
1015 1016 1017
  fclose(input->file);
  if (input->file_type == FILE_TYPE_Y4M)
    y4m_input_close(&input->y4m);
1018 1019
}

1020
static struct stream_state *new_stream(struct VpxEncoderConfig *global,
1021
                                       struct stream_state *prev) {
1022 1023 1024
  struct stream_state *stream;

  stream = calloc(1, sizeof(*stream));
1025
  if (stream == NULL) {
1026
    fatal("Failed to allocate new stream.");
1027 1028
  }

1029 1030 1031 1032 1033 1034 1035 1036
  if (prev) {
    memcpy(stream, prev, sizeof(*stream));
    stream->index++;
    prev->next = stream;
  } else {
    vpx_codec_err_t  res;

    /* Populate encoder configuration */
1037
    res = vpx_codec_enc_config_default(global->codec->codec_interface(),
1038 1039 1040 1041
                                       &stream->config.cfg,
                                       global->usage);
    if (res)
      fatal("Failed to get config: %s\n", vpx_codec_err_to_string(res));
John Koleszar's avatar
John Koleszar committed
1042

1043 1044 1045 1046
    /* Change the default timebase to a high enough value so that the
     * encoder will always create strictly increasing timestamps.
     */
    stream->config.cfg.g_timebase.den = 1000;
1047

1048 1049 1050 1051 1052
    /* Never use the library's default resolution, require it be parsed
     * from the file or set on the command line.
     */
    stream->config.cfg.g_w = 0;
    stream->config.cfg.g_h = 0;
John Koleszar's avatar
John Koleszar committed
1053

1054 1055
    /* Initialize remaining stream parameters */
    stream->config.write_webm = 1;
1056
#if CONFIG_WEBM_IO
1057
    stream->config.stereo_fmt = STEREO_FORMAT_MONO;
1058 1059 1060
    stream->ebml.last_pts_ns = -1;
    stream->ebml.writer = NULL;
    stream->ebml.segment = NULL;
1061
#endif
John Koleszar's avatar
John Koleszar committed
1062

1063 1064
    /* Allows removal of the application version from the EBML tags */
    stream->ebml.debug = global->debug;
1065 1066 1067 1068

    /* Default lag_in_frames is 0 in realtime mode */
    if (global->deadline == VPX_DL_REALTIME)
      stream->config.cfg.g_lag_in_frames = 0;
John Koleszar's avatar
John Koleszar committed
1069
  }
John Koleszar's avatar
John Koleszar committed
1070

1071 1072
  /* Output files must be specified for each stream */
  stream->config.out_fn = NULL;
John Koleszar's avatar
John Koleszar committed
1073

1074 1075
  stream->next = NULL;
  return stream;
1076
}
John Koleszar's avatar
John Koleszar committed
1077

1078

1079
static int parse_stream_params(struct VpxEncoderConfig *global,
1080
                               struct stream_state  *stream,
1081 1082 1083 1084 1085 1086 1087
                               char **argv) {
  char                   **argi, **argj;
  struct arg               arg;
  static const arg_def_t **ctrl_args = no_args;
  static const int        *ctrl_args_map = NULL;
  struct stream_config    *config = &stream->config;
  int                      eos_mark_found = 0;
1088
#if CONFIG_VP9_HIGHBITDEPTH
1089 1090
  int                      test_16bit_internal = 0;
#endif
1091

1092
  // Handle codec specific options
1093 1094
  if (0) {
#if CONFIG_VP8_ENCODER
1095
  } else if (strcmp(global->codec->name, "vp8") == 0) {
1096 1097
    ctrl_args = vp8_args;
    ctrl_args_map = vp8_arg_ctrl_map;
1098 1099
#endif
#if CONFIG_VP9_ENCODER
1100
  } else if (strcmp(global->codec->name, "vp9") == 0) {
1101 1102
    ctrl_args = vp9_args;
    ctrl_args_map = vp9_arg_ctrl_map;
1103 1104 1105 1106 1107
#endif
#if CONFIG_VP10_ENCODER
  } else if (strcmp(global->codec->name, "vp10") == 0) {
    // TODO(jingning): Reuse VP9 specific encoder configuration parameters.
    // Consider to expand this set for VP10 encoder control.
hui su's avatar
hui su committed
1108 1109
    ctrl_args = vp10_args;
    ctrl_args_map = vp10_arg_ctrl_map;
1110
#endif
1111
  }
1112

John Koleszar's avatar
John Koleszar committed
1113 1114
  for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
    arg.argv_step = 1;
John Koleszar's avatar
John Koleszar committed
1115

1116 1117 1118 1119 1120 1121 1122 1123 1124 1125
    /* Once we've found an end-of-stream marker (--) we want to continue
     * shifting arguments but not consuming them.
     */
    if (eos_mark_found) {
      argj++;
      continue;
    } else if (!strcmp(*argj, "--")) {
      eos_mark_found = 1;
      continue;
    }
John Koleszar's avatar
John Koleszar committed
1126

Adrian Grange's avatar
Adrian Grange committed
1127
    if (arg_match(&arg, &outputfile, argi)) {
1128
      config->out_fn = arg.val;
1129
    } else if (arg_match(&arg, &fpf_name, argi)) {
1130
      config->stats_fn = arg.val;
1131 1132 1133
#if CONFIG_FP_MB_STATS
    } else if (arg_match(&arg, &fpmbf_name, argi)) {
      config->fpmb_stats_fn = arg.val;
1134 1135 1136 1137 1138 1139
#endif
    } else if (arg_match(&arg, &use_webm, argi)) {
#if CONFIG_WEBM_IO
      config->write_webm = 1;
#else
      die("Error: --webm specified but webm is disabled.");
1140
#endif
1141
    } else if (arg_match(&arg, &use_ivf, argi)) {
1142
      config->write_webm = 0;
1143
    } else if (arg_match(&arg, &threads, argi)) {
1144
      config->cfg.g_threads = arg_parse_uint(&arg);
1145
    } else if (arg_match(&arg, &profile, argi)) {
1146
      config->cfg.g_profile = arg_parse_uint(&arg);
1147
    } else if (arg_match(&arg, &width, argi)) {
1148
      config->cfg.g_w = arg_parse_uint(&arg);
1149
    } else if (arg_match(&arg, &height, argi)) {
1150
      config->cfg.g_h = arg_parse_uint(&arg);
1151
#if CONFIG_VP9_HIGHBITDEPTH
1152 1153 1154 1155 1156
    } else if (arg_match(&arg, &bitdeptharg, argi)) {
      config->cfg.g_bit_depth = arg_parse_enum_or_int(&arg);
    } else if (arg_match(&arg, &inbitdeptharg, argi)) {
      config->cfg.g_input_bit_depth = arg_parse_uint(&arg);
#endif
1157
#if CONFIG_WEBM_IO
1158
    } else if (arg_match(&arg, &stereo_mode, argi)) {
1159
      config->stereo_fmt = arg_parse_enum_or_int(&arg);
1160
#endif
1161
    } else if (arg_match(&arg, &timebase, argi)) {
1162 1163
      config->cfg.g_timebase = arg_parse_rational(&arg);
      validate_positive_rational(arg.name, &config->cfg.g_timebase);
1164
    } else if (arg_match(&arg, &error_resilient, argi)) {
1165
      config->cfg.g_error_resilient = arg_parse_uint(&arg);
1166
    } else if (arg_match(&arg, &lag_in_frames, argi)) {
1167
      config->cfg.g_lag_in_frames = arg_parse_uint(&arg);
1168 1169 1170 1171 1172 1173
      if (global->deadline == VPX_DL_REALTIME &&
          config->cfg.g_lag_in_frames != 0) {
        warn("non-zero %s option ignored in realtime mode.\n", arg.name);
        config->cfg.g_lag_in_frames = 0;
      }
    } else if (arg_match(&arg, &dropframe_thresh, argi)) {
1174
      config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
1175
    } else if (arg_match(&arg, &resize_allowed, argi)) {
1176
      config->cfg.rc_resize_allowed = arg_parse_uint(&arg);
1177 1178 1179 1180
    } else if (arg_match(&arg, &resize_width, argi)) {
      config->cfg.rc_scaled_width = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &resize_height, argi)) {
      config->cfg.rc_scaled_height = arg_parse_uint(&arg);
1181
    } else if (arg_match(&arg, &resize_up_thresh, argi)) {
1182
      config->cfg.rc_resize_up_thresh = arg_parse_uint(&arg);
1183
    } else if (arg_match(&arg, &resize_down_thresh, argi)) {
1184
      config->cfg.rc_resize_down_thresh = arg_parse_uint(&arg);
1185
    } else if (arg_match(&arg, &end_usage, argi)) {
1186
      config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg);
1187
    } else if (arg_match(&arg, &target_bitrate, argi)) {