chromium/third_party/libaom/source/libaom/av1/encoder/encode_strategy.c

/*
 * Copyright (c) 2019, 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 <stdint.h>

#include "av1/common/blockd.h"
#include "config/aom_config.h"
#include "config/aom_scale_rtcd.h"

#include "aom/aom_codec.h"
#include "aom/aom_encoder.h"

#if CONFIG_MISMATCH_DEBUG
#include "aom_util/debug_util.h"
#endif  // CONFIG_MISMATCH_DEBUG

#include "av1/common/av1_common_int.h"
#include "av1/common/reconinter.h"

#include "av1/encoder/encoder.h"
#include "av1/encoder/encode_strategy.h"
#include "av1/encoder/encodeframe.h"
#include "av1/encoder/encoder_alloc.h"
#include "av1/encoder/firstpass.h"
#include "av1/encoder/gop_structure.h"
#include "av1/encoder/pass2_strategy.h"
#include "av1/encoder/temporal_filter.h"
#if CONFIG_THREE_PASS
#include "av1/encoder/thirdpass.h"
#endif  // CONFIG_THREE_PASS
#include "av1/encoder/tpl_model.h"

#if CONFIG_TUNE_VMAF
#include "av1/encoder/tune_vmaf.h"
#endif

#define TEMPORAL_FILTER_KEY_FRAME

static inline void set_refresh_frame_flags(
    RefreshFrameInfo *const refresh_frame, bool refresh_gf, bool refresh_bwdref,
    bool refresh_arf) {}

void av1_configure_buffer_updates(AV1_COMP *const cpi,
                                  RefreshFrameInfo *const refresh_frame,
                                  const FRAME_UPDATE_TYPE type,
                                  const REFBUF_STATE refbuf_state,
                                  int force_refresh_all) {}

static void set_additional_frame_flags(const AV1_COMMON *const cm,
                                       unsigned int *const frame_flags) {}

static void set_ext_overrides(AV1_COMMON *const cm,
                              EncodeFrameParams *const frame_params,
                              ExternalFlags *const ext_flags) {}

static int choose_primary_ref_frame(
    AV1_COMP *const cpi, const EncodeFrameParams *const frame_params) {}

static void adjust_frame_rate(AV1_COMP *cpi, int64_t ts_start, int64_t ts_end) {}

// Determine whether there is a forced keyframe pending in the lookahead buffer
int is_forced_keyframe_pending(struct lookahead_ctx *lookahead,
                               const int up_to_index,
                               const COMPRESSOR_STAGE compressor_stage) {}

// Check if we should encode an ARF or internal ARF.  If not, try a LAST
// Do some setup associated with the chosen source
// temporal_filtered, flush, and frame_update_type are outputs.
// Return the frame source, or NULL if we couldn't find one
static struct lookahead_entry *choose_frame_source(
    AV1_COMP *const cpi, int *const flush, int *pop_lookahead,
    struct lookahead_entry **last_source, int *const show_frame) {}

// Don't allow a show_existing_frame to coincide with an error resilient or
// S-Frame. An exception can be made in the case of a keyframe, since it does
// not depend on any previous frames.
static int allow_show_existing(const AV1_COMP *const cpi,
                               unsigned int frame_flags) {}

// Update frame_flags to tell the encoder's caller what sort of frame was
// encoded.
static void update_frame_flags(const AV1_COMMON *const cm,
                               const RefreshFrameInfo *const refresh_frame,
                               unsigned int *frame_flags) {}

#define DUMP_REF_FRAME_IMAGES

#if DUMP_REF_FRAME_IMAGES == 1
static int dump_one_image(AV1_COMMON *cm,
                          const YV12_BUFFER_CONFIG *const ref_buf,
                          char *file_name) {
  int h;
  FILE *f_ref = NULL;

  if (ref_buf == NULL) {
    printf("Frame data buffer is NULL.\n");
    return AOM_CODEC_MEM_ERROR;
  }

  if ((f_ref = fopen(file_name, "wb")) == NULL) {
    printf("Unable to open file %s to write.\n", file_name);
    return AOM_CODEC_MEM_ERROR;
  }

  // --- Y ---
  for (h = 0; h < cm->height; ++h) {
    fwrite(&ref_buf->y_buffer[h * ref_buf->y_stride], 1, cm->width, f_ref);
  }
  // --- U ---
  for (h = 0; h < (cm->height >> 1); ++h) {
    fwrite(&ref_buf->u_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
           f_ref);
  }
  // --- V ---
  for (h = 0; h < (cm->height >> 1); ++h) {
    fwrite(&ref_buf->v_buffer[h * ref_buf->uv_stride], 1, (cm->width >> 1),
           f_ref);
  }

  fclose(f_ref);

  return AOM_CODEC_OK;
}

static void dump_ref_frame_images(AV1_COMP *cpi) {
  AV1_COMMON *const cm = &cpi->common;
  MV_REFERENCE_FRAME ref_frame;

  for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
    char file_name[256] = "";
    snprintf(file_name, sizeof(file_name), "/tmp/enc_F%d_ref_%d.yuv",
             cm->current_frame.frame_number, ref_frame);
    dump_one_image(cm, get_ref_frame_yv12_buf(cpi, ref_frame), file_name);
  }
}
#endif  // DUMP_REF_FRAME_IMAGES == 1

int av1_get_refresh_ref_frame_map(int refresh_frame_flags) {}

static int get_free_ref_map_index(RefFrameMapPair ref_map_pairs[REF_FRAMES]) {}

static int get_refresh_idx(RefFrameMapPair ref_frame_map_pairs[REF_FRAMES],
                           int update_arf, GF_GROUP *gf_group, int gf_index,
                           int enable_refresh_skip, int cur_frame_disp) {}

// Computes the reference refresh index for INTNL_ARF_UPDATE frame.
int av1_calc_refresh_idx_for_intnl_arf(
    AV1_COMP *cpi, RefFrameMapPair ref_frame_map_pairs[REF_FRAMES],
    int gf_index) {}

int av1_get_refresh_frame_flags(
    const AV1_COMP *const cpi, const EncodeFrameParams *const frame_params,
    FRAME_UPDATE_TYPE frame_update_type, int gf_index, int cur_disp_order,
    RefFrameMapPair ref_frame_map_pairs[REF_FRAMES]) {}

#if !CONFIG_REALTIME_ONLY
// Apply temporal filtering to source frames and encode the filtered frame.
// If the current frame does not require filtering, this function is identical
// to av1_encode() except that tpl is not performed.
static int denoise_and_encode(AV1_COMP *const cpi, uint8_t *const dest,
                              size_t dest_size,
                              EncodeFrameInput *const frame_input,
                              const EncodeFrameParams *const frame_params,
                              EncodeFrameResults *const frame_results) {
#if CONFIG_COLLECT_COMPONENT_TIMING
  if (cpi->oxcf.pass == 2) start_timing(cpi, denoise_and_encode_time);
#endif
  const AV1EncoderConfig *const oxcf = &cpi->oxcf;
  AV1_COMMON *const cm = &cpi->common;

  GF_GROUP *const gf_group = &cpi->ppi->gf_group;
  FRAME_UPDATE_TYPE update_type =
      get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index);
  const int is_second_arf =
      av1_gop_is_second_arf(gf_group, cpi->gf_frame_index);

  // Decide whether to apply temporal filtering to the source frame.
  int apply_filtering =
      av1_is_temporal_filter_on(oxcf) && !is_stat_generation_stage(cpi);
  if (update_type != KF_UPDATE && update_type != ARF_UPDATE && !is_second_arf) {
    apply_filtering = 0;
  }
  if (apply_filtering) {
    if (frame_params->frame_type == KEY_FRAME) {
      // TODO(angiebird): Move the noise level check to av1_tf_info_filtering.
      // Decide whether it is allowed to perform key frame filtering
      int allow_kf_filtering = oxcf->kf_cfg.enable_keyframe_filtering &&
                               !frame_params->show_existing_frame &&
                               !is_lossless_requested(&oxcf->rc_cfg);
      if (allow_kf_filtering) {
        double y_noise_level = 0.0;
        av1_estimate_noise_level(
            frame_input->source, &y_noise_level, AOM_PLANE_Y, AOM_PLANE_Y,
            cm->seq_params->bit_depth, NOISE_ESTIMATION_EDGE_THRESHOLD);
        apply_filtering = y_noise_level > 0;
      } else {
        apply_filtering = 0;
      }
      // If we are doing kf filtering, set up a few things.
      if (apply_filtering) {
        av1_setup_past_independence(cm);
      }
    } else if (is_second_arf) {
      apply_filtering = cpi->sf.hl_sf.second_alt_ref_filtering;
    }
  }

#if CONFIG_COLLECT_COMPONENT_TIMING
  if (cpi->oxcf.pass == 2) start_timing(cpi, apply_filtering_time);
#endif
  // Save the pointer to the original source image.
  YV12_BUFFER_CONFIG *source_buffer = frame_input->source;
  // apply filtering to frame
  if (apply_filtering) {
    int show_existing_alt_ref = 0;
    FRAME_DIFF frame_diff;
    int top_index = 0;
    int bottom_index = 0;
    const int q_index = av1_rc_pick_q_and_bounds(
        cpi, cpi->oxcf.frm_dim_cfg.width, cpi->oxcf.frm_dim_cfg.height,
        cpi->gf_frame_index, &bottom_index, &top_index);

    // TODO(bohanli): figure out why we need frame_type in cm here.
    cm->current_frame.frame_type = frame_params->frame_type;
    if (update_type == KF_UPDATE || update_type == ARF_UPDATE) {
      YV12_BUFFER_CONFIG *tf_buf = av1_tf_info_get_filtered_buf(
          &cpi->ppi->tf_info, cpi->gf_frame_index, &frame_diff);
      if (tf_buf != NULL) {
        frame_input->source = tf_buf;
        show_existing_alt_ref = av1_check_show_filtered_frame(
            tf_buf, &frame_diff, q_index, cm->seq_params->bit_depth);
        if (show_existing_alt_ref) {
          cpi->common.showable_frame |= 1;
        } else {
          cpi->common.showable_frame = 0;
        }
      }
      if (gf_group->frame_type[cpi->gf_frame_index] != KEY_FRAME) {
        cpi->ppi->show_existing_alt_ref = show_existing_alt_ref;
      }
    }

    if (is_second_arf) {
      // Allocate the memory for tf_buf_second_arf buffer, only when it is
      // required.
      int ret = aom_realloc_frame_buffer(
          &cpi->ppi->tf_info.tf_buf_second_arf, oxcf->frm_dim_cfg.width,
          oxcf->frm_dim_cfg.height, cm->seq_params->subsampling_x,
          cm->seq_params->subsampling_y, cm->seq_params->use_highbitdepth,
          cpi->oxcf.border_in_pixels, cm->features.byte_alignment, NULL, NULL,
          NULL, cpi->alloc_pyramid, 0);
      if (ret)
        aom_internal_error(cm->error, AOM_CODEC_MEM_ERROR,
                           "Failed to allocate tf_buf_second_arf");

      YV12_BUFFER_CONFIG *tf_buf_second_arf =
          &cpi->ppi->tf_info.tf_buf_second_arf;
      // We didn't apply temporal filtering for second arf ahead in
      // av1_tf_info_filtering().
      const int arf_src_index = gf_group->arf_src_offset[cpi->gf_frame_index];
      // Right now, we are still using tf_buf_second_arf due to
      // implementation complexity.
      // TODO(angiebird): Reuse tf_info->tf_buf here.
      av1_temporal_filter(cpi, arf_src_index, cpi->gf_frame_index, &frame_diff,
                          tf_buf_second_arf);
      show_existing_alt_ref = av1_check_show_filtered_frame(
          tf_buf_second_arf, &frame_diff, q_index, cm->seq_params->bit_depth);
      if (show_existing_alt_ref) {
        aom_extend_frame_borders(tf_buf_second_arf, av1_num_planes(cm));
        frame_input->source = tf_buf_second_arf;
      }
      // Currently INTNL_ARF_UPDATE only do show_existing.
      cpi->common.showable_frame |= 1;
    }

    // Copy source metadata to the temporal filtered frame
    if (source_buffer->metadata &&
        aom_copy_metadata_to_frame_buffer(frame_input->source,
                                          source_buffer->metadata)) {
      aom_internal_error(
          cm->error, AOM_CODEC_MEM_ERROR,
          "Failed to copy source metadata to the temporal filtered frame");
    }
  }
#if CONFIG_COLLECT_COMPONENT_TIMING
  if (cpi->oxcf.pass == 2) end_timing(cpi, apply_filtering_time);
#endif

  int set_mv_params = frame_params->frame_type == KEY_FRAME ||
                      update_type == ARF_UPDATE || update_type == GF_UPDATE;
  cm->show_frame = frame_params->show_frame;
  cm->current_frame.frame_type = frame_params->frame_type;
  // TODO(bohanli): Why is this? what part of it is necessary?
  av1_set_frame_size(cpi, cm->width, cm->height);
  if (set_mv_params) av1_set_mv_search_params(cpi);

#if CONFIG_RD_COMMAND
  if (frame_params->frame_type == KEY_FRAME) {
    char filepath[] = "rd_command.txt";
    av1_read_rd_command(filepath, &cpi->rd_command);
  }
#endif  // CONFIG_RD_COMMAND
  if (cpi->gf_frame_index == 0 && !is_stat_generation_stage(cpi)) {
    // perform tpl after filtering
    int allow_tpl =
        oxcf->gf_cfg.lag_in_frames > 1 && oxcf->algo_cfg.enable_tpl_model;
    if (gf_group->size > MAX_LENGTH_TPL_FRAME_STATS) {
      allow_tpl = 0;
    }
    if (frame_params->frame_type != KEY_FRAME) {
      // In rare case, it's possible to have non ARF/GF update_type here.
      // We should set allow_tpl to zero in the situation
      allow_tpl =
          allow_tpl && (update_type == ARF_UPDATE || update_type == GF_UPDATE ||
                        (cpi->use_ducky_encode &&
                         cpi->ducky_encode_info.frame_info.gop_mode ==
                             DUCKY_ENCODE_GOP_MODE_RCL));
    }

    if (allow_tpl) {
      if (!cpi->skip_tpl_setup_stats) {
        av1_tpl_preload_rc_estimate(cpi, frame_params);
        av1_tpl_setup_stats(cpi, 0, frame_params);
#if CONFIG_BITRATE_ACCURACY && !CONFIG_THREE_PASS
        assert(cpi->gf_frame_index == 0);
        av1_vbr_rc_update_q_index_list(&cpi->vbr_rc_info, &cpi->ppi->tpl_data,
                                       gf_group, cm->seq_params->bit_depth);
#endif
      }
    } else {
      av1_init_tpl_stats(&cpi->ppi->tpl_data);
    }
#if CONFIG_BITRATE_ACCURACY && CONFIG_THREE_PASS
    if (cpi->oxcf.pass == AOM_RC_SECOND_PASS &&
        cpi->second_pass_log_stream != NULL) {
      TPL_INFO *tpl_info;
      AOM_CHECK_MEM_ERROR(cm->error, tpl_info, aom_malloc(sizeof(*tpl_info)));
      av1_pack_tpl_info(tpl_info, gf_group, &cpi->ppi->tpl_data);
      av1_write_tpl_info(tpl_info, cpi->second_pass_log_stream,
                         cpi->common.error);
      aom_free(tpl_info);
    }
#endif  // CONFIG_BITRATE_ACCURACY && CONFIG_THREE_PASS
  }

  if (av1_encode(cpi, dest, dest_size, frame_input, frame_params,
                 frame_results) != AOM_CODEC_OK) {
    return AOM_CODEC_ERROR;
  }

  // Set frame_input source to true source for psnr calculation.
  if (apply_filtering && is_psnr_calc_enabled(cpi)) {
    cpi->source = av1_realloc_and_scale_if_required(
        cm, source_buffer, &cpi->scaled_source, cm->features.interp_filter, 0,
        false, true, cpi->oxcf.border_in_pixels, cpi->alloc_pyramid);
    cpi->unscaled_source = source_buffer;
  }
#if CONFIG_COLLECT_COMPONENT_TIMING
  if (cpi->oxcf.pass == 2) end_timing(cpi, denoise_and_encode_time);
#endif
  return AOM_CODEC_OK;
}
#endif  // !CONFIG_REALTIME_ONLY

/*!\cond */
// Struct to keep track of relevant reference frame data.
RefBufMapData;
/*!\endcond */

// Comparison function to sort reference frames in ascending display order.
static int compare_map_idx_pair_asc(const void *a, const void *b) {}

// Checks to see if a particular reference frame is already in the reference
// frame map.
static int is_in_ref_map(RefBufMapData *map, int disp_order, int n_frames) {}

// Add a reference buffer index to a named reference slot.
static void add_ref_to_slot(RefBufMapData *ref, int *const remapped_ref_idx,
                            int frame) {}

// Threshold dictating when we are allowed to start considering
// leaving lowest level frames unmapped.
#define LOW_LEVEL_FRAMES_TR

// Find which reference buffer should be left out of the named mapping.
// This is because there are 8 reference buffers and only 7 named slots.
static void set_unmapped_ref(RefBufMapData *buffer_map, int n_bufs,
                             int n_min_level_refs, int min_level,
                             int cur_frame_disp) {}

void av1_get_ref_frames(RefFrameMapPair ref_frame_map_pairs[REF_FRAMES],
                        int cur_frame_disp, const AV1_COMP *cpi, int gf_index,
                        int is_parallel_encode,
                        int remapped_ref_idx[REF_FRAMES]) {}

int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
                        uint8_t *const dest, size_t dest_size,
                        unsigned int *frame_flags, int64_t *const time_stamp,
                        int64_t *const time_end,
                        const aom_rational64_t *const timestamp_ratio,
                        int *const pop_lookahead, int flush) {}