2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
4 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
13 #include "./aom_config.h"
24 #include "third_party/libyuv/include/libyuv/scale.h"
27 #include "aom/aom_encoder.h"
28 #if CONFIG_AV1_DECODER
29 #include "aom/aom_decoder.h"
34 #include "./tools_common.h"
35 #include "examples/encoder_util.h"
37 #if CONFIG_AV1_ENCODER
38 #include "aom/aomcx.h"
40 #if CONFIG_AV1_DECODER
41 #include "aom/aomdx.h"
44 #include "./aomstats.h"
45 #include "./rate_hist.h"
46 #include "./warnings.h"
47 #include "aom/aom_integer.h"
48 #include "aom_dsp/aom_dsp_common.h"
49 #include "aom_ports/aom_timer.h"
50 #include "aom_ports/mem_ops.h"
52 #include "./webmenc.h"
54 #include "./y4minput.h"
56 /* Swallow warnings about unused results of fread/fwrite */
57 static size_t wrap_fread(void *ptr
, size_t size
, size_t nmemb
, FILE *stream
) {
58 return fread(ptr
, size
, nmemb
, stream
);
60 #define fread wrap_fread
62 static size_t wrap_fwrite(const void *ptr
, size_t size
, size_t nmemb
,
64 return fwrite(ptr
, size
, nmemb
, stream
);
66 #define fwrite wrap_fwrite
68 static const char *exec_name
;
70 static void warn_or_exit_on_errorv(aom_codec_ctx_t
*ctx
, int fatal
,
71 const char *s
, va_list ap
) {
73 const char *detail
= aom_codec_error_detail(ctx
);
75 vfprintf(stderr
, s
, ap
);
76 fprintf(stderr
, ": %s\n", aom_codec_error(ctx
));
78 if (detail
) fprintf(stderr
, " %s\n", detail
);
80 if (fatal
) exit(EXIT_FAILURE
);
84 static void ctx_exit_on_error(aom_codec_ctx_t
*ctx
, const char *s
, ...) {
88 warn_or_exit_on_errorv(ctx
, 1, s
, ap
);
92 static void warn_or_exit_on_error(aom_codec_ctx_t
*ctx
, int fatal
,
97 warn_or_exit_on_errorv(ctx
, fatal
, s
, ap
);
101 static int read_frame(struct AvxInputContext
*input_ctx
, aom_image_t
*img
) {
102 FILE *f
= input_ctx
->file
;
103 y4m_input
*y4m
= &input_ctx
->y4m
;
106 if (input_ctx
->file_type
== FILE_TYPE_Y4M
) {
107 if (y4m_input_fetch_frame(y4m
, f
, img
) < 1) return 0;
109 shortread
= read_yuv_frame(input_ctx
, img
);
115 static int file_is_y4m(const char detect
[4]) {
116 if (memcmp(detect
, "YUV4", 4) == 0) {
122 static int fourcc_is_ivf(const char detect
[4]) {
123 if (memcmp(detect
, "DKIF", 4) == 0) {
129 static const arg_def_t debugmode
=
130 ARG_DEF("D", "debug", 0, "Debug mode (makes output deterministic)");
131 static const arg_def_t outputfile
=
132 ARG_DEF("o", "output", 1, "Output filename");
133 static const arg_def_t use_yv12
=
134 ARG_DEF(NULL
, "yv12", 0, "Input file is YV12 ");
135 static const arg_def_t use_i420
=
136 ARG_DEF(NULL
, "i420", 0, "Input file is I420 (default)");
137 static const arg_def_t use_i422
=
138 ARG_DEF(NULL
, "i422", 0, "Input file is I422");
139 static const arg_def_t use_i444
=
140 ARG_DEF(NULL
, "i444", 0, "Input file is I444");
141 static const arg_def_t use_i440
=
142 ARG_DEF(NULL
, "i440", 0, "Input file is I440");
143 static const arg_def_t codecarg
= ARG_DEF(NULL
, "codec", 1, "Codec to use");
144 static const arg_def_t passes
=
145 ARG_DEF("p", "passes", 1, "Number of passes (1/2)");
146 static const arg_def_t pass_arg
=
147 ARG_DEF(NULL
, "pass", 1, "Pass to execute (1/2)");
148 static const arg_def_t fpf_name
=
149 ARG_DEF(NULL
, "fpf", 1, "First pass statistics file name");
150 #if CONFIG_FP_MB_STATS
151 static const arg_def_t fpmbf_name
=
152 ARG_DEF(NULL
, "fpmbf", 1, "First pass block statistics file name");
154 static const arg_def_t limit
=
155 ARG_DEF(NULL
, "limit", 1, "Stop encoding after n input frames");
156 static const arg_def_t skip
=
157 ARG_DEF(NULL
, "skip", 1, "Skip the first n input frames");
158 static const arg_def_t deadline
=
159 ARG_DEF("d", "deadline", 1, "Deadline per frame (usec)");
160 static const arg_def_t good_dl
=
161 ARG_DEF(NULL
, "good", 0, "Use Good Quality Deadline");
162 static const arg_def_t quietarg
=
163 ARG_DEF("q", "quiet", 0, "Do not print encode progress");
164 static const arg_def_t verbosearg
=
165 ARG_DEF("v", "verbose", 0, "Show encoder parameters");
166 static const arg_def_t psnrarg
=
167 ARG_DEF(NULL
, "psnr", 0, "Show PSNR in status line");
169 static const struct arg_enum_list test_decode_enum
[] = {
170 { "off", TEST_DECODE_OFF
},
171 { "fatal", TEST_DECODE_FATAL
},
172 { "warn", TEST_DECODE_WARN
},
175 static const arg_def_t recontest
= ARG_DEF_ENUM(
176 NULL
, "test-decode", 1, "Test encode/decode mismatch", test_decode_enum
);
177 static const arg_def_t framerate
=
178 ARG_DEF(NULL
, "fps", 1, "Stream frame rate (rate/scale)");
179 static const arg_def_t use_webm
=
180 ARG_DEF(NULL
, "webm", 0, "Output WebM (default when WebM IO is enabled)");
181 static const arg_def_t use_ivf
= ARG_DEF(NULL
, "ivf", 0, "Output IVF");
182 static const arg_def_t out_part
=
183 ARG_DEF("P", "output-partitions", 0,
184 "Makes encoder output partitions. Requires IVF output!");
185 static const arg_def_t q_hist_n
=
186 ARG_DEF(NULL
, "q-hist", 1, "Show quantizer histogram (n-buckets)");
187 static const arg_def_t rate_hist_n
=
188 ARG_DEF(NULL
, "rate-hist", 1, "Show rate histogram (n-buckets)");
189 static const arg_def_t disable_warnings
=
190 ARG_DEF(NULL
, "disable-warnings", 0,
191 "Disable warnings about potentially incorrect encode settings.");
192 static const arg_def_t disable_warning_prompt
=
193 ARG_DEF("y", "disable-warning-prompt", 0,
194 "Display warnings, but do not prompt user to continue.");
196 #if CONFIG_HIGHBITDEPTH
197 static const struct arg_enum_list bitdepth_enum
[] = {
198 { "8", AOM_BITS_8
}, { "10", AOM_BITS_10
}, { "12", AOM_BITS_12
}, { NULL
, 0 }
201 static const arg_def_t bitdeptharg
= ARG_DEF_ENUM(
203 "Bit depth for codec (8 for version <=1, 10 or 12 for version 2)",
205 static const arg_def_t inbitdeptharg
=
206 ARG_DEF(NULL
, "input-bit-depth", 1, "Bit depth of input");
209 static const arg_def_t
*main_args
[] = { &debugmode
,
228 &disable_warning_prompt
,
232 static const arg_def_t usage
=
233 ARG_DEF("u", "usage", 1, "Usage profile number to use");
234 static const arg_def_t threads
=
235 ARG_DEF("t", "threads", 1, "Max number of threads to use");
236 static const arg_def_t profile
=
237 ARG_DEF(NULL
, "profile", 1, "Bitstream profile number to use");
238 static const arg_def_t width
= ARG_DEF("w", "width", 1, "Frame width");
239 static const arg_def_t height
= ARG_DEF("h", "height", 1, "Frame height");
241 static const struct arg_enum_list stereo_mode_enum
[] = {
242 { "mono", STEREO_FORMAT_MONO
},
243 { "left-right", STEREO_FORMAT_LEFT_RIGHT
},
244 { "bottom-top", STEREO_FORMAT_BOTTOM_TOP
},
245 { "top-bottom", STEREO_FORMAT_TOP_BOTTOM
},
246 { "right-left", STEREO_FORMAT_RIGHT_LEFT
},
249 static const arg_def_t stereo_mode
= ARG_DEF_ENUM(
250 NULL
, "stereo-mode", 1, "Stereo 3D video format", stereo_mode_enum
);
252 static const arg_def_t timebase
= ARG_DEF(
253 NULL
, "timebase", 1, "Output timestamp precision (fractional seconds)");
254 static const arg_def_t error_resilient
=
255 ARG_DEF(NULL
, "error-resilient", 1, "Enable error resiliency features");
256 static const arg_def_t lag_in_frames
=
257 ARG_DEF(NULL
, "lag-in-frames", 1, "Max number of frames to lag");
259 static const arg_def_t large_scale_tile
=
260 ARG_DEF(NULL
, "large-scale-tile", 1,
261 "Large scale tile coding (0: off (default), 1: on)");
262 #endif // CONFIG_EXT_TILE
264 static const arg_def_t
*global_args
[] = { &use_yv12
,
280 #if CONFIG_HIGHBITDEPTH
286 #endif // CONFIG_EXT_TILE
289 static const arg_def_t dropframe_thresh
=
290 ARG_DEF(NULL
, "drop-frame", 1, "Temporal resampling threshold (buf %)");
291 static const arg_def_t resize_mode
=
292 ARG_DEF(NULL
, "resize-mode", 1, "Frame resize mode");
293 static const arg_def_t resize_denominator
=
294 ARG_DEF(NULL
, "resize-denominator", 1, "Frame resize denominator");
295 static const arg_def_t resize_kf_denominator
= ARG_DEF(
296 NULL
, "resize-kf-denominator", 1, "Frame resize keyframe denominator");
297 #if CONFIG_FRAME_SUPERRES
298 static const arg_def_t superres_mode
=
299 ARG_DEF(NULL
, "superres-mode", 1, "Frame super-resolution mode");
300 static const arg_def_t superres_denominator
= ARG_DEF(
301 NULL
, "superres-denominator", 1, "Frame super-resolution denominator");
302 static const arg_def_t superres_kf_denominator
=
303 ARG_DEF(NULL
, "superres-kf-denominator", 1,
304 "Frame super-resolution keyframe denominator");
305 static const arg_def_t superres_qthresh
= ARG_DEF(
306 NULL
, "superres-qthresh", 1, "Frame super-resolution qindex threshold");
307 static const arg_def_t superres_kf_qthresh
=
308 ARG_DEF(NULL
, "superres-kf-qthresh", 1,
309 "Frame super-resolution keyframe qindex threshold");
310 #endif // CONFIG_FRAME_SUPERRES
311 static const struct arg_enum_list end_usage_enum
[] = { { "vbr", AOM_VBR
},
316 static const arg_def_t end_usage
=
317 ARG_DEF_ENUM(NULL
, "end-usage", 1, "Rate control mode", end_usage_enum
);
318 static const arg_def_t target_bitrate
=
319 ARG_DEF(NULL
, "target-bitrate", 1, "Bitrate (kbps)");
320 static const arg_def_t min_quantizer
=
321 ARG_DEF(NULL
, "min-q", 1, "Minimum (best) quantizer");
322 static const arg_def_t max_quantizer
=
323 ARG_DEF(NULL
, "max-q", 1, "Maximum (worst) quantizer");
324 static const arg_def_t undershoot_pct
=
325 ARG_DEF(NULL
, "undershoot-pct", 1, "Datarate undershoot (min) target (%)");
326 static const arg_def_t overshoot_pct
=
327 ARG_DEF(NULL
, "overshoot-pct", 1, "Datarate overshoot (max) target (%)");
328 static const arg_def_t buf_sz
=
329 ARG_DEF(NULL
, "buf-sz", 1, "Client buffer size (ms)");
330 static const arg_def_t buf_initial_sz
=
331 ARG_DEF(NULL
, "buf-initial-sz", 1, "Client initial buffer size (ms)");
332 static const arg_def_t buf_optimal_sz
=
333 ARG_DEF(NULL
, "buf-optimal-sz", 1, "Client optimal buffer size (ms)");
334 static const arg_def_t
*rc_args
[] = { &dropframe_thresh
,
337 &resize_kf_denominator
,
338 #if CONFIG_FRAME_SUPERRES
340 &superres_denominator
,
341 &superres_kf_denominator
,
343 &superres_kf_qthresh
,
344 #endif // CONFIG_FRAME_SUPERRES
356 static const arg_def_t bias_pct
=
357 ARG_DEF(NULL
, "bias-pct", 1, "CBR/VBR bias (0=CBR, 100=VBR)");
358 static const arg_def_t minsection_pct
=
359 ARG_DEF(NULL
, "minsection-pct", 1, "GOP min bitrate (% of target)");
360 static const arg_def_t maxsection_pct
=
361 ARG_DEF(NULL
, "maxsection-pct", 1, "GOP max bitrate (% of target)");
362 static const arg_def_t
*rc_twopass_args
[] = { &bias_pct
, &minsection_pct
,
363 &maxsection_pct
, NULL
};
365 static const arg_def_t kf_min_dist
=
366 ARG_DEF(NULL
, "kf-min-dist", 1, "Minimum keyframe interval (frames)");
367 static const arg_def_t kf_max_dist
=
368 ARG_DEF(NULL
, "kf-max-dist", 1, "Maximum keyframe interval (frames)");
369 static const arg_def_t kf_disabled
=
370 ARG_DEF(NULL
, "disable-kf", 0, "Disable keyframe placement");
371 static const arg_def_t
*kf_args
[] = { &kf_min_dist
, &kf_max_dist
, &kf_disabled
,
374 static const arg_def_t noise_sens
=
375 ARG_DEF(NULL
, "noise-sensitivity", 1, "Noise sensitivity (frames to blur)");
376 static const arg_def_t sharpness
=
377 ARG_DEF(NULL
, "sharpness", 1, "Loop filter sharpness (0..7)");
378 static const arg_def_t static_thresh
=
379 ARG_DEF(NULL
, "static-thresh", 1, "Motion detection threshold");
380 static const arg_def_t auto_altref
=
381 ARG_DEF(NULL
, "auto-alt-ref", 1, "Enable automatic alt reference frames");
382 static const arg_def_t arnr_maxframes
=
383 ARG_DEF(NULL
, "arnr-maxframes", 1, "AltRef max frames (0..15)");
384 static const arg_def_t arnr_strength
=
385 ARG_DEF(NULL
, "arnr-strength", 1, "AltRef filter strength (0..6)");
386 static const struct arg_enum_list tuning_enum
[] = {
387 { "psnr", AOM_TUNE_PSNR
},
388 { "ssim", AOM_TUNE_SSIM
},
389 #ifdef CONFIG_DIST_8X8
390 { "cdef-dist", AOM_TUNE_CDEF_DIST
},
391 { "daala-dist", AOM_TUNE_DAALA_DIST
},
395 static const arg_def_t tune_metric
=
396 ARG_DEF_ENUM(NULL
, "tune", 1, "Distortion metric tuned with", tuning_enum
);
397 static const arg_def_t cq_level
=
398 ARG_DEF(NULL
, "cq-level", 1, "Constant/Constrained Quality level");
399 static const arg_def_t max_intra_rate_pct
=
400 ARG_DEF(NULL
, "max-intra-rate", 1, "Max I-frame bitrate (pct)");
402 #if CONFIG_AV1_ENCODER
403 static const arg_def_t cpu_used_av1
=
404 ARG_DEF(NULL
, "cpu-used", 1, "CPU Used (0..8)");
406 static const arg_def_t single_tile_decoding
=
407 ARG_DEF(NULL
, "single-tile-decoding", 1,
408 "Single tile decoding (0: off (default), 1: on)");
409 #endif // CONFIG_EXT_TILE
410 static const arg_def_t tile_cols
=
411 ARG_DEF(NULL
, "tile-columns", 1, "Number of tile columns to use, log2");
412 static const arg_def_t tile_rows
=
413 ARG_DEF(NULL
, "tile-rows", 1,
414 "Number of tile rows to use, log2 (set to 0 while threads > 1)");
416 static const arg_def_t tile_width
=
417 ARG_DEF(NULL
, "tile-width", 1, "Tile widths (comma separated)");
418 static const arg_def_t tile_height
=
419 ARG_DEF(NULL
, "tile-height", 1, "Tile heights (command separated)");
421 #if CONFIG_DEPENDENT_HORZTILES
422 static const arg_def_t tile_dependent_rows
=
423 ARG_DEF(NULL
, "tile-dependent-rows", 1, "Enable dependent Tile rows");
425 #if CONFIG_LOOPFILTERING_ACROSS_TILES
426 static const arg_def_t tile_loopfilter
= ARG_DEF(
427 NULL
, "tile-loopfilter", 1, "Enable loop filter across tile boundary");
428 #endif // CONFIG_LOOPFILTERING_ACROSS_TILES
429 static const arg_def_t lossless
=
430 ARG_DEF(NULL
, "lossless", 1, "Lossless mode (0: false (default), 1: true)");
432 static const arg_def_t enable_qm
=
433 ARG_DEF(NULL
, "enable-qm", 1,
434 "Enable quantisation matrices (0: false (default), 1: true)");
435 static const arg_def_t qm_min
= ARG_DEF(
436 NULL
, "qm-min", 1, "Min quant matrix flatness (0..15), default is 8");
437 static const arg_def_t qm_max
= ARG_DEF(
438 NULL
, "qm-max", 1, "Max quant matrix flatness (0..15), default is 16");
441 static const arg_def_t enable_dist_8x8
=
442 ARG_DEF(NULL
, "enable-dist-8x8", 1,
443 "Enable dist-8x8 (0: false (default), 1: true)");
444 #endif // CONFIG_DIST_8X8
445 static const arg_def_t num_tg
= ARG_DEF(
446 NULL
, "num-tile-groups", 1, "Maximum number of tile groups, default is 1");
447 static const arg_def_t mtu_size
=
448 ARG_DEF(NULL
, "mtu-size", 1,
449 "MTU size for a tile group, default is 0 (no MTU targeting), "
450 "overrides maximum number of tile groups");
451 #if CONFIG_TEMPMV_SIGNALING
452 static const arg_def_t disable_tempmv
= ARG_DEF(
453 NULL
, "disable-tempmv", 1, "Disable temporal mv prediction (default is 0)");
455 static const arg_def_t frame_parallel_decoding
=
456 ARG_DEF(NULL
, "frame-parallel", 1,
457 "Enable frame parallel decodability features "
458 "(0: false (default), 1: true)");
459 #if !CONFIG_EXT_DELTA_Q
460 static const arg_def_t aq_mode
= ARG_DEF(
462 "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
463 "3: cyclic refresh, 4: delta quant)");
465 static const arg_def_t aq_mode
= ARG_DEF(
467 "Adaptive quantization mode (0: off (default), 1: variance 2: complexity, "
468 "3: cyclic refresh)");
470 #if CONFIG_EXT_DELTA_Q
471 static const arg_def_t deltaq_mode
= ARG_DEF(
472 NULL
, "deltaq-mode", 1,
473 "Delta qindex mode (0: off (default), 1: deltaq 2: deltaq + deltalf)");
475 static const arg_def_t frame_periodic_boost
=
476 ARG_DEF(NULL
, "frame-boost", 1,
477 "Enable frame periodic boost (0: off (default), 1: on)");
478 static const arg_def_t gf_cbr_boost_pct
= ARG_DEF(
479 NULL
, "gf-cbr-boost", 1, "Boost for Golden Frame in CBR mode (pct)");
480 static const arg_def_t max_inter_rate_pct
=
481 ARG_DEF(NULL
, "max-inter-rate", 1, "Max P-frame bitrate (pct)");
482 static const arg_def_t min_gf_interval
= ARG_DEF(
483 NULL
, "min-gf-interval", 1,
484 "min gf/arf frame interval (default 0, indicating in-built behavior)");
485 static const arg_def_t max_gf_interval
= ARG_DEF(
486 NULL
, "max-gf-interval", 1,
487 "max gf/arf frame interval (default 0, indicating in-built behavior)");
489 static const struct arg_enum_list color_space_enum
[] = {
490 { "unknown", AOM_CS_UNKNOWN
}, { "bt601", AOM_CS_BT_601
},
491 { "bt709", AOM_CS_BT_709
}, { "smpte170", AOM_CS_SMPTE_170
},
492 { "smpte240", AOM_CS_SMPTE_240
}, { "bt2020ncl", AOM_CS_BT_2020_NCL
},
493 { "bt2020cl", AOM_CS_BT_2020_CL
}, { "sRGB", AOM_CS_SRGB
},
494 { "ICtCp", AOM_CS_ICTCP
}, { NULL
, 0 }
497 static const arg_def_t input_color_space
=
498 ARG_DEF_ENUM(NULL
, "color-space", 1,
499 "The color space of input content:", color_space_enum
);
501 static const struct arg_enum_list transfer_function_enum
[] = {
502 { "unknown", AOM_TF_UNKNOWN
},
503 { "bt709", AOM_TF_BT_709
},
505 { "hlg", AOM_TF_HLG
},
509 static const arg_def_t input_transfer_function
= ARG_DEF_ENUM(
510 NULL
, "transfer-function", 1,
511 "The transfer function of input content:", transfer_function_enum
);
513 static const struct arg_enum_list chroma_sample_position_enum
[] = {
514 { "unknown", AOM_CSP_UNKNOWN
},
515 { "vertical", AOM_CSP_VERTICAL
},
516 { "colocated", AOM_CSP_COLOCATED
},
520 static const arg_def_t input_chroma_sample_position
=
521 ARG_DEF_ENUM(NULL
, "chroma-sample-position", 1,
522 "The chroma sample position when chroma 4:2:0 is signaled:",
523 chroma_sample_position_enum
);
525 static const struct arg_enum_list tune_content_enum
[] = {
526 { "default", AOM_CONTENT_DEFAULT
},
527 { "screen", AOM_CONTENT_SCREEN
},
531 static const arg_def_t tune_content
= ARG_DEF_ENUM(
532 NULL
, "tune-content", 1, "Tune content type", tune_content_enum
);
535 #if CONFIG_AV1_ENCODER
536 #if CONFIG_EXT_PARTITION
537 static const struct arg_enum_list superblock_size_enum
[] = {
538 { "dynamic", AOM_SUPERBLOCK_SIZE_DYNAMIC
},
539 { "64", AOM_SUPERBLOCK_SIZE_64X64
},
540 { "128", AOM_SUPERBLOCK_SIZE_128X128
},
543 static const arg_def_t superblock_size
= ARG_DEF_ENUM(
544 NULL
, "sb-size", 1, "Superblock size to use", superblock_size_enum
);
545 #endif // CONFIG_EXT_PARTITION
547 static const arg_def_t
*av1_args
[] = { &cpu_used_av1
,
552 &single_tile_decoding
,
553 #endif // CONFIG_EXT_TILE
556 #if CONFIG_DEPENDENT_HORZTILES
557 &tile_dependent_rows
,
559 #if CONFIG_LOOPFILTERING_ACROSS_TILES
561 #endif // CONFIG_LOOPFILTERING_ACROSS_TILES
578 &frame_parallel_decoding
,
580 #if CONFIG_EXT_DELTA_Q
583 &frame_periodic_boost
,
587 &input_transfer_function
,
588 &input_chroma_sample_position
,
591 #if CONFIG_EXT_PARTITION
593 #endif // CONFIG_EXT_PARTITION
596 #if CONFIG_TEMPMV_SIGNALING
599 #if CONFIG_HIGHBITDEPTH
602 #endif // CONFIG_HIGHBITDEPTH
604 static const int av1_arg_ctrl_map
[] = { AOME_SET_CPUUSED
,
605 AOME_SET_ENABLEAUTOALTREF
,
607 AOME_SET_STATIC_THRESHOLD
,
609 AV1E_SET_SINGLE_TILE_DECODING
,
610 #endif // CONFIG_EXT_TILE
611 AV1E_SET_TILE_COLUMNS
,
613 #if CONFIG_DEPENDENT_HORZTILES
614 AV1E_SET_TILE_DEPENDENT_ROWS
,
616 #if CONFIG_LOOPFILTERING_ACROSS_TILES
617 AV1E_SET_TILE_LOOPFILTER
,
618 #endif // CONFIG_LOOPFILTERING_ACROSS_TILES
619 AOME_SET_ARNR_MAXFRAMES
,
620 AOME_SET_ARNR_STRENGTH
,
623 AOME_SET_MAX_INTRA_BITRATE_PCT
,
624 AV1E_SET_MAX_INTER_BITRATE_PCT
,
625 AV1E_SET_GF_CBR_BOOST_PCT
,
633 AV1E_SET_ENABLE_DIST_8X8
,
635 AV1E_SET_FRAME_PARALLEL_DECODING
,
637 #if CONFIG_EXT_DELTA_Q
638 AV1E_SET_DELTAQ_MODE
,
640 AV1E_SET_FRAME_PERIODIC_BOOST
,
641 AV1E_SET_NOISE_SENSITIVITY
,
642 AV1E_SET_TUNE_CONTENT
,
643 AV1E_SET_COLOR_SPACE
,
644 AV1E_SET_TRANSFER_FUNCTION
,
645 AV1E_SET_CHROMA_SAMPLE_POSITION
,
646 AV1E_SET_MIN_GF_INTERVAL
,
647 AV1E_SET_MAX_GF_INTERVAL
,
648 #if CONFIG_EXT_PARTITION
649 AV1E_SET_SUPERBLOCK_SIZE
,
650 #endif // CONFIG_EXT_PARTITION
653 #if CONFIG_TEMPMV_SIGNALING
654 AV1E_SET_DISABLE_TEMPMV
,
659 static const arg_def_t
*no_args
[] = { NULL
};
661 void usage_exit(void) {
663 const int num_encoder
= get_aom_encoder_count();
665 fprintf(stderr
, "Usage: %s <options> -o dst_filename src_filename \n",
668 fprintf(stderr
, "\nOptions:\n");
669 arg_show_usage(stderr
, main_args
);
670 fprintf(stderr
, "\nEncoder Global Options:\n");
671 arg_show_usage(stderr
, global_args
);
672 fprintf(stderr
, "\nRate Control Options:\n");
673 arg_show_usage(stderr
, rc_args
);
674 fprintf(stderr
, "\nTwopass Rate Control Options:\n");
675 arg_show_usage(stderr
, rc_twopass_args
);
676 fprintf(stderr
, "\nKeyframe Placement Options:\n");
677 arg_show_usage(stderr
, kf_args
);
678 #if CONFIG_AV1_ENCODER
679 fprintf(stderr
, "\nAV1 Specific Options:\n");
680 arg_show_usage(stderr
, av1_args
);
683 "\nStream timebase (--timebase):\n"
684 " The desired precision of timestamps in the output, expressed\n"
685 " in fractional seconds. Default is 1/1000.\n");
686 fprintf(stderr
, "\nIncluded encoders:\n\n");
688 for (i
= 0; i
< num_encoder
; ++i
) {
689 const AvxInterface
*const encoder
= get_aom_encoder_by_index(i
);
690 const char *defstr
= (i
== (num_encoder
- 1)) ? "(default)" : "";
691 fprintf(stderr
, " %-6s - %s %s\n", encoder
->name
,
692 aom_codec_iface_name(encoder
->codec_interface()), defstr
);
694 fprintf(stderr
, "\n ");
695 fprintf(stderr
, "Use --codec to switch to a non-default encoder.\n\n");
700 #if CONFIG_AV1_ENCODER
701 #define ARG_CTRL_CNT_MAX NELEMENTS(av1_arg_ctrl_map)
705 typedef int stereo_format_t
;
706 struct WebmOutputContext
{
711 /* Per-stream configuration */
712 struct stream_config
{
713 struct aom_codec_enc_cfg cfg
;
715 const char *stats_fn
;
716 #if CONFIG_FP_MB_STATS
717 const char *fpmb_stats_fn
;
719 stereo_format_t stereo_fmt
;
720 int arg_ctrls
[ARG_CTRL_CNT_MAX
][2];
723 // whether to use 16bit internal buffers
724 int use_16bit_internal
;
727 struct stream_state
{
729 struct stream_state
*next
;
730 struct stream_config config
;
732 struct rate_hist
*rate_hist
;
733 struct WebmOutputContext webm_ctx
;
734 uint64_t psnr_sse_total
;
735 uint64_t psnr_samples_total
;
736 double psnr_totals
[4];
739 aom_codec_ctx_t encoder
;
740 unsigned int frames_out
;
744 #if CONFIG_FP_MB_STATS
745 stats_io_t fpmb_stats
;
747 struct aom_image
*img
;
748 aom_codec_ctx_t decoder
;
752 static void validate_positive_rational(const char *msg
,
753 struct aom_rational
*rat
) {
759 if (rat
->num
< 0) die("Error: %s must be positive\n", msg
);
761 if (!rat
->den
) die("Error: %s has zero denominator\n", msg
);
764 static void parse_global_config(struct AvxEncoderConfig
*global
, char **argv
) {
767 const int num_encoder
= get_aom_encoder_count();
769 if (num_encoder
< 1) die("Error: no valid encoder available\n");
771 /* Initialize default parameters */
772 memset(global
, 0, sizeof(*global
));
773 global
->codec
= get_aom_encoder_by_index(num_encoder
- 1);
775 global
->color_type
= I420
;
776 /* Assign default deadline to good quality */
777 global
->deadline
= AOM_DL_GOOD_QUALITY
;
779 for (argi
= argj
= argv
; (*argj
= *argi
); argi
+= arg
.argv_step
) {
782 if (arg_match(&arg
, &codecarg
, argi
)) {
783 global
->codec
= get_aom_encoder_by_name(arg
.val
);
785 die("Error: Unrecognized argument (%s) to --codec\n", arg
.val
);
786 } else if (arg_match(&arg
, &passes
, argi
)) {
787 global
->passes
= arg_parse_uint(&arg
);
789 if (global
->passes
< 1 || global
->passes
> 2)
790 die("Error: Invalid number of passes (%d)\n", global
->passes
);
791 } else if (arg_match(&arg
, &pass_arg
, argi
)) {
792 global
->pass
= arg_parse_uint(&arg
);
794 if (global
->pass
< 1 || global
->pass
> 2)
795 die("Error: Invalid pass selected (%d)\n", global
->pass
);
796 } else if (arg_match(&arg
, &usage
, argi
))
797 global
->usage
= arg_parse_uint(&arg
);
798 else if (arg_match(&arg
, &deadline
, argi
))
799 global
->deadline
= arg_parse_uint(&arg
);
800 else if (arg_match(&arg
, &good_dl
, argi
))
801 global
->deadline
= AOM_DL_GOOD_QUALITY
;
802 else if (arg_match(&arg
, &use_yv12
, argi
))
803 global
->color_type
= YV12
;
804 else if (arg_match(&arg
, &use_i420
, argi
))
805 global
->color_type
= I420
;
806 else if (arg_match(&arg
, &use_i422
, argi
))
807 global
->color_type
= I422
;
808 else if (arg_match(&arg
, &use_i444
, argi
))
809 global
->color_type
= I444
;
810 else if (arg_match(&arg
, &use_i440
, argi
))
811 global
->color_type
= I440
;
812 else if (arg_match(&arg
, &quietarg
, argi
))
814 else if (arg_match(&arg
, &verbosearg
, argi
))
816 else if (arg_match(&arg
, &limit
, argi
))
817 global
->limit
= arg_parse_uint(&arg
);
818 else if (arg_match(&arg
, &skip
, argi
))
819 global
->skip_frames
= arg_parse_uint(&arg
);
820 else if (arg_match(&arg
, &psnrarg
, argi
))
821 global
->show_psnr
= 1;
822 else if (arg_match(&arg
, &recontest
, argi
))
823 global
->test_decode
= arg_parse_enum_or_int(&arg
);
824 else if (arg_match(&arg
, &framerate
, argi
)) {
825 global
->framerate
= arg_parse_rational(&arg
);
826 validate_positive_rational(arg
.name
, &global
->framerate
);
827 global
->have_framerate
= 1;
828 } else if (arg_match(&arg
, &out_part
, argi
))
829 global
->out_part
= 1;
830 else if (arg_match(&arg
, &debugmode
, argi
))
832 else if (arg_match(&arg
, &q_hist_n
, argi
))
833 global
->show_q_hist_buckets
= arg_parse_uint(&arg
);
834 else if (arg_match(&arg
, &rate_hist_n
, argi
))
835 global
->show_rate_hist_buckets
= arg_parse_uint(&arg
);
836 else if (arg_match(&arg
, &disable_warnings
, argi
))
837 global
->disable_warnings
= 1;
838 else if (arg_match(&arg
, &disable_warning_prompt
, argi
))
839 global
->disable_warning_prompt
= 1;
845 /* DWIM: Assume the user meant passes=2 if pass=2 is specified */
846 if (global
->pass
> global
->passes
) {
847 warn("Assuming --pass=%d implies --passes=%d\n", global
->pass
,
849 global
->passes
= global
->pass
;
852 /* Validate global config */
853 if (global
->passes
== 0) {
854 #if CONFIG_AV1_ENCODER
855 // Make default AV1 passes = 2 until there is a better quality 1-pass
857 if (global
->codec
!= NULL
&& global
->codec
->name
!= NULL
)
858 global
->passes
= (strcmp(global
->codec
->name
, "av1") == 0) ? 2 : 1;
865 static void open_input_file(struct AvxInputContext
*input
) {
866 /* Parse certain options from the input file, if possible */
867 input
->file
= strcmp(input
->filename
, "-") ? fopen(input
->filename
, "rb")
868 : set_binary_mode(stdin
);
870 if (!input
->file
) fatal("Failed to open input file");
872 if (!fseeko(input
->file
, 0, SEEK_END
)) {
873 /* Input file is seekable. Figure out how long it is, so we can get
876 input
->length
= ftello(input
->file
);
880 /* Default to 1:1 pixel aspect ratio. */
881 input
->pixel_aspect_ratio
.numerator
= 1;
882 input
->pixel_aspect_ratio
.denominator
= 1;
884 /* For RAW input sources, these bytes will applied on the first frame
887 input
->detect
.buf_read
= fread(input
->detect
.buf
, 1, 4, input
->file
);
888 input
->detect
.position
= 0;
890 if (input
->detect
.buf_read
== 4 && file_is_y4m(input
->detect
.buf
)) {
891 if (y4m_input_open(&input
->y4m
, input
->file
, input
->detect
.buf
, 4,
892 input
->only_i420
) >= 0) {
893 input
->file_type
= FILE_TYPE_Y4M
;
894 input
->width
= input
->y4m
.pic_w
;
895 input
->height
= input
->y4m
.pic_h
;
896 input
->pixel_aspect_ratio
.numerator
= input
->y4m
.par_n
;
897 input
->pixel_aspect_ratio
.denominator
= input
->y4m
.par_d
;
898 input
->framerate
.numerator
= input
->y4m
.fps_n
;
899 input
->framerate
.denominator
= input
->y4m
.fps_d
;
900 input
->fmt
= input
->y4m
.aom_fmt
;
901 input
->bit_depth
= input
->y4m
.bit_depth
;
903 fatal("Unsupported Y4M stream.");
904 } else if (input
->detect
.buf_read
== 4 && fourcc_is_ivf(input
->detect
.buf
)) {
905 fatal("IVF is not supported as input.");
907 input
->file_type
= FILE_TYPE_RAW
;
911 static void close_input_file(struct AvxInputContext
*input
) {
913 if (input
->file_type
== FILE_TYPE_Y4M
) y4m_input_close(&input
->y4m
);
916 static struct stream_state
*new_stream(struct AvxEncoderConfig
*global
,
917 struct stream_state
*prev
) {
918 struct stream_state
*stream
;
920 stream
= calloc(1, sizeof(*stream
));
921 if (stream
== NULL
) {
922 fatal("Failed to allocate new stream.");
926 memcpy(stream
, prev
, sizeof(*stream
));
932 /* Populate encoder configuration */
933 res
= aom_codec_enc_config_default(global
->codec
->codec_interface(),
934 &stream
->config
.cfg
, global
->usage
);
935 if (res
) fatal("Failed to get config: %s\n", aom_codec_err_to_string(res
));
937 /* Change the default timebase to a high enough value so that the
938 * encoder will always create strictly increasing timestamps.
940 stream
->config
.cfg
.g_timebase
.den
= 1000;
942 /* Never use the library's default resolution, require it be parsed
943 * from the file or set on the command line.
945 stream
->config
.cfg
.g_w
= 0;
946 stream
->config
.cfg
.g_h
= 0;
948 /* Initialize remaining stream parameters */
949 stream
->config
.write_webm
= 1;
951 stream
->config
.stereo_fmt
= STEREO_FORMAT_MONO
;
952 stream
->webm_ctx
.last_pts_ns
= -1;
953 stream
->webm_ctx
.writer
= NULL
;
954 stream
->webm_ctx
.segment
= NULL
;
957 /* Allows removal of the application version from the EBML tags */
958 stream
->webm_ctx
.debug
= global
->debug
;
961 /* Output files must be specified for each stream */
962 stream
->config
.out_fn
= NULL
;
968 static int parse_stream_params(struct AvxEncoderConfig
*global
,
969 struct stream_state
*stream
, char **argv
) {
972 static const arg_def_t
**ctrl_args
= no_args
;
973 static const int *ctrl_args_map
= NULL
;
974 struct stream_config
*config
= &stream
->config
;
975 int eos_mark_found
= 0;
978 // Handle codec specific options
980 #if CONFIG_AV1_ENCODER
981 } else if (strcmp(global
->codec
->name
, "av1") == 0) {
982 // TODO(jingning): Reuse AV1 specific encoder configuration parameters.
983 // Consider to expand this set for AV1 encoder control.
984 ctrl_args
= av1_args
;
985 ctrl_args_map
= av1_arg_ctrl_map
;
989 for (argi
= argj
= argv
; (*argj
= *argi
); argi
+= arg
.argv_step
) {
992 /* Once we've found an end-of-stream marker (--) we want to continue
993 * shifting arguments but not consuming them.
995 if (eos_mark_found
) {
998 } else if (!strcmp(*argj
, "--")) {
1003 if (arg_match(&arg
, &outputfile
, argi
)) {
1004 config
->out_fn
= arg
.val
;
1006 const size_t out_fn_len
= strlen(config
->out_fn
);
1007 if (out_fn_len
>= 4 &&
1008 !strcmp(config
->out_fn
+ out_fn_len
- 4, ".ivf")) {
1009 config
->write_webm
= 0;
1012 } else if (arg_match(&arg
, &fpf_name
, argi
)) {
1013 config
->stats_fn
= arg
.val
;
1014 #if CONFIG_FP_MB_STATS
1015 } else if (arg_match(&arg
, &fpmbf_name
, argi
)) {
1016 config
->fpmb_stats_fn
= arg
.val
;
1018 } else if (arg_match(&arg
, &use_webm
, argi
)) {
1020 config
->write_webm
= 1;
1023 die("Error: --webm specified but webm is disabled.");
1025 } else if (arg_match(&arg
, &use_ivf
, argi
)) {
1026 config
->write_webm
= 0;
1027 } else if (arg_match(&arg
, &threads
, argi
)) {
1028 config
->cfg
.g_threads
= arg_parse_uint(&arg
);
1029 } else if (arg_match(&arg
, &profile
, argi
)) {
1030 config
->cfg
.g_profile
= arg_parse_uint(&arg
);
1031 } else if (arg_match(&arg
, &width
, argi
)) {
1032 config
->cfg
.g_w
= arg_parse_uint(&arg
);
1033 } else if (arg_match(&arg
, &height
, argi
)) {
1034 config
->cfg
.g_h
= arg_parse_uint(&arg
);
1035 #if CONFIG_HIGHBITDEPTH
1036 } else if (arg_match(&arg
, &bitdeptharg
, argi
)) {
1037 config
->cfg
.g_bit_depth
= arg_parse_enum_or_int(&arg
);
1038 } else if (arg_match(&arg
, &inbitdeptharg
, argi
)) {
1039 config
->cfg
.g_input_bit_depth
= arg_parse_uint(&arg
);
1042 } else if (arg_match(&arg
, &stereo_mode
, argi
)) {
1043 config
->stereo_fmt
= arg_parse_enum_or_int(&arg
);
1045 } else if (arg_match(&arg
, &timebase
, argi
)) {
1046 config
->cfg
.g_timebase
= arg_parse_rational(&arg
);
1047 validate_positive_rational(arg
.name
, &config
->cfg
.g_timebase
);
1048 } else if (arg_match(&arg
, &error_resilient
, argi
)) {
1049 config
->cfg
.g_error_resilient
= arg_parse_uint(&arg
);
1050 } else if (arg_match(&arg
, &lag_in_frames
, argi
)) {
1051 config
->cfg
.g_lag_in_frames
= arg_parse_uint(&arg
);
1053 } else if (arg_match(&arg
, &large_scale_tile
, argi
)) {
1054 config
->cfg
.large_scale_tile
= arg_parse_uint(&arg
);
1055 #endif // CONFIG_EXT_TILE
1056 } else if (arg_match(&arg
, &dropframe_thresh
, argi
)) {
1057 config
->cfg
.rc_dropframe_thresh
= arg_parse_uint(&arg
);
1058 } else if (arg_match(&arg
, &resize_mode
, argi
)) {
1059 config
->cfg
.rc_resize_mode
= arg_parse_uint(&arg
);
1060 } else if (arg_match(&arg
, &resize_denominator
, argi
)) {
1061 config
->cfg
.rc_resize_denominator
= arg_parse_uint(&arg
);
1062 } else if (arg_match(&arg
, &resize_kf_denominator
, argi
)) {
1063 config
->cfg
.rc_resize_kf_denominator
= arg_parse_uint(&arg
);
1064 #if CONFIG_FRAME_SUPERRES
1065 } else if (arg_match(&arg
, &superres_mode
, argi
)) {
1066 config
->cfg
.rc_superres_mode
= arg_parse_uint(&arg
);
1067 } else if (arg_match(&arg
, &superres_denominator
, argi
)) {
1068 config
->cfg
.rc_superres_denominator
= arg_parse_uint(&arg
);
1069 } else if (arg_match(&arg
, &superres_kf_denominator
, argi
)) {
1070 config
->cfg
.rc_superres_kf_denominator
= arg_parse_uint(&arg
);
1071 } else if (arg_match(&arg
, &superres_qthresh
, argi
)) {
1072 config
->cfg
.rc_superres_qthresh
= arg_parse_uint(&arg
);
1073 } else if (arg_match(&arg
, &superres_kf_qthresh
, argi
)) {
1074 config
->cfg
.rc_superres_kf_qthresh
= arg_parse_uint(&arg
);
1075 #endif // CONFIG_FRAME_SUPERRES
1076 } else if (arg_match(&arg
, &end_usage
, argi
)) {
1077 config
->cfg
.rc_end_usage
= arg_parse_enum_or_int(&arg
);
1078 } else if (arg_match(&arg
, &target_bitrate
, argi
)) {
1079 config
->cfg
.rc_target_bitrate
= arg_parse_uint(&arg
);
1080 } else if (arg_match(&arg
, &min_quantizer
, argi
)) {
1081 config
->cfg
.rc_min_quantizer
= arg_parse_uint(&arg
);
1082 } else if (arg_match(&arg
, &max_quantizer
, argi
)) {
1083 config
->cfg
.rc_max_quantizer
= arg_parse_uint(&arg
);
1084 } else if (arg_match(&arg
, &undershoot_pct
, argi
)) {
1085 config
->cfg
.rc_undershoot_pct
= arg_parse_uint(&arg
);
1086 } else if (arg_match(&arg
, &overshoot_pct
, argi
)) {
1087 config
->cfg
.rc_overshoot_pct
= arg_parse_uint(&arg
);
1088 } else if (arg_match(&arg
, &buf_sz
, argi
)) {
1089 config
->cfg
.rc_buf_sz
= arg_parse_uint(&arg
);
1090 } else if (arg_match(&arg
, &buf_initial_sz
, argi
)) {
1091 config
->cfg
.rc_buf_initial_sz
= arg_parse_uint(&arg
);
1092 } else if (arg_match(&arg
, &buf_optimal_sz
, argi
)) {
1093 config
->cfg
.rc_buf_optimal_sz
= arg_parse_uint(&arg
);
1094 } else if (arg_match(&arg
, &bias_pct
, argi
)) {
1095 config
->cfg
.rc_2pass_vbr_bias_pct
= arg_parse_uint(&arg
);
1096 if (global
->passes
< 2)
1097 warn("option %s ignored in one-pass mode.\n", arg
.name
);
1098 } else if (arg_match(&arg
, &minsection_pct
, argi
)) {
1099 config
->cfg
.rc_2pass_vbr_minsection_pct
= arg_parse_uint(&arg
);
1101 if (global
->passes
< 2)
1102 warn("option %s ignored in one-pass mode.\n", arg
.name
);
1103 } else if (arg_match(&arg
, &maxsection_pct
, argi
)) {
1104 config
->cfg
.rc_2pass_vbr_maxsection_pct
= arg_parse_uint(&arg
);
1106 if (global
->passes
< 2)
1107 warn("option %s ignored in one-pass mode.\n", arg
.name
);
1108 } else if (arg_match(&arg
, &kf_min_dist
, argi
)) {
1109 config
->cfg
.kf_min_dist
= arg_parse_uint(&arg
);
1110 } else if (arg_match(&arg
, &kf_max_dist
, argi
)) {
1111 config
->cfg
.kf_max_dist
= arg_parse_uint(&arg
);
1112 } else if (arg_match(&arg
, &kf_disabled
, argi
)) {
1113 config
->cfg
.kf_mode
= AOM_KF_DISABLED
;
1115 } else if (arg_match(&arg
, &tile_width
, argi
)) {
1116 config
->cfg
.tile_width_count
=
1117 arg_parse_list(&arg
, config
->cfg
.tile_widths
, MAX_TILE_WIDTHS
);
1118 } else if (arg_match(&arg
, &tile_height
, argi
)) {
1119 config
->cfg
.tile_height_count
=
1120 arg_parse_list(&arg
, config
->cfg
.tile_heights
, MAX_TILE_HEIGHTS
);
1124 for (i
= 0; ctrl_args
[i
]; i
++) {
1125 if (arg_match(&arg
, ctrl_args
[i
], argi
)) {
1129 /* Point either to the next free element or the first
1130 * instance of this control.
1132 for (j
= 0; j
< config
->arg_ctrl_cnt
; j
++)
1133 if (ctrl_args_map
!= NULL
&&
1134 config
->arg_ctrls
[j
][0] == ctrl_args_map
[i
])
1138 assert(j
< (int)ARG_CTRL_CNT_MAX
);
1139 if (ctrl_args_map
!= NULL
&& j
< (int)ARG_CTRL_CNT_MAX
) {
1140 config
->arg_ctrls
[j
][0] = ctrl_args_map
[i
];
1141 config
->arg_ctrls
[j
][1] = arg_parse_enum_or_int(&arg
);
1142 if (j
== config
->arg_ctrl_cnt
) config
->arg_ctrl_cnt
++;
1149 #if CONFIG_HIGHBITDEPTH
1150 config
->use_16bit_internal
=
1151 config
->cfg
.g_bit_depth
> AOM_BITS_8
|| !CONFIG_LOWBITDEPTH
;
1153 return eos_mark_found
;
1156 #define FOREACH_STREAM(iterator, list) \
1157 for (struct stream_state *iterator = list; iterator; \
1158 iterator = iterator->next)
1160 static void validate_stream_config(const struct stream_state
*stream
,
1161 const struct AvxEncoderConfig
*global
) {
1162 const struct stream_state
*streami
;
1165 if (!stream
->config
.cfg
.g_w
|| !stream
->config
.cfg
.g_h
)
1167 "Stream %d: Specify stream dimensions with --width (-w) "
1168 " and --height (-h)",
1171 // Check that the codec bit depth is greater than the input bit depth.
1172 if (stream
->config
.cfg
.g_input_bit_depth
>
1173 (unsigned int)stream
->config
.cfg
.g_bit_depth
) {
1174 fatal("Stream %d: codec bit depth (%d) less than input bit depth (%d)",
1175 stream
->index
, (int)stream
->config
.cfg
.g_bit_depth
,
1176 stream
->config
.cfg
.g_input_bit_depth
);
1179 for (streami
= stream
; streami
; streami
= streami
->next
) {
1180 /* All streams require output files */
1181 if (!streami
->config
.out_fn
)
1182 fatal("Stream %d: Output file is required (specify with -o)",
1185 /* Check for two streams outputting to the same file */
1186 if (streami
!= stream
) {
1187 const char *a
= stream
->config
.out_fn
;
1188 const char *b
= streami
->config
.out_fn
;
1189 if (!strcmp(a
, b
) && strcmp(a
, "/dev/null") && strcmp(a
, ":nul"))
1190 fatal("Stream %d: duplicate output file (from stream %d)",
1191 streami
->index
, stream
->index
);
1194 /* Check for two streams sharing a stats file. */
1195 if (streami
!= stream
) {
1196 const char *a
= stream
->config
.stats_fn
;
1197 const char *b
= streami
->config
.stats_fn
;
1198 if (a
&& b
&& !strcmp(a
, b
))
1199 fatal("Stream %d: duplicate stats file (from stream %d)",
1200 streami
->index
, stream
->index
);
1203 #if CONFIG_FP_MB_STATS
1204 /* Check for two streams sharing a mb stats file. */
1205 if (streami
!= stream
) {
1206 const char *a
= stream
->config
.fpmb_stats_fn
;
1207 const char *b
= streami
->config
.fpmb_stats_fn
;
1208 if (a
&& b
&& !strcmp(a
, b
))
1209 fatal("Stream %d: duplicate mb stats file (from stream %d)",
1210 streami
->index
, stream
->index
);
1216 static void set_stream_dimensions(struct stream_state
*stream
, unsigned int w
,
1218 if (!stream
->config
.cfg
.g_w
) {
1219 if (!stream
->config
.cfg
.g_h
)
1220 stream
->config
.cfg
.g_w
= w
;
1222 stream
->config
.cfg
.g_w
= w
* stream
->config
.cfg
.g_h
/ h
;
1224 if (!stream
->config
.cfg
.g_h
) {
1225 stream
->config
.cfg
.g_h
= h
* stream
->config
.cfg
.g_w
/ w
;
1229 static const char *file_type_to_string(enum VideoFileType t
) {
1231 case FILE_TYPE_RAW
: return "RAW";
1232 case FILE_TYPE_Y4M
: return "Y4M";
1233 default: return "Other";
1237 static const char *image_format_to_string(aom_img_fmt_t f
) {
1239 case AOM_IMG_FMT_I420
: return "I420";
1240 case AOM_IMG_FMT_I422
: return "I422";
1241 case AOM_IMG_FMT_I444
: return "I444";
1242 case AOM_IMG_FMT_I440
: return "I440";
1243 case AOM_IMG_FMT_YV12
: return "YV12";
1244 case AOM_IMG_FMT_I42016
: return "I42016";
1245 case AOM_IMG_FMT_I42216
: return "I42216";
1246 case AOM_IMG_FMT_I44416
: return "I44416";
1247 case AOM_IMG_FMT_I44016
: return "I44016";
1248 default: return "Other";
1252 static void show_stream_config(struct stream_state
*stream
,
1253 struct AvxEncoderConfig
*global
,
1254 struct AvxInputContext
*input
) {
1255 #define SHOW(field) \
1256 fprintf(stderr, " %-28s = %d\n", #field, stream->config.cfg.field)
1258 if (stream
->index
== 0) {
1259 fprintf(stderr
, "Codec: %s\n",
1260 aom_codec_iface_name(global
->codec
->codec_interface()));
1261 fprintf(stderr
, "Source file: %s File Type: %s Format: %s\n",
1262 input
->filename
, file_type_to_string(input
->file_type
),
1263 image_format_to_string(input
->fmt
));
1265 if (stream
->next
|| stream
->index
)
1266 fprintf(stderr
, "\nStream Index: %d\n", stream
->index
);
1267 fprintf(stderr
, "Destination file: %s\n", stream
->config
.out_fn
);
1268 fprintf(stderr
, "Coding path: %s\n",
1269 stream
->config
.use_16bit_internal
? "HBD" : "LBD");
1270 fprintf(stderr
, "Encoder parameters:\n");
1278 SHOW(g_input_bit_depth
);
1279 SHOW(g_timebase
.num
);
1280 SHOW(g_timebase
.den
);
1281 SHOW(g_error_resilient
);
1283 SHOW(g_lag_in_frames
);
1285 SHOW(large_scale_tile
);
1286 #endif // CONFIG_EXT_TILE
1287 SHOW(rc_dropframe_thresh
);
1288 SHOW(rc_resize_mode
);
1289 SHOW(rc_resize_denominator
);
1290 SHOW(rc_resize_kf_denominator
);
1291 #if CONFIG_FRAME_SUPERRES
1292 SHOW(rc_superres_mode
);
1293 SHOW(rc_superres_denominator
);
1294 SHOW(rc_superres_kf_denominator
);
1295 SHOW(rc_superres_qthresh
);
1296 SHOW(rc_superres_kf_qthresh
);
1297 #endif // CONFIG_FRAME_SUPERRES
1299 SHOW(rc_target_bitrate
);
1300 SHOW(rc_min_quantizer
);
1301 SHOW(rc_max_quantizer
);
1302 SHOW(rc_undershoot_pct
);
1303 SHOW(rc_overshoot_pct
);
1305 SHOW(rc_buf_initial_sz
);
1306 SHOW(rc_buf_optimal_sz
);
1307 SHOW(rc_2pass_vbr_bias_pct
);
1308 SHOW(rc_2pass_vbr_minsection_pct
);
1309 SHOW(rc_2pass_vbr_maxsection_pct
);
1315 static void open_output_file(struct stream_state
*stream
,
1316 struct AvxEncoderConfig
*global
,
1317 const struct AvxRational
*pixel_aspect_ratio
) {
1318 const char *fn
= stream
->config
.out_fn
;
1319 const struct aom_codec_enc_cfg
*const cfg
= &stream
->config
.cfg
;
1321 if (cfg
->g_pass
== AOM_RC_FIRST_PASS
) return;
1323 stream
->file
= strcmp(fn
, "-") ? fopen(fn
, "wb") : set_binary_mode(stdout
);
1325 if (!stream
->file
) fatal("Failed to open output file");
1327 if (stream
->config
.write_webm
&& fseek(stream
->file
, 0, SEEK_CUR
))
1328 fatal("WebM output to pipes not supported.");
1331 if (stream
->config
.write_webm
) {
1332 stream
->webm_ctx
.stream
= stream
->file
;
1333 write_webm_file_header(&stream
->webm_ctx
, cfg
, stream
->config
.stereo_fmt
,
1334 global
->codec
->fourcc
, pixel_aspect_ratio
);
1337 (void)pixel_aspect_ratio
;
1340 if (!stream
->config
.write_webm
) {
1341 ivf_write_file_header(stream
->file
, cfg
, global
->codec
->fourcc
, 0);
1345 static void close_output_file(struct stream_state
*stream
,
1346 unsigned int fourcc
) {
1347 const struct aom_codec_enc_cfg
*const cfg
= &stream
->config
.cfg
;
1349 if (cfg
->g_pass
== AOM_RC_FIRST_PASS
) return;
1352 if (stream
->config
.write_webm
) {
1353 write_webm_file_footer(&stream
->webm_ctx
);
1357 if (!stream
->config
.write_webm
) {
1358 if (!fseek(stream
->file
, 0, SEEK_SET
))
1359 ivf_write_file_header(stream
->file
, &stream
->config
.cfg
, fourcc
,
1360 stream
->frames_out
);
1363 fclose(stream
->file
);
1366 static void setup_pass(struct stream_state
*stream
,
1367 struct AvxEncoderConfig
*global
, int pass
) {
1368 if (stream
->config
.stats_fn
) {
1369 if (!stats_open_file(&stream
->stats
, stream
->config
.stats_fn
, pass
))
1370 fatal("Failed to open statistics store");
1372 if (!stats_open_mem(&stream
->stats
, pass
))
1373 fatal("Failed to open statistics store");
1376 #if CONFIG_FP_MB_STATS
1377 if (stream
->config
.fpmb_stats_fn
) {
1378 if (!stats_open_file(&stream
->fpmb_stats
, stream
->config
.fpmb_stats_fn
,
1380 fatal("Failed to open mb statistics store");
1382 if (!stats_open_mem(&stream
->fpmb_stats
, pass
))
1383 fatal("Failed to open mb statistics store");
1387 stream
->config
.cfg
.g_pass
= global
->passes
== 2
1388 ? pass
? AOM_RC_LAST_PASS
: AOM_RC_FIRST_PASS
1391 stream
->config
.cfg
.rc_twopass_stats_in
= stats_get(&stream
->stats
);
1392 #if CONFIG_FP_MB_STATS
1393 stream
->config
.cfg
.rc_firstpass_mb_stats_in
=
1394 stats_get(&stream
->fpmb_stats
);
1398 stream
->cx_time
= 0;
1400 stream
->frames_out
= 0;
1403 static void initialize_encoder(struct stream_state
*stream
,
1404 struct AvxEncoderConfig
*global
) {
1408 flags
|= global
->show_psnr
? AOM_CODEC_USE_PSNR
: 0;
1409 flags
|= global
->out_part
? AOM_CODEC_USE_OUTPUT_PARTITION
: 0;
1410 #if CONFIG_HIGHBITDEPTH
1411 flags
|= stream
->config
.use_16bit_internal
? AOM_CODEC_USE_HIGHBITDEPTH
: 0;
1414 /* Construct Encoder Context */
1415 aom_codec_enc_init(&stream
->encoder
, global
->codec
->codec_interface(),
1416 &stream
->config
.cfg
, flags
);
1417 ctx_exit_on_error(&stream
->encoder
, "Failed to initialize encoder");
1419 /* Note that we bypass the aom_codec_control wrapper macro because
1420 * we're being clever to store the control IDs in an array. Real
1421 * applications will want to make use of the enumerations directly
1423 for (i
= 0; i
< stream
->config
.arg_ctrl_cnt
; i
++) {
1424 int ctrl
= stream
->config
.arg_ctrls
[i
][0];
1425 int value
= stream
->config
.arg_ctrls
[i
][1];
1426 if (aom_codec_control_(&stream
->encoder
, ctrl
, value
))
1427 fprintf(stderr
, "Error: Tried to set control %d = %d\n", ctrl
, value
);
1429 ctx_exit_on_error(&stream
->encoder
, "Failed to control codec");
1432 #if CONFIG_AV1_DECODER
1433 if (global
->test_decode
!= TEST_DECODE_OFF
) {
1434 const AvxInterface
*decoder
= get_aom_decoder_by_name(global
->codec
->name
);
1435 aom_codec_dec_cfg_t cfg
= { 0, 0, 0, CONFIG_LOWBITDEPTH
};
1436 aom_codec_dec_init(&stream
->decoder
, decoder
->codec_interface(), &cfg
, 0);
1439 if (strcmp(global
->codec
->name
, "av1") == 0) {
1440 aom_codec_control(&stream
->decoder
, AV1_SET_DECODE_TILE_ROW
, -1);
1441 ctx_exit_on_error(&stream
->decoder
, "Failed to set decode_tile_row");
1443 aom_codec_control(&stream
->decoder
, AV1_SET_DECODE_TILE_COL
, -1);
1444 ctx_exit_on_error(&stream
->decoder
, "Failed to set decode_tile_col");
1446 #endif // CONFIG_EXT_TILE
1451 static void encode_frame(struct stream_state
*stream
,
1452 struct AvxEncoderConfig
*global
, struct aom_image
*img
,
1453 unsigned int frames_in
) {
1454 aom_codec_pts_t frame_start
, next_frame_start
;
1455 struct aom_codec_enc_cfg
*cfg
= &stream
->config
.cfg
;
1456 struct aom_usec_timer timer
;
1459 (cfg
->g_timebase
.den
* (int64_t)(frames_in
- 1) * global
->framerate
.den
) /
1460 cfg
->g_timebase
.num
/ global
->framerate
.num
;
1462 (cfg
->g_timebase
.den
* (int64_t)(frames_in
)*global
->framerate
.den
) /
1463 cfg
->g_timebase
.num
/ global
->framerate
.num
;
1465 /* Scale if necessary */
1466 #if CONFIG_HIGHBITDEPTH
1468 if ((img
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) &&
1469 (img
->d_w
!= cfg
->g_w
|| img
->d_h
!= cfg
->g_h
)) {
1470 if (img
->fmt
!= AOM_IMG_FMT_I42016
) {
1471 fprintf(stderr
, "%s can only scale 4:2:0 inputs\n", exec_name
);
1477 aom_img_alloc(NULL
, AOM_IMG_FMT_I42016
, cfg
->g_w
, cfg
->g_h
, 16);
1480 (uint16
*)img
->planes
[AOM_PLANE_Y
], img
->stride
[AOM_PLANE_Y
] / 2,
1481 (uint16
*)img
->planes
[AOM_PLANE_U
], img
->stride
[AOM_PLANE_U
] / 2,
1482 (uint16
*)img
->planes
[AOM_PLANE_V
], img
->stride
[AOM_PLANE_V
] / 2,
1483 img
->d_w
, img
->d_h
, (uint16
*)stream
->img
->planes
[AOM_PLANE_Y
],
1484 stream
->img
->stride
[AOM_PLANE_Y
] / 2,
1485 (uint16
*)stream
->img
->planes
[AOM_PLANE_U
],
1486 stream
->img
->stride
[AOM_PLANE_U
] / 2,
1487 (uint16
*)stream
->img
->planes
[AOM_PLANE_V
],
1488 stream
->img
->stride
[AOM_PLANE_V
] / 2, stream
->img
->d_w
,
1489 stream
->img
->d_h
, kFilterBox
);
1492 stream
->encoder
.err
= 1;
1493 ctx_exit_on_error(&stream
->encoder
,
1494 "Stream %d: Failed to encode frame.\n"
1495 "Scaling disabled in this configuration. \n"
1496 "To enable, configure with --enable-libyuv\n",
1502 if (img
&& (img
->d_w
!= cfg
->g_w
|| img
->d_h
!= cfg
->g_h
)) {
1503 if (img
->fmt
!= AOM_IMG_FMT_I420
&& img
->fmt
!= AOM_IMG_FMT_YV12
) {
1504 fprintf(stderr
, "%s can only scale 4:2:0 8bpp inputs\n", exec_name
);
1510 aom_img_alloc(NULL
, AOM_IMG_FMT_I420
, cfg
->g_w
, cfg
->g_h
, 16);
1512 img
->planes
[AOM_PLANE_Y
], img
->stride
[AOM_PLANE_Y
],
1513 img
->planes
[AOM_PLANE_U
], img
->stride
[AOM_PLANE_U
],
1514 img
->planes
[AOM_PLANE_V
], img
->stride
[AOM_PLANE_V
], img
->d_w
, img
->d_h
,
1515 stream
->img
->planes
[AOM_PLANE_Y
], stream
->img
->stride
[AOM_PLANE_Y
],
1516 stream
->img
->planes
[AOM_PLANE_U
], stream
->img
->stride
[AOM_PLANE_U
],
1517 stream
->img
->planes
[AOM_PLANE_V
], stream
->img
->stride
[AOM_PLANE_V
],
1518 stream
->img
->d_w
, stream
->img
->d_h
, kFilterBox
);
1521 stream
->encoder
.err
= 1;
1522 ctx_exit_on_error(&stream
->encoder
,
1523 "Stream %d: Failed to encode frame.\n"
1524 "Scaling disabled in this configuration. \n"
1525 "To enable, configure with --enable-libyuv\n",
1530 aom_usec_timer_start(&timer
);
1531 aom_codec_encode(&stream
->encoder
, img
, frame_start
,
1532 (unsigned long)(next_frame_start
- frame_start
), 0,
1534 aom_usec_timer_mark(&timer
);
1535 stream
->cx_time
+= aom_usec_timer_elapsed(&timer
);
1536 ctx_exit_on_error(&stream
->encoder
, "Stream %d: Failed to encode frame",
1540 static void update_quantizer_histogram(struct stream_state
*stream
) {
1541 if (stream
->config
.cfg
.g_pass
!= AOM_RC_FIRST_PASS
) {
1544 aom_codec_control(&stream
->encoder
, AOME_GET_LAST_QUANTIZER_64
, &q
);
1545 ctx_exit_on_error(&stream
->encoder
, "Failed to read quantizer");
1546 stream
->counts
[q
]++;
1550 static void get_cx_data(struct stream_state
*stream
,
1551 struct AvxEncoderConfig
*global
, int *got_data
) {
1552 const aom_codec_cx_pkt_t
*pkt
;
1553 const struct aom_codec_enc_cfg
*cfg
= &stream
->config
.cfg
;
1554 aom_codec_iter_t iter
= NULL
;
1557 while ((pkt
= aom_codec_get_cx_data(&stream
->encoder
, &iter
))) {
1558 static size_t fsize
= 0;
1559 static FileOffset ivf_header_pos
= 0;
1561 switch (pkt
->kind
) {
1562 case AOM_CODEC_CX_FRAME_PKT
:
1563 if (!(pkt
->data
.frame
.flags
& AOM_FRAME_IS_FRAGMENT
)) {
1564 stream
->frames_out
++;
1567 fprintf(stderr
, " %6luF", (unsigned long)pkt
->data
.frame
.sz
);
1569 update_rate_histogram(stream
->rate_hist
, cfg
, pkt
);
1571 if (stream
->config
.write_webm
) {
1572 write_webm_block(&stream
->webm_ctx
, cfg
, pkt
);
1575 if (!stream
->config
.write_webm
) {
1576 if (pkt
->data
.frame
.partition_id
<= 0) {
1577 ivf_header_pos
= ftello(stream
->file
);
1578 fsize
= pkt
->data
.frame
.sz
;
1580 ivf_write_frame_header(stream
->file
, pkt
->data
.frame
.pts
, fsize
);
1582 fsize
+= pkt
->data
.frame
.sz
;
1584 if (!(pkt
->data
.frame
.flags
& AOM_FRAME_IS_FRAGMENT
)) {
1585 const FileOffset currpos
= ftello(stream
->file
);
1586 fseeko(stream
->file
, ivf_header_pos
, SEEK_SET
);
1587 ivf_write_frame_size(stream
->file
, fsize
);
1588 fseeko(stream
->file
, currpos
, SEEK_SET
);
1592 (void)fwrite(pkt
->data
.frame
.buf
, 1, pkt
->data
.frame
.sz
,
1595 stream
->nbytes
+= pkt
->data
.raw
.sz
;
1598 #if CONFIG_AV1_DECODER
1599 if (global
->test_decode
!= TEST_DECODE_OFF
&& !stream
->mismatch_seen
) {
1600 aom_codec_decode(&stream
->decoder
, pkt
->data
.frame
.buf
,
1601 (unsigned int)pkt
->data
.frame
.sz
, NULL
, 0);
1602 if (stream
->decoder
.err
) {
1603 warn_or_exit_on_error(&stream
->decoder
,
1604 global
->test_decode
== TEST_DECODE_FATAL
,
1605 "Failed to decode frame %d in stream %d",
1606 stream
->frames_out
+ 1, stream
->index
);
1607 stream
->mismatch_seen
= stream
->frames_out
+ 1;
1612 case AOM_CODEC_STATS_PKT
:
1613 stream
->frames_out
++;
1614 stats_write(&stream
->stats
, pkt
->data
.twopass_stats
.buf
,
1615 pkt
->data
.twopass_stats
.sz
);
1616 stream
->nbytes
+= pkt
->data
.raw
.sz
;
1618 #if CONFIG_FP_MB_STATS
1619 case AOM_CODEC_FPMB_STATS_PKT
:
1620 stats_write(&stream
->fpmb_stats
, pkt
->data
.firstpass_mb_stats
.buf
,
1621 pkt
->data
.firstpass_mb_stats
.sz
);
1622 stream
->nbytes
+= pkt
->data
.raw
.sz
;
1625 case AOM_CODEC_PSNR_PKT
:
1627 if (global
->show_psnr
) {
1630 stream
->psnr_sse_total
+= pkt
->data
.psnr
.sse
[0];
1631 stream
->psnr_samples_total
+= pkt
->data
.psnr
.samples
[0];
1632 for (i
= 0; i
< 4; i
++) {
1634 fprintf(stderr
, "%.3f ", pkt
->data
.psnr
.psnr
[i
]);
1635 stream
->psnr_totals
[i
] += pkt
->data
.psnr
.psnr
[i
];
1637 stream
->psnr_count
++;
1646 static void show_psnr(struct stream_state
*stream
, double peak
) {
1650 if (!stream
->psnr_count
) return;
1652 fprintf(stderr
, "Stream %d PSNR (Overall/Avg/Y/U/V)", stream
->index
);
1653 ovpsnr
= sse_to_psnr((double)stream
->psnr_samples_total
, peak
,
1654 (double)stream
->psnr_sse_total
);
1655 fprintf(stderr
, " %.3f", ovpsnr
);
1657 for (i
= 0; i
< 4; i
++) {
1658 fprintf(stderr
, " %.3f", stream
->psnr_totals
[i
] / stream
->psnr_count
);
1660 fprintf(stderr
, "\n");
1663 static float usec_to_fps(uint64_t usec
, unsigned int frames
) {
1664 return (float)(usec
> 0 ? frames
* 1000000.0 / (float)usec
: 0);
1667 static void test_decode(struct stream_state
*stream
,
1668 enum TestDecodeFatality fatal
) {
1669 aom_image_t enc_img
, dec_img
;
1671 if (stream
->mismatch_seen
) return;
1673 /* Get the internal reference frame */
1674 aom_codec_control(&stream
->encoder
, AV1_GET_NEW_FRAME_IMAGE
, &enc_img
);
1675 aom_codec_control(&stream
->decoder
, AV1_GET_NEW_FRAME_IMAGE
, &dec_img
);
1677 #if CONFIG_HIGHBITDEPTH
1678 if ((enc_img
.fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) !=
1679 (dec_img
.fmt
& AOM_IMG_FMT_HIGHBITDEPTH
)) {
1680 if (enc_img
.fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) {
1681 aom_image_t enc_hbd_img
;
1682 aom_img_alloc(&enc_hbd_img
, enc_img
.fmt
- AOM_IMG_FMT_HIGHBITDEPTH
,
1683 enc_img
.d_w
, enc_img
.d_h
, 16);
1684 aom_img_truncate_16_to_8(&enc_hbd_img
, &enc_img
);
1685 enc_img
= enc_hbd_img
;
1687 if (dec_img
.fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) {
1688 aom_image_t dec_hbd_img
;
1689 aom_img_alloc(&dec_hbd_img
, dec_img
.fmt
- AOM_IMG_FMT_HIGHBITDEPTH
,
1690 dec_img
.d_w
, dec_img
.d_h
, 16);
1691 aom_img_truncate_16_to_8(&dec_hbd_img
, &dec_img
);
1692 dec_img
= dec_hbd_img
;
1697 ctx_exit_on_error(&stream
->encoder
, "Failed to get encoder reference frame");
1698 ctx_exit_on_error(&stream
->decoder
, "Failed to get decoder reference frame");
1700 if (!aom_compare_img(&enc_img
, &dec_img
)) {
1701 int y
[4], u
[4], v
[4];
1702 #if CONFIG_HIGHBITDEPTH
1703 if (enc_img
.fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) {
1704 aom_find_mismatch_high(&enc_img
, &dec_img
, y
, u
, v
);
1706 aom_find_mismatch(&enc_img
, &dec_img
, y
, u
, v
);
1709 aom_find_mismatch(&enc_img
, &dec_img
, y
, u
, v
);
1711 stream
->decoder
.err
= 1;
1712 warn_or_exit_on_error(&stream
->decoder
, fatal
== TEST_DECODE_FATAL
,
1713 "Stream %d: Encode/decode mismatch on frame %d at"
1714 " Y[%d, %d] {%d/%d},"
1715 " U[%d, %d] {%d/%d},"
1716 " V[%d, %d] {%d/%d}",
1717 stream
->index
, stream
->frames_out
, y
[0], y
[1], y
[2],
1718 y
[3], u
[0], u
[1], u
[2], u
[3], v
[0], v
[1], v
[2], v
[3]);
1719 stream
->mismatch_seen
= stream
->frames_out
;
1722 aom_img_free(&enc_img
);
1723 aom_img_free(&dec_img
);
1726 static void print_time(const char *label
, int64_t etl
) {
1733 etl
-= hours
* 3600;
1738 fprintf(stderr
, "[%3s %2" PRId64
":%02" PRId64
":%02" PRId64
"] ", label
,
1741 fprintf(stderr
, "[%3s unknown] ", label
);
1745 int main(int argc
, const char **argv_
) {
1748 #if CONFIG_HIGHBITDEPTH
1749 aom_image_t raw_shift
;
1750 int allocated_raw_shift
= 0;
1751 int use_16bit_internal
= 0;
1752 int input_shift
= 0;
1754 int frame_avail
, got_data
;
1756 struct AvxInputContext input
;
1757 struct AvxEncoderConfig global
;
1758 struct stream_state
*streams
= NULL
;
1759 char **argv
, **argi
;
1760 uint64_t cx_time
= 0;
1763 int profile_updated
= 0;
1765 memset(&input
, 0, sizeof(input
));
1766 exec_name
= argv_
[0];
1768 if (argc
< 3) usage_exit();
1770 /* Setup default input stream settings */
1771 input
.framerate
.numerator
= 30;
1772 input
.framerate
.denominator
= 1;
1773 input
.only_i420
= 1;
1774 input
.bit_depth
= 0;
1776 /* First parse the global configuration values, because we want to apply
1777 * other parameters on top of the default configuration provided by the
1780 argv
= argv_dup(argc
- 1, argv_
+ 1);
1781 parse_global_config(&global
, argv
);
1783 switch (global
.color_type
) {
1784 case I420
: input
.fmt
= AOM_IMG_FMT_I420
; break;
1785 case I422
: input
.fmt
= AOM_IMG_FMT_I422
; break;
1786 case I444
: input
.fmt
= AOM_IMG_FMT_I444
; break;
1787 case I440
: input
.fmt
= AOM_IMG_FMT_I440
; break;
1788 case YV12
: input
.fmt
= AOM_IMG_FMT_YV12
; break;
1792 /* Now parse each stream's parameters. Using a local scope here
1793 * due to the use of 'stream' as loop variable in FOREACH_STREAM
1796 struct stream_state
*stream
= NULL
;
1799 stream
= new_stream(&global
, stream
);
1801 if (!streams
) streams
= stream
;
1802 } while (parse_stream_params(&global
, stream
, argv
));
1805 /* Check for unrecognized options */
1806 for (argi
= argv
; *argi
; argi
++)
1807 if (argi
[0][0] == '-' && argi
[0][1])
1808 die("Error: Unrecognized option %s\n", *argi
);
1810 FOREACH_STREAM(stream
, streams
) {
1811 check_encoder_config(global
.disable_warning_prompt
, &global
,
1812 &stream
->config
.cfg
);
1815 /* Handle non-option arguments */
1816 input
.filename
= argv
[0];
1818 if (!input
.filename
) usage_exit();
1820 /* Decide if other chroma subsamplings than 4:2:0 are supported */
1821 if (global
.codec
->fourcc
== AV1_FOURCC
) input
.only_i420
= 0;
1823 for (pass
= global
.pass
? global
.pass
- 1 : 0; pass
< global
.passes
; pass
++) {
1824 int frames_in
= 0, seen_frames
= 0;
1825 int64_t estimated_time_left
= -1;
1826 int64_t average_rate
= -1;
1827 int64_t lagged_count
= 0;
1829 open_input_file(&input
);
1831 /* If the input file doesn't specify its w/h (raw files), try to get
1832 * the data from the first stream's configuration.
1834 if (!input
.width
|| !input
.height
) {
1835 FOREACH_STREAM(stream
, streams
) {
1836 if (stream
->config
.cfg
.g_w
&& stream
->config
.cfg
.g_h
) {
1837 input
.width
= stream
->config
.cfg
.g_w
;
1838 input
.height
= stream
->config
.cfg
.g_h
;
1844 /* Update stream configurations from the input file's parameters */
1845 if (!input
.width
|| !input
.height
)
1847 "Specify stream dimensions with --width (-w) "
1848 " and --height (-h)");
1850 /* If input file does not specify bit-depth but input-bit-depth parameter
1851 * exists, assume that to be the input bit-depth. However, if the
1852 * input-bit-depth paramter does not exist, assume the input bit-depth
1853 * to be the same as the codec bit-depth.
1855 if (!input
.bit_depth
) {
1856 FOREACH_STREAM(stream
, streams
) {
1857 if (stream
->config
.cfg
.g_input_bit_depth
)
1858 input
.bit_depth
= stream
->config
.cfg
.g_input_bit_depth
;
1860 input
.bit_depth
= stream
->config
.cfg
.g_input_bit_depth
=
1861 (int)stream
->config
.cfg
.g_bit_depth
;
1863 if (input
.bit_depth
> 8) input
.fmt
|= AOM_IMG_FMT_HIGHBITDEPTH
;
1865 FOREACH_STREAM(stream
, streams
) {
1866 stream
->config
.cfg
.g_input_bit_depth
= input
.bit_depth
;
1870 FOREACH_STREAM(stream
, streams
) {
1871 if (input
.fmt
!= AOM_IMG_FMT_I420
&& input
.fmt
!= AOM_IMG_FMT_I42016
) {
1872 /* Automatically upgrade if input is non-4:2:0 but a 4:2:0 profile
1874 switch (stream
->config
.cfg
.g_profile
) {
1876 stream
->config
.cfg
.g_profile
= 1;
1877 profile_updated
= 1;
1880 stream
->config
.cfg
.g_profile
= 3;
1881 profile_updated
= 1;
1886 /* Automatically set the codec bit depth to match the input bit depth.
1887 * Upgrade the profile if required. */
1888 if (stream
->config
.cfg
.g_input_bit_depth
>
1889 (unsigned int)stream
->config
.cfg
.g_bit_depth
) {
1890 stream
->config
.cfg
.g_bit_depth
= stream
->config
.cfg
.g_input_bit_depth
;
1892 if (stream
->config
.cfg
.g_bit_depth
> 8) {
1893 switch (stream
->config
.cfg
.g_profile
) {
1895 stream
->config
.cfg
.g_profile
= 2;
1896 profile_updated
= 1;
1899 stream
->config
.cfg
.g_profile
= 3;
1900 profile_updated
= 1;
1905 if (stream
->config
.cfg
.g_profile
> 1) {
1906 if (!CONFIG_HIGHBITDEPTH
) fatal("Unsupported profile.");
1907 stream
->config
.use_16bit_internal
= 1;
1909 if (profile_updated
&& !global
.quiet
) {
1911 "Warning: automatically upgrading to profile %d to "
1912 "match input format.\n",
1913 stream
->config
.cfg
.g_profile
);
1917 FOREACH_STREAM(stream
, streams
) {
1918 set_stream_dimensions(stream
, input
.width
, input
.height
);
1920 FOREACH_STREAM(stream
, streams
) { validate_stream_config(stream
, &global
); }
1922 /* Ensure that --passes and --pass are consistent. If --pass is set and
1923 * --passes=2, ensure --fpf was set.
1925 if (global
.pass
&& global
.passes
== 2) {
1926 FOREACH_STREAM(stream
, streams
) {
1927 if (!stream
->config
.stats_fn
)
1928 die("Stream %d: Must specify --fpf when --pass=%d"
1929 " and --passes=2\n",
1930 stream
->index
, global
.pass
);
1935 FOREACH_STREAM(stream
, streams
) {
1936 if (stream
->config
.write_webm
) {
1937 stream
->config
.write_webm
= 0;
1939 "aomenc was compiled without WebM container support."
1940 "Producing IVF output");
1945 /* Use the frame rate from the file only if none was specified
1946 * on the command-line.
1948 if (!global
.have_framerate
) {
1949 global
.framerate
.num
= input
.framerate
.numerator
;
1950 global
.framerate
.den
= input
.framerate
.denominator
;
1951 FOREACH_STREAM(stream
, streams
) {
1952 stream
->config
.cfg
.g_timebase
.den
= global
.framerate
.num
;
1953 stream
->config
.cfg
.g_timebase
.num
= global
.framerate
.den
;
1957 /* Show configuration */
1958 if (global
.verbose
&& pass
== 0) {
1959 FOREACH_STREAM(stream
, streams
) {
1960 show_stream_config(stream
, &global
, &input
);
1964 if (pass
== (global
.pass
? global
.pass
- 1 : 0)) {
1965 if (input
.file_type
== FILE_TYPE_Y4M
)
1966 /*The Y4M reader does its own allocation.
1967 Just initialize this here to avoid problems if we never read any
1969 memset(&raw
, 0, sizeof(raw
));
1971 aom_img_alloc(&raw
, input
.fmt
, input
.width
, input
.height
, 32);
1973 FOREACH_STREAM(stream
, streams
) {
1975 init_rate_histogram(&stream
->config
.cfg
, &global
.framerate
);
1979 FOREACH_STREAM(stream
, streams
) { setup_pass(stream
, &global
, pass
); }
1980 FOREACH_STREAM(stream
, streams
) {
1981 open_output_file(stream
, &global
, &input
.pixel_aspect_ratio
);
1983 FOREACH_STREAM(stream
, streams
) { initialize_encoder(stream
, &global
); }
1985 #if CONFIG_HIGHBITDEPTH
1986 if (strcmp(global
.codec
->name
, "av1") == 0 ||
1987 strcmp(global
.codec
->name
, "av1") == 0) {
1988 // Check to see if at least one stream uses 16 bit internal.
1989 // Currently assume that the bit_depths for all streams using
1990 // highbitdepth are the same.
1991 FOREACH_STREAM(stream
, streams
) {
1992 if (stream
->config
.use_16bit_internal
) {
1993 use_16bit_internal
= 1;
1995 if (stream
->config
.cfg
.g_profile
== 0) {
1998 input_shift
= (int)stream
->config
.cfg
.g_bit_depth
-
1999 stream
->config
.cfg
.g_input_bit_depth
;
2008 while (frame_avail
|| got_data
) {
2009 struct aom_usec_timer timer
;
2011 if (!global
.limit
|| frames_in
< global
.limit
) {
2012 frame_avail
= read_frame(&input
, &raw
);
2014 if (frame_avail
) frames_in
++;
2016 frames_in
> global
.skip_frames
? frames_in
- global
.skip_frames
: 0;
2018 if (!global
.quiet
) {
2019 float fps
= usec_to_fps(cx_time
, seen_frames
);
2020 fprintf(stderr
, "\rPass %d/%d ", pass
+ 1, global
.passes
);
2022 if (stream_cnt
== 1)
2023 fprintf(stderr
, "frame %4d/%-4d %7" PRId64
"B ", frames_in
,
2024 streams
->frames_out
, (int64_t)streams
->nbytes
);
2026 fprintf(stderr
, "frame %4d ", frames_in
);
2028 fprintf(stderr
, "%7" PRId64
" %s %.2f %s ",
2029 cx_time
> 9999999 ? cx_time
/ 1000 : cx_time
,
2030 cx_time
> 9999999 ? "ms" : "us", fps
>= 1.0 ? fps
: fps
* 60,
2031 fps
>= 1.0 ? "fps" : "fpm");
2032 print_time("ETA", estimated_time_left
);
2039 if (frames_in
> global
.skip_frames
) {
2040 #if CONFIG_HIGHBITDEPTH
2041 aom_image_t
*frame_to_encode
;
2042 if (input_shift
|| (use_16bit_internal
&& input
.bit_depth
== 8)) {
2043 assert(use_16bit_internal
);
2044 // Input bit depth and stream bit depth do not match, so up
2045 // shift frame to stream bit depth
2046 if (!allocated_raw_shift
) {
2047 aom_img_alloc(&raw_shift
, raw
.fmt
| AOM_IMG_FMT_HIGHBITDEPTH
,
2048 input
.width
, input
.height
, 32);
2049 allocated_raw_shift
= 1;
2051 aom_img_upshift(&raw_shift
, &raw
, input_shift
);
2052 frame_to_encode
= &raw_shift
;
2054 frame_to_encode
= &raw
;
2056 aom_usec_timer_start(&timer
);
2057 if (use_16bit_internal
) {
2058 assert(frame_to_encode
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
);
2059 FOREACH_STREAM(stream
, streams
) {
2060 if (stream
->config
.use_16bit_internal
)
2061 encode_frame(stream
, &global
,
2062 frame_avail
? frame_to_encode
: NULL
, frames_in
);
2067 assert((frame_to_encode
->fmt
& AOM_IMG_FMT_HIGHBITDEPTH
) == 0);
2068 FOREACH_STREAM(stream
, streams
) {
2069 encode_frame(stream
, &global
, frame_avail
? frame_to_encode
: NULL
,
2074 aom_usec_timer_start(&timer
);
2075 FOREACH_STREAM(stream
, streams
) {
2076 encode_frame(stream
, &global
, frame_avail
? &raw
: NULL
, frames_in
);
2079 aom_usec_timer_mark(&timer
);
2080 cx_time
+= aom_usec_timer_elapsed(&timer
);
2082 FOREACH_STREAM(stream
, streams
) { update_quantizer_histogram(stream
); }
2085 FOREACH_STREAM(stream
, streams
) {
2086 get_cx_data(stream
, &global
, &got_data
);
2089 if (!got_data
&& input
.length
&& streams
!= NULL
&&
2090 !streams
->frames_out
) {
2091 lagged_count
= global
.limit
? seen_frames
: ftello(input
.file
);
2092 } else if (input
.length
) {
2097 const int64_t frame_in_lagged
= (seen_frames
- lagged_count
) * 1000;
2099 rate
= cx_time
? frame_in_lagged
* (int64_t)1000000 / cx_time
: 0;
2100 remaining
= 1000 * (global
.limit
- global
.skip_frames
-
2101 seen_frames
+ lagged_count
);
2103 const int64_t input_pos
= ftello(input
.file
);
2104 const int64_t input_pos_lagged
= input_pos
- lagged_count
;
2105 const int64_t input_limit
= input
.length
;
2107 rate
= cx_time
? input_pos_lagged
* (int64_t)1000000 / cx_time
: 0;
2108 remaining
= input_limit
- input_pos
+ lagged_count
;
2112 (average_rate
<= 0) ? rate
: (average_rate
* 7 + rate
) / 8;
2113 estimated_time_left
= average_rate
? remaining
/ average_rate
: -1;
2116 if (got_data
&& global
.test_decode
!= TEST_DECODE_OFF
) {
2117 FOREACH_STREAM(stream
, streams
) {
2118 test_decode(stream
, global
.test_decode
);
2124 if (!global
.quiet
) fprintf(stderr
, "\033[K");
2127 if (stream_cnt
> 1) fprintf(stderr
, "\n");
2129 if (!global
.quiet
) {
2130 FOREACH_STREAM(stream
, streams
) {
2131 fprintf(stderr
, "\rPass %d/%d frame %4d/%-4d %7" PRId64
"B %7" PRId64
2134 " %7" PRId64
" %s (%.2f fps)\033[K\n",
2135 pass
+ 1, global
.passes
, frames_in
, stream
->frames_out
,
2136 (int64_t)stream
->nbytes
,
2137 seen_frames
? (int64_t)(stream
->nbytes
* 8 / seen_frames
) : 0,
2139 ? (int64_t)stream
->nbytes
* 8 *
2140 (int64_t)global
.framerate
.num
/ global
.framerate
.den
/
2143 stream
->cx_time
> 9999999 ? stream
->cx_time
/ 1000
2145 stream
->cx_time
> 9999999 ? "ms" : "us",
2146 usec_to_fps(stream
->cx_time
, seen_frames
));
2150 if (global
.show_psnr
) {
2151 if (global
.codec
->fourcc
== AV1_FOURCC
) {
2152 FOREACH_STREAM(stream
, streams
) {
2153 show_psnr(stream
, (1 << stream
->config
.cfg
.g_input_bit_depth
) - 1);
2156 FOREACH_STREAM(stream
, streams
) { show_psnr(stream
, 255.0); }
2160 FOREACH_STREAM(stream
, streams
) { aom_codec_destroy(&stream
->encoder
); }
2162 if (global
.test_decode
!= TEST_DECODE_OFF
) {
2163 FOREACH_STREAM(stream
, streams
) { aom_codec_destroy(&stream
->decoder
); }
2166 close_input_file(&input
);
2168 if (global
.test_decode
== TEST_DECODE_FATAL
) {
2169 FOREACH_STREAM(stream
, streams
) { res
|= stream
->mismatch_seen
; }
2171 FOREACH_STREAM(stream
, streams
) {
2172 close_output_file(stream
, global
.codec
->fourcc
);
2175 FOREACH_STREAM(stream
, streams
) {
2176 stats_close(&stream
->stats
, global
.passes
- 1);
2179 #if CONFIG_FP_MB_STATS
2180 FOREACH_STREAM(stream
, streams
) {
2181 stats_close(&stream
->fpmb_stats
, global
.passes
- 1);
2185 if (global
.pass
) break;
2188 if (global
.show_q_hist_buckets
) {
2189 FOREACH_STREAM(stream
, streams
) {
2190 show_q_histogram(stream
->counts
, global
.show_q_hist_buckets
);
2194 if (global
.show_rate_hist_buckets
) {
2195 FOREACH_STREAM(stream
, streams
) {
2196 show_rate_histogram(stream
->rate_hist
, &stream
->config
.cfg
,
2197 global
.show_rate_hist_buckets
);
2200 FOREACH_STREAM(stream
, streams
) { destroy_rate_histogram(stream
->rate_hist
); }
2202 #if CONFIG_INTERNAL_STATS
2203 /* TODO(jkoleszar): This doesn't belong in this executable. Do it for now,
2204 * to match some existing utilities.
2206 if (!(global
.pass
== 1 && global
.passes
== 2)) {
2207 FOREACH_STREAM(stream
, streams
) {
2208 FILE *f
= fopen("opsnr.stt", "a");
2209 if (stream
->mismatch_seen
) {
2210 fprintf(f
, "First mismatch occurred in frame %d\n",
2211 stream
->mismatch_seen
);
2213 fprintf(f
, "No mismatch detected in recon buffers\n");
2220 #if CONFIG_HIGHBITDEPTH
2221 if (allocated_raw_shift
) aom_img_free(&raw_shift
);
2226 return res
? EXIT_FAILURE
: EXIT_SUCCESS
;