/* * 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. */ #ifndef AOM_AV1_ENCODER_TEMPORAL_FILTER_H_ #define AOM_AV1_ENCODER_TEMPORAL_FILTER_H_ #include <stdbool.h> #include "aom_util/aom_pthread.h" #ifdef __cplusplus extern "C" { #endif /*!\cond */ struct AV1_COMP; struct AV1EncoderConfig; struct ThreadData; // TODO(wtc): These two variables are only used in avx2, sse2, neon // implementations, where the block size is still hard coded to TF_BLOCK_SIZE. // This should be fixed to align with the c implementation. #define BH … #define BW … // Block size used in temporal filtering. #define TF_BLOCK_SIZE … // Window size for temporal filtering. #define TF_WINDOW_LENGTH … // A constant number, sqrt(pi / 2), used for noise estimation. static const double SQRT_PI_BY_2 = …; // Hyper-parameters used to compute filtering weight. These hyper-parameters can // be tuned for a better performance. // 0. A scale factor used in temporal filtering to raise the filter weight from // `double` with range [0, 1] to `int` with range [0, 1000]. #define TF_WEIGHT_SCALE … // 1. Weight factor used to balance the weighted-average between window error // and block error. The weight is for window error while the weight for block // error is always set as 1. #define TF_WINDOW_BLOCK_BALANCE_WEIGHT … // 2. Threshold for using q to adjust the filtering weight. Concretely, when // using a small q (high bitrate), we would like to reduce the filtering // strength such that more detailed information can be preserved. Hence, when // q is smaller than this threshold, we will adjust the filtering weight // based on the q-value. #define TF_Q_DECAY_THRESHOLD … // 3. Normalization factor used to normalize the motion search error. Since the // motion search error can be large and uncontrollable, we will simply // normalize it before using it to compute the filtering weight. #define TF_SEARCH_ERROR_NORM_WEIGHT … // 4. Threshold for using `arnr_strength` to adjust the filtering strength. // Concretely, users can use `arnr_strength` arguments to control the // strength of temporal filtering. When `arnr_strength` is small enough ( // i.e., smaller than this threshold), we will adjust the filtering weight // based on the strength value. #define TF_STRENGTH_THRESHOLD … // 5. Threshold for using motion search distance to adjust the filtering weight. // Concretely, larger motion search vector leads to a higher probability of // unreliable search. Hence, we would like to reduce the filtering strength // when the distance is large enough. Considering that the distance actually // relies on the frame size, this threshold is also a resolution-based // threshold. Taking 720p videos as an instance, if this field equals to 0.1, // then the actual threshold will be 720 * 0.1 = 72. Similarly, the threshold // for 360p videos will be 360 * 0.1 = 36. #define TF_SEARCH_DISTANCE_THRESHOLD … // 6. Threshold to identify if the q is in a relative high range. // Above this cutoff q, a stronger filtering is applied. // For a high q, the quantization throws away more information, and thus a // stronger filtering is less likely to distort the encoded quality, while a // stronger filtering could reduce bit rates. // Ror a low q, more details are expected to be retained. Filtering is thus // more conservative. #define TF_QINDEX_CUTOFF … #define NOISE_ESTIMATION_EDGE_THRESHOLD … // Sum and SSE source vs filtered frame difference returned by // temporal filter. FRAME_DIFF; /*!\endcond */ /*! * \brief Parameters related to temporal filtering. */ TemporalFilterCtx; /*! * buffer count in TEMPORAL_FILTER_INFO * Currently we only apply filtering on KEY and ARF after * define_gf_group(). Hence, the count is two. */ #define TF_INFO_BUF_COUNT … /*! * \brief Temporal filter info for a gop */ TEMPORAL_FILTER_INFO; /*!\brief Check whether we should apply temporal filter at all. * \param[in] oxcf AV1 encoder config * * \return 1: temporal filter is on 0: temporal is off */ int av1_is_temporal_filter_on(const struct AV1EncoderConfig *oxcf); /*!\brief Allocate buffers for TEMPORAL_FILTER_INFO * \param[in,out] tf_info Temporal filter info for a gop * \param[in,out] cpi Top level encoder instance structure * * \return True on success, false on memory allocation failure. */ bool av1_tf_info_alloc(TEMPORAL_FILTER_INFO *tf_info, const struct AV1_COMP *cpi); /*!\brief Free buffers for TEMPORAL_FILTER_INFO * \param[in,out] tf_info Temporal filter info for a gop */ void av1_tf_info_free(TEMPORAL_FILTER_INFO *tf_info); /*!\brief Reset validity of tf_buf in TEMPORAL_FILTER_INFO * \param[in,out] tf_info Temporal filter info for a gop */ void av1_tf_info_reset(TEMPORAL_FILTER_INFO *tf_info); /*!\brief Apply temporal filter for key frame and ARF in a gop * \param[in,out] tf_info Temporal filter info for a gop * \param[in,out] cpi Top level encoder instance structure * \param[in] gf_group GF/ARF group data structure */ void av1_tf_info_filtering(TEMPORAL_FILTER_INFO *tf_info, struct AV1_COMP *cpi, const GF_GROUP *gf_group); /*!\brief Get a filtered buffer from TEMPORAL_FILTER_INFO * \param[in,out] tf_info Temporal filter info for a gop * \param[in] gf_index gf_index for the target buffer * \param[out] show_tf_buf whether the target buffer can be shown * directly */ YV12_BUFFER_CONFIG *av1_tf_info_get_filtered_buf(TEMPORAL_FILTER_INFO *tf_info, int gf_index, FRAME_DIFF *frame_diff); /*!\cond */ // Data related to temporal filtering. TemporalFilterData; // Data related to temporal filter multi-thread synchronization. AV1TemporalFilterSync; // Estimates noise level from a given frame using a single plane (Y, U, or V). // This is an adaptation of the mehtod in the following paper: // Shen-Chuan Tai, Shih-Ming Yang, "A fast method for image noise // estimation using Laplacian operator and adaptive edge detection", // Proc. 3rd International Symposium on Communications, Control and // Signal Processing, 2008, St Julians, Malta. // Inputs: // frame: Pointer to the frame to estimate noise level from. // noise_level: Pointer to store the estimated noise. // plane_from: Index of the starting plane used for noise estimation. // Commonly, 0 for Y-plane, 1 for U-plane, and 2 for V-plane. // plane_to: Index of the end plane used for noise estimation. // bit_depth: Actual bit-depth instead of the encoding bit-depth of the frame. // edge_thresh: Edge threshold. void av1_estimate_noise_level(const YV12_BUFFER_CONFIG *frame, double *noise_level, int plane_from, int plane_to, int bit_depth, int edge_thresh); /*!\endcond */ /*!\brief Does temporal filter for a given macroblock row. * * \ingroup src_frame_proc * \param[in] cpi Top level encoder instance structure * \param[in] td Pointer to thread data * \param[in] mb_row Macroblock row to be filtered filtering * * \remark Nothing will be returned, but the contents of td->diff will be modified. */ void av1_tf_do_filtering_row(struct AV1_COMP *cpi, struct ThreadData *td, int mb_row); /*!\brief Performs temporal filtering if needed on a source frame. * For example to create a filtered alternate reference frame (ARF) * * In this function, the lookahead index is different from the 0-based * real index. For example, if we want to filter the first frame in the * pre-fetched buffer `cpi->lookahead`, the lookahead index will be -1 instead * of 0. More concretely, 0 indicates the first LOOKAHEAD frame, which is the * second frame in the pre-fetched buffer. Another example: if we want to filter * the 17-th frame, which is an ARF, the lookahead index is 15 instead of 16. * Futhermore, negative number is used for key frame in one-pass mode, where key * frame is filtered with the frames before it instead of after it. For example, * -15 means to filter the 17-th frame, which is a key frame in one-pass mode. * * \ingroup src_frame_proc * \param[in] cpi Top level encoder instance * structure * \param[in] filter_frame_lookahead_idx The index of the * to-filter frame in the lookahead * buffer cpi->lookahead. * \param[in] gf_frame_index Index of GOP * \param[in,out] frame_diff structure of sse and sum of the * filtered frame. * \param[out] output_frame Ouput filtered frame. */ void av1_temporal_filter(struct AV1_COMP *cpi, const int filter_frame_lookahead_idx, int gf_frame_index, FRAME_DIFF *frame_diff, YV12_BUFFER_CONFIG *output_frame); /*!\brief Check whether a filtered frame can be show directly * * This function will use the filtered frame's sse and current q index * to make decision. * * \ingroup src_frame_proc * \param[in] frame filtered frame's buffer * \param[in] frame_diff structure of sse and sum of the * filtered frame. * \param[in] q_index q_index used for this frame * \param[in] bit_depth bit depth * \return return 1 if this frame can be shown directly, otherwise * return 0 */ int av1_check_show_filtered_frame(const YV12_BUFFER_CONFIG *frame, const FRAME_DIFF *frame_diff, int q_index, aom_bit_depth_t bit_depth); /*!\cond */ // Allocates memory for members of TemporalFilterData. // Inputs: // tf_data: Pointer to the structure containing temporal filter related data. // num_pels: Number of pixels in the block across all planes. // is_high_bitdepth: Whether the frame is high-bitdepth or not. // Returns: // True if allocation is successful and false otherwise. static inline bool tf_alloc_and_reset_data(TemporalFilterData *tf_data, int num_pels, int is_high_bitdepth) { … } // Setup macroblockd params for temporal filtering process. // Inputs: // mbd: Pointer to the block for filtering. // tf_data: Pointer to the structure containing temporal filter related data. // scale: Scaling factor. // Returns: // Nothing will be returned. Contents of mbd will be modified. static inline void tf_setup_macroblockd(MACROBLOCKD *mbd, TemporalFilterData *tf_data, const struct scale_factors *scale) { … } // Deallocates the memory allocated for members of TemporalFilterData. // Inputs: // tf_data: Pointer to the structure containing temporal filter related data. // is_high_bitdepth: Whether the frame is high-bitdepth or not. // Returns: // Nothing will be returned. static inline void tf_dealloc_data(TemporalFilterData *tf_data, int is_high_bitdepth) { … } // Saves the state prior to temporal filter process. // Inputs: // mbd: Pointer to the block for filtering. // input_mbmi: Backup block info to save input state. // input_buffer: Backup buffer pointer to save input state. // num_planes: Number of planes. // Returns: // Nothing will be returned. Contents of input_mbmi and input_buffer will be // modified. static inline void tf_save_state(MACROBLOCKD *mbd, MB_MODE_INFO ***input_mbmi, uint8_t **input_buffer, int num_planes) { … } // Restores the initial state after temporal filter process. // Inputs: // mbd: Pointer to the block for filtering. // input_mbmi: Backup block info from where input state is restored. // input_buffer: Backup buffer pointer from where input state is restored. // num_planes: Number of planes. // Returns: // Nothing will be returned. Contents of mbd will be modified. static inline void tf_restore_state(MACROBLOCKD *mbd, MB_MODE_INFO **input_mbmi, uint8_t **input_buffer, int num_planes) { … } /*!\endcond */ #ifdef __cplusplus } // extern "C" #endif #endif // AOM_AV1_ENCODER_TEMPORAL_FILTER_H_