/* * 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;
}
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.