/* * Copyright (c) 2016, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. If the Alliance for Open * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
if (global->pass) { /* DWIM: Assume the user meant passes=2 if pass=2 is specified */ if (global->pass > global->passes) {
aom_tools_warn("Assuming --pass=%d implies --passes=%d\n", global->pass,
global->pass);
global->passes = global->pass;
}
} /* Validate global config */ if (global->passes == 0) { #if CONFIG_AV1_ENCODER // Make default AV1 passes = 2 until there is a better quality 1-pass // encoder if (global->codec != NULL)
global->passes =
(strcmp(get_short_name_by_aom_encoder(global->codec), "av1") == 0 &&
global->usage != AOM_USAGE_REALTIME)
? 2
: 1; #else
global->passes = 1; #endif
}
if (global->usage == AOM_USAGE_REALTIME && global->passes > 1) {
aom_tools_warn("Enforcing one-pass encoding in realtime mode\n"); if (global->pass > 1)
die("Error: Invalid --pass=%d for one-pass encoding\n", global->pass);
global->passes = 1;
}
if (global->usage == AOM_USAGE_ALL_INTRA && global->passes > 1) {
aom_tools_warn("Enforcing one-pass encoding in all intra mode\n");
global->passes = 1;
}
}
staticvoid open_input_file(struct AvxInputContext *input,
aom_chroma_sample_position_t csp) { /* Parse certain options from the input file, if possible */
input->file = strcmp(input->filename, "-") ? fopen(input->filename, "rb")
: set_binary_mode(stdin);
if (!input->file) fatal("Failed to open input file");
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);
}
/* 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;
/* Populate encoder configuration */
res = aom_codec_enc_config_default(global->codec, &stream->config.cfg,
global->usage); if (res) fatal("Failed to get config: %s\n", aom_codec_err_to_string(res));
/* 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;
/* 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;
/* Allows removal of the application version from the EBML tags */
stream->webm_ctx.debug = global->debug;
memcpy(&stream->config.cfg.encoder_cfg, &global->encoder_config, sizeof(stream->config.cfg.encoder_cfg));
}
/* Output files must be specified for each stream */
stream->config.out_fn = NULL;
stream->config.two_pass_input = NULL;
stream->config.two_pass_output = NULL;
stream->config.two_pass_width = 0;
stream->config.two_pass_height = 0;
stream->next = NULL; return stream;
}
staticvoid set_config_arg_ctrls(struct stream_config *config, int key, conststruct arg *arg) { int j; if (key == AV1E_SET_FILM_GRAIN_TABLE) {
config->film_grain_filename = arg->val; return;
}
// For target level, the settings should accumulate rather than overwrite, // so we simply append it. if (key == AV1E_SET_TARGET_SEQ_LEVEL_IDX) {
j = config->arg_ctrl_cnt;
assert(j < ARG_CTRL_CNT_MAX);
config->arg_ctrls[j][0] = key;
config->arg_ctrls[j][1] = arg_parse_enum_or_int(arg);
++config->arg_ctrl_cnt; return;
}
/* Point either to the next free element or the first instance of this * control.
*/ for (j = 0; j < config->arg_ctrl_cnt; j++) if (config->arg_ctrls[j][0] == key) break;
if (j == config->arg_ctrl_cnt) config->arg_ctrl_cnt++;
}
staticvoid set_config_arg_key_vals(struct stream_config *config, constchar *name, conststruct arg *arg) { int j; constchar *val = arg->val; // For target level, the settings should accumulate rather than overwrite, // so we simply append it. if (strcmp(name, "target-seq-level-idx") == 0) {
j = config->arg_key_val_cnt;
assert(j < ARG_KEY_VAL_CNT_MAX);
config->arg_key_vals[j][0] = name;
config->arg_key_vals[j][1] = val;
++config->arg_key_val_cnt; return;
}
/* Point either to the next free element or the first instance of this * option.
*/ for (j = 0; j < config->arg_key_val_cnt; j++) if (strcmp(name, config->arg_key_vals[j][0]) == 0) break;
// Handle codec specific options if (0) { #if CONFIG_AV1_ENCODER
} elseif (strcmp(get_short_name_by_aom_encoder(global->codec), "av1") == 0) { // TODO(jingning): Reuse AV1 specific encoder configuration parameters. // Consider to expand this set for AV1 encoder control. #if __STDC_VERSION__ >= 201112L
_Static_assert(NELEMENTS(av1_ctrl_args) == NELEMENTS(av1_arg_ctrl_map), "The av1_ctrl_args and av1_arg_ctrl_map arrays must be of " "the same size."); #else
assert(NELEMENTS(av1_ctrl_args) == NELEMENTS(av1_arg_ctrl_map)); #endif
ctrl_args = av1_ctrl_args;
ctrl_args_map = av1_arg_ctrl_map;
key_val_args = av1_key_val_args; #endif
}
for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) {
arg.argv_step = 1;
/* 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;
} elseif (!strcmp(*argj, "--")) {
eos_mark_found = 1; continue;
}
if (global->usage == AOM_USAGE_REALTIME && config->cfg.g_lag_in_frames != 0) {
aom_tools_warn("non-zero lag-in-frames option ignored in realtime mode.\n");
config->cfg.g_lag_in_frames = 0;
}
if (global->usage == AOM_USAGE_ALL_INTRA) { if (config->cfg.g_lag_in_frames != 0) {
aom_tools_warn( "non-zero lag-in-frames option ignored in all intra mode.\n");
config->cfg.g_lag_in_frames = 0;
} if (config->cfg.kf_max_dist != 0) {
aom_tools_warn( "non-zero max key frame distance option ignored in all intra " "mode.\n");
config->cfg.kf_max_dist = 0;
}
}
// set the passes field using key & val API if (config->arg_key_val_cnt >= ARG_KEY_VAL_CNT_MAX) {
die("Not enough buffer for the key & value API.");
}
config->arg_key_vals[config->arg_key_val_cnt][0] = "passes"; switch (global->passes) { case 0: config->arg_key_vals[config->arg_key_val_cnt][1] = "0"; break; case 1: config->arg_key_vals[config->arg_key_val_cnt][1] = "1"; break; case 2: config->arg_key_vals[config->arg_key_val_cnt][1] = "2"; break; case 3: config->arg_key_vals[config->arg_key_val_cnt][1] = "3"; break; default: die("Invalid value of --passes.");
}
config->arg_key_val_cnt++;
// set the two_pass_output field if (!config->two_pass_output && global->passes == 3) { // If not specified, set the name of two_pass_output file here.
snprintf(stream->tmp_out_fn, sizeof(stream->tmp_out_fn), "%.980s_pass2_%d.ivf", stream->config.out_fn, stream->index);
stream->config.two_pass_output = stream->tmp_out_fn;
} if (config->two_pass_output) {
config->arg_key_vals[config->arg_key_val_cnt][0] = "two-pass-output";
config->arg_key_vals[config->arg_key_val_cnt][1] = config->two_pass_output;
config->arg_key_val_cnt++;
}
if (!stream->config.cfg.g_w || !stream->config.cfg.g_h)
fatal( "Stream %d: Specify stream dimensions with --width (-w) " " and --height (-h)",
stream->index);
/* Even if bit depth is set on the command line flag to be lower, * it is upgraded to at least match the input bit depth.
*/
assert(stream->config.cfg.g_input_bit_depth <=
(unsignedint)stream->config.cfg.g_bit_depth);
for (streami = stream; streami; streami = streami->next) { /* All streams require output files */ if (!streami->config.out_fn)
fatal("Stream %d: Output file is required (specify with -o)",
streami->index);
/* Check for two streams outputting to the same file */ if (streami != stream) { constchar *a = stream->config.out_fn; constchar *b = streami->config.out_fn; if (!strcmp(a, b) && strcmp(a, "/dev/null") && strcmp(a, ":nul"))
fatal("Stream %d: duplicate output file (from stream %d)",
streami->index, stream->index);
}
/* Check for two streams sharing a stats file. */ if (streami != stream) { constchar *a = stream->config.stats_fn; constchar *b = streami->config.stats_fn; if (a && b && !strcmp(a, b))
fatal("Stream %d: duplicate stats file (from stream %d)",
streami->index, stream->index);
}
}
}
staticvoid set_stream_dimensions(struct stream_state *stream, unsignedint w, unsignedint h) { if (!stream->config.cfg.g_w) { if (!stream->config.cfg.g_h)
stream->config.cfg.g_w = w; else
stream->config.cfg.g_w = w * stream->config.cfg.g_h / h;
} if (!stream->config.cfg.g_h) {
stream->config.cfg.g_h = h * stream->config.cfg.g_w / w;
}
}
staticconstchar *file_type_to_string(enum VideoFileType t) { switch (t) { case FILE_TYPE_RAW: return"RAW"; case FILE_TYPE_Y4M: return"Y4M"; default: return"Other";
}
}
#if CONFIG_WEBM_IO if (stream->config.write_webm) { if (write_webm_file_footer(&stream->webm_ctx) != 0) {
fatal("WebM writer finalization failed.");
}
} #endif
if (!stream->config.write_webm && stream->config.write_ivf) { if (!fseek(stream->file, 0, SEEK_SET))
ivf_write_file_header(stream->file, &stream->config.cfg, fourcc,
stream->frames_out);
}
fclose(stream->file);
}
staticvoid setup_pass(struct stream_state *stream, struct AvxEncoderConfig *global, int pass) { if (stream->config.stats_fn) { if (!stats_open_file(&stream->stats, stream->config.stats_fn, pass))
fatal("Failed to open statistics store");
} else { if (!stats_open_mem(&stream->stats, pass))
fatal("Failed to open statistics store");
}
if (global->passes == 1) {
stream->config.cfg.g_pass = AOM_RC_ONE_PASS;
} else { switch (pass) { case 0: stream->config.cfg.g_pass = AOM_RC_FIRST_PASS; break; case 1: stream->config.cfg.g_pass = AOM_RC_SECOND_PASS; break; case 2: stream->config.cfg.g_pass = AOM_RC_THIRD_PASS; break; default: fatal("Failed to set pass");
}
}
if (pass) {
stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats);
}
for (i = 0; i < stream->config.arg_ctrl_cnt; i++) { int ctrl = stream->config.arg_ctrls[i][0]; int value = stream->config.arg_ctrls[i][1]; if (aom_codec_control(&stream->encoder, ctrl, value))
fprintf(stderr, "Error: Tried to set control %d = %d\n", ctrl, value);
ctx_exit_on_error(&stream->encoder, "Failed to control codec");
}
for (i = 0; i < stream->config.arg_key_val_cnt; i++) { constchar *name = stream->config.arg_key_vals[i][0]; constchar *val = stream->config.arg_key_vals[i][1]; if (aom_codec_set_option(&stream->encoder, name, val))
fprintf(stderr, "Error: Tried to set option %s = %s\n", name, val);
ctx_exit_on_error(&stream->encoder, "Failed to set codec option");
}
#if CONFIG_TUNE_VMAF if (stream->config.vmaf_model_path) {
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_VMAF_MODEL_PATH,
stream->config.vmaf_model_path);
ctx_exit_on_error(&stream->encoder, "Failed to set vmaf model path");
} #endif if (stream->config.partition_info_path) {
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_SET_PARTITION_INFO_PATH,
stream->config.partition_info_path);
ctx_exit_on_error(&stream->encoder, "Failed to set partition info path");
} if (stream->config.enable_rate_guide_deltaq) {
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_ENABLE_RATE_GUIDE_DELTAQ,
stream->config.enable_rate_guide_deltaq);
ctx_exit_on_error(&stream->encoder, "Failed to enable rate guide deltaq");
} if (stream->config.rate_distribution_info) {
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_SET_RATE_DISTRIBUTION_INFO,
stream->config.rate_distribution_info);
ctx_exit_on_error(&stream->encoder, "Failed to set rate distribution info");
}
if (stream->config.film_grain_filename) {
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_FILM_GRAIN_TABLE,
stream->config.film_grain_filename);
ctx_exit_on_error(&stream->encoder, "Failed to set film grain table");
}
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder, AV1E_SET_COLOR_RANGE,
stream->config.color_range);
ctx_exit_on_error(&stream->encoder, "Failed to set color range");
if (strcmp(get_short_name_by_aom_encoder(global->codec), "av1") == 0) {
AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1_SET_TILE_MODE,
stream->config.cfg.large_scale_tile);
ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_mode");
AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1D_SET_IS_ANNEXB,
stream->config.cfg.save_as_annexb);
ctx_exit_on_error(&stream->decoder, "Failed to set is_annexb");
AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1_SET_DECODE_TILE_ROW,
-1);
ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_row");
AOM_CODEC_CONTROL_TYPECHECKED(&stream->decoder, AV1_SET_DECODE_TILE_COL,
-1);
ctx_exit_on_error(&stream->decoder, "Failed to set decode_tile_col");
}
} #endif
}
// Convert the input image 'img' to a monochrome image. The Y plane of the // output image is a shallow copy of the Y plane of the input image, therefore // the input image must remain valid for the lifetime of the output image. The U // and V planes of the output image are set to null pointers. The output image // format is AOM_IMG_FMT_I420 because libaom does not have AOM_IMG_FMT_I400. staticvoid convert_image_to_monochrome(conststruct aom_image *img, struct aom_image *monochrome_img) {
*monochrome_img = *img;
monochrome_img->fmt = AOM_IMG_FMT_I420; if (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) {
monochrome_img->fmt |= AOM_IMG_FMT_HIGHBITDEPTH;
}
monochrome_img->monochrome = 1;
monochrome_img->csp = AOM_CSP_UNKNOWN;
monochrome_img->x_chroma_shift = 1;
monochrome_img->y_chroma_shift = 1;
monochrome_img->planes[AOM_PLANE_U] = NULL;
monochrome_img->planes[AOM_PLANE_V] = NULL;
monochrome_img->stride[AOM_PLANE_U] = 0;
monochrome_img->stride[AOM_PLANE_V] = 0;
monochrome_img->sz = 0;
monochrome_img->bps = (img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) ? 16 : 8;
monochrome_img->img_data = NULL;
monochrome_img->img_data_owner = 0;
monochrome_img->self_allocd = 0;
}
ctx_exit_on_error(&stream->encoder, "Failed to get encoder reference frame");
ctx_exit_on_error(&stream->decoder, "Failed to get decoder reference frame");
if (!aom_compare_img(&enc_img, &dec_img)) { int y[4], u[4], v[4]; if (enc_img.fmt & AOM_IMG_FMT_HIGHBITDEPTH) {
aom_find_mismatch_high(&enc_img, &dec_img, y, u, v);
} else {
aom_find_mismatch(&enc_img, &dec_img, y, u, v);
}
stream->decoder.err = 1;
warn_or_exit_on_error(&stream->decoder, fatal == TEST_DECODE_FATAL, "Stream %d: Encode/decode mismatch on frame %d at" " Y[%d, %d] {%d/%d}," " U[%d, %d] {%d/%d}," " V[%d, %d] {%d/%d}",
stream->index, stream->frames_out, y[0], y[1], y[2],
y[3], u[0], u[1], u[2], u[3], v[0], v[1], v[2], v[3]);
stream->mismatch_seen = stream->frames_out;
}
staticvoid clear_stream_count_state(struct stream_state *stream) { // PSNR counters for (int k = 0; k < 2; k++) {
stream->psnr_sse_total[k] = 0;
stream->psnr_samples_total[k] = 0; for (int i = 0; i < 4; i++) {
stream->psnr_totals[k][i] = 0;
}
stream->psnr_count[k] = 0;
} // q hist
memset(stream->counts, 0, sizeof(stream->counts));
}
// aomenc will downscale the second pass if: // 1. the specific pass is not given by commandline (aomenc will perform all // passes) // 2. there are more than 2 passes in total // 3. current pass is the second pass (the parameter pass starts with 0 so // pass == 1) staticint pass_need_downscale(int global_pass, int global_passes, int pass) { return !global_pass && global_passes > 2 && pass == 1;
}
int main(int argc, constchar **argv_) { int pass;
aom_image_t raw;
aom_image_t raw_shift; int allocated_raw_shift = 0; int do_16bit_internal = 0; int input_shift = 0; int frame_avail, got_data;
struct AvxInputContext input; struct AvxEncoderConfig global; struct stream_state *streams = NULL; char **argv, **argi;
uint64_t cx_time = 0; int stream_cnt = 0; int res = 0; int profile_updated = 0;
/* First parse the global configuration values, because we want to apply * other parameters on top of the default configuration provided by the * codec.
*/
argv = argv_dup(argc - 1, argv_ + 1); if (!argv) {
fprintf(stderr, "Error allocating argument list\n"); return EXIT_FAILURE;
}
parse_global_config(&global, &argv);
if (argc < 2) usage_exit();
switch (global.color_type) { case I420: input.fmt = AOM_IMG_FMT_I420; break; case I422: input.fmt = AOM_IMG_FMT_I422; break; case I444: input.fmt = AOM_IMG_FMT_I444; break; case YV12: input.fmt = AOM_IMG_FMT_YV12; break; case NV12: input.fmt = AOM_IMG_FMT_NV12; break;
}
{ /* Now parse each stream's parameters. Using a local scope here * due to the use of 'stream' as loop variable in FOREACH_STREAM * loops
*/ struct stream_state *stream = NULL;
do {
stream = new_stream(&global, stream);
stream_cnt++; if (!streams) streams = stream;
} while (parse_stream_params(&global, stream, argv));
}
/* Check for unrecognized options */ for (argi = argv; *argi; argi++) if (argi[0][0] == '-' && argi[0][1])
die("Error: Unrecognized option %s\n", *argi);
// If large_scale_tile = 1, only support to output to ivf format. if (stream->config.cfg.large_scale_tile && !stream->config.write_ivf)
die("only support ivf output format while large-scale-tile=1\n");
}
// Set the output to the specified two-pass output file, and // restore the width and height to the original values.
FOREACH_STREAM(stream, streams) { if (need_downscale) {
stream->config.out_fn = stream->config.two_pass_output; // Libaom currently only supports the ivf format for the third pass.
stream->config.write_ivf = 1;
stream->config.write_webm = 0;
} else {
stream->config.out_fn = stream->orig_out_fn;
stream->config.write_ivf = stream->orig_write_ivf;
stream->config.write_webm = stream->orig_write_webm;
}
stream->config.cfg.g_w = stream->orig_width;
stream->config.cfg.g_h = stream->orig_height;
}
// For second pass in three-pass encoding, set the input to // the given two-pass-input file if available. If the scaled input is not // given, we will attempt to re-scale the original input.
input.filename = orig_input_filename; constchar *two_pass_input = NULL; if (need_downscale) {
FOREACH_STREAM(stream, streams) { if (stream->config.two_pass_input) {
two_pass_input = stream->config.two_pass_input;
input.filename = two_pass_input; break;
}
}
}
open_input_file(&input, global.csp);
/* If the input file doesn't specify its w/h (raw files), try to get * the data from the first stream's configuration.
*/ if (!input.width || !input.height) { if (two_pass_input) {
FOREACH_STREAM(stream, streams) { if (stream->config.two_pass_width && stream->config.two_pass_height) {
input.width = stream->config.two_pass_width;
input.height = stream->config.two_pass_height; break;
}
}
} else {
FOREACH_STREAM(stream, streams) { if (stream->config.cfg.g_w && stream->config.cfg.g_h) {
input.width = stream->config.cfg.g_w;
input.height = stream->config.cfg.g_h; break;
}
}
}
}
/* Update stream configurations from the input file's parameters */ if (!input.width || !input.height) { if (two_pass_input) {
fatal( "Specify downscaled stream dimensions with --two-pass-width " " and --two-pass-height");
} else {
fatal( "Specify stream dimensions with --width (-w) " " and --height (-h)");
}
}
/* If input file does not specify bit-depth but input-bit-depth parameter * exists, assume that to be the input bit-depth. However, if the * input-bit-depth paramter does not exist, assume the input bit-depth * to be the same as the codec bit-depth.
*/ if (!input.bit_depth) {
FOREACH_STREAM(stream, streams) { if (stream->config.cfg.g_input_bit_depth)
input.bit_depth = stream->config.cfg.g_input_bit_depth; else
input.bit_depth = stream->config.cfg.g_input_bit_depth =
(int)stream->config.cfg.g_bit_depth;
} if (input.bit_depth > 8) input.fmt |= AOM_IMG_FMT_HIGHBITDEPTH;
} else {
FOREACH_STREAM(stream, streams) {
stream->config.cfg.g_input_bit_depth = input.bit_depth;
}
}
FOREACH_STREAM(stream, streams) { if (input.fmt != AOM_IMG_FMT_I420 && input.fmt != AOM_IMG_FMT_I42016 &&
input.fmt != AOM_IMG_FMT_NV12) { /* Automatically upgrade if input is non-4:2:0 but a 4:2:0 profile
was selected. */ switch (stream->config.cfg.g_profile) { case 0: if (input.bit_depth < 12 && (input.fmt == AOM_IMG_FMT_I444 ||
input.fmt == AOM_IMG_FMT_I44416)) { if (!stream->config.cfg.monochrome) {
stream->config.cfg.g_profile = 1;
profile_updated = 1;
}
} elseif (input.bit_depth == 12 ||
((input.fmt == AOM_IMG_FMT_I422 ||
input.fmt == AOM_IMG_FMT_I42216) &&
!stream->config.cfg.monochrome)) {
stream->config.cfg.g_profile = 2;
profile_updated = 1;
} break; case 1: if (input.bit_depth == 12 || input.fmt == AOM_IMG_FMT_I422 ||
input.fmt == AOM_IMG_FMT_I42216) {
stream->config.cfg.g_profile = 2;
profile_updated = 1;
} elseif (input.bit_depth < 12 &&
(input.fmt == AOM_IMG_FMT_I420 ||
input.fmt == AOM_IMG_FMT_I42016)) {
stream->config.cfg.g_profile = 0;
profile_updated = 1;
} break; case 2: if (input.bit_depth < 12 && (input.fmt == AOM_IMG_FMT_I444 ||
input.fmt == AOM_IMG_FMT_I44416)) {
stream->config.cfg.g_profile = 1;
profile_updated = 1;
} elseif (input.bit_depth < 12 &&
(input.fmt == AOM_IMG_FMT_I420 ||
input.fmt == AOM_IMG_FMT_I42016)) {
stream->config.cfg.g_profile = 0;
profile_updated = 1;
} elseif (input.bit_depth == 12 &&
input.file_type == FILE_TYPE_Y4M) { // Note that here the input file values for chroma subsampling // are used instead of those from the command line.
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_SET_CHROMA_SUBSAMPLING_X,
input.y4m.dst_c_dec_h >> 1);
ctx_exit_on_error(&stream->encoder, "Failed to set chroma subsampling x");
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_SET_CHROMA_SUBSAMPLING_Y,
input.y4m.dst_c_dec_v >> 1);
ctx_exit_on_error(&stream->encoder, "Failed to set chroma subsampling y");
} elseif (input.bit_depth == 12 &&
input.file_type == FILE_TYPE_RAW) {
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_SET_CHROMA_SUBSAMPLING_X,
stream->chroma_subsampling_x);
ctx_exit_on_error(&stream->encoder, "Failed to set chroma subsampling x");
AOM_CODEC_CONTROL_TYPECHECKED(&stream->encoder,
AV1E_SET_CHROMA_SUBSAMPLING_Y,
stream->chroma_subsampling_y);
ctx_exit_on_error(&stream->encoder, "Failed to set chroma subsampling y");
} break; default: break;
}
} /* Automatically set the codec bit depth to match the input bit depth.
* Upgrade the profile if required. */ if (stream->config.cfg.g_input_bit_depth >
(unsignedint)stream->config.cfg.g_bit_depth) {
stream->config.cfg.g_bit_depth = stream->config.cfg.g_input_bit_depth; if (!global.quiet) {
fprintf(stderr, "Warning: automatically updating bit depth to %d to " "match input format.\n",
stream->config.cfg.g_input_bit_depth);
}
} #if !CONFIG_AV1_HIGHBITDEPTH if (stream->config.cfg.g_bit_depth > 8) {
fatal("Unsupported bit-depth with CONFIG_AV1_HIGHBITDEPTH=0\n");
} #endif// CONFIG_AV1_HIGHBITDEPTH if (stream->config.cfg.g_bit_depth > 10) { switch (stream->config.cfg.g_profile) { case 0: case 1:
stream->config.cfg.g_profile = 2;
profile_updated = 1; break; default: break;
}
} if (stream->config.cfg.g_bit_depth > 8) {
stream->config.use_16bit_internal = 1;
} if (profile_updated && !global.quiet) {
fprintf(stderr, "Warning: automatically updating to profile %d to " "match input format.\n",
stream->config.cfg.g_profile);
} if ((global.show_psnr == 2) && (stream->config.cfg.g_input_bit_depth ==
stream->config.cfg.g_bit_depth)) {
fprintf(stderr, "Warning: --psnr==2 and --psnr==1 will provide same " "results when input bit-depth == stream bit-depth, " "falling back to default psnr value\n");
global.show_psnr = 1;
} if (global.show_psnr < 0 || global.show_psnr > 2) {
fprintf(stderr, "Warning: --psnr can take only 0,1,2 as values," "falling back to default psnr value\n");
global.show_psnr = 1;
} /* Set limit */
stream->config.cfg.g_limit = global.limit;
}
/* Ensure that --passes and --pass are consistent. If --pass is set and * --passes >= 2, ensure --fpf was set.
*/ if (global.pass > 0 && global.pass <= 3 && global.passes >= 2) {
FOREACH_STREAM(stream, streams) { if (!stream->config.stats_fn)
die("Stream %d: Must specify --fpf when --pass=%d" " and --passes=%d\n",
stream->index, global.pass, global.passes);
}
}
/* Use the frame rate from the file only if none was specified * on the command-line.
*/ if (!global.have_framerate) {
global.framerate.num = input.framerate.numerator;
global.framerate.den = input.framerate.denominator;
}
FOREACH_STREAM(stream, streams) {
stream->config.cfg.g_timebase.den = global.framerate.num;
stream->config.cfg.g_timebase.num = global.framerate.den;
} /* Show configuration */ if (global.verbose && pass == 0) {
FOREACH_STREAM(stream, streams) {
show_stream_config(stream, &global, &input);
}
}
if (pass == (global.pass ? global.pass - 1 : 0)) { // The Y4M reader does its own allocation. if (input.file_type != FILE_TYPE_Y4M) {
aom_img_alloc(&raw, input.fmt, input.width, input.height, 32);
}
FOREACH_STREAM(stream, streams) {
stream->rate_hist =
init_rate_histogram(&stream->config.cfg, &global.framerate);
}
}
FOREACH_STREAM(stream, streams) { setup_pass(stream, &global, pass); }
FOREACH_STREAM(stream, streams) { initialize_encoder(stream, &global); }
FOREACH_STREAM(stream, streams) { char *encoder_settings = NULL; #if CONFIG_WEBM_IO // Test frameworks may compare outputs from different versions, but only // wish to check for bitstream changes. The encoder-settings tag, however, // can vary if the version is updated, even if no encoder algorithm // changes were made. To work around this issue, do not output // the encoder-settings tag when --debug is enabled (which is the flag // that test frameworks should use, when they want deterministic output // from the container format). if (stream->config.write_webm && !stream->webm_ctx.debug) {
encoder_settings = extract_encoder_settings(
aom_codec_version_str(), argv_, argc, input.filename); if (encoder_settings == NULL) {
fprintf(
stderr, "Warning: unable to extract encoder settings. Continuing...\n");
}
} #endif
open_output_file(stream, &global, &input.pixel_aspect_ratio,
encoder_settings);
free(encoder_settings);
}
if (strcmp(get_short_name_by_aom_encoder(global.codec), "av1") == 0) { // Check to see if at least one stream uses 16 bit internal. // Currently assume that the bit_depths for all streams using // highbitdepth are the same.
FOREACH_STREAM(stream, streams) { if (stream->config.use_16bit_internal) {
do_16bit_internal = 1;
}
input_shift = (int)stream->config.cfg.g_bit_depth -
stream->config.cfg.g_input_bit_depth;
}
}
frame_avail = 1;
got_data = 0;
while (frame_avail || got_data) { struct aom_usec_timer timer;
fprintf(stderr, "%7" PRId64 " %s %.2f %s ",
cx_time > 9999999 ? cx_time / 1000 : cx_time,
cx_time > 9999999 ? "ms" : "us", fps >= 1.0 ? fps : fps * 60,
fps >= 1.0 ? "fps" : "fpm");
print_time("ETA", estimated_time_left); // mingw-w64 gcc does not match msvc for stderr buffering behavior // and uses line buffering, thus the progress output is not // real-time. The fflush() is here to make sure the progress output // is sent out while the clip is being processed.
fflush(stderr);
}
} else {
frame_avail = 0;
}
if (frames_in > global.skip_frames) {
aom_image_t *frame_to_encode; if (input_shift || (do_16bit_internal && input.bit_depth == 8)) {
assert(do_16bit_internal); // Input bit depth and stream bit depth do not match, so up // shift frame to stream bit depth if (!allocated_raw_shift) {
aom_img_alloc(&raw_shift, raw.fmt | AOM_IMG_FMT_HIGHBITDEPTH,
input.width, input.height, 32);
allocated_raw_shift = 1;
}
aom_img_upshift(&raw_shift, &raw, input_shift);
frame_to_encode = &raw_shift;
} else {
frame_to_encode = &raw;
}
aom_usec_timer_start(&timer); if (do_16bit_internal) {
assert(frame_to_encode->fmt & AOM_IMG_FMT_HIGHBITDEPTH);
FOREACH_STREAM(stream, streams) { if (stream->config.use_16bit_internal)
encode_frame(stream, &global,
frame_avail ? frame_to_encode : NULL, frames_in); else
assert(0);
}
} else {
assert((frame_to_encode->fmt & AOM_IMG_FMT_HIGHBITDEPTH) == 0);
FOREACH_STREAM(stream, streams) {
encode_frame(stream, &global, frame_avail ? frame_to_encode : NULL,
frames_in);
}
}
aom_usec_timer_mark(&timer);
cx_time += aom_usec_timer_elapsed(&timer);
if (pass == global.passes - 1) {
FOREACH_STREAM(stream, streams) { int num_operating_points; int levels[32]; int target_levels[32];
aom_codec_control(&stream->encoder, AV1E_GET_NUM_OPERATING_POINTS,
&num_operating_points);
aom_codec_control(&stream->encoder, AV1E_GET_SEQ_LEVEL_IDX, levels);
aom_codec_control(&stream->encoder, AV1E_GET_TARGET_SEQ_LEVEL_IDX,
target_levels);
for (int i = 0; i < num_operating_points; i++) { if (levels[i] > target_levels[i]) { if (levels[i] == 31) {
aom_tools_warn( "Failed to encode to target level %d.%d for operating point " "%d. The output level is SEQ_LEVEL_MAX",
2 + (target_levels[i] >> 2), target_levels[i] & 3, i);
} else {
aom_tools_warn( "Failed to encode to target level %d.%d for operating point " "%d. The output level is %d.%d",
2 + (target_levels[i] >> 2), target_levels[i] & 3, i,
2 + (levels[i] >> 2), levels[i] & 3);
}
}
}
}
}
#if CONFIG_INTERNAL_STATS /* TODO(jkoleszar): This doesn't belong in this executable. Do it for now, * to match some existing utilities.
*/ if (!(global.pass == 1 && global.passes == 2)) {
FOREACH_STREAM(stream, streams) {
FILE *f = fopen("opsnr.stt", "a"); if (stream->mismatch_seen) {
fprintf(f, "First mismatch occurred in frame %d\n",
stream->mismatch_seen);
} else {
fprintf(f, "No mismatch detected in recon buffers\n");
}
fclose(f);
}
} #endif
if (allocated_raw_shift) aom_img_free(&raw_shift);
aom_img_free(&raw);
free(argv);
free(streams); return res ? EXIT_FAILURE : EXIT_SUCCESS;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.39 Sekunden
(vorverarbeitet am 2026-04-28)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.