Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/third_party/aom/apps/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 101 kB image not shown  

Quelle  aomenc.c   Sprache: C

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


#include "apps/aomenc.h"

#include "config/aom_config.h"

#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if CONFIG_AV1_DECODER
#include "aom/aom_decoder.h"
#include "aom/aomdx.h"
#endif

#include "aom/aom_encoder.h"
#include "aom/aom_integer.h"
#include "aom/aomcx.h"
#include "aom_dsp/aom_dsp_common.h"
#include "aom_ports/aom_timer.h"
#include "aom_ports/mem_ops.h"
#include "common/args.h"
#include "common/ivfenc.h"
#include "common/tools_common.h"
#include "common/warnings.h"

#if CONFIG_WEBM_IO
#include "common/webmenc.h"
#endif

#include "common/y4minput.h"
#include "examples/encoder_util.h"
#include "stats/aomstats.h"
#include "stats/rate_hist.h"

#if CONFIG_LIBYUV
#include "third_party/libyuv/include/libyuv/scale.h"
#endif

/* Swallow warnings about unused results of fread/fwrite */
static size_t wrap_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
  return fread(ptr, size, nmemb, stream);
}
#define fread wrap_fread

static size_t wrap_fwrite(const void *ptr, size_t size, size_t nmemb,
                          FILE *stream) {
  return fwrite(ptr, size, nmemb, stream);
}
#define fwrite wrap_fwrite

static const char *exec_name;

static AOM_TOOLS_FORMAT_PRINTF(3, 0) void warn_or_exit_on_errorv(
    aom_codec_ctx_t *ctx, int fatal, const char *s, va_list ap) {
  if (ctx->err) {
    const char *detail = aom_codec_error_detail(ctx);

    vfprintf(stderr, s, ap);
    fprintf(stderr, ": %s\n", aom_codec_error(ctx));

    if (detail) fprintf(stderr, " %s\n", detail);

    if (fatal) {
      aom_codec_destroy(ctx);
      exit(EXIT_FAILURE);
    }
  }
}

static AOM_TOOLS_FORMAT_PRINTF(2,
                               3) void ctx_exit_on_error(aom_codec_ctx_t *ctx,
                                                         const char *s, ...) {
  va_list ap;

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

static AOM_TOOLS_FORMAT_PRINTF(3, 4) void warn_or_exit_on_error(
    aom_codec_ctx_t *ctx, int fatal, const char *s, ...) {
  va_list ap;

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

static int read_frame(struct AvxInputContext *input_ctx, aom_image_t *img) {
  FILE *f = input_ctx->file;
  y4m_input *y4m = &input_ctx->y4m;
  int shortread = 0;

  if (input_ctx->file_type == FILE_TYPE_Y4M) {
    if (y4m_input_fetch_frame(y4m, f, img) < 1) return 0;
  } else {
    shortread = read_yuv_frame(input_ctx, img);
  }

  return !shortread;
}

static int file_is_y4m(const char detect[4]) {
  if (memcmp(detect, "YUV4", 4) == 0) {
    return 1;
  }
  return 0;
}

static int fourcc_is_ivf(const char detect[4]) {
  if (memcmp(detect, "DKIF", 4) == 0) {
    return 1;
  }
  return 0;
}

static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
                                        AOME_SET_ENABLEAUTOALTREF,
                                        AOME_SET_SHARPNESS,
                                        AOME_SET_STATIC_THRESHOLD,
                                        AV1E_SET_ROW_MT,
                                        AV1E_SET_FP_MT,
                                        AV1E_SET_TILE_COLUMNS,
                                        AV1E_SET_TILE_ROWS,
                                        AV1E_SET_ENABLE_TPL_MODEL,
                                        AV1E_SET_ENABLE_KEYFRAME_FILTERING,
                                        AOME_SET_ARNR_MAXFRAMES,
                                        AOME_SET_ARNR_STRENGTH,
                                        AOME_SET_TUNING,
                                        AOME_SET_CQ_LEVEL,
                                        AOME_SET_MAX_INTRA_BITRATE_PCT,
                                        AV1E_SET_MAX_INTER_BITRATE_PCT,
                                        AV1E_SET_GF_CBR_BOOST_PCT,
                                        AV1E_SET_LOSSLESS,
                                        AV1E_SET_ENABLE_CDEF,
                                        AV1E_SET_ENABLE_RESTORATION,
                                        AV1E_SET_ENABLE_RECT_PARTITIONS,
                                        AV1E_SET_ENABLE_AB_PARTITIONS,
                                        AV1E_SET_ENABLE_1TO4_PARTITIONS,
                                        AV1E_SET_MIN_PARTITION_SIZE,
                                        AV1E_SET_MAX_PARTITION_SIZE,
                                        AV1E_SET_ENABLE_DUAL_FILTER,
                                        AV1E_SET_ENABLE_CHROMA_DELTAQ,
                                        AV1E_SET_ENABLE_INTRA_EDGE_FILTER,
                                        AV1E_SET_ENABLE_ORDER_HINT,
                                        AV1E_SET_ENABLE_TX64,
                                        AV1E_SET_ENABLE_FLIP_IDTX,
                                        AV1E_SET_ENABLE_RECT_TX,
                                        AV1E_SET_ENABLE_DIST_WTD_COMP,
                                        AV1E_SET_ENABLE_MASKED_COMP,
                                        AV1E_SET_ENABLE_ONESIDED_COMP,
                                        AV1E_SET_ENABLE_INTERINTRA_COMP,
                                        AV1E_SET_ENABLE_SMOOTH_INTERINTRA,
                                        AV1E_SET_ENABLE_DIFF_WTD_COMP,
                                        AV1E_SET_ENABLE_INTERINTER_WEDGE,
                                        AV1E_SET_ENABLE_INTERINTRA_WEDGE,
                                        AV1E_SET_ENABLE_GLOBAL_MOTION,
                                        AV1E_SET_ENABLE_WARPED_MOTION,
                                        AV1E_SET_ENABLE_FILTER_INTRA,
                                        AV1E_SET_ENABLE_SMOOTH_INTRA,
                                        AV1E_SET_ENABLE_PAETH_INTRA,
                                        AV1E_SET_ENABLE_CFL_INTRA,
                                        AV1E_SET_ENABLE_DIAGONAL_INTRA,
                                        AV1E_SET_FORCE_VIDEO_MODE,
                                        AV1E_SET_ENABLE_OBMC,
                                        AV1E_SET_ENABLE_OVERLAY,
                                        AV1E_SET_ENABLE_PALETTE,
                                        AV1E_SET_ENABLE_INTRABC,
                                        AV1E_SET_ENABLE_ANGLE_DELTA,
                                        AV1E_SET_DISABLE_TRELLIS_QUANT,
                                        AV1E_SET_ENABLE_QM,
                                        AV1E_SET_QM_MIN,
                                        AV1E_SET_QM_MAX,
                                        AV1E_SET_REDUCED_TX_TYPE_SET,
                                        AV1E_SET_INTRA_DCT_ONLY,
                                        AV1E_SET_INTER_DCT_ONLY,
                                        AV1E_SET_INTRA_DEFAULT_TX_ONLY,
                                        AV1E_SET_QUANT_B_ADAPT,
                                        AV1E_SET_COEFF_COST_UPD_FREQ,
                                        AV1E_SET_MODE_COST_UPD_FREQ,
                                        AV1E_SET_MV_COST_UPD_FREQ,
                                        AV1E_SET_FRAME_PARALLEL_DECODING,
                                        AV1E_SET_ERROR_RESILIENT_MODE,
                                        AV1E_SET_AQ_MODE,
                                        AV1E_SET_DELTAQ_MODE,
                                        AV1E_SET_DELTAQ_STRENGTH,
                                        AV1E_SET_DELTALF_MODE,
                                        AV1E_SET_FRAME_PERIODIC_BOOST,
                                        AV1E_SET_NOISE_SENSITIVITY,
                                        AV1E_SET_TUNE_CONTENT,
                                        AV1E_SET_CDF_UPDATE_MODE,
                                        AV1E_SET_COLOR_PRIMARIES,
                                        AV1E_SET_TRANSFER_CHARACTERISTICS,
                                        AV1E_SET_MATRIX_COEFFICIENTS,
                                        AV1E_SET_CHROMA_SAMPLE_POSITION,
                                        AV1E_SET_MIN_GF_INTERVAL,
                                        AV1E_SET_MAX_GF_INTERVAL,
                                        AV1E_SET_GF_MIN_PYRAMID_HEIGHT,
                                        AV1E_SET_GF_MAX_PYRAMID_HEIGHT,
                                        AV1E_SET_SUPERBLOCK_SIZE,
                                        AV1E_SET_NUM_TG,
                                        AV1E_SET_MTU,
                                        AV1E_SET_TIMING_INFO_TYPE,
                                        AV1E_SET_FILM_GRAIN_TEST_VECTOR,
                                        AV1E_SET_FILM_GRAIN_TABLE,
#if CONFIG_DENOISE
                                        AV1E_SET_DENOISE_NOISE_LEVEL,
                                        AV1E_SET_DENOISE_BLOCK_SIZE,
                                        AV1E_SET_ENABLE_DNL_DENOISING,
#endif  // CONFIG_DENOISE
                                        AV1E_SET_MAX_REFERENCE_FRAMES,
                                        AV1E_SET_REDUCED_REFERENCE_SET,
                                        AV1E_SET_ENABLE_REF_FRAME_MVS,
                                        AV1E_SET_TARGET_SEQ_LEVEL_IDX,
                                        AV1E_SET_TIER_MASK,
                                        AV1E_SET_MIN_CR,
                                        AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP,
                                        AV1E_SET_CHROMA_SUBSAMPLING_X,
                                        AV1E_SET_CHROMA_SUBSAMPLING_Y,
#if CONFIG_TUNE_VMAF
                                        AV1E_SET_VMAF_MODEL_PATH,
#endif
                                        AV1E_SET_DV_COST_UPD_FREQ,
                                        AV1E_SET_PARTITION_INFO_PATH,
                                        AV1E_SET_ENABLE_DIRECTIONAL_INTRA,
                                        AV1E_SET_ENABLE_TX_SIZE_SEARCH,
                                        AV1E_SET_LOOPFILTER_CONTROL,
                                        AV1E_SET_AUTO_INTRA_TOOLS_OFF,
                                        AV1E_ENABLE_RATE_GUIDE_DELTAQ,
                                        AV1E_SET_RATE_DISTRIBUTION_INFO,
                                        0 };

static const arg_def_t *const main_args[] = {
  &g_av1_codec_arg_defs.help,
  &g_av1_codec_arg_defs.use_cfg,
  &g_av1_codec_arg_defs.debugmode,
  &g_av1_codec_arg_defs.outputfile,
  &g_av1_codec_arg_defs.codecarg,
  &g_av1_codec_arg_defs.passes,
  &g_av1_codec_arg_defs.pass_arg,
  &g_av1_codec_arg_defs.fpf_name,
  &g_av1_codec_arg_defs.limit,
  &g_av1_codec_arg_defs.skip,
  &g_av1_codec_arg_defs.good_dl,
  &g_av1_codec_arg_defs.rt_dl,
  &g_av1_codec_arg_defs.ai_dl,
  &g_av1_codec_arg_defs.quietarg,
  &g_av1_codec_arg_defs.verbosearg,
  &g_av1_codec_arg_defs.psnrarg,
  &g_av1_codec_arg_defs.use_webm,
  &g_av1_codec_arg_defs.use_ivf,
  &g_av1_codec_arg_defs.use_obu,
  &g_av1_codec_arg_defs.q_hist_n,
  &g_av1_codec_arg_defs.rate_hist_n,
  &g_av1_codec_arg_defs.disable_warnings,
  &g_av1_codec_arg_defs.disable_warning_prompt,
  &g_av1_codec_arg_defs.recontest,
  NULL
};

static const arg_def_t *const global_args[] = {
  &g_av1_codec_arg_defs.use_nv12,
  &g_av1_codec_arg_defs.use_yv12,
  &g_av1_codec_arg_defs.use_i420,
  &g_av1_codec_arg_defs.use_i422,
  &g_av1_codec_arg_defs.use_i444,
  &g_av1_codec_arg_defs.usage,
  &g_av1_codec_arg_defs.threads,
  &g_av1_codec_arg_defs.profile,
  &g_av1_codec_arg_defs.width,
  &g_av1_codec_arg_defs.height,
  &g_av1_codec_arg_defs.forced_max_frame_width,
  &g_av1_codec_arg_defs.forced_max_frame_height,
#if CONFIG_WEBM_IO
  &g_av1_codec_arg_defs.stereo_mode,
#endif
  &g_av1_codec_arg_defs.timebase,
  &g_av1_codec_arg_defs.framerate,
  &g_av1_codec_arg_defs.global_error_resilient,
  &g_av1_codec_arg_defs.bitdeptharg,
  &g_av1_codec_arg_defs.inbitdeptharg,
  &g_av1_codec_arg_defs.lag_in_frames,
  &g_av1_codec_arg_defs.large_scale_tile,
  &g_av1_codec_arg_defs.monochrome,
  &g_av1_codec_arg_defs.full_still_picture_hdr,
  &g_av1_codec_arg_defs.use_16bit_internal,
  &g_av1_codec_arg_defs.save_as_annexb,
  NULL
};

static const arg_def_t *const rc_args[] = {
  &g_av1_codec_arg_defs.dropframe_thresh,
  &g_av1_codec_arg_defs.resize_mode,
  &g_av1_codec_arg_defs.resize_denominator,
  &g_av1_codec_arg_defs.resize_kf_denominator,
  &g_av1_codec_arg_defs.superres_mode,
  &g_av1_codec_arg_defs.superres_denominator,
  &g_av1_codec_arg_defs.superres_kf_denominator,
  &g_av1_codec_arg_defs.superres_qthresh,
  &g_av1_codec_arg_defs.superres_kf_qthresh,
  &g_av1_codec_arg_defs.end_usage,
  &g_av1_codec_arg_defs.target_bitrate,
  &g_av1_codec_arg_defs.min_quantizer,
  &g_av1_codec_arg_defs.max_quantizer,
  &g_av1_codec_arg_defs.undershoot_pct,
  &g_av1_codec_arg_defs.overshoot_pct,
  &g_av1_codec_arg_defs.buf_sz,
  &g_av1_codec_arg_defs.buf_initial_sz,
  &g_av1_codec_arg_defs.buf_optimal_sz,
  &g_av1_codec_arg_defs.bias_pct,
  &g_av1_codec_arg_defs.minsection_pct,
  &g_av1_codec_arg_defs.maxsection_pct,
  NULL
};

static const arg_def_t *const kf_args[] = {
  &g_av1_codec_arg_defs.fwd_kf_enabled,
  &g_av1_codec_arg_defs.kf_min_dist,
  &g_av1_codec_arg_defs.kf_max_dist,
  &g_av1_codec_arg_defs.kf_disabled,
  &g_av1_codec_arg_defs.sframe_dist,
  &g_av1_codec_arg_defs.sframe_mode,
  NULL
};

// TODO(bohanli): Currently all options are supported by the key & value API.
// Consider removing the control ID usages?
static const arg_def_t *const av1_ctrl_args[] = {
  &g_av1_codec_arg_defs.cpu_used_av1,
  &g_av1_codec_arg_defs.auto_altref,
  &g_av1_codec_arg_defs.sharpness,
  &g_av1_codec_arg_defs.static_thresh,
  &g_av1_codec_arg_defs.rowmtarg,
  &g_av1_codec_arg_defs.fpmtarg,
  &g_av1_codec_arg_defs.tile_cols,
  &g_av1_codec_arg_defs.tile_rows,
  &g_av1_codec_arg_defs.enable_tpl_model,
  &g_av1_codec_arg_defs.enable_keyframe_filtering,
  &g_av1_codec_arg_defs.arnr_maxframes,
  &g_av1_codec_arg_defs.arnr_strength,
  &g_av1_codec_arg_defs.tune_metric,
  &g_av1_codec_arg_defs.cq_level,
  &g_av1_codec_arg_defs.max_intra_rate_pct,
  &g_av1_codec_arg_defs.max_inter_rate_pct,
  &g_av1_codec_arg_defs.gf_cbr_boost_pct,
  &g_av1_codec_arg_defs.lossless,
  &g_av1_codec_arg_defs.enable_cdef,
  &g_av1_codec_arg_defs.enable_restoration,
  &g_av1_codec_arg_defs.enable_rect_partitions,
  &g_av1_codec_arg_defs.enable_ab_partitions,
  &g_av1_codec_arg_defs.enable_1to4_partitions,
  &g_av1_codec_arg_defs.min_partition_size,
  &g_av1_codec_arg_defs.max_partition_size,
  &g_av1_codec_arg_defs.enable_dual_filter,
  &g_av1_codec_arg_defs.enable_chroma_deltaq,
  &g_av1_codec_arg_defs.enable_intra_edge_filter,
  &g_av1_codec_arg_defs.enable_order_hint,
  &g_av1_codec_arg_defs.enable_tx64,
  &g_av1_codec_arg_defs.enable_flip_idtx,
  &g_av1_codec_arg_defs.enable_rect_tx,
  &g_av1_codec_arg_defs.enable_dist_wtd_comp,
  &g_av1_codec_arg_defs.enable_masked_comp,
  &g_av1_codec_arg_defs.enable_onesided_comp,
  &g_av1_codec_arg_defs.enable_interintra_comp,
  &g_av1_codec_arg_defs.enable_smooth_interintra,
  &g_av1_codec_arg_defs.enable_diff_wtd_comp,
  &g_av1_codec_arg_defs.enable_interinter_wedge,
  &g_av1_codec_arg_defs.enable_interintra_wedge,
  &g_av1_codec_arg_defs.enable_global_motion,
  &g_av1_codec_arg_defs.enable_warped_motion,
  &g_av1_codec_arg_defs.enable_filter_intra,
  &g_av1_codec_arg_defs.enable_smooth_intra,
  &g_av1_codec_arg_defs.enable_paeth_intra,
  &g_av1_codec_arg_defs.enable_cfl_intra,
  &g_av1_codec_arg_defs.enable_diagonal_intra,
  &g_av1_codec_arg_defs.force_video_mode,
  &g_av1_codec_arg_defs.enable_obmc,
  &g_av1_codec_arg_defs.enable_overlay,
  &g_av1_codec_arg_defs.enable_palette,
  &g_av1_codec_arg_defs.enable_intrabc,
  &g_av1_codec_arg_defs.enable_angle_delta,
  &g_av1_codec_arg_defs.disable_trellis_quant,
  &g_av1_codec_arg_defs.enable_qm,
  &g_av1_codec_arg_defs.qm_min,
  &g_av1_codec_arg_defs.qm_max,
  &g_av1_codec_arg_defs.reduced_tx_type_set,
  &g_av1_codec_arg_defs.use_intra_dct_only,
  &g_av1_codec_arg_defs.use_inter_dct_only,
  &g_av1_codec_arg_defs.use_intra_default_tx_only,
  &g_av1_codec_arg_defs.quant_b_adapt,
  &g_av1_codec_arg_defs.coeff_cost_upd_freq,
  &g_av1_codec_arg_defs.mode_cost_upd_freq,
  &g_av1_codec_arg_defs.mv_cost_upd_freq,
  &g_av1_codec_arg_defs.frame_parallel_decoding,
  &g_av1_codec_arg_defs.error_resilient_mode,
  &g_av1_codec_arg_defs.aq_mode,
  &g_av1_codec_arg_defs.deltaq_mode,
  &g_av1_codec_arg_defs.deltaq_strength,
  &g_av1_codec_arg_defs.deltalf_mode,
  &g_av1_codec_arg_defs.frame_periodic_boost,
  &g_av1_codec_arg_defs.noise_sens,
  &g_av1_codec_arg_defs.tune_content,
  &g_av1_codec_arg_defs.cdf_update_mode,
  &g_av1_codec_arg_defs.input_color_primaries,
  &g_av1_codec_arg_defs.input_transfer_characteristics,
  &g_av1_codec_arg_defs.input_matrix_coefficients,
  &g_av1_codec_arg_defs.input_chroma_sample_position,
  &g_av1_codec_arg_defs.min_gf_interval,
  &g_av1_codec_arg_defs.max_gf_interval,
  &g_av1_codec_arg_defs.gf_min_pyr_height,
  &g_av1_codec_arg_defs.gf_max_pyr_height,
  &g_av1_codec_arg_defs.superblock_size,
  &g_av1_codec_arg_defs.num_tg,
  &g_av1_codec_arg_defs.mtu_size,
  &g_av1_codec_arg_defs.timing_info,
  &g_av1_codec_arg_defs.film_grain_test,
  &g_av1_codec_arg_defs.film_grain_table,
#if CONFIG_DENOISE
  &g_av1_codec_arg_defs.denoise_noise_level,
  &g_av1_codec_arg_defs.denoise_block_size,
  &g_av1_codec_arg_defs.enable_dnl_denoising,
#endif  // CONFIG_DENOISE
  &g_av1_codec_arg_defs.max_reference_frames,
  &g_av1_codec_arg_defs.reduced_reference_set,
  &g_av1_codec_arg_defs.enable_ref_frame_mvs,
  &g_av1_codec_arg_defs.target_seq_level_idx,
  &g_av1_codec_arg_defs.set_tier_mask,
  &g_av1_codec_arg_defs.set_min_cr,
  &g_av1_codec_arg_defs.vbr_corpus_complexity_lap,
  &g_av1_codec_arg_defs.input_chroma_subsampling_x,
  &g_av1_codec_arg_defs.input_chroma_subsampling_y,
#if CONFIG_TUNE_VMAF
  &g_av1_codec_arg_defs.vmaf_model_path,
#endif
  &g_av1_codec_arg_defs.dv_cost_upd_freq,
  &g_av1_codec_arg_defs.partition_info_path,
  &g_av1_codec_arg_defs.enable_directional_intra,
  &g_av1_codec_arg_defs.enable_tx_size_search,
  &g_av1_codec_arg_defs.loopfilter_control,
  &g_av1_codec_arg_defs.auto_intra_tools_off,
  &g_av1_codec_arg_defs.enable_rate_guide_deltaq,
  &g_av1_codec_arg_defs.rate_distribution_info,
  NULL,
};

static const arg_def_t *const av1_key_val_args[] = {
  &g_av1_codec_arg_defs.passes,
  &g_av1_codec_arg_defs.two_pass_output,
  &g_av1_codec_arg_defs.second_pass_log,
  &g_av1_codec_arg_defs.fwd_kf_dist,
  &g_av1_codec_arg_defs.strict_level_conformance,
  &g_av1_codec_arg_defs.sb_qp_sweep,
  &g_av1_codec_arg_defs.dist_metric,
  &g_av1_codec_arg_defs.kf_max_pyr_height,
  &g_av1_codec_arg_defs.auto_tiles,
  NULL,
};

static const arg_def_t *const no_args[] = { NULL };

static void show_help(FILE *fout, int shorthelp) {
  fprintf(fout, "Usage: %s -o dst_filename src_filename\n",
          exec_name);

  if (shorthelp) {
    fprintf(fout, "Use --help to see the full list of options.\n");
    return;
  }

  fprintf(fout, "\nOptions:\n");
  arg_show_usage(fout, main_args);
  fprintf(fout, "\nEncoder Global Options:\n");
  arg_show_usage(fout, global_args);
  fprintf(fout, "\nRate Control Options:\n");
  arg_show_usage(fout, rc_args);
  fprintf(fout, "\nKeyframe Placement Options:\n");
  arg_show_usage(fout, kf_args);
#if CONFIG_AV1_ENCODER
  fprintf(fout, "\nAV1 Specific Options:\n");
  arg_show_usage(fout, av1_ctrl_args);
  arg_show_usage(fout, av1_key_val_args);
#endif
  fprintf(fout,
          "\nStream timebase (--timebase):\n"
          " The desired precision of timestamps in the output, expressed\n"
          " in fractional seconds. Default is 1/1000.\n");
  fprintf(fout, "\nIncluded encoders:\n\n");

  const int num_encoder = get_aom_encoder_count();
  for (int i = 0; i < num_encoder; ++i) {
    aom_codec_iface_t *encoder = get_aom_encoder_by_index(i);
    const char *defstr = (i == (num_encoder - 1)) ? "(default)" : "";
    fprintf(fout, " %-6s - %s %s\n", get_short_name_by_aom_encoder(encoder),
            aom_codec_iface_name(encoder), defstr);
  }
  fprintf(fout, "\n ");
  fprintf(fout, "Use --codec to switch to a non-default encoder.\n\n");
}

void usage_exit(void) {
  show_help(stderr, 1);
  exit(EXIT_FAILURE);
}

#if CONFIG_AV1_ENCODER
#define ARG_CTRL_CNT_MAX NELEMENTS(av1_arg_ctrl_map)
#define ARG_KEY_VAL_CNT_MAX NELEMENTS(av1_key_val_args)
#endif

#if !CONFIG_WEBM_IO
typedef int stereo_format_t;
struct WebmOutputContext {
  int debug;
};
#endif

/* Per-stream configuration */
struct stream_config {
  struct aom_codec_enc_cfg cfg;
  const char *out_fn;
  const char *stats_fn;
  stereo_format_t stereo_fmt;
  int arg_ctrls[ARG_CTRL_CNT_MAX][2];
  int arg_ctrl_cnt;
  const char *arg_key_vals[ARG_KEY_VAL_CNT_MAX][2];
  int arg_key_val_cnt;
  int write_webm;
  const char *film_grain_filename;
  int write_ivf;
  // whether to use 16bit internal buffers
  int use_16bit_internal;
#if CONFIG_TUNE_VMAF
  const char *vmaf_model_path;
#endif
  const char *partition_info_path;
  unsigned int enable_rate_guide_deltaq;
  const char *rate_distribution_info;
  aom_color_range_t color_range;
  const char *two_pass_input;
  const char *two_pass_output;
  int two_pass_width;
  int two_pass_height;
};

struct stream_state {
  int index;
  struct stream_state *next;
  struct stream_config config;
  FILE *file;
  struct rate_hist *rate_hist;
  struct WebmOutputContext webm_ctx;
  uint64_t psnr_sse_total[2];
  uint64_t psnr_samples_total[2];
  double psnr_totals[2][4];
  int psnr_count[2];
  int counts[64];
  aom_codec_ctx_t encoder;
  unsigned int frames_out;
  uint64_t cx_time;
  size_t nbytes;
  stats_io_t stats;
  struct aom_image *img;
  aom_codec_ctx_t decoder;
  int mismatch_seen;
  unsigned int chroma_subsampling_x;
  unsigned int chroma_subsampling_y;
  const char *orig_out_fn;
  unsigned int orig_width;
  unsigned int orig_height;
  int orig_write_webm;
  int orig_write_ivf;
  char tmp_out_fn[1000];
};

static void validate_positive_rational(const char *msg,
                                       struct aom_rational *rat) {
  if (rat->den < 0) {
    rat->num *= -1;
    rat->den *= -1;
  }

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

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

static void init_config(cfg_options_t *config) {
  memset(config, 0, sizeof(cfg_options_t));
  config->super_block_size = 0;  // Dynamic
  config->max_partition_size = 128;
  config->min_partition_size = 4;
  config->disable_trellis_quant = 3;
}

/* Parses global config arguments into the AvxEncoderConfig. Note that
 * argv is modified and overwrites all parsed arguments.
 */

static void parse_global_config(struct AvxEncoderConfig *global, char ***argv) {
  char **argi, **argj;
  struct arg arg;
  const int num_encoder = get_aom_encoder_count();
  char **argv_local = (char **)*argv;
  if (num_encoder < 1) die("Error: no valid encoder available\n");

  /* Initialize default parameters */
  memset(global, 0, sizeof(*global));
  global->codec = get_aom_encoder_by_index(num_encoder - 1);
  global->passes = 0;
  global->color_type = I420;
  global->csp = AOM_CSP_UNKNOWN;
  global->show_psnr = 0;

  int cfg_included = 0;
  init_config(&global->encoder_config);

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

    if (arg_match(&arg, &g_av1_codec_arg_defs.use_cfg, argi)) {
      if (!cfg_included) {
        parse_cfg(arg.val, &global->encoder_config);
        cfg_included = 1;
      }
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.help, argi)) {
      show_help(stdout, 0);
      exit(EXIT_SUCCESS);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.codecarg, argi)) {
      global->codec = get_aom_encoder_by_short_name(arg.val);
      if (!global->codec)
        die("Error: Unrecognized argument (%s) to --codec\n", arg.val);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.passes, argi)) {
      global->passes = arg_parse_uint(&arg);

      if (global->passes < 1 || global->passes > 3)
        die("Error: Invalid number of passes (%d)\n", global->passes);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.pass_arg, argi)) {
      global->pass = arg_parse_uint(&arg);

      if (global->pass < 1 || global->pass > 3)
        die("Error: Invalid pass selected (%d)\n", global->pass);
    } else if (arg_match(&arg,
                         &g_av1_codec_arg_defs.input_chroma_sample_position,
                         argi)) {
      global->csp = arg_parse_enum(&arg);
      /* Flag is used by later code as well, preserve it. */
      argj++;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.usage, argi)) {
      global->usage = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.good_dl, argi)) {
      global->usage = AOM_USAGE_GOOD_QUALITY;  // Good quality usage
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.rt_dl, argi)) {
      global->usage = AOM_USAGE_REALTIME;  // Real-time usage
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.ai_dl, argi)) {
      global->usage = AOM_USAGE_ALL_INTRA;  // All intra usage
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_nv12, argi)) {
      global->color_type = NV12;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_yv12, argi)) {
      global->color_type = YV12;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_i420, argi)) {
      global->color_type = I420;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_i422, argi)) {
      global->color_type = I422;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_i444, argi)) {
      global->color_type = I444;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.quietarg, argi)) {
      global->quiet = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.verbosearg, argi)) {
      global->verbose = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.limit, argi)) {
      global->limit = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.skip, argi)) {
      global->skip_frames = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.psnrarg, argi)) {
      if (arg.val)
        global->show_psnr = arg_parse_int(&arg);
      else
        global->show_psnr = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.recontest, argi)) {
      global->test_decode = arg_parse_enum_or_int(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.framerate, argi)) {
      global->framerate = arg_parse_rational(&arg);
      validate_positive_rational(arg.name, &global->framerate);
      global->have_framerate = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.debugmode, argi)) {
      global->debug = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.q_hist_n, argi)) {
      global->show_q_hist_buckets = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.rate_hist_n, argi)) {
      global->show_rate_hist_buckets = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.disable_warnings, argi)) {
      global->disable_warnings = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.disable_warning_prompt,
                         argi)) {
      global->disable_warning_prompt = 1;
    } else {
      argj++;
    }
  }

  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;
  }
}

static void 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);
  }

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

  /* For RAW input sources, these bytes will applied on the first frame
   *  in read_frame().
   */

  input->detect.buf_read = fread(input->detect.buf, 1, 4, input->file);
  input->detect.position = 0;

  if (input->detect.buf_read == 4 && file_is_y4m(input->detect.buf)) {
    if (y4m_input_open(&input->y4m, input->file, input->detect.buf, 4, csp,
                       input->only_i420) >= 0) {
      input->file_type = FILE_TYPE_Y4M;
      input->width = input->y4m.pic_w;
      input->height = input->y4m.pic_h;
      input->pixel_aspect_ratio.numerator = input->y4m.par_n;
      input->pixel_aspect_ratio.denominator = input->y4m.par_d;
      input->framerate.numerator = input->y4m.fps_n;
      input->framerate.denominator = input->y4m.fps_d;
      input->fmt = input->y4m.aom_fmt;
      input->bit_depth = input->y4m.bit_depth;
      input->color_range = input->y4m.color_range;
    } else
      fatal("Unsupported Y4M stream.");
  } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) {
    fatal("IVF is not supported as input.");
  } else {
    input->file_type = FILE_TYPE_RAW;
  }
}

static void close_input_file(struct AvxInputContext *input) {
  fclose(input->file);
  if (input->file_type == FILE_TYPE_Y4M) y4m_input_close(&input->y4m);
}

static struct stream_state *new_stream(struct AvxEncoderConfig *global,
                                       struct stream_state *prev) {
  struct stream_state *stream;

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

  if (prev) {
    memcpy(stream, prev, sizeof(*stream));
    stream->index++;
    prev->next = stream;
  } else {
    aom_codec_err_t res;

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

    /* Initialize remaining stream parameters */
    stream->config.write_webm = 1;
    stream->config.write_ivf = 0;

#if CONFIG_WEBM_IO
    stream->config.stereo_fmt = STEREO_FORMAT_MONO;
    stream->webm_ctx.last_pts_ns = -1;
    stream->webm_ctx.writer = NULL;
    stream->webm_ctx.segment = NULL;
#endif

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

static void set_config_arg_ctrls(struct stream_config *config, int key,
                                 const struct 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;

  /* Update/insert */
  assert(j < ARG_CTRL_CNT_MAX);
  config->arg_ctrls[j][0] = key;
  config->arg_ctrls[j][1] = arg_parse_enum_or_int(arg);

  if (key == AOME_SET_ENABLEAUTOALTREF && config->arg_ctrls[j][1] > 1) {
    aom_tools_warn(
        "auto-alt-ref > 1 is deprecated... setting auto-alt-ref=1\n");
    config->arg_ctrls[j][1] = 1;
  }

  if (j == config->arg_ctrl_cnt) config->arg_ctrl_cnt++;
}

static void set_config_arg_key_vals(struct stream_config *config,
                                    const char *name, const struct arg *arg) {
  int j;
  const char *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;

  /* Update/insert */
  assert(j < ARG_KEY_VAL_CNT_MAX);
  config->arg_key_vals[j][0] = name;
  config->arg_key_vals[j][1] = val;

  if (strcmp(name, g_av1_codec_arg_defs.auto_altref.long_name) == 0) {
    int auto_altref = arg_parse_int(arg);
    if (auto_altref > 1) {
      aom_tools_warn(
          "auto-alt-ref > 1 is deprecated... setting auto-alt-ref=1\n");
      config->arg_key_vals[j][1] = "1";
    }
  }

  if (j == config->arg_key_val_cnt) config->arg_key_val_cnt++;
}

static int parse_stream_params(struct AvxEncoderConfig *global,
                               struct stream_state *stream, char **argv) {
  char **argi, **argj;
  struct arg arg;
  const arg_def_t *const *ctrl_args = no_args;
  const arg_def_t *const *key_val_args = no_args;
  const int *ctrl_args_map = NULL;
  struct stream_config *config = &stream->config;
  int eos_mark_found = 0;
  int webm_forced = 0;

  // Handle codec specific options
  if (0) {
#if CONFIG_AV1_ENCODER
  } else if (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;
    } else if (!strcmp(*argj, "--")) {
      eos_mark_found = 1;
      continue;
    }

    if (arg_match(&arg, &g_av1_codec_arg_defs.outputfile, argi)) {
      config->out_fn = arg.val;
      if (!webm_forced) {
        const size_t out_fn_len = strlen(config->out_fn);
        if (out_fn_len >= 4 &&
            !strcmp(config->out_fn + out_fn_len - 4, ".ivf")) {
          config->write_webm = 0;
          config->write_ivf = 1;
        } else if (out_fn_len >= 4 &&
                   !strcmp(config->out_fn + out_fn_len - 4, ".obu")) {
          config->write_webm = 0;
          config->write_ivf = 0;
        }
      }
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.fpf_name, argi)) {
      config->stats_fn = arg.val;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_webm, argi)) {
#if CONFIG_WEBM_IO
      config->write_webm = 1;
      webm_forced = 1;
#else
      die("Error: --webm specified but webm is disabled.");
#endif
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_ivf, argi)) {
      config->write_webm = 0;
      config->write_ivf = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_obu, argi)) {
      config->write_webm = 0;
      config->write_ivf = 0;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.threads, argi)) {
      config->cfg.g_threads = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.profile, argi)) {
      config->cfg.g_profile = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.width, argi)) {
      config->cfg.g_w = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.height, argi)) {
      config->cfg.g_h = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.forced_max_frame_width,
                         argi)) {
      config->cfg.g_forced_max_frame_width = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.forced_max_frame_height,
                         argi)) {
      config->cfg.g_forced_max_frame_height = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.bitdeptharg, argi)) {
      config->cfg.g_bit_depth = arg_parse_enum_or_int(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.inbitdeptharg, argi)) {
      config->cfg.g_input_bit_depth = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.input_chroma_subsampling_x,
                         argi)) {
      stream->chroma_subsampling_x = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.input_chroma_subsampling_y,
                         argi)) {
      stream->chroma_subsampling_y = arg_parse_uint(&arg);
#if CONFIG_WEBM_IO
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.stereo_mode, argi)) {
      config->stereo_fmt = arg_parse_enum_or_int(&arg);
#endif
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.timebase, argi)) {
      config->cfg.g_timebase = arg_parse_rational(&arg);
      validate_positive_rational(arg.name, &config->cfg.g_timebase);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.global_error_resilient,
                         argi)) {
      config->cfg.g_error_resilient = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.lag_in_frames, argi)) {
      config->cfg.g_lag_in_frames = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.large_scale_tile, argi)) {
      config->cfg.large_scale_tile = arg_parse_uint(&arg);
      if (config->cfg.large_scale_tile) {
        global->codec = get_aom_encoder_by_short_name("av1");
      }
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.monochrome, argi)) {
      config->cfg.monochrome = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.full_still_picture_hdr,
                         argi)) {
      config->cfg.full_still_picture_hdr = 1;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_16bit_internal,
                         argi)) {
      config->use_16bit_internal = CONFIG_AV1_HIGHBITDEPTH;
      if (!config->use_16bit_internal) {
        aom_tools_warn("%s option ignored with CONFIG_AV1_HIGHBITDEPTH=0.\n",
                       arg.name);
      }
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.dropframe_thresh, argi)) {
      config->cfg.rc_dropframe_thresh = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.resize_mode, argi)) {
      config->cfg.rc_resize_mode = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.resize_denominator,
                         argi)) {
      config->cfg.rc_resize_denominator = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.resize_kf_denominator,
                         argi)) {
      config->cfg.rc_resize_kf_denominator = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.superres_mode, argi)) {
      config->cfg.rc_superres_mode = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.superres_denominator,
                         argi)) {
      config->cfg.rc_superres_denominator = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.superres_kf_denominator,
                         argi)) {
      config->cfg.rc_superres_kf_denominator = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.superres_qthresh, argi)) {
      config->cfg.rc_superres_qthresh = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.superres_kf_qthresh,
                         argi)) {
      config->cfg.rc_superres_kf_qthresh = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.end_usage, argi)) {
      config->cfg.rc_end_usage = arg_parse_enum_or_int(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.target_bitrate, argi)) {
      config->cfg.rc_target_bitrate = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.min_quantizer, argi)) {
      config->cfg.rc_min_quantizer = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.max_quantizer, argi)) {
      config->cfg.rc_max_quantizer = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.undershoot_pct, argi)) {
      config->cfg.rc_undershoot_pct = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.overshoot_pct, argi)) {
      config->cfg.rc_overshoot_pct = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.buf_sz, argi)) {
      config->cfg.rc_buf_sz = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.buf_initial_sz, argi)) {
      config->cfg.rc_buf_initial_sz = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.buf_optimal_sz, argi)) {
      config->cfg.rc_buf_optimal_sz = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.bias_pct, argi)) {
      config->cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg);
      if (global->passes < 2)
        aom_tools_warn("option %s ignored in one-pass mode.\n", arg.name);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.minsection_pct, argi)) {
      config->cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg);

      if (global->passes < 2)
        aom_tools_warn("option %s ignored in one-pass mode.\n", arg.name);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.maxsection_pct, argi)) {
      config->cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg);

      if (global->passes < 2)
        aom_tools_warn("option %s ignored in one-pass mode.\n", arg.name);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.fwd_kf_enabled, argi)) {
      config->cfg.fwd_kf_enabled = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.kf_min_dist, argi)) {
      config->cfg.kf_min_dist = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.kf_max_dist, argi)) {
      config->cfg.kf_max_dist = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.kf_disabled, argi)) {
      config->cfg.kf_mode = AOM_KF_DISABLED;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.sframe_dist, argi)) {
      config->cfg.sframe_dist = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.sframe_mode, argi)) {
      config->cfg.sframe_mode = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.save_as_annexb, argi)) {
      config->cfg.save_as_annexb = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.tile_width, argi)) {
      config->cfg.tile_width_count =
          arg_parse_list(&arg, config->cfg.tile_widths, MAX_TILE_WIDTHS);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.tile_height, argi)) {
      config->cfg.tile_height_count =
          arg_parse_list(&arg, config->cfg.tile_heights, MAX_TILE_HEIGHTS);
#if CONFIG_TUNE_VMAF
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.vmaf_model_path, argi)) {
      config->vmaf_model_path = arg.val;
#endif
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.partition_info_path,
                         argi)) {
      config->partition_info_path = arg.val;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.enable_rate_guide_deltaq,
                         argi)) {
      config->enable_rate_guide_deltaq = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.rate_distribution_info,
                         argi)) {
      config->rate_distribution_info = arg.val;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.use_fixed_qp_offsets,
                         argi)) {
      config->cfg.use_fixed_qp_offsets = arg_parse_uint(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.fixed_qp_offsets, argi)) {
      config->cfg.use_fixed_qp_offsets = 1;
    } else if (global->usage == AOM_USAGE_REALTIME &&
               arg_match(&arg, &g_av1_codec_arg_defs.enable_restoration,
                         argi)) {
      if (arg_parse_uint(&arg) == 1) {
        aom_tools_warn("non-zero %s option ignored in realtime mode.\n",
                       arg.name);
      }
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.two_pass_input, argi)) {
      config->two_pass_input = arg.val;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.two_pass_output, argi)) {
      config->two_pass_output = arg.val;
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.two_pass_width, argi)) {
      config->two_pass_width = arg_parse_int(&arg);
    } else if (arg_match(&arg, &g_av1_codec_arg_defs.two_pass_height, argi)) {
      config->two_pass_height = arg_parse_int(&arg);
    } else {
      int i, match = 0;
      // check if the control ID API supports this arg
      if (ctrl_args_map) {
        for (i = 0; ctrl_args[i]; i++) {
          if (arg_match(&arg, ctrl_args[i], argi)) {
            match = 1;
            set_config_arg_ctrls(config, ctrl_args_map[i], &arg);
            break;
          }
        }
      }
      if (!match) {
        // check if the key & value API supports this arg
        for (i = 0; key_val_args[i]; i++) {
          if (arg_match(&arg, key_val_args[i], argi)) {
            match = 1;
            set_config_arg_key_vals(config, key_val_args[i]->long_name, &arg);
            break;
          }
        }
      }
      if (!match) argj++;
    }
  }
  config->use_16bit_internal |= config->cfg.g_bit_depth > AOM_BITS_8;

  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++;
  }

  return eos_mark_found;
}

#define FOREACH_STREAM(iterator, list)                 \
  for (struct stream_state *iterator = list; iterator; \
       iterator = iterator->next)

static void validate_stream_config(const struct stream_state *stream,
                                   const struct AvxEncoderConfig *global) {
  const struct stream_state *streami;
  (void)global;

  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 <=
         (unsigned int)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) {
      const char *a = stream->config.out_fn;
      const char *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) {
      const char *a = stream->config.stats_fn;
      const char *b = streami->config.stats_fn;
      if (a && b && !strcmp(a, b))
        fatal("Stream %d: duplicate stats file (from stream %d)",
              streami->index, stream->index);
    }
  }
}

static void set_stream_dimensions(struct stream_state *stream, unsigned int w,
                                  unsigned int 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;
  }
}

static const char *file_type_to_string(enum VideoFileType t) {
  switch (t) {
    case FILE_TYPE_RAW: return "RAW";
    case FILE_TYPE_Y4M: return "Y4M";
    defaultreturn "Other";
  }
}

static void show_stream_config(struct stream_state *stream,
                               struct AvxEncoderConfig *global,
                               struct AvxInputContext *input) {
#define SHOW(field) \
  fprintf(stderr, " %-28s = %d\n"#field, stream->config.cfg.field)

  if (stream->index == 0) {
    fprintf(stderr, "Codec: %s\n", aom_codec_iface_name(global->codec));
    fprintf(stderr, "Source file: %s File Type: %s Format: %s\n",
            input->filename, file_type_to_string(input->file_type),
            image_format_to_string(input->fmt));
  }
  if (stream->next || stream->index)
    fprintf(stderr, "\nStream Index: %d\n", stream->index);
  fprintf(stderr, "Destination file: %s\n", stream->config.out_fn);
  fprintf(stderr, "Coding path: %s\n",
          stream->config.use_16bit_internal ? "HBD" : "LBD");
  fprintf(stderr, "Encoder parameters:\n");

  SHOW(g_usage);
  SHOW(g_threads);
  SHOW(g_profile);
  SHOW(g_w);
  SHOW(g_h);
  SHOW(g_bit_depth);
  SHOW(g_input_bit_depth);
  SHOW(g_timebase.num);
  SHOW(g_timebase.den);
  SHOW(g_error_resilient);
  SHOW(g_pass);
  SHOW(g_lag_in_frames);
  SHOW(large_scale_tile);
  SHOW(rc_dropframe_thresh);
  SHOW(rc_resize_mode);
  SHOW(rc_resize_denominator);
  SHOW(rc_resize_kf_denominator);
  SHOW(rc_superres_mode);
  SHOW(rc_superres_denominator);
  SHOW(rc_superres_kf_denominator);
  SHOW(rc_superres_qthresh);
  SHOW(rc_superres_kf_qthresh);
  SHOW(rc_end_usage);
  SHOW(rc_target_bitrate);
  SHOW(rc_min_quantizer);
  SHOW(rc_max_quantizer);
  SHOW(rc_undershoot_pct);
  SHOW(rc_overshoot_pct);
  SHOW(rc_buf_sz);
  SHOW(rc_buf_initial_sz);
  SHOW(rc_buf_optimal_sz);
  SHOW(rc_2pass_vbr_bias_pct);
  SHOW(rc_2pass_vbr_minsection_pct);
  SHOW(rc_2pass_vbr_maxsection_pct);
  SHOW(fwd_kf_enabled);
  SHOW(kf_mode);
  SHOW(kf_min_dist);
  SHOW(kf_max_dist);

#define SHOW_PARAMS(field)                    \
  fprintf(stderr, " %-28s = %d\n"#field, \
          stream->config.cfg.encoder_cfg.field)
  if (global->encoder_config.init_by_cfg_file) {
    SHOW_PARAMS(super_block_size);
    SHOW_PARAMS(max_partition_size);
    SHOW_PARAMS(min_partition_size);
    SHOW_PARAMS(disable_ab_partition_type);
    SHOW_PARAMS(disable_rect_partition_type);
    SHOW_PARAMS(disable_1to4_partition_type);
    SHOW_PARAMS(disable_flip_idtx);
    SHOW_PARAMS(disable_cdef);
    SHOW_PARAMS(disable_lr);
    SHOW_PARAMS(disable_obmc);
    SHOW_PARAMS(disable_warp_motion);
    SHOW_PARAMS(disable_global_motion);
    SHOW_PARAMS(disable_dist_wtd_comp);
    SHOW_PARAMS(disable_diff_wtd_comp);
    SHOW_PARAMS(disable_inter_intra_comp);
    SHOW_PARAMS(disable_masked_comp);
    SHOW_PARAMS(disable_one_sided_comp);
    SHOW_PARAMS(disable_palette);
    SHOW_PARAMS(disable_intrabc);
    SHOW_PARAMS(disable_cfl);
    SHOW_PARAMS(disable_smooth_intra);
    SHOW_PARAMS(disable_filter_intra);
    SHOW_PARAMS(disable_dual_filter);
    SHOW_PARAMS(disable_intra_angle_delta);
    SHOW_PARAMS(disable_intra_edge_filter);
    SHOW_PARAMS(disable_tx_64x64);
    SHOW_PARAMS(disable_smooth_inter_intra);
    SHOW_PARAMS(disable_inter_inter_wedge);
    SHOW_PARAMS(disable_inter_intra_wedge);
    SHOW_PARAMS(disable_paeth_intra);
    SHOW_PARAMS(disable_trellis_quant);
    SHOW_PARAMS(disable_ref_frame_mv);
    SHOW_PARAMS(reduced_reference_set);
    SHOW_PARAMS(reduced_tx_type_set);
  }
}

static void open_output_file(struct stream_state *stream,
                             struct AvxEncoderConfig *global,
                             const struct AvxRational *pixel_aspect_ratio,
                             const char *encoder_settings) {
  const char *fn = stream->config.out_fn;
  const struct aom_codec_enc_cfg *const cfg = &stream->config.cfg;

  if (cfg->g_pass == AOM_RC_FIRST_PASS) return;

  stream->file = strcmp(fn, "-") ? fopen(fn, "wb") : set_binary_mode(stdout);

  if (!stream->file) fatal("Failed to open output file");

  if (stream->config.write_webm && fseek(stream->file, 0, SEEK_CUR))
    fatal("WebM output to pipes not supported.");

#if CONFIG_WEBM_IO
  if (stream->config.write_webm) {
    stream->webm_ctx.stream = stream->file;
    if (write_webm_file_header(&stream->webm_ctx, &stream->encoder, cfg,
                               stream->config.stereo_fmt,
                               get_fourcc_by_aom_encoder(global->codec),
                               pixel_aspect_ratio, encoder_settings) != 0) {
      fatal("WebM writer initialization failed.");
    }
  }
#else
  (void)pixel_aspect_ratio;
  (void)encoder_settings;
#endif

  if (!stream->config.write_webm && stream->config.write_ivf) {
    ivf_write_file_header(stream->file, cfg,
                          get_fourcc_by_aom_encoder(global->codec), 0);
  }
}

static void close_output_file(struct stream_state *stream,
                              unsigned int fourcc) {
  const struct aom_codec_enc_cfg *const cfg = &stream->config.cfg;

  if (cfg->g_pass == AOM_RC_FIRST_PASS) return;

#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);
}

static void 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);
  }

  stream->cx_time = 0;
  stream->nbytes = 0;
  stream->frames_out = 0;
}

static void initialize_encoder(struct stream_state *stream,
                               struct AvxEncoderConfig *global) {
  int i;
  int flags = 0;

  flags |= (global->show_psnr >= 1) ? AOM_CODEC_USE_PSNR : 0;
  flags |= stream->config.use_16bit_internal ? AOM_CODEC_USE_HIGHBITDEPTH : 0;

  /* Construct Encoder Context */
  aom_codec_enc_init(&stream->encoder, global->codec, &stream->config.cfg,
                     flags);
  ctx_exit_on_error(&stream->encoder, "Failed to initialize encoder");

  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++) {
    const char *name = stream->config.arg_key_vals[i][0];
    const char *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 CONFIG_AV1_DECODER
  if (global->test_decode != TEST_DECODE_OFF) {
    aom_codec_iface_t *decoder = get_aom_decoder_by_short_name(
        get_short_name_by_aom_encoder(global->codec));
    aom_codec_dec_cfg_t cfg = { 0, 0, 0, !stream->config.use_16bit_internal };
    aom_codec_dec_init(&stream->decoder, decoder, &cfg, 0);

    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.
static void convert_image_to_monochrome(const struct 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;
}

static void encode_frame(struct stream_state *stream,
                         struct AvxEncoderConfig *global, struct aom_image *img,
                         unsigned int frames_in) {
  aom_codec_pts_t frame_start, next_frame_start;
  struct aom_codec_enc_cfg *cfg = &stream->config.cfg;
  struct aom_usec_timer timer;

  frame_start =
      (cfg->g_timebase.den * (int64_t)(frames_in - 1) * global->framerate.den) /
      cfg->g_timebase.num / global->framerate.num;
  next_frame_start =
      (cfg->g_timebase.den * (int64_t)(frames_in)*global->framerate.den) /
      cfg->g_timebase.num / global->framerate.num;

  /* Scale if necessary */
  if (img) {
    if ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) &&
        (img->d_w != cfg->g_w || img->d_h != cfg->g_h)) {
      if (img->fmt != AOM_IMG_FMT_I42016) {
        fprintf(stderr, "%s can only scale 4:2:0 inputs\n", exec_name);
        exit(EXIT_FAILURE);
      }
#if CONFIG_LIBYUV
      if (!stream->img) {
        stream->img =
            aom_img_alloc(NULL, AOM_IMG_FMT_I42016, cfg->g_w, cfg->g_h, 16);
      }
      I420Scale_16(
          (uint16_t *)img->planes[AOM_PLANE_Y], img->stride[AOM_PLANE_Y] / 2,
          (uint16_t *)img->planes[AOM_PLANE_U], img->stride[AOM_PLANE_U] / 2,
          (uint16_t *)img->planes[AOM_PLANE_V], img->stride[AOM_PLANE_V] / 2,
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=97 H=97 G=96

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.