update libaom to rev 5bdd95475e07ac8641114cb139105b8d734a1b60 (without moz.build and aom_ports/aom_once.h)

This commit is contained in:
Roy Tam 2019-03-29 21:53:07 +08:00
commit fb515ea77b
177 changed files with 21088 additions and 11681 deletions

View file

@ -293,8 +293,11 @@ if(CONFIG_AV1_DECODER AND ENABLE_EXAMPLES)
if(EMSCRIPTEN)
add_preproc_definition(_POSIX_SOURCE)
append_link_flag_to_target("inspect" "-s TOTAL_MEMORY=402653184")
append_link_flag_to_target("inspect" "--emrun")
append_link_flag_to_target("inspect" "-s USE_PTHREADS=0")
append_link_flag_to_target("inspect" "-s WASM=1")
append_link_flag_to_target("inspect" "-s MODULARIZE=1")
append_link_flag_to_target("inspect" "-s ALLOW_MEMORY_GROWTH=1")
append_link_flag_to_target(
"inspect" "-s \'EXTRA_EXPORTED_RUNTIME_METHODS=[\"UTF8ToString\"]\'")
append_link_flag_to_target("inspect"

View file

@ -406,8 +406,7 @@ typedef struct aom_codec_enc_cfg {
* upscaling after the encode/decode process. Taking control of upscaling and
* using restoration filters should allow it to outperform normal resizing.
*
* Mode 0 is SUPERRES_NONE, mode 1 is SUPERRES_FIXED, mode 2 is
* SUPERRES_RANDOM and mode 3 is SUPERRES_QTHRESH.
* Valid values are 0 to 4 as defined in enum SUPERRES_MODE.
*/
unsigned int rc_superres_mode;
@ -862,6 +861,11 @@ aom_codec_err_t aom_codec_enc_config_set(aom_codec_ctx_t *ctx,
*/
aom_fixed_buf_t *aom_codec_get_global_headers(aom_codec_ctx_t *ctx);
/*!\brief usage parameter analogous to AV1 GOOD QUALITY mode. */
#define AOM_USAGE_GOOD_QUALITY (0)
/*!\brief usage parameter analogous to AV1 REALTIME mode. */
#define AOM_USAGE_REALTIME (1)
/*!\brief Encode a frame
*
* Encodes a video frame at the given "presentation time." The presentation

View file

@ -512,16 +512,25 @@ enum aome_enc_control_id {
*/
AV1E_SET_RENDER_SIZE,
/*!\brief Codec control function to set target level.
*
* 255: off (default); 0: only keep level stats; 10: target for level 1.0;
* 11: target for level 1.1; ... 62: target for level 6.2
/*!\brief Control to set target sequence level index for a certain operating
* point(OP).
* Possible values are in the form of "ABxy"(pad leading zeros if less than
* 4 digits).
* AB: OP index.
* xy: Target level index for the OP. Can be values 0~23(corresponding to
* level 2.0 ~ 7.3) or 31(maximum level parameter, no level-based
* constraints).
* E.g. "0" means target level index 0 for the 0th OP;
* "111" means target level index 11 for the 1st OP;
* "1021" means target level index 21 for the 10th OP.
* If the target level is not specified for an OP, the maximum level parameter
* of 31 is used as default.
*/
AV1E_SET_TARGET_LEVEL,
AV1E_SET_TARGET_SEQ_LEVEL_IDX,
/*!\brief Codec control function to get bitstream level.
/*!\brief Codec control function to get sequence level index.
*/
AV1E_GET_LEVEL,
AV1E_GET_SEQ_LEVEL_IDX,
/*!\brief Codec control function to set intended superblock size.
*
@ -575,8 +584,9 @@ enum aome_enc_control_id {
*
* 0 = apply trellis quantization
* 1 = do not apply trellis quantization
* 2 = disable trellis quantization partially
*
* By default, the encoder applies trellis optimization on quantized
* By default, the encoder applies optimization on quantized
* coefficients.
*
*/
@ -718,6 +728,43 @@ enum aome_enc_control_id {
*/
AV1E_SET_ENABLE_RECT_PARTITIONS,
/*!\brief Codec control function to enable/disable AB partitions.
*
* This will enable or disable usage of AB partitions. The default
* value is 1.
*
*/
AV1E_SET_ENABLE_AB_PARTITIONS,
/*!\brief Codec control function to enable/disable 1:4 and 4:1 partitions.
*
* This will enable or disable usage of 1:4 and 4:1 partitions. The default
* value is 1.
*
*/
AV1E_SET_ENABLE_1TO4_PARTITIONS,
/*!\brief Codec control function to set min partition size.
*
* This will set min partition size. The default value is 4 for 4x4.
* valid values are [4, 8, 16, 32, 64, 128]
* min_partition_size is applied to both width and height of the partition.
* i.e, both width and height of a partition can not be smaller than
* the min_partition_size, except the partition at the picture boundary.
*
*/
AV1E_SET_MIN_PARTITION_SIZE,
/*!\brief Codec control function to set max partition size.
*
* This will set max partition size. The default value is 128 for 128x128.
* valid values are [4, 8, 16, 32, 64, 128]
* max_partition_size is applied to both width and height of the partition.
* i.e, both width and height of a partition can not be larger than
* the max_partition_size.
*/
AV1E_SET_MAX_PARTITION_SIZE,
/*!\brief Codec control function to turn on / off intra edge filter
* at sequence level.
*
@ -747,6 +794,25 @@ enum aome_enc_control_id {
*/
AV1E_SET_ENABLE_TX64,
/*!\brief Codec control function to turn on / off flip and identity
* transforms.
*
* This will enable or disable usage of flip and identity transform
* types in any direction. The default value is 1. Including:
* FLIPADST_DCT, DCT_FLIPADST, FLIPADST_FLIPADST, ADST_FLIPADST,
* FLIPADST_ADST, IDTX, V_DCT, H_DCT, V_ADST, H_ADST, V_FLIPADST,
* H_FLIPADST
*/
AV1E_SET_ENABLE_FLIP_IDTX,
/*!\brief Codec control function to set transform block size search method.
*
* This will set the transform block size search method.
* 0: use Full RD search, 1: use Fast RD search, 2: always use largest
* allowed transform block size based on partition size.
*/
AV1E_SET_TX_SIZE_SEARCH_METHOD,
/*!\brief Codec control function to turn on / off dist-wtd compound mode
* at sequence level.
*
@ -793,6 +859,15 @@ enum aome_enc_control_id {
*/
AV1E_SET_ENABLE_MASKED_COMP,
/*!\brief Codec control function to turn on / off one sided compound usage
* for a sequence.
*
* This will enable or disable usage of one sided compound
* modes. The default value is 1.
*
*/
AV1E_SET_ENABLE_ONESIDED_COMP,
/*!\brief Codec control function to turn on / off interintra compound
* for a sequence.
*
@ -979,16 +1054,44 @@ enum aome_enc_control_id {
/*!\brief Control to use dct only for inter modes */
AV1E_SET_INTER_DCT_ONLY,
/*!\brief Control to use default tx type only for intra modes */
AV1E_SET_INTRA_DEFAULT_TX_ONLY,
/*!\brief Control to use adaptive quantize_b */
AV1E_SET_QUANT_B_ADAPT,
/*!\brief Control to select maximum height for the GF group pyramid structure
* (valid values: 1 - 4) */
* (valid values: 0 - 4) */
AV1E_SET_GF_MAX_PYRAMID_HEIGHT,
/*!\brief Control to select maximum reference frames allowed per frame
* (valid values: 3 - 7) */
AV1E_SET_MAX_REFERENCE_FRAMES,
/*!\brief Control to use reduced set of single and compound references. */
AV1E_SET_REDUCED_REFERENCE_SET,
/*!\brief Control to set frequency of the cost updates for coefficients
* Possible values are:
* 0: Update at SB level (default)
* 1: Update at SB row level in tile
* 2: Update at tile level
*/
AV1E_SET_COEFF_COST_UPD_FREQ,
/*!\brief Control to set frequency of the cost updates for mode
* Possible values are:
* 0: Update at SB level (default)
* 1: Update at SB row level in tile
* 2: Update at tile level
*/
AV1E_SET_MODE_COST_UPD_FREQ,
/*!\brief Control to set bit mask that specifies which tier each of the 32
* possible operating points conforms to.
* Bit value 0: Main Tier; 1: High Tier.
*/
AV1E_SET_TIER_MASK,
};
/*!\brief aom 1-D scaling mode
@ -1095,13 +1198,11 @@ AOM_CTRL_USE_TYPE(AOME_SET_ACTIVEMAP, aom_active_map_t *)
AOM_CTRL_USE_TYPE(AOME_SET_SCALEMODE, aom_scaling_mode_t *)
#define AOM_CTRL_AOME_SET_SCALEMODE
AOM_CTRL_USE_TYPE(AOME_SET_SPATIAL_LAYER_ID, int)
AOM_CTRL_USE_TYPE(AOME_SET_SPATIAL_LAYER_ID, unsigned int)
#define AOM_CTRL_AOME_SET_SPATIAL_LAYER_ID
AOM_CTRL_USE_TYPE(AOME_SET_CPUUSED, int)
#define AOM_CTRL_AOME_SET_CPUUSED
AOM_CTRL_USE_TYPE(AOME_SET_DEVSF, int)
#define AOM_CTRL_AOME_SET_DEVSF
AOM_CTRL_USE_TYPE(AOME_SET_ENABLEAUTOALTREF, unsigned int)
#define AOM_CTRL_AOME_SET_ENABLEAUTOALTREF
@ -1122,12 +1223,12 @@ AOM_CTRL_USE_TYPE(AOME_SET_TUNING, int) /* aom_tune_metric */
AOM_CTRL_USE_TYPE(AOME_SET_CQ_LEVEL, unsigned int)
#define AOM_CTRL_AOME_SET_CQ_LEVEL
AOM_CTRL_USE_TYPE(AV1E_SET_ROW_MT, int)
AOM_CTRL_USE_TYPE(AV1E_SET_ROW_MT, unsigned int)
#define AOM_CTRL_AV1E_SET_ROW_MT
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_COLUMNS, int)
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_COLUMNS, unsigned int)
#define AOM_CTRL_AV1E_SET_TILE_COLUMNS
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ROWS, int)
AOM_CTRL_USE_TYPE(AV1E_SET_TILE_ROWS, unsigned int)
#define AOM_CTRL_AV1E_SET_TILE_ROWS
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_TPL_MODEL, unsigned int)
@ -1193,88 +1294,109 @@ AOM_CTRL_USE_TYPE(AV1E_SET_MTU, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_TIMING_INFO_TYPE, int) /* aom_timing_info_type_t */
#define AOM_CTRL_AV1E_SET_TIMING_INFO_TYPE
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_RECT_PARTITIONS, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_RECT_PARTITIONS, int)
#define AOM_CTRL_AV1E_SET_ENABLE_RECT_PARTITIONS
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRA_EDGE_FILTER, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_AB_PARTITIONS, int)
#define AOM_CTRL_AV1E_SET_ENABLE_AB_PARTITIONS
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_1TO4_PARTITIONS, int)
#define AOM_CTRL_AV1E_SET_ENABLE_1TO4_PARTITIONS
AOM_CTRL_USE_TYPE(AV1E_SET_MIN_PARTITION_SIZE, int)
#define AOM_CTRL_AV1E_SET_MIN_PARTITION_SIZE
AOM_CTRL_USE_TYPE(AV1E_SET_MAX_PARTITION_SIZE, int)
#define AOM_CTRL_AV1E_SET_MAX_PARTITION_SIZE
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRA_EDGE_FILTER, int)
#define AOM_CTRL_AV1E_SET_ENABLE_INTRA_EDGE_FILTER
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ORDER_HINT, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ORDER_HINT, int)
#define AOM_CTRL_AV1E_SET_ENABLE_ORDER_HINT
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_TX64, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_TX64, int)
#define AOM_CTRL_AV1E_SET_ENABLE_TX64
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIST_WTD_COMP, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_TX_SIZE_SEARCH_METHOD, int)
#define AOM_CTRL_AV1E_SET_TXSIZE_SEARCH_METHOD
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_FLIP_IDTX, int)
#define AOM_CTRL_AV1E_SET_ENABLE_FLIP_IDTX
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIST_WTD_COMP, int)
#define AOM_CTRL_AV1E_SET_ENABLE_DIST_WTD_COMP
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_REF_FRAME_MVS, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_REF_FRAME_MVS, int)
#define AOM_CTRL_AV1E_SET_ENABLE_REF_FRAME_MVS
AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_REF_FRAME_MVS, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_REF_FRAME_MVS, int)
#define AOM_CTRL_AV1E_SET_ALLOW_REF_FRAME_MVS
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DUAL_FILTER, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DUAL_FILTER, int)
#define AOM_CTRL_AV1E_SET_ENABLE_DUAL_FILTER
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_MASKED_COMP, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_MASKED_COMP, int)
#define AOM_CTRL_AV1E_SET_ENABLE_MASKED_COMP
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_COMP, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ONESIDED_COMP, int)
#define AOM_CTRL_AV1E_SET_ENABLE_ONESIDED_COMP
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_COMP, int)
#define AOM_CTRL_AV1E_SET_ENABLE_INTERINTRA_COMP
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTERINTRA, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTERINTRA, int)
#define AOM_CTRL_AV1E_SET_ENABLE_SMOOTH_INTERINTRA
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIFF_WTD_COMP, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DIFF_WTD_COMP, int)
#define AOM_CTRL_AV1E_SET_ENABLE_DIFF_WTD_COMP
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTER_WEDGE, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTER_WEDGE, int)
#define AOM_CTRL_AV1E_SET_ENABLE_INTERINTER_WEDGE
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_WEDGE, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTERINTRA_WEDGE, int)
#define AOM_CTRL_AV1E_SET_ENABLE_INTERINTRA_WEDGE
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_GLOBAL_MOTION, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_GLOBAL_MOTION, int)
#define AOM_CTRL_AV1E_SET_ENABLE_GLOBAL_MOTION
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_WARPED_MOTION, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_WARPED_MOTION, int)
#define AOM_CTRL_AV1E_SET_ENABLE_WARPED_MOTION
AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_WARPED_MOTION, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ALLOW_WARPED_MOTION, int)
#define AOM_CTRL_AV1E_SET_ALLOW_WARPED_MOTION
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_FILTER_INTRA, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_FILTER_INTRA, int)
#define AOM_CTRL_AV1E_SET_ENABLE_FILTER_INTRA
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTRA, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SMOOTH_INTRA, int)
#define AOM_CTRL_AV1E_SET_ENABLE_SMOOTH_INTRA
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PAETH_INTRA, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PAETH_INTRA, int)
#define AOM_CTRL_AV1E_SET_ENABLE_PAETH_INTRA
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_CFL_INTRA, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_CFL_INTRA, int)
#define AOM_CTRL_AV1E_SET_ENABLE_CFL_INTRA
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SUPERRES, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_SUPERRES, int)
#define AOM_CTRL_AV1E_SET_ENABLE_SUPERRES
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PALETTE, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_PALETTE, int)
#define AOM_CTRL_AV1E_SET_ENABLE_PALETTE
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRABC, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_INTRABC, int)
#define AOM_CTRL_AV1E_SET_ENABLE_INTRABC
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ANGLE_DELTA, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_ANGLE_DELTA, int)
#define AOM_CTRL_AV1E_SET_ENABLE_ANGLE_DELTA
AOM_CTRL_USE_TYPE(AV1E_SET_FRAME_PARALLEL_DECODING, unsigned int)
#define AOM_CTRL_AV1E_SET_FRAME_PARALLEL_DECODING
AOM_CTRL_USE_TYPE(AV1E_SET_ERROR_RESILIENT_MODE, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_ERROR_RESILIENT_MODE, int)
#define AOM_CTRL_AV1E_SET_ERROR_RESILIENT_MODE
AOM_CTRL_USE_TYPE(AV1E_SET_S_FRAME_MODE, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_S_FRAME_MODE, int)
#define AOM_CTRL_AV1E_SET_S_FRAME_MODE
AOM_CTRL_USE_TYPE(AV1E_SET_AQ_MODE, unsigned int)
@ -1322,14 +1444,8 @@ AOM_CTRL_USE_TYPE(AV1E_SET_RENDER_SIZE, int *)
AOM_CTRL_USE_TYPE(AV1E_SET_SUPERBLOCK_SIZE, unsigned int)
#define AOM_CTRL_AV1E_SET_SUPERBLOCK_SIZE
AOM_CTRL_USE_TYPE(AV1E_SET_TARGET_LEVEL, unsigned int)
#define AOM_CTRL_AV1E_SET_TARGET_LEVEL
AOM_CTRL_USE_TYPE(AV1E_GET_LEVEL, int *)
#define AOM_CTRL_AV1E_GET_LEVEL
AOM_CTRL_USE_TYPE(AV1E_SET_ANS_WINDOW_SIZE_LOG2, unsigned int)
#define AOM_CTRL_AV1E_SET_ANS_WINDOW_SIZE_LOG2
AOM_CTRL_USE_TYPE(AV1E_GET_SEQ_LEVEL_IDX, int *)
#define AOM_CTRL_AV1E_GET_SEQ_LEVEL_IDX
AOM_CTRL_USE_TYPE(AV1E_SET_SINGLE_TILE_DECODING, unsigned int)
#define AOM_CTRL_AV1E_SET_SINGLE_TILE_DECODING
@ -1337,13 +1453,13 @@ AOM_CTRL_USE_TYPE(AV1E_SET_SINGLE_TILE_DECODING, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, unsigned int)
#define AOM_CTRL_AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST
AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TEST_VECTOR, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TEST_VECTOR, int)
#define AOM_CTRL_AV1E_SET_FILM_GRAIN_TEST_VECTOR
AOM_CTRL_USE_TYPE(AV1E_SET_FILM_GRAIN_TABLE, const char *)
#define AOM_CTRL_AV1E_SET_FILM_GRAIN_TABLE
AOM_CTRL_USE_TYPE(AV1E_SET_CDF_UPDATE_MODE, int)
AOM_CTRL_USE_TYPE(AV1E_SET_CDF_UPDATE_MODE, unsigned int)
#define AOM_CTRL_AV1E_SET_CDF_UPDATE_MODE
#ifdef CONFIG_DENOISE
@ -1360,24 +1476,42 @@ AOM_CTRL_USE_TYPE(AV1E_SET_CHROMA_SUBSAMPLING_X, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_CHROMA_SUBSAMPLING_Y, unsigned int)
#define AOM_CTRL_AV1E_SET_CHROMA_SUBSAMPLING_Y
AOM_CTRL_USE_TYPE(AV1E_SET_REDUCED_TX_TYPE_SET, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_REDUCED_TX_TYPE_SET, int)
#define AOM_CTRL_AV1E_SET_REDUCED_TX_TYPE_SET
AOM_CTRL_USE_TYPE(AV1E_SET_INTRA_DCT_ONLY, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_INTRA_DCT_ONLY, int)
#define AOM_CTRL_AV1E_SET_INTRA_DCT_ONLY
AOM_CTRL_USE_TYPE(AV1E_SET_INTER_DCT_ONLY, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_INTER_DCT_ONLY, int)
#define AOM_CTRL_AV1E_SET_INTER_DCT_ONLY
AOM_CTRL_USE_TYPE(AV1E_SET_QUANT_B_ADAPT, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_INTRA_DEFAULT_TX_ONLY, int)
#define AOM_CTRL_AV1E_SET_INTRA_DEFAULT_TX_ONLY
AOM_CTRL_USE_TYPE(AV1E_SET_QUANT_B_ADAPT, int)
#define AOM_CTRL_AV1E_SET_QUANT_B_ADAPT
AOM_CTRL_USE_TYPE(AV1E_SET_GF_MAX_PYRAMID_HEIGHT, unsigned int)
#define AOM_CTRL_AV1E_SET_GF_MAX_PYRAMID_HEIGHT
AOM_CTRL_USE_TYPE(AV1E_SET_MAX_REFERENCE_FRAMES, unsigned int)
AOM_CTRL_USE_TYPE(AV1E_SET_MAX_REFERENCE_FRAMES, int)
#define AOM_CTRL_AV1E_SET_MAX_REFERENCE_FRAMES
AOM_CTRL_USE_TYPE(AV1E_SET_REDUCED_REFERENCE_SET, int)
#define AOM_CTRL_AV1E_SET_REDUCED_REFERENCE_SET
AOM_CTRL_USE_TYPE(AV1E_SET_COEFF_COST_UPD_FREQ, unsigned int)
#define AOM_CTRL_AV1E_SET_COEFF_COST_UPD_FREQ
AOM_CTRL_USE_TYPE(AV1E_SET_MODE_COST_UPD_FREQ, unsigned int)
#define AOM_CTRL_AV1E_SET_MODE_COST_UPD_FREQ
AOM_CTRL_USE_TYPE(AV1E_SET_TARGET_SEQ_LEVEL_IDX, int)
#define AOM_CTRL_AV1E_SET_TARGET_SEQ_LEVEL_IDX
AOM_CTRL_USE_TYPE(AV1E_SET_TIER_MASK, unsigned int)
#define AOM_CTRL_AV1E_SET_TIER_MASK
/*!\endcond */
/*! @} - end defgroup aom_encoder */
#ifdef __cplusplus

View file

@ -194,6 +194,7 @@ if(CONFIG_AV1_ENCODER)
"${AOM_ROOT}/aom_dsp/x86/highbd_subtract_sse2.c"
"${AOM_ROOT}/aom_dsp/x86/highbd_variance_sse2.c"
"${AOM_ROOT}/aom_dsp/x86/quantize_sse2.c"
"${AOM_ROOT}/aom_dsp/x86/adaptive_quantize_sse2.c"
"${AOM_ROOT}/aom_dsp/x86/quantize_x86.h"
"${AOM_ROOT}/aom_dsp/x86/sum_squares_sse2.c"
"${AOM_ROOT}/aom_dsp/x86/variance_sse2.c")
@ -362,6 +363,8 @@ function(setup_aom_dsp_targets)
endif()
endif()
target_sources(aom PRIVATE $<TARGET_OBJECTS:aom_dsp>)
# Pass the new lib targets up to the parent scope instance of
# $AOM_LIB_TARGETS.
set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE)

View file

@ -518,9 +518,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/void aom_quantize_b/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
specialize qw/aom_quantize_b sse2/, "$ssse3_x86_64", "$avx_x86_64";
add_proto qw/void aom_quantize_b_adaptive/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
specialize qw/aom_quantize_b_adaptive sse2/;
add_proto qw/void aom_quantize_b_32x32/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
specialize qw/aom_quantize_b_32x32/, "$ssse3_x86_64", "$avx_x86_64";
add_proto qw/void aom_quantize_b_32x32_adaptive/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
specialize qw/aom_quantize_b_32x32_adaptive sse2/;
add_proto qw/void aom_quantize_b_64x64/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
specialize qw/aom_quantize_b_64x64 ssse3/;
} # CONFIG_AV1_ENCODER
@ -533,7 +539,7 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/aom_highbd_quantize_b_32x32 sse2/;
add_proto qw/void aom_highbd_quantize_b_64x64/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan";
specialize qw/aom_highbd_quantize_b_64x64 sse2/;
} # CONFIG_AV1_ENCODER
#
@ -835,6 +841,30 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
specialize qw/aom_highbd_sad16x64x4d sse2/;
specialize qw/aom_highbd_sad64x16x4d sse2/;
#
# Avg
#
add_proto qw/unsigned int aom_avg_8x8/, "const uint8_t *, int p";
specialize qw/aom_avg_8x8 sse2/;
add_proto qw/unsigned int aom_avg_4x4/, "const uint8_t *, int p";
specialize qw/aom_avg_4x4 sse2/;
add_proto qw/void aom_minmax_8x8/, "const uint8_t *s, int p, const uint8_t *d, int dp, int *min, int *max";
specialize qw/aom_minmax_8x8 sse2/;
add_proto qw/void aom_int_pro_row/, "int16_t *hbuf, const uint8_t *ref, const int ref_stride, const int height";
# TODO(kyslov@) bring back SSE2 by extending it to 128 block size
#specialize qw/aom_int_pro_row sse2/;
add_proto qw/int16_t aom_int_pro_col/, "const uint8_t *ref, const int width";
# TODO(kyslov@) bring back SSE2 by extending it to 128 block size
#specialize qw/aom_int_pro_col sse2/;
add_proto qw/int aom_vector_var/, "const int16_t *ref, const int16_t *src, const int bwl";
# TODO(kyslov@) bring back SSE2 by extending it to 128 block size
#specialize qw/aom_vector_var sse2/;
#
# hamadard transform and satd for implmenting temporal dependency model
#
@ -1358,6 +1388,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
#
# Subpixel Variance
#
add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance128x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_12_sub_pixel_variance128x128 sse2/;
add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance128x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_12_sub_pixel_variance128x64 sse2/;
add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance64x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_12_sub_pixel_variance64x128 sse2/;
add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_12_sub_pixel_variance64x64 sse2/;
@ -1394,6 +1433,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance4x8/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
add_proto qw/uint32_t aom_highbd_12_sub_pixel_variance4x4/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance128x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_10_sub_pixel_variance128x128 sse2/;
add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance128x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_10_sub_pixel_variance128x64 sse2/;
add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance64x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_10_sub_pixel_variance64x128 sse2/;
add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_10_sub_pixel_variance64x64 sse2/;
@ -1430,6 +1478,15 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance4x8/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
add_proto qw/uint32_t aom_highbd_10_sub_pixel_variance4x4/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance128x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_8_sub_pixel_variance128x128 sse2/;
add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance128x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_8_sub_pixel_variance128x64 sse2/;
add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance64x128/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_8_sub_pixel_variance64x128 sse2/;
add_proto qw/uint32_t aom_highbd_8_sub_pixel_variance64x64/, "const uint8_t *src_ptr, int source_stride, int xoffset, int yoffset, const uint8_t *ref_ptr, int ref_stride, uint32_t *sse";
specialize qw/aom_highbd_8_sub_pixel_variance64x64 sse2/;

View file

@ -14,6 +14,40 @@
#include "config/aom_dsp_rtcd.h"
#include "aom_ports/mem.h"
void aom_minmax_8x8_c(const uint8_t *s, int p, const uint8_t *d, int dp,
int *min, int *max) {
int i, j;
*min = 255;
*max = 0;
for (i = 0; i < 8; ++i, s += p, d += dp) {
for (j = 0; j < 8; ++j) {
int diff = abs(s[j] - d[j]);
*min = diff < *min ? diff : *min;
*max = diff > *max ? diff : *max;
}
}
}
unsigned int aom_avg_4x4_c(const uint8_t *s, int p) {
int i, j;
int sum = 0;
for (i = 0; i < 4; ++i, s += p)
for (j = 0; j < 4; sum += s[j], ++j) {
}
return (sum + 8) >> 4;
}
unsigned int aom_avg_8x8_c(const uint8_t *s, int p) {
int i, j;
int sum = 0;
for (i = 0; i < 8; ++i, s += p)
for (j = 0; j < 8; sum += s[j], ++j) {
}
return (sum + 32) >> 6;
}
// src_diff: first pass, 9 bit, dynamic range [-255, 255]
// second pass, 12 bit, dynamic range [-2040, 2040]
static void hadamard_col8(const int16_t *src_diff, ptrdiff_t src_stride,
@ -146,3 +180,48 @@ int aom_satd_c(const tran_low_t *coeff, int length) {
// satd: 26 bits, dynamic range [-32640 * 1024, 32640 * 1024]
return satd;
}
// Integer projection onto row vectors.
// height: value range {16, 32, 64, 128}.
void aom_int_pro_row_c(int16_t hbuf[16], const uint8_t *ref,
const int ref_stride, const int height) {
int idx;
const int norm_factor = height >> 1;
for (idx = 0; idx < 16; ++idx) {
int i;
hbuf[idx] = 0;
// hbuf[idx]: 14 bit, dynamic range [0, 32640].
for (i = 0; i < height; ++i) hbuf[idx] += ref[i * ref_stride];
// hbuf[idx]: 9 bit, dynamic range [0, 1020].
hbuf[idx] /= norm_factor;
++ref;
}
}
// width: value range {16, 32, 64, 128}.
int16_t aom_int_pro_col_c(const uint8_t *ref, const int width) {
int idx;
int16_t sum = 0;
// sum: 14 bit, dynamic range [0, 32640]
for (idx = 0; idx < width; ++idx) sum += ref[idx];
return sum;
}
// ref: [0 - 510]
// src: [0 - 510]
// bwl: {2, 3, 4, 5}
int aom_vector_var_c(const int16_t *ref, const int16_t *src, const int bwl) {
int i;
int width = 4 << bwl;
int sse = 0, mean = 0, var;
for (i = 0; i < width; ++i) {
int diff = ref[i] - src[i]; // diff: dynamic range [-510, 510], 10 bits.
mean += diff; // mean: dynamic range 16 bits.
sse += diff * diff; // sse: dynamic range 26 bits.
}
// (mean * mean): dynamic range 31 bits.
var = sse - ((mean * mean) >> (bwl + 2));
return var;
}

View file

@ -60,9 +60,9 @@ int aom_rb_read_inv_signed_literal(struct aom_read_bit_buffer *rb, int bits) {
uint32_t aom_rb_read_uvlc(struct aom_read_bit_buffer *rb) {
int leading_zeros = 0;
while (!aom_rb_read_bit(rb)) ++leading_zeros;
while (leading_zeros < 32 && !aom_rb_read_bit(rb)) ++leading_zeros;
// Maximum 32 bits.
if (leading_zeros >= 32) return UINT32_MAX;
if (leading_zeros == 32) return UINT32_MAX;
const uint32_t base = (1u << leading_zeros) - 1;
const uint32_t value = aom_rb_read_literal(rb, leading_zeros);
return base + value;

View file

@ -232,7 +232,6 @@ static int scaling_lut_y[256];
static int scaling_lut_cb[256];
static int scaling_lut_cr[256];
static int grain_center;
static int grain_min;
static int grain_max;
@ -1077,7 +1076,7 @@ int av1_add_film_grain_run(const aom_film_grain_t *params, uint8_t *luma,
int overlap = params->overlap_flag;
int bit_depth = params->bit_depth;
grain_center = 128 << (bit_depth - 8);
const int grain_center = 128 << (bit_depth - 8);
grain_min = 0 - grain_center;
grain_max = (256 << (bit_depth - 8)) - 1 - grain_center;

View file

@ -11,6 +11,7 @@
#include "aom_dsp/quantize.h"
#include "aom_mem/aom_mem.h"
#include "av1/encoder/av1_quantize.h"
void quantize_b_adaptive_helper_c(
const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
@ -28,15 +29,18 @@ void quantize_b_adaptive_helper_c(
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
int prescan_add[2];
for (i = 0; i < 2; ++i)
prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7);
// Pre-scan pass
for (i = (int)n_coeffs - 1; i >= 0; i--) {
const int rc = scan[i];
const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS);
const int coeff = coeff_ptr[rc] * wt;
int prescan_add = ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * 325, 7);
if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add) &&
coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add))
const int prescan_add_val = prescan_add[rc != 0];
if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) &&
coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val))
non_zero_count--;
else
break;
@ -44,6 +48,9 @@ void quantize_b_adaptive_helper_c(
// Quantization pass: All coefficients with index >= zero_flag are
// skippable. Note: zero_flag can be zero.
#if SKIP_EOB_FACTOR_ADJUST
int first = -1;
#endif // SKIP_EOB_FACTOR_ADJUST
for (i = 0; i < non_zero_count; i++) {
const int rc = scan[i];
const int coeff = coeff_ptr[rc];
@ -68,9 +75,32 @@ void quantize_b_adaptive_helper_c(
const tran_low_t abs_dqcoeff = (tmp32 * dequant) >> log_scale;
dqcoeff_ptr[rc] = (tran_low_t)((abs_dqcoeff ^ coeff_sign) - coeff_sign);
if (tmp32) eob = i;
if (tmp32) {
eob = i;
#if SKIP_EOB_FACTOR_ADJUST
if (first == -1) first = i;
#endif // SKIP_EOB_FACTOR_ADJUST
}
}
}
#if SKIP_EOB_FACTOR_ADJUST
if (eob >= 0 && first == eob) {
const int rc = scan[eob];
if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) {
const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS);
const int coeff = coeff_ptr[rc] * wt;
const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST;
const int prescan_add_val =
ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7);
if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) &&
coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val)) {
qcoeff_ptr[rc] = 0;
dqcoeff_ptr[rc] = 0;
eob = -1;
}
}
}
#endif // SKIP_EOB_FACTOR_ADJUST
*eob_ptr = eob + 1;
}
@ -155,6 +185,10 @@ void highbd_quantize_b_adaptive_helper_c(
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
int prescan_add[2];
for (i = 0; i < 2; ++i)
prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7);
// Pre-scan pass
for (i = 0; i < n_coeffs; i++) {
const int rc = scan[i];
@ -163,14 +197,17 @@ void highbd_quantize_b_adaptive_helper_c(
// If the coefficient is out of the base ZBIN range, keep it for
// quantization.
int prescan_add = ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * 325, 7);
if (coeff >= (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add) &&
coeff <= (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add))
const int prescan_add_val = prescan_add[rc != 0];
if (coeff >= (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) &&
coeff <= (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val))
idx_arr[idx++] = i;
}
// Quantization pass: only process the coefficients selected in
// pre-scan pass. Note: idx can be zero.
#if SKIP_EOB_FACTOR_ADJUST
int first = -1;
#endif // SKIP_EOB_FACTOR_ADJUST
for (i = 0; i < idx; i++) {
const int rc = scan[idx_arr[i]];
const int coeff = coeff_ptr[rc];
@ -189,8 +226,31 @@ void highbd_quantize_b_adaptive_helper_c(
(dequant_ptr[rc != 0] * iwt + (1 << (AOM_QM_BITS - 1))) >> AOM_QM_BITS;
const tran_low_t abs_dqcoeff = (abs_qcoeff * dequant) >> log_scale;
dqcoeff_ptr[rc] = (tran_low_t)((abs_dqcoeff ^ coeff_sign) - coeff_sign);
if (abs_qcoeff) eob = idx_arr[i];
if (abs_qcoeff) {
eob = idx_arr[i];
#if SKIP_EOB_FACTOR_ADJUST
if (first == -1) first = eob;
#endif // SKIP_EOB_FACTOR_ADJUST
}
}
#if SKIP_EOB_FACTOR_ADJUST
if (eob >= 0 && first == eob) {
const int rc = scan[eob];
if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) {
const qm_val_t wt = qm_ptr != NULL ? qm_ptr[rc] : (1 << AOM_QM_BITS);
const int coeff = coeff_ptr[rc] * wt;
const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST;
const int prescan_add_val =
ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7);
if (coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val) &&
coeff > (nzbins[rc != 0] * (1 << AOM_QM_BITS) - prescan_add_val)) {
qcoeff_ptr[rc] = 0;
dqcoeff_ptr[rc] = 0;
eob = -1;
}
}
}
#endif // SKIP_EOB_FACTOR_ADJUST
*eob_ptr = eob + 1;
}

View file

@ -0,0 +1,421 @@
/*
* 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 <assert.h>
#include <emmintrin.h>
#include "config/aom_dsp_rtcd.h"
#include "aom/aom_integer.h"
#include "av1/encoder/av1_quantize.h"
#include "aom_dsp/x86/quantize_x86.h"
void aom_quantize_b_adaptive_sse2(
const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
const int16_t *round_ptr, const int16_t *quant_ptr,
const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
const __m128i zero = _mm_setzero_si128();
int index = 16;
int non_zero_count = (int)n_coeffs;
__m128i zbin, round, quant, dequant, shift;
__m128i coeff0, coeff1, coeff0_sign, coeff1_sign;
__m128i qcoeff0, qcoeff1;
__m128i cmp_mask0, cmp_mask1;
__m128i eob = zero, eob0, prescan0, prescan1, all_zero;
const int zbins[2] = { ROUND_POWER_OF_TWO(zbin_ptr[0], 0),
ROUND_POWER_OF_TWO(zbin_ptr[1], 0) };
int prescan_add[2];
for (int i = 0; i < 2; ++i)
prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7);
// max buffer is of size 256 as this functions calls with
// maximum n_coeffs as 256
int16_t prescan[256];
memset(prescan, -1, n_coeffs * sizeof(int16_t));
// TODO(Aniket): Experiment the following loop with intrinsic
for (int i = (int)n_coeffs - 1; i >= 0; i--) {
const int rc = scan[i];
const qm_val_t wt = 1 << AOM_QM_BITS;
const int coeff = coeff_ptr[rc] * wt;
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int prescan_add_val = prescan_add[rc != 0];
if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) {
prescan[rc] = 0;
non_zero_count--;
} else {
break;
}
}
#if SKIP_EOB_FACTOR_ADJUST
int first = -1;
#endif
// Setup global values.
load_b_values(zbin_ptr, &zbin, round_ptr, &round, quant_ptr, &quant,
dequant_ptr, &dequant, quant_shift_ptr, &shift);
// Do DC and first 15 AC.
coeff0 = load_coefficients(coeff_ptr);
coeff1 = load_coefficients(coeff_ptr + 8);
// Poor man's abs().
coeff0_sign = _mm_srai_epi16(coeff0, 15);
coeff1_sign = _mm_srai_epi16(coeff1, 15);
qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign);
prescan0 = _mm_loadu_si128((const __m128i *)prescan);
prescan1 = _mm_loadu_si128((const __m128i *)(prescan + 8));
cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin));
zbin = _mm_unpackhi_epi64(zbin, zbin); // Switch DC to AC
cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin));
all_zero = _mm_or_si128(cmp_mask0, cmp_mask1);
if (_mm_movemask_epi8(all_zero) == 0) {
_mm_store_si128((__m128i *)(qcoeff_ptr), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + 4), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + 8), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + 12), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + 4), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + 8), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + 12), zero);
round = _mm_unpackhi_epi64(round, round);
quant = _mm_unpackhi_epi64(quant, quant);
shift = _mm_unpackhi_epi64(shift, shift);
dequant = _mm_unpackhi_epi64(dequant, dequant);
} else {
calculate_qcoeff(&qcoeff0, round, quant, shift);
round = _mm_unpackhi_epi64(round, round);
quant = _mm_unpackhi_epi64(quant, quant);
shift = _mm_unpackhi_epi64(shift, shift);
calculate_qcoeff(&qcoeff1, round, quant, shift);
// Reinsert signs
qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign);
// Mask out zbin threshold coeffs
qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0);
qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1);
store_coefficients(qcoeff0, qcoeff_ptr);
store_coefficients(qcoeff1, qcoeff_ptr + 8);
coeff0 = calculate_dqcoeff(qcoeff0, dequant);
dequant = _mm_unpackhi_epi64(dequant, dequant);
coeff1 = calculate_dqcoeff(qcoeff1, dequant);
store_coefficients(coeff0, dqcoeff_ptr);
store_coefficients(coeff1, dqcoeff_ptr + 8);
eob = scan_for_eob(&coeff0, &coeff1, cmp_mask0, cmp_mask1, iscan, 0, zero);
}
// AC only loop.
// TODO(Aniket): Reduce the processing of coeff quatization
// based on eob logic
while (index < n_coeffs) {
coeff0 = load_coefficients(coeff_ptr + index);
coeff1 = load_coefficients(coeff_ptr + index + 8);
coeff0_sign = _mm_srai_epi16(coeff0, 15);
coeff1_sign = _mm_srai_epi16(coeff1, 15);
qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign);
prescan0 = _mm_loadu_si128((const __m128i *)(prescan + index));
prescan1 = _mm_loadu_si128((const __m128i *)(prescan + index + 8));
cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin));
cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin));
all_zero = _mm_or_si128(cmp_mask0, cmp_mask1);
if (_mm_movemask_epi8(all_zero) == 0) {
_mm_store_si128((__m128i *)(qcoeff_ptr + index), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + index + 4), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + index + 8), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + index + 12), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index + 4), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index + 8), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index + 12), zero);
index += 16;
continue;
}
calculate_qcoeff(&qcoeff0, round, quant, shift);
calculate_qcoeff(&qcoeff1, round, quant, shift);
qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign);
qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0);
qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1);
store_coefficients(qcoeff0, qcoeff_ptr + index);
store_coefficients(qcoeff1, qcoeff_ptr + index + 8);
coeff0 = calculate_dqcoeff(qcoeff0, dequant);
coeff1 = calculate_dqcoeff(qcoeff1, dequant);
store_coefficients(coeff0, dqcoeff_ptr + index);
store_coefficients(coeff1, dqcoeff_ptr + index + 8);
eob0 = scan_for_eob(&coeff0, &coeff1, cmp_mask0, cmp_mask1, iscan, index,
zero);
eob = _mm_max_epi16(eob, eob0);
index += 16;
}
*eob_ptr = accumulate_eob(eob);
#if SKIP_EOB_FACTOR_ADJUST
// TODO(Aniket): Experiment the following loop with intrinsic by combining
// with the quantization loop above
for (int i = 0; i < non_zero_count; i++) {
const int rc = scan[i];
const int qcoeff = qcoeff_ptr[rc];
if (qcoeff) {
first = i;
break;
}
}
if ((*eob_ptr - 1) >= 0 && first == (*eob_ptr - 1)) {
const int rc = scan[(*eob_ptr - 1)];
if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) {
const qm_val_t wt = (1 << AOM_QM_BITS);
const int coeff = coeff_ptr[rc] * wt;
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST;
const int prescan_add_val =
ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7);
if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) {
qcoeff_ptr[rc] = 0;
dqcoeff_ptr[rc] = 0;
*eob_ptr = 0;
}
}
}
#endif
}
void aom_quantize_b_32x32_adaptive_sse2(
const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
const int16_t *round_ptr, const int16_t *quant_ptr,
const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
int index = 16;
int non_zero_count = (int)n_coeffs;
const int log_scale = 1;
const __m128i zero = _mm_setzero_si128();
const __m128i one = _mm_set1_epi16(1);
const __m128i log_scale_vec = _mm_set1_epi16(log_scale);
__m128i zbin, round, quant, dequant, shift;
__m128i coeff0, coeff1, coeff0_sign, coeff1_sign;
__m128i qcoeff0, qcoeff1;
__m128i cmp_mask0, cmp_mask1;
__m128i eob = zero, eob0, prescan0, prescan1, all_zero;
const int zbins[2] = { ROUND_POWER_OF_TWO(zbin_ptr[0], log_scale),
ROUND_POWER_OF_TWO(zbin_ptr[1], log_scale) };
int prescan_add[2];
for (int i = 0; i < 2; ++i)
prescan_add[i] = ROUND_POWER_OF_TWO(dequant_ptr[i] * EOB_FACTOR, 7);
// max buffer is of size 1024 as this functions calls with
// maximum n_coeffs as 1024
int16_t prescan[1024];
memset(prescan, -1, n_coeffs * sizeof(int16_t));
// TODO(Aniket): Experiment the following loop with intrinsic
for (int i = (int)n_coeffs - 1; i >= 0; i--) {
const int rc = scan[i];
const qm_val_t wt = 1 << AOM_QM_BITS;
const int coeff = coeff_ptr[rc] * wt;
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int prescan_add_val = prescan_add[rc != 0];
if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) {
prescan[rc] = 0;
non_zero_count--;
} else {
break;
}
}
#if SKIP_EOB_FACTOR_ADJUST
int first = -1;
#endif
// Setup global values.
zbin = _mm_load_si128((const __m128i *)zbin_ptr);
round = _mm_load_si128((const __m128i *)round_ptr);
quant = _mm_load_si128((const __m128i *)quant_ptr);
dequant = _mm_load_si128((const __m128i *)dequant_ptr);
shift = _mm_load_si128((const __m128i *)quant_shift_ptr);
// Shift with rounding.
zbin = _mm_add_epi16(zbin, log_scale_vec);
round = _mm_add_epi16(round, log_scale_vec);
zbin = _mm_srli_epi16(zbin, log_scale);
round = _mm_srli_epi16(round, log_scale);
zbin = _mm_sub_epi16(zbin, one);
// Do DC and first 15 AC.
coeff0 = load_coefficients(coeff_ptr);
coeff1 = load_coefficients(coeff_ptr + 8);
coeff0_sign = _mm_srai_epi16(coeff0, 15);
coeff1_sign = _mm_srai_epi16(coeff1, 15);
qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign);
prescan0 = _mm_loadu_si128((const __m128i *)prescan);
prescan1 = _mm_loadu_si128((const __m128i *)(prescan + 8));
cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin));
zbin = _mm_unpackhi_epi64(zbin, zbin); // Switch DC to AC
cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin));
all_zero = _mm_or_si128(cmp_mask0, cmp_mask1);
if (_mm_movemask_epi8(all_zero) == 0) {
_mm_store_si128((__m128i *)(qcoeff_ptr), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + 4), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + 8), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + 12), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + 4), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + 8), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + 12), zero);
round = _mm_unpackhi_epi64(round, round);
quant = _mm_unpackhi_epi64(quant, quant);
shift = _mm_unpackhi_epi64(shift, shift);
dequant = _mm_unpackhi_epi64(dequant, dequant);
} else {
calculate_qcoeff_log_scale(&qcoeff0, round, quant, &shift, &log_scale);
round = _mm_unpackhi_epi64(round, round);
quant = _mm_unpackhi_epi64(quant, quant);
shift = _mm_unpackhi_epi64(shift, shift);
calculate_qcoeff_log_scale(&qcoeff1, round, quant, &shift, &log_scale);
// Reinsert signs
qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign);
// Mask out zbin threshold coeffs
qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0);
qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1);
store_coefficients(qcoeff0, qcoeff_ptr);
store_coefficients(qcoeff1, qcoeff_ptr + 8);
calculate_dqcoeff_and_store_log_scale(qcoeff0, dequant, zero, dqcoeff_ptr,
&log_scale);
dequant = _mm_unpackhi_epi64(dequant, dequant);
calculate_dqcoeff_and_store_log_scale(qcoeff1, dequant, zero,
dqcoeff_ptr + 8, &log_scale);
eob =
scan_for_eob(&qcoeff0, &qcoeff1, cmp_mask0, cmp_mask1, iscan, 0, zero);
}
// AC only loop.
// TODO(Aniket): Reduce the processing of coeff quatization
// based on eob logic
while (index < n_coeffs) {
coeff0 = load_coefficients(coeff_ptr + index);
coeff1 = load_coefficients(coeff_ptr + index + 8);
coeff0_sign = _mm_srai_epi16(coeff0, 15);
coeff1_sign = _mm_srai_epi16(coeff1, 15);
qcoeff0 = invert_sign_sse2(coeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(coeff1, coeff1_sign);
prescan0 = _mm_loadu_si128((const __m128i *)(prescan + index));
prescan1 = _mm_loadu_si128((const __m128i *)(prescan + index + 8));
cmp_mask0 = _mm_and_si128(prescan0, _mm_cmpgt_epi16(qcoeff0, zbin));
cmp_mask1 = _mm_and_si128(prescan1, _mm_cmpgt_epi16(qcoeff1, zbin));
all_zero = _mm_or_si128(cmp_mask0, cmp_mask1);
if (_mm_movemask_epi8(all_zero) == 0) {
_mm_store_si128((__m128i *)(qcoeff_ptr + index), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + index + 4), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + index + 8), zero);
_mm_store_si128((__m128i *)(qcoeff_ptr + index + 12), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index + 4), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index + 8), zero);
_mm_store_si128((__m128i *)(dqcoeff_ptr + index + 12), zero);
index += 16;
continue;
}
calculate_qcoeff_log_scale(&qcoeff0, round, quant, &shift, &log_scale);
calculate_qcoeff_log_scale(&qcoeff1, round, quant, &shift, &log_scale);
qcoeff0 = invert_sign_sse2(qcoeff0, coeff0_sign);
qcoeff1 = invert_sign_sse2(qcoeff1, coeff1_sign);
qcoeff0 = _mm_and_si128(qcoeff0, cmp_mask0);
qcoeff1 = _mm_and_si128(qcoeff1, cmp_mask1);
store_coefficients(qcoeff0, qcoeff_ptr + index);
store_coefficients(qcoeff1, qcoeff_ptr + index + 8);
calculate_dqcoeff_and_store_log_scale(qcoeff0, dequant, zero,
dqcoeff_ptr + index, &log_scale);
calculate_dqcoeff_and_store_log_scale(qcoeff1, dequant, zero,
dqcoeff_ptr + index + 8, &log_scale);
eob0 = scan_for_eob(&qcoeff0, &qcoeff1, cmp_mask0, cmp_mask1, iscan, index,
zero);
eob = _mm_max_epi16(eob, eob0);
index += 16;
}
*eob_ptr = accumulate_eob(eob);
#if SKIP_EOB_FACTOR_ADJUST
// TODO(Aniket): Experiment the following loop with intrinsic by combining
// with the quantization loop above
for (int i = 0; i < non_zero_count; i++) {
const int rc = scan[i];
const int qcoeff = qcoeff_ptr[rc];
if (qcoeff) {
first = i;
break;
}
}
if ((*eob_ptr - 1) >= 0 && first == (*eob_ptr - 1)) {
const int rc = scan[(*eob_ptr - 1)];
if (qcoeff_ptr[rc] == 1 || qcoeff_ptr[rc] == -1) {
const qm_val_t wt = (1 << AOM_QM_BITS);
const int coeff = coeff_ptr[rc] * wt;
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int factor = EOB_FACTOR + SKIP_EOB_FACTOR_ADJUST;
const int prescan_add_val =
ROUND_POWER_OF_TWO(dequant_ptr[rc != 0] * factor, 7);
if (abs_coeff < (zbins[rc != 0] * (1 << AOM_QM_BITS) + prescan_add_val)) {
qcoeff_ptr[rc] = 0;
dqcoeff_ptr[rc] = 0;
*eob_ptr = 0;
}
}
}
#endif
}

View file

@ -16,6 +16,129 @@
#include "aom_dsp/x86/bitdepth_conversion_sse2.h"
#include "aom_ports/mem.h"
void aom_minmax_8x8_sse2(const uint8_t *s, int p, const uint8_t *d, int dp,
int *min, int *max) {
__m128i u0, s0, d0, diff, maxabsdiff, minabsdiff, negdiff, absdiff0, absdiff;
u0 = _mm_setzero_si128();
// Row 0
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff0 = _mm_max_epi16(diff, negdiff);
// Row 1
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(absdiff0, absdiff);
minabsdiff = _mm_min_epi16(absdiff0, absdiff);
// Row 2
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 2 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 3
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 3 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 4
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 4 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 5
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 5 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 6
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 6 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
// Row 7
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0);
d0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(d + 7 * dp)), u0);
diff = _mm_subs_epi16(s0, d0);
negdiff = _mm_subs_epi16(u0, diff);
absdiff = _mm_max_epi16(diff, negdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, absdiff);
minabsdiff = _mm_min_epi16(minabsdiff, absdiff);
maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_si128(maxabsdiff, 8));
maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 32));
maxabsdiff = _mm_max_epi16(maxabsdiff, _mm_srli_epi64(maxabsdiff, 16));
*max = _mm_extract_epi16(maxabsdiff, 0);
minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_si128(minabsdiff, 8));
minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 32));
minabsdiff = _mm_min_epi16(minabsdiff, _mm_srli_epi64(minabsdiff, 16));
*min = _mm_extract_epi16(minabsdiff, 0);
}
unsigned int aom_avg_8x8_sse2(const uint8_t *s, int p) {
__m128i s0, s1, u0;
unsigned int avg = 0;
u0 = _mm_setzero_si128();
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 4 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 5 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 6 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 7 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 8));
s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 32));
s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16));
avg = _mm_extract_epi16(s0, 0);
return (avg + 32) >> 6;
}
unsigned int aom_avg_4x4_sse2(const uint8_t *s, int p) {
__m128i s0, s1, u0;
unsigned int avg = 0;
u0 = _mm_setzero_si128();
s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s)), u0);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 2 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i *)(s + 3 * p)), u0);
s0 = _mm_adds_epu16(s0, s1);
s0 = _mm_adds_epu16(s0, _mm_srli_si128(s0, 4));
s0 = _mm_adds_epu16(s0, _mm_srli_epi64(s0, 16));
avg = _mm_extract_epi16(s0, 0);
return (avg + 8) >> 4;
}
static void hadamard_col8_sse2(__m128i *in, int iter) {
__m128i a0 = in[0];
__m128i a1 = in[1];

View file

@ -34,31 +34,214 @@ DECLARE_ALIGNED(32, static const uint8_t, filt4_d4_global_avx2[]) = {
2, 3, 4, 5, 3, 4, 5, 6, 4, 5, 6, 7, 5, 6, 7, 8,
};
DECLARE_ALIGNED(32, static const uint8_t, filt_center_global_avx2[32]) = {
3, 255, 4, 255, 5, 255, 6, 255, 7, 255, 8, 255, 9, 255, 10, 255,
3, 255, 4, 255, 5, 255, 6, 255, 7, 255, 8, 255, 9, 255, 10, 255
};
#define CONVOLVE_SR_HORIZONTAL_FILTER_8TAP \
for (i = 0; i < (im_h - 2); i += 2) { \
__m256i data = _mm256_castsi128_si256( \
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); \
data = _mm256_inserti128_si256( \
data, \
_mm_loadu_si128( \
(__m128i *)&src_ptr[(i * src_stride) + j + src_stride]), \
1); \
\
__m256i res = convolve_lowbd_x(data, coeffs_h, filt); \
res = \
_mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); \
_mm256_store_si256((__m256i *)&im_block[i * im_stride], res); \
} \
\
__m256i data_1 = _mm256_castsi128_si256( \
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j])); \
\
__m256i res = convolve_lowbd_x(data_1, coeffs_h, filt); \
\
res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); \
\
_mm256_store_si256((__m256i *)&im_block[i * im_stride], res);
DECLARE_ALIGNED(32, static const uint8_t, filt1_global_avx2[32]) = {
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8,
0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8
};
#define CONVOLVE_SR_VERTICAL_FILTER_8TAP \
__m256i src_0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride)); \
__m256i src_1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride)); \
__m256i src_2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride)); \
__m256i src_3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride)); \
__m256i src_4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride)); \
__m256i src_5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride)); \
\
__m256i s[8]; \
s[0] = _mm256_unpacklo_epi16(src_0, src_1); \
s[1] = _mm256_unpacklo_epi16(src_2, src_3); \
s[2] = _mm256_unpacklo_epi16(src_4, src_5); \
\
s[4] = _mm256_unpackhi_epi16(src_0, src_1); \
s[5] = _mm256_unpackhi_epi16(src_2, src_3); \
s[6] = _mm256_unpackhi_epi16(src_4, src_5); \
\
for (i = 0; i < h; i += 2) { \
const int16_t *data = &im_block[i * im_stride]; \
\
const __m256i s6 = _mm256_loadu_si256((__m256i *)(data + 6 * im_stride)); \
const __m256i s7 = _mm256_loadu_si256((__m256i *)(data + 7 * im_stride)); \
\
s[3] = _mm256_unpacklo_epi16(s6, s7); \
s[7] = _mm256_unpackhi_epi16(s6, s7); \
\
__m256i res_a = convolve(s, coeffs_v); \
__m256i res_b = convolve(s + 4, coeffs_v); \
\
res_a = \
_mm256_sra_epi32(_mm256_add_epi32(res_a, sum_round_v), sum_shift_v); \
res_b = \
_mm256_sra_epi32(_mm256_add_epi32(res_b, sum_round_v), sum_shift_v); \
\
const __m256i res_a_round = _mm256_sra_epi32( \
_mm256_add_epi32(res_a, round_const_v), round_shift_v); \
const __m256i res_b_round = _mm256_sra_epi32( \
_mm256_add_epi32(res_b, round_const_v), round_shift_v); \
\
const __m256i res_16bit = _mm256_packs_epi32(res_a_round, res_b_round); \
const __m256i res_8b = _mm256_packus_epi16(res_16bit, res_16bit); \
\
const __m128i res_0 = _mm256_castsi256_si128(res_8b); \
const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1); \
\
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j]; \
__m128i *const p_1 = (__m128i *)&dst[i * dst_stride + j + dst_stride]; \
if (w - j > 4) { \
_mm_storel_epi64(p_0, res_0); \
_mm_storel_epi64(p_1, res_1); \
} else if (w == 4) { \
xx_storel_32(p_0, res_0); \
xx_storel_32(p_1, res_1); \
} else { \
*(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0); \
*(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1); \
} \
\
s[0] = s[1]; \
s[1] = s[2]; \
s[2] = s[3]; \
\
s[4] = s[5]; \
s[5] = s[6]; \
s[6] = s[7]; \
}
DECLARE_ALIGNED(32, static const uint8_t, filt2_global_avx2[32]) = {
2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10,
2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10
};
DECLARE_ALIGNED(32, static const uint8_t, filt3_global_avx2[32]) = {
4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12
};
DECLARE_ALIGNED(32, static const uint8_t, filt4_global_avx2[32]) = {
6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14,
6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14
};
#define DIST_WTD_CONVOLVE_HORIZONTAL_FILTER_8TAP \
for (i = 0; i < im_h; i += 2) { \
__m256i data = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)src_h)); \
if (i + 1 < im_h) \
data = _mm256_inserti128_si256( \
data, _mm_loadu_si128((__m128i *)(src_h + src_stride)), 1); \
src_h += (src_stride << 1); \
__m256i res = convolve_lowbd_x(data, coeffs_x, filt); \
\
res = \
_mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h); \
\
_mm256_store_si256((__m256i *)&im_block[i * im_stride], res); \
}
#define DIST_WTD_CONVOLVE_VERTICAL_FILTER_8TAP \
__m256i s[8]; \
__m256i s0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride)); \
__m256i s1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride)); \
__m256i s2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride)); \
__m256i s3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride)); \
__m256i s4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride)); \
__m256i s5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride)); \
\
s[0] = _mm256_unpacklo_epi16(s0, s1); \
s[1] = _mm256_unpacklo_epi16(s2, s3); \
s[2] = _mm256_unpacklo_epi16(s4, s5); \
\
s[4] = _mm256_unpackhi_epi16(s0, s1); \
s[5] = _mm256_unpackhi_epi16(s2, s3); \
s[6] = _mm256_unpackhi_epi16(s4, s5); \
\
for (i = 0; i < h; i += 2) { \
const int16_t *data = &im_block[i * im_stride]; \
\
const __m256i s6 = _mm256_loadu_si256((__m256i *)(data + 6 * im_stride)); \
const __m256i s7 = _mm256_loadu_si256((__m256i *)(data + 7 * im_stride)); \
\
s[3] = _mm256_unpacklo_epi16(s6, s7); \
s[7] = _mm256_unpackhi_epi16(s6, s7); \
\
const __m256i res_a = convolve(s, coeffs_y); \
const __m256i res_a_round = _mm256_sra_epi32( \
_mm256_add_epi32(res_a, round_const_v), round_shift_v); \
\
if (w - j > 4) { \
const __m256i res_b = convolve(s + 4, coeffs_y); \
const __m256i res_b_round = _mm256_sra_epi32( \
_mm256_add_epi32(res_b, round_const_v), round_shift_v); \
const __m256i res_16b = _mm256_packs_epi32(res_a_round, res_b_round); \
const __m256i res_unsigned = _mm256_add_epi16(res_16b, offset_const); \
\
if (do_average) { \
const __m256i data_ref_0 = load_line2_avx2( \
&dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]); \
const __m256i comp_avg_res = \
comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); \
\
const __m256i round_result = convolve_rounding( \
&comp_avg_res, &offset_const, &rounding_const, rounding_shift); \
\
const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); \
const __m128i res_0 = _mm256_castsi256_si128(res_8); \
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); \
\
_mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0); \
_mm_storel_epi64( \
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1); \
} else { \
const __m128i res_0 = _mm256_castsi256_si128(res_unsigned); \
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); \
\
const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1); \
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), \
res_1); \
} \
} else { \
const __m256i res_16b = _mm256_packs_epi32(res_a_round, res_a_round); \
const __m256i res_unsigned = _mm256_add_epi16(res_16b, offset_const); \
\
if (do_average) { \
const __m256i data_ref_0 = load_line2_avx2( \
&dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]); \
\
const __m256i comp_avg_res = \
comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg); \
\
const __m256i round_result = convolve_rounding( \
&comp_avg_res, &offset_const, &rounding_const, rounding_shift); \
\
const __m256i res_8 = _mm256_packus_epi16(round_result, round_result); \
const __m128i res_0 = _mm256_castsi256_si128(res_8); \
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1); \
\
*(uint32_t *)(&dst0[i * dst_stride0 + j]) = _mm_cvtsi128_si32(res_0); \
*(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) = \
_mm_cvtsi128_si32(res_1); \
\
} else { \
const __m128i res_0 = _mm256_castsi256_si128(res_unsigned); \
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0); \
\
const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1); \
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]), \
res_1); \
} \
} \
\
s[0] = s[1]; \
s[1] = s[2]; \
s[2] = s[3]; \
\
s[4] = s[5]; \
s[5] = s[6]; \
s[6] = s[7]; \
}
static INLINE void prepare_coeffs_lowbd(
const InterpFilterParams *const filter_params, const int subpel_q4,
__m256i *const coeffs /* [4] */) {
@ -120,6 +303,17 @@ static INLINE __m256i convolve_lowbd(const __m256i *const s,
return res;
}
static INLINE __m256i convolve_lowbd_4tap(const __m256i *const s,
const __m256i *const coeffs) {
const __m256i res_23 = _mm256_maddubs_epi16(s[0], coeffs[0]);
const __m256i res_45 = _mm256_maddubs_epi16(s[1], coeffs[1]);
// order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
const __m256i res = _mm256_add_epi16(res_45, res_23);
return res;
}
static INLINE __m256i convolve(const __m256i *const s,
const __m256i *const coeffs) {
const __m256i res_0 = _mm256_madd_epi16(s[0], coeffs[0]);
@ -155,6 +349,17 @@ static INLINE __m256i convolve_lowbd_x(const __m256i data,
return convolve_lowbd(s, coeffs);
}
static INLINE __m256i convolve_lowbd_x_4tap(const __m256i data,
const __m256i *const coeffs,
const __m256i *const filt) {
__m256i s[2];
s[0] = _mm256_shuffle_epi8(data, filt[0]);
s[1] = _mm256_shuffle_epi8(data, filt[1]);
return convolve_lowbd_4tap(s, coeffs);
}
static INLINE void add_store_aligned_256(CONV_BUF_TYPE *const dst,
const __m256i *const res,
const int do_average) {

View file

@ -1,259 +0,0 @@
;
; 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 "third_party/x86inc/x86inc.asm"
SECTION_RODATA
pw_4: times 8 dw 4
pw_8: times 8 dw 8
pw_16: times 4 dd 16
pw_32: times 4 dd 32
SECTION .text
INIT_XMM sse2
cglobal highbd_dc_predictor_4x4, 4, 5, 4, dst, stride, above, left, goffset
GET_GOT goffsetq
movq m0, [aboveq]
movq m2, [leftq]
paddw m0, m2
pshuflw m1, m0, 0xe
paddw m0, m1
pshuflw m1, m0, 0x1
paddw m0, m1
paddw m0, [GLOBAL(pw_4)]
psraw m0, 3
pshuflw m0, m0, 0x0
movq [dstq ], m0
movq [dstq+strideq*2], m0
lea dstq, [dstq+strideq*4]
movq [dstq ], m0
movq [dstq+strideq*2], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal highbd_dc_predictor_8x8, 4, 5, 4, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [aboveq]
mova m2, [leftq]
DEFINE_ARGS dst, stride, stride3, one
mov oned, 0x00010001
lea stride3q, [strideq*3]
movd m3, oned
pshufd m3, m3, 0x0
paddw m0, m2
pmaddwd m0, m3
packssdw m0, m1
pmaddwd m0, m3
packssdw m0, m1
pmaddwd m0, m3
paddw m0, [GLOBAL(pw_8)]
psrlw m0, 4
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
mova [dstq ], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*4 ], m0
mova [dstq+stride3q*2], m0
lea dstq, [dstq+strideq*8]
mova [dstq ], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*4 ], m0
mova [dstq+stride3q*2], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal highbd_dc_predictor_16x16, 4, 5, 5, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [aboveq]
mova m3, [aboveq+16]
mova m2, [leftq]
mova m4, [leftq+16]
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 4
paddw m0, m2
paddw m0, m3
paddw m0, m4
movhlps m2, m0
paddw m0, m2
punpcklwd m0, m1
movhlps m2, m0
paddd m0, m2
punpckldq m0, m1
movhlps m2, m0
paddd m0, m2
paddd m0, [GLOBAL(pw_16)]
psrad m0, 5
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
.loop:
mova [dstq ], m0
mova [dstq +16], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2 +16], m0
mova [dstq+strideq*4 ], m0
mova [dstq+strideq*4 +16], m0
mova [dstq+stride3q*2 ], m0
mova [dstq+stride3q*2+16], m0
lea dstq, [dstq+strideq*8]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal highbd_dc_predictor_32x32, 4, 5, 7, dst, stride, above, left, goffset
GET_GOT goffsetq
mova m0, [aboveq]
mova m2, [aboveq+16]
mova m3, [aboveq+32]
mova m4, [aboveq+48]
paddw m0, m2
paddw m3, m4
mova m2, [leftq]
mova m4, [leftq+16]
mova m5, [leftq+32]
mova m6, [leftq+48]
paddw m2, m4
paddw m5, m6
paddw m0, m3
paddw m2, m5
pxor m1, m1
paddw m0, m2
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 8
movhlps m2, m0
paddw m0, m2
punpcklwd m0, m1
movhlps m2, m0
paddd m0, m2
punpckldq m0, m1
movhlps m2, m0
paddd m0, m2
paddd m0, [GLOBAL(pw_32)]
psrad m0, 6
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
.loop:
mova [dstq ], m0
mova [dstq +16 ], m0
mova [dstq +32 ], m0
mova [dstq +48 ], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2+16 ], m0
mova [dstq+strideq*2+32 ], m0
mova [dstq+strideq*2+48 ], m0
mova [dstq+strideq*4 ], m0
mova [dstq+strideq*4+16 ], m0
mova [dstq+strideq*4+32 ], m0
mova [dstq+strideq*4+48 ], m0
mova [dstq+stride3q*2 ], m0
mova [dstq+stride3q*2 +16], m0
mova [dstq+stride3q*2 +32], m0
mova [dstq+stride3q*2 +48], m0
lea dstq, [dstq+strideq*8]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal highbd_v_predictor_4x4, 3, 3, 1, dst, stride, above
movq m0, [aboveq]
movq [dstq ], m0
movq [dstq+strideq*2], m0
lea dstq, [dstq+strideq*4]
movq [dstq ], m0
movq [dstq+strideq*2], m0
RET
INIT_XMM sse2
cglobal highbd_v_predictor_8x8, 3, 3, 1, dst, stride, above
mova m0, [aboveq]
DEFINE_ARGS dst, stride, stride3
lea stride3q, [strideq*3]
mova [dstq ], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*4 ], m0
mova [dstq+stride3q*2], m0
lea dstq, [dstq+strideq*8]
mova [dstq ], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*4 ], m0
mova [dstq+stride3q*2], m0
RET
INIT_XMM sse2
cglobal highbd_v_predictor_16x16, 3, 4, 2, dst, stride, above
mova m0, [aboveq]
mova m1, [aboveq+16]
DEFINE_ARGS dst, stride, stride3, nlines4
lea stride3q, [strideq*3]
mov nlines4d, 4
.loop:
mova [dstq ], m0
mova [dstq +16], m1
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2 +16], m1
mova [dstq+strideq*4 ], m0
mova [dstq+strideq*4 +16], m1
mova [dstq+stride3q*2 ], m0
mova [dstq+stride3q*2+16], m1
lea dstq, [dstq+strideq*8]
dec nlines4d
jnz .loop
REP_RET
INIT_XMM sse2
cglobal highbd_v_predictor_32x32, 3, 4, 4, dst, stride, above
mova m0, [aboveq]
mova m1, [aboveq+16]
mova m2, [aboveq+32]
mova m3, [aboveq+48]
DEFINE_ARGS dst, stride, stride3, nlines4
lea stride3q, [strideq*3]
mov nlines4d, 8
.loop:
mova [dstq ], m0
mova [dstq +16], m1
mova [dstq +32], m2
mova [dstq +48], m3
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2 +16], m1
mova [dstq+strideq*2 +32], m2
mova [dstq+strideq*2 +48], m3
mova [dstq+strideq*4 ], m0
mova [dstq+strideq*4 +16], m1
mova [dstq+strideq*4 +32], m2
mova [dstq+strideq*4 +48], m3
mova [dstq+stride3q*2 ], m0
mova [dstq+stride3q*2 +16], m1
mova [dstq+stride3q*2 +32], m2
mova [dstq+stride3q*2 +48], m3
lea dstq, [dstq+strideq*8]
dec nlines4d
jnz .loop
REP_RET

View file

@ -146,3 +146,61 @@ void aom_highbd_quantize_b_32x32_sse2(
}
*eob_ptr = eob + 1;
}
void aom_highbd_quantize_b_64x64_sse2(
const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr,
const int16_t *round_ptr, const int16_t *quant_ptr,
const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr,
const int16_t *scan, const int16_t *iscan) {
__m128i zbins[2];
__m128i nzbins[2];
int idx = 0;
int idx_arr[1024];
int i, eob = -1;
const int zbin0_tmp = ROUND_POWER_OF_TWO(zbin_ptr[0], 2);
const int zbin1_tmp = ROUND_POWER_OF_TWO(zbin_ptr[1], 2);
(void)scan;
zbins[0] = _mm_set_epi32(zbin1_tmp, zbin1_tmp, zbin1_tmp, zbin0_tmp);
zbins[1] = _mm_set1_epi32(zbin1_tmp);
nzbins[0] = _mm_setzero_si128();
nzbins[1] = _mm_setzero_si128();
nzbins[0] = _mm_sub_epi32(nzbins[0], zbins[0]);
nzbins[1] = _mm_sub_epi32(nzbins[1], zbins[1]);
memset(qcoeff_ptr, 0, n_coeffs * sizeof(*qcoeff_ptr));
memset(dqcoeff_ptr, 0, n_coeffs * sizeof(*dqcoeff_ptr));
// Pre-scan pass
for (i = 0; i < n_coeffs / 4; i++) {
__m128i coeffs, cmp1, cmp2;
int test;
coeffs = _mm_load_si128((const __m128i *)(coeff_ptr + i * 4));
cmp1 = _mm_cmplt_epi32(coeffs, zbins[i != 0]);
cmp2 = _mm_cmpgt_epi32(coeffs, nzbins[i != 0]);
cmp1 = _mm_and_si128(cmp1, cmp2);
test = _mm_movemask_epi8(cmp1);
if (!(test & 0xf)) idx_arr[idx++] = i * 4;
if (!(test & 0xf0)) idx_arr[idx++] = i * 4 + 1;
if (!(test & 0xf00)) idx_arr[idx++] = i * 4 + 2;
if (!(test & 0xf000)) idx_arr[idx++] = i * 4 + 3;
}
// Quantization pass: only process the coefficients selected in
// pre-scan pass. Note: idx can be zero.
for (i = 0; i < idx; i++) {
const int rc = idx_arr[i];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
const int abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
const int64_t tmp1 = abs_coeff + ROUND_POWER_OF_TWO(round_ptr[rc != 0], 2);
const int64_t tmp2 = ((tmp1 * quant_ptr[rc != 0]) >> 16) + tmp1;
const uint32_t abs_qcoeff =
(uint32_t)((tmp2 * quant_shift_ptr[rc != 0]) >> 14);
qcoeff_ptr[rc] = (int)(abs_qcoeff ^ coeff_sign) - coeff_sign;
dqcoeff_ptr[rc] = qcoeff_ptr[rc] * dequant_ptr[rc != 0] / 4;
if (abs_qcoeff) eob = iscan[idx_arr[i]] > eob ? iscan[idx_arr[i]] : eob;
}
*eob_ptr = eob + 1;
}

View file

@ -287,30 +287,38 @@ DECLS(sse2);
uint32_t aom_highbd_8_sub_pixel_variance##w##x##h##_##opt( \
const uint8_t *src8, int src_stride, int x_offset, int y_offset, \
const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr) { \
uint32_t sse; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
int se = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse, NULL, \
NULL); \
if (w > wf) { \
unsigned int sse2; \
int se = 0; \
unsigned int sse = 0; \
unsigned int sse2; \
int row_rep = (w > 64) ? 2 : 1; \
for (int wd_64 = 0; wd_64 < row_rep; wd_64++) { \
src += wd_64 * 64; \
dst += wd_64 * 64; \
int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \
&sse2, NULL, NULL); \
src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse2, \
NULL, NULL); \
se += se2; \
sse += sse2; \
if (w > wf * 2) { \
if (w > wf) { \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, h, \
&sse2, NULL, NULL); \
se += se2; \
sse += sse2; \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, h, \
src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \
&sse2, NULL, NULL); \
se += se2; \
sse += sse2; \
if (w > wf * 2) { \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, \
h, &sse2, NULL, NULL); \
se += se2; \
sse += sse2; \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, \
h, &sse2, NULL, NULL); \
se += se2; \
sse += sse2; \
} \
} \
} \
*sse_ptr = sse; \
@ -322,33 +330,42 @@ DECLS(sse2);
const uint8_t *dst8, int dst_stride, uint32_t *sse_ptr) { \
int64_t var; \
uint32_t sse; \
uint64_t long_sse = 0; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
int se = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse, NULL, \
NULL); \
if (w > wf) { \
uint32_t sse2; \
int se = 0; \
int row_rep = (w > 64) ? 2 : 1; \
for (int wd_64 = 0; wd_64 < row_rep; wd_64++) { \
src += wd_64 * 64; \
dst += wd_64 * 64; \
int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \
&sse2, NULL, NULL); \
src, src_stride, x_offset, y_offset, dst, dst_stride, h, &sse, NULL, \
NULL); \
se += se2; \
sse += sse2; \
if (w > wf * 2) { \
long_sse += sse; \
if (w > wf) { \
uint32_t sse2; \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, h, \
src + 16, src_stride, x_offset, y_offset, dst + 16, dst_stride, h, \
&sse2, NULL, NULL); \
se += se2; \
sse += sse2; \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, h, \
&sse2, NULL, NULL); \
se += se2; \
sse += sse2; \
long_sse += sse2; \
if (w > wf * 2) { \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 32, src_stride, x_offset, y_offset, dst + 32, dst_stride, \
h, &sse2, NULL, NULL); \
se += se2; \
long_sse += sse2; \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 48, src_stride, x_offset, y_offset, dst + 48, dst_stride, \
h, &sse2, NULL, NULL); \
se += se2; \
long_sse += sse2; \
} \
} \
} \
se = ROUND_POWER_OF_TWO(se, 2); \
sse = ROUND_POWER_OF_TWO(sse, 4); \
sse = (uint32_t)ROUND_POWER_OF_TWO(long_sse, 4); \
*sse_ptr = sse; \
var = (int64_t)(sse) - ((cast se * se) >> (wlog2 + hlog2)); \
return (var >= 0) ? (uint32_t)var : 0; \
@ -364,35 +381,38 @@ DECLS(sse2);
uint64_t long_sse = 0; \
uint16_t *src = CONVERT_TO_SHORTPTR(src8); \
uint16_t *dst = CONVERT_TO_SHORTPTR(dst8); \
int row_rep = (w > 64) ? 2 : 1; \
for (start_row = 0; start_row < h; start_row += 16) { \
uint32_t sse2; \
int height = h - start_row < 16 ? h - start_row : 16; \
int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + (start_row * src_stride), src_stride, x_offset, y_offset, \
dst + (start_row * dst_stride), dst_stride, height, &sse2, NULL, \
NULL); \
se += se2; \
long_sse += sse2; \
if (w > wf) { \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 16 + (start_row * src_stride), src_stride, x_offset, \
y_offset, dst + 16 + (start_row * dst_stride), dst_stride, height, \
&sse2, NULL, NULL); \
uint16_t *src_tmp = src + (start_row * src_stride); \
uint16_t *dst_tmp = dst + (start_row * dst_stride); \
for (int wd_64 = 0; wd_64 < row_rep; wd_64++) { \
src_tmp += wd_64 * 64; \
dst_tmp += wd_64 * 64; \
int se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src_tmp, src_stride, x_offset, y_offset, dst_tmp, dst_stride, \
height, &sse2, NULL, NULL); \
se += se2; \
long_sse += sse2; \
if (w > wf * 2) { \
if (w > wf) { \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 32 + (start_row * src_stride), src_stride, x_offset, \
y_offset, dst + 32 + (start_row * dst_stride), dst_stride, \
height, &sse2, NULL, NULL); \
se += se2; \
long_sse += sse2; \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src + 48 + (start_row * src_stride), src_stride, x_offset, \
y_offset, dst + 48 + (start_row * dst_stride), dst_stride, \
height, &sse2, NULL, NULL); \
src_tmp + 16, src_stride, x_offset, y_offset, dst_tmp + 16, \
dst_stride, height, &sse2, NULL, NULL); \
se += se2; \
long_sse += sse2; \
if (w > wf * 2) { \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src_tmp + 32, src_stride, x_offset, y_offset, dst_tmp + 32, \
dst_stride, height, &sse2, NULL, NULL); \
se += se2; \
long_sse += sse2; \
se2 = aom_highbd_sub_pixel_variance##wf##xh_##opt( \
src_tmp + 48, src_stride, x_offset, y_offset, dst_tmp + 48, \
dst_stride, height, &sse2, NULL, NULL); \
se += se2; \
long_sse += sse2; \
} \
} \
} \
} \
@ -403,22 +423,25 @@ DECLS(sse2);
return (var >= 0) ? (uint32_t)var : 0; \
}
#define FNS(opt) \
FN(64, 64, 16, 6, 6, opt, (int64_t)); \
FN(64, 32, 16, 6, 5, opt, (int64_t)); \
FN(32, 64, 16, 5, 6, opt, (int64_t)); \
FN(32, 32, 16, 5, 5, opt, (int64_t)); \
FN(32, 16, 16, 5, 4, opt, (int64_t)); \
FN(16, 32, 16, 4, 5, opt, (int64_t)); \
FN(16, 16, 16, 4, 4, opt, (int64_t)); \
FN(16, 8, 16, 4, 3, opt, (int64_t)); \
FN(8, 16, 8, 3, 4, opt, (int64_t)); \
FN(8, 8, 8, 3, 3, opt, (int64_t)); \
FN(8, 4, 8, 3, 2, opt, (int64_t)); \
FN(16, 4, 16, 4, 2, opt, (int64_t)); \
FN(8, 32, 8, 3, 5, opt, (int64_t)); \
FN(32, 8, 16, 5, 3, opt, (int64_t)); \
FN(16, 64, 16, 4, 6, opt, (int64_t)); \
#define FNS(opt) \
FN(128, 128, 16, 7, 7, opt, (int64_t)); \
FN(128, 64, 16, 7, 6, opt, (int64_t)); \
FN(64, 128, 16, 6, 7, opt, (int64_t)); \
FN(64, 64, 16, 6, 6, opt, (int64_t)); \
FN(64, 32, 16, 6, 5, opt, (int64_t)); \
FN(32, 64, 16, 5, 6, opt, (int64_t)); \
FN(32, 32, 16, 5, 5, opt, (int64_t)); \
FN(32, 16, 16, 5, 4, opt, (int64_t)); \
FN(16, 32, 16, 4, 5, opt, (int64_t)); \
FN(16, 16, 16, 4, 4, opt, (int64_t)); \
FN(16, 8, 16, 4, 3, opt, (int64_t)); \
FN(8, 16, 8, 3, 4, opt, (int64_t)); \
FN(8, 8, 8, 3, 3, opt, (int64_t)); \
FN(8, 4, 8, 3, 2, opt, (int64_t)); \
FN(16, 4, 16, 4, 2, opt, (int64_t)); \
FN(8, 32, 8, 3, 5, opt, (int64_t)); \
FN(32, 8, 16, 5, 3, opt, (int64_t)); \
FN(16, 64, 16, 4, 6, opt, (int64_t)); \
FN(64, 16, 16, 6, 4, opt, (int64_t))
FNS(sse2);

File diff suppressed because it is too large Load diff

View file

@ -1,625 +0,0 @@
;
; 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 "third_party/x86inc/x86inc.asm"
SECTION_RODATA
pb_1: times 16 db 1
pw_4: times 8 dw 4
pw_8: times 8 dw 8
pw_16: times 8 dw 16
pw_32: times 8 dw 32
dc_128: times 16 db 128
pw2_4: times 8 dw 2
pw2_8: times 8 dw 4
pw2_16: times 8 dw 8
pw2_32: times 8 dw 16
SECTION .text
; ------------------------------------------
; input: x, y, z, result
;
; trick from pascal
; (x+2y+z+2)>>2 can be calculated as:
; result = avg(x,z)
; result -= xor(x,z) & 1
; result = avg(result,y)
; ------------------------------------------
%macro X_PLUS_2Y_PLUS_Z_PLUS_2_RSH_2 4
pavgb %4, %1, %3
pxor %3, %1
pand %3, [GLOBAL(pb_1)]
psubb %4, %3
pavgb %4, %2
%endmacro
INIT_XMM sse2
cglobal dc_predictor_4x4, 4, 5, 3, dst, stride, above, left, goffset
GET_GOT goffsetq
movd m2, [leftq]
movd m0, [aboveq]
pxor m1, m1
punpckldq m0, m2
psadbw m0, m1
paddw m0, [GLOBAL(pw_4)]
psraw m0, 3
pshuflw m0, m0, 0x0
packuswb m0, m0
movd [dstq ], m0
movd [dstq+strideq], m0
lea dstq, [dstq+strideq*2]
movd [dstq ], m0
movd [dstq+strideq], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_left_predictor_4x4, 2, 5, 2, dst, stride, above, left, goffset
movifnidn leftq, leftmp
GET_GOT goffsetq
pxor m1, m1
movd m0, [leftq]
psadbw m0, m1
paddw m0, [GLOBAL(pw2_4)]
psraw m0, 2
pshuflw m0, m0, 0x0
packuswb m0, m0
movd [dstq ], m0
movd [dstq+strideq], m0
lea dstq, [dstq+strideq*2]
movd [dstq ], m0
movd [dstq+strideq], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_top_predictor_4x4, 3, 5, 2, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
movd m0, [aboveq]
psadbw m0, m1
paddw m0, [GLOBAL(pw2_4)]
psraw m0, 2
pshuflw m0, m0, 0x0
packuswb m0, m0
movd [dstq ], m0
movd [dstq+strideq], m0
lea dstq, [dstq+strideq*2]
movd [dstq ], m0
movd [dstq+strideq], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_predictor_8x8, 4, 5, 3, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
movq m0, [aboveq]
movq m2, [leftq]
DEFINE_ARGS dst, stride, stride3
lea stride3q, [strideq*3]
psadbw m0, m1
psadbw m2, m1
paddw m0, m2
paddw m0, [GLOBAL(pw_8)]
psraw m0, 4
punpcklbw m0, m0
pshuflw m0, m0, 0x0
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_top_predictor_8x8, 3, 5, 2, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
movq m0, [aboveq]
DEFINE_ARGS dst, stride, stride3
lea stride3q, [strideq*3]
psadbw m0, m1
paddw m0, [GLOBAL(pw2_8)]
psraw m0, 3
punpcklbw m0, m0
pshuflw m0, m0, 0x0
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_left_predictor_8x8, 2, 5, 2, dst, stride, above, left, goffset
movifnidn leftq, leftmp
GET_GOT goffsetq
pxor m1, m1
movq m0, [leftq]
DEFINE_ARGS dst, stride, stride3
lea stride3q, [strideq*3]
psadbw m0, m1
paddw m0, [GLOBAL(pw2_8)]
psraw m0, 3
punpcklbw m0, m0
pshuflw m0, m0, 0x0
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_128_predictor_4x4, 2, 5, 1, dst, stride, above, left, goffset
GET_GOT goffsetq
DEFINE_ARGS dst, stride, stride3
lea stride3q, [strideq*3]
movd m0, [GLOBAL(dc_128)]
movd [dstq ], m0
movd [dstq+strideq ], m0
movd [dstq+strideq*2], m0
movd [dstq+stride3q ], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_128_predictor_8x8, 2, 5, 1, dst, stride, above, left, goffset
GET_GOT goffsetq
DEFINE_ARGS dst, stride, stride3
lea stride3q, [strideq*3]
movq m0, [GLOBAL(dc_128)]
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [aboveq]
mova m2, [leftq]
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 4
psadbw m0, m1
psadbw m2, m1
paddw m0, m2
movhlps m2, m0
paddw m0, m2
paddw m0, [GLOBAL(pw_16)]
psraw m0, 5
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
packuswb m0, m0
.loop:
mova [dstq ], m0
mova [dstq+strideq ], m0
mova [dstq+strideq*2], m0
mova [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal dc_top_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [aboveq]
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 4
psadbw m0, m1
movhlps m2, m0
paddw m0, m2
paddw m0, [GLOBAL(pw2_16)]
psraw m0, 4
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
packuswb m0, m0
.loop:
mova [dstq ], m0
mova [dstq+strideq ], m0
mova [dstq+strideq*2], m0
mova [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal dc_left_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [leftq]
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 4
psadbw m0, m1
movhlps m2, m0
paddw m0, m2
paddw m0, [GLOBAL(pw2_16)]
psraw m0, 4
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
packuswb m0, m0
.loop:
mova [dstq ], m0
mova [dstq+strideq ], m0
mova [dstq+strideq*2], m0
mova [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal dc_128_predictor_16x16, 4, 5, 3, dst, stride, above, left, goffset
GET_GOT goffsetq
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 4
mova m0, [GLOBAL(dc_128)]
.loop:
mova [dstq ], m0
mova [dstq+strideq ], m0
mova [dstq+strideq*2], m0
mova [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
RET
INIT_XMM sse2
cglobal dc_predictor_32x32, 4, 5, 5, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [aboveq]
mova m2, [aboveq+16]
mova m3, [leftq]
mova m4, [leftq+16]
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 8
psadbw m0, m1
psadbw m2, m1
psadbw m3, m1
psadbw m4, m1
paddw m0, m2
paddw m0, m3
paddw m0, m4
movhlps m2, m0
paddw m0, m2
paddw m0, [GLOBAL(pw_32)]
psraw m0, 6
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
packuswb m0, m0
.loop:
mova [dstq ], m0
mova [dstq +16], m0
mova [dstq+strideq ], m0
mova [dstq+strideq +16], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2+16], m0
mova [dstq+stride3q ], m0
mova [dstq+stride3q +16], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal dc_top_predictor_32x32, 4, 5, 5, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [aboveq]
mova m2, [aboveq+16]
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 8
psadbw m0, m1
psadbw m2, m1
paddw m0, m2
movhlps m2, m0
paddw m0, m2
paddw m0, [GLOBAL(pw2_32)]
psraw m0, 5
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
packuswb m0, m0
.loop:
mova [dstq ], m0
mova [dstq +16], m0
mova [dstq+strideq ], m0
mova [dstq+strideq +16], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2+16], m0
mova [dstq+stride3q ], m0
mova [dstq+stride3q +16], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal dc_left_predictor_32x32, 4, 5, 5, dst, stride, above, left, goffset
GET_GOT goffsetq
pxor m1, m1
mova m0, [leftq]
mova m2, [leftq+16]
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 8
psadbw m0, m1
psadbw m2, m1
paddw m0, m2
movhlps m2, m0
paddw m0, m2
paddw m0, [GLOBAL(pw2_32)]
psraw m0, 5
pshuflw m0, m0, 0x0
punpcklqdq m0, m0
packuswb m0, m0
.loop:
mova [dstq ], m0
mova [dstq +16], m0
mova [dstq+strideq ], m0
mova [dstq+strideq +16], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2+16], m0
mova [dstq+stride3q ], m0
mova [dstq+stride3q +16], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
REP_RET
INIT_XMM sse2
cglobal dc_128_predictor_32x32, 4, 5, 3, dst, stride, above, left, goffset
GET_GOT goffsetq
DEFINE_ARGS dst, stride, stride3, lines4
lea stride3q, [strideq*3]
mov lines4d, 8
mova m0, [GLOBAL(dc_128)]
.loop:
mova [dstq ], m0
mova [dstq +16], m0
mova [dstq+strideq ], m0
mova [dstq+strideq +16], m0
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2+16], m0
mova [dstq+stride3q ], m0
mova [dstq+stride3q +16], m0
lea dstq, [dstq+strideq*4]
dec lines4d
jnz .loop
RESTORE_GOT
RET
INIT_XMM sse2
cglobal v_predictor_4x4, 3, 3, 1, dst, stride, above
movd m0, [aboveq]
movd [dstq ], m0
movd [dstq+strideq], m0
lea dstq, [dstq+strideq*2]
movd [dstq ], m0
movd [dstq+strideq], m0
RET
INIT_XMM sse2
cglobal v_predictor_8x8, 3, 3, 1, dst, stride, above
movq m0, [aboveq]
DEFINE_ARGS dst, stride, stride3
lea stride3q, [strideq*3]
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
movq [dstq ], m0
movq [dstq+strideq ], m0
movq [dstq+strideq*2], m0
movq [dstq+stride3q ], m0
RET
INIT_XMM sse2
cglobal v_predictor_16x16, 3, 4, 1, dst, stride, above
mova m0, [aboveq]
DEFINE_ARGS dst, stride, stride3, nlines4
lea stride3q, [strideq*3]
mov nlines4d, 4
.loop:
mova [dstq ], m0
mova [dstq+strideq ], m0
mova [dstq+strideq*2], m0
mova [dstq+stride3q ], m0
lea dstq, [dstq+strideq*4]
dec nlines4d
jnz .loop
REP_RET
INIT_XMM sse2
cglobal v_predictor_32x32, 3, 4, 2, dst, stride, above
mova m0, [aboveq]
mova m1, [aboveq+16]
DEFINE_ARGS dst, stride, stride3, nlines4
lea stride3q, [strideq*3]
mov nlines4d, 8
.loop:
mova [dstq ], m0
mova [dstq +16], m1
mova [dstq+strideq ], m0
mova [dstq+strideq +16], m1
mova [dstq+strideq*2 ], m0
mova [dstq+strideq*2+16], m1
mova [dstq+stride3q ], m0
mova [dstq+stride3q +16], m1
lea dstq, [dstq+strideq*4]
dec nlines4d
jnz .loop
REP_RET
INIT_XMM sse2
cglobal h_predictor_4x4, 2, 4, 4, dst, stride, line, left
movifnidn leftq, leftmp
movd m0, [leftq]
punpcklbw m0, m0
punpcklbw m0, m0
pshufd m1, m0, 0x1
movd [dstq ], m0
movd [dstq+strideq], m1
pshufd m2, m0, 0x2
lea dstq, [dstq+strideq*2]
pshufd m3, m0, 0x3
movd [dstq ], m2
movd [dstq+strideq], m3
RET
INIT_XMM sse2
cglobal h_predictor_8x8, 2, 5, 3, dst, stride, line, left
movifnidn leftq, leftmp
mov lineq, -2
DEFINE_ARGS dst, stride, line, left, stride3
lea stride3q, [strideq*3]
movq m0, [leftq ]
punpcklbw m0, m0 ; l1 l1 l2 l2 ... l8 l8
.loop:
pshuflw m1, m0, 0x0 ; l1 l1 l1 l1 l1 l1 l1 l1
pshuflw m2, m0, 0x55 ; l2 l2 l2 l2 l2 l2 l2 l2
movq [dstq ], m1
movq [dstq+strideq], m2
pshuflw m1, m0, 0xaa
pshuflw m2, m0, 0xff
movq [dstq+strideq*2], m1
movq [dstq+stride3q ], m2
pshufd m0, m0, 0xe ; [63:0] l5 l5 l6 l6 l7 l7 l8 l8
inc lineq
lea dstq, [dstq+strideq*4]
jnz .loop
REP_RET
INIT_XMM sse2
cglobal h_predictor_16x16, 2, 5, 3, dst, stride, line, left
movifnidn leftq, leftmp
mov lineq, -4
DEFINE_ARGS dst, stride, line, left, stride3
lea stride3q, [strideq*3]
.loop:
movd m0, [leftq]
punpcklbw m0, m0
punpcklbw m0, m0 ; l1 to l4 each repeated 4 times
pshufd m1, m0, 0x0 ; l1 repeated 16 times
pshufd m2, m0, 0x55 ; l2 repeated 16 times
mova [dstq ], m1
mova [dstq+strideq ], m2
pshufd m1, m0, 0xaa
pshufd m2, m0, 0xff
mova [dstq+strideq*2], m1
mova [dstq+stride3q ], m2
inc lineq
lea leftq, [leftq+4 ]
lea dstq, [dstq+strideq*4]
jnz .loop
REP_RET
INIT_XMM sse2
cglobal h_predictor_32x32, 2, 5, 3, dst, stride, line, left
movifnidn leftq, leftmp
mov lineq, -8
DEFINE_ARGS dst, stride, line, left, stride3
lea stride3q, [strideq*3]
.loop:
movd m0, [leftq]
punpcklbw m0, m0
punpcklbw m0, m0 ; l1 to l4 each repeated 4 times
pshufd m1, m0, 0x0 ; l1 repeated 16 times
pshufd m2, m0, 0x55 ; l2 repeated 16 times
mova [dstq ], m1
mova [dstq+16 ], m1
mova [dstq+strideq ], m2
mova [dstq+strideq+16 ], m2
pshufd m1, m0, 0xaa
pshufd m2, m0, 0xff
mova [dstq+strideq*2 ], m1
mova [dstq+strideq*2+16], m1
mova [dstq+stride3q ], m2
mova [dstq+stride3q+16 ], m2
inc lineq
lea leftq, [leftq+4 ]
lea dstq, [dstq+strideq*4]
jnz .loop
REP_RET

View file

@ -23,8 +23,8 @@ static INLINE __m128i abs_diff(__m128i a, __m128i b) {
}
// this function treats its input as 2 parallel 8x4 matrices, transposes each of
// them to 4x8 independently while flipping the second matrix horizontaly. Used
// for 14 taps pq pairs creation
// them to 4x8 independently while flipping the second matrix horizontally.
// Used for 14 taps pq pairs creation
static INLINE void transpose_pq_14_sse2(__m128i *x0, __m128i *x1, __m128i *x2,
__m128i *x3, __m128i *q0p0,
__m128i *q1p1, __m128i *q2p2,

View file

@ -32,6 +32,11 @@ static INLINE __m128i invert_sign_sse2(__m128i a, __m128i sign) {
return _mm_sub_epi16(a, sign);
}
static INLINE __m128i invert_sign_32_sse2(__m128i a, __m128i sign) {
a = _mm_xor_si128(a, sign);
return _mm_sub_epi32(a, sign);
}
static INLINE void calculate_qcoeff(__m128i *coeff, const __m128i round,
const __m128i quant, const __m128i shift) {
__m128i tmp, qcoeff;
@ -41,10 +46,53 @@ static INLINE void calculate_qcoeff(__m128i *coeff, const __m128i round,
*coeff = _mm_mulhi_epi16(qcoeff, shift);
}
static INLINE void calculate_qcoeff_log_scale(__m128i *coeff,
const __m128i round,
const __m128i quant,
const __m128i *shift,
const int *log_scale) {
__m128i tmp, tmp1, qcoeff;
qcoeff = _mm_adds_epi16(*coeff, round);
tmp = _mm_mulhi_epi16(qcoeff, quant);
qcoeff = _mm_add_epi16(tmp, qcoeff);
tmp = _mm_mullo_epi16(qcoeff, *shift);
tmp = _mm_srli_epi16(tmp, (16 - *log_scale));
tmp1 = _mm_mulhi_epi16(qcoeff, *shift);
tmp1 = _mm_slli_epi16(tmp1, *log_scale);
*coeff = _mm_or_si128(tmp, tmp1);
}
static INLINE __m128i calculate_dqcoeff(__m128i qcoeff, __m128i dequant) {
return _mm_mullo_epi16(qcoeff, dequant);
}
static INLINE void calculate_dqcoeff_and_store_log_scale(__m128i qcoeff,
__m128i dequant,
const __m128i zero,
tran_low_t *dqcoeff,
const int *log_scale) {
// calculate abs
__m128i coeff_sign = _mm_srai_epi16(qcoeff, 15);
__m128i coeff = invert_sign_sse2(qcoeff, coeff_sign);
const __m128i sign_0 = _mm_unpacklo_epi16(coeff_sign, zero);
const __m128i sign_1 = _mm_unpackhi_epi16(coeff_sign, zero);
const __m128i low = _mm_mullo_epi16(coeff, dequant);
const __m128i high = _mm_mulhi_epi16(coeff, dequant);
__m128i dqcoeff32_0 = _mm_unpacklo_epi16(low, high);
__m128i dqcoeff32_1 = _mm_unpackhi_epi16(low, high);
dqcoeff32_0 = _mm_srli_epi32(dqcoeff32_0, *log_scale);
dqcoeff32_1 = _mm_srli_epi32(dqcoeff32_1, *log_scale);
dqcoeff32_0 = invert_sign_32_sse2(dqcoeff32_0, sign_0);
dqcoeff32_1 = invert_sign_32_sse2(dqcoeff32_1, sign_1);
_mm_store_si128((__m128i *)(dqcoeff), dqcoeff32_0);
_mm_store_si128((__m128i *)(dqcoeff + 4), dqcoeff32_1);
}
// Scan 16 values for eob reference in scan_ptr. Use masks (-1) from comparing
// to zbin to add 1 to the index in 'scan'.
static INLINE __m128i scan_for_eob(__m128i *coeff0, __m128i *coeff1,

View file

@ -1,222 +0,0 @@
;
; 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 "aom_ports/x86_abi_support.asm"
; tabulate_ssim - sums sum_s,sum_r,sum_sq_s,sum_sq_r, sum_sxr
%macro TABULATE_SSIM 0
paddusw xmm15, xmm3 ; sum_s
paddusw xmm14, xmm4 ; sum_r
movdqa xmm1, xmm3
pmaddwd xmm1, xmm1
paddd xmm13, xmm1 ; sum_sq_s
movdqa xmm2, xmm4
pmaddwd xmm2, xmm2
paddd xmm12, xmm2 ; sum_sq_r
pmaddwd xmm3, xmm4
paddd xmm11, xmm3 ; sum_sxr
%endmacro
; Sum across the register %1 starting with q words
%macro SUM_ACROSS_Q 1
movdqa xmm2,%1
punpckldq %1,xmm0
punpckhdq xmm2,xmm0
paddq %1,xmm2
movdqa xmm2,%1
punpcklqdq %1,xmm0
punpckhqdq xmm2,xmm0
paddq %1,xmm2
%endmacro
; Sum across the register %1 starting with q words
%macro SUM_ACROSS_W 1
movdqa xmm1, %1
punpcklwd %1,xmm0
punpckhwd xmm1,xmm0
paddd %1, xmm1
SUM_ACROSS_Q %1
%endmacro
SECTION .text
;void ssim_parms_sse2(
; unsigned char *s,
; int sp,
; unsigned char *r,
; int rp
; uint32_t *sum_s,
; uint32_t *sum_r,
; uint32_t *sum_sq_s,
; uint32_t *sum_sq_r,
; uint32_t *sum_sxr);
;
; TODO: Use parm passing through structure, probably don't need the pxors
; ( calling app will initialize to 0 ) could easily fit everything in sse2
; without too much hastle, and can probably do better estimates with psadw
; or pavgb At this point this is just meant to be first pass for calculating
; all the parms needed for 16x16 ssim so we can play with dssim as distortion
; in mode selection code.
global sym(aom_ssim_parms_16x16_sse2) PRIVATE
sym(aom_ssim_parms_16x16_sse2):
push rbp
mov rbp, rsp
SHADOW_ARGS_TO_STACK 9
SAVE_XMM 15
push rsi
push rdi
; end prolog
mov rsi, arg(0) ;s
mov rcx, arg(1) ;sp
mov rdi, arg(2) ;r
mov rax, arg(3) ;rp
pxor xmm0, xmm0
pxor xmm15,xmm15 ;sum_s
pxor xmm14,xmm14 ;sum_r
pxor xmm13,xmm13 ;sum_sq_s
pxor xmm12,xmm12 ;sum_sq_r
pxor xmm11,xmm11 ;sum_sxr
mov rdx, 16 ;row counter
.NextRow:
;grab source and reference pixels
movdqu xmm5, [rsi]
movdqu xmm6, [rdi]
movdqa xmm3, xmm5
movdqa xmm4, xmm6
punpckhbw xmm3, xmm0 ; high_s
punpckhbw xmm4, xmm0 ; high_r
TABULATE_SSIM
movdqa xmm3, xmm5
movdqa xmm4, xmm6
punpcklbw xmm3, xmm0 ; low_s
punpcklbw xmm4, xmm0 ; low_r
TABULATE_SSIM
add rsi, rcx ; next s row
add rdi, rax ; next r row
dec rdx ; counter
jnz .NextRow
SUM_ACROSS_W xmm15
SUM_ACROSS_W xmm14
SUM_ACROSS_Q xmm13
SUM_ACROSS_Q xmm12
SUM_ACROSS_Q xmm11
mov rdi,arg(4)
movd [rdi], xmm15;
mov rdi,arg(5)
movd [rdi], xmm14;
mov rdi,arg(6)
movd [rdi], xmm13;
mov rdi,arg(7)
movd [rdi], xmm12;
mov rdi,arg(8)
movd [rdi], xmm11;
; begin epilog
pop rdi
pop rsi
RESTORE_XMM
UNSHADOW_ARGS
pop rbp
ret
;void ssim_parms_sse2(
; unsigned char *s,
; int sp,
; unsigned char *r,
; int rp
; uint32_t *sum_s,
; uint32_t *sum_r,
; uint32_t *sum_sq_s,
; uint32_t *sum_sq_r,
; uint32_t *sum_sxr);
;
; TODO: Use parm passing through structure, probably don't need the pxors
; ( calling app will initialize to 0 ) could easily fit everything in sse2
; without too much hastle, and can probably do better estimates with psadw
; or pavgb At this point this is just meant to be first pass for calculating
; all the parms needed for 16x16 ssim so we can play with dssim as distortion
; in mode selection code.
global sym(aom_ssim_parms_8x8_sse2) PRIVATE
sym(aom_ssim_parms_8x8_sse2):
push rbp
mov rbp, rsp
SHADOW_ARGS_TO_STACK 9
SAVE_XMM 15
push rsi
push rdi
; end prolog
mov rsi, arg(0) ;s
mov rcx, arg(1) ;sp
mov rdi, arg(2) ;r
mov rax, arg(3) ;rp
pxor xmm0, xmm0
pxor xmm15,xmm15 ;sum_s
pxor xmm14,xmm14 ;sum_r
pxor xmm13,xmm13 ;sum_sq_s
pxor xmm12,xmm12 ;sum_sq_r
pxor xmm11,xmm11 ;sum_sxr
mov rdx, 8 ;row counter
.NextRow:
;grab source and reference pixels
movq xmm3, [rsi]
movq xmm4, [rdi]
punpcklbw xmm3, xmm0 ; low_s
punpcklbw xmm4, xmm0 ; low_r
TABULATE_SSIM
add rsi, rcx ; next s row
add rdi, rax ; next r row
dec rdx ; counter
jnz .NextRow
SUM_ACROSS_W xmm15
SUM_ACROSS_W xmm14
SUM_ACROSS_Q xmm13
SUM_ACROSS_Q xmm12
SUM_ACROSS_Q xmm11
mov rdi,arg(4)
movd [rdi], xmm15;
mov rdi,arg(5)
movd [rdi], xmm14;
mov rdi,arg(6)
movd [rdi], xmm13;
mov rdi,arg(7)
movd [rdi], xmm12;
mov rdi,arg(8)
movd [rdi], xmm11;
; begin epilog
pop rdi
pop rsi
RESTORE_XMM
UNSHADOW_ARGS
pop rbp
ret

View file

@ -168,6 +168,36 @@ static INLINE void transpose_16bit_16x16_avx2(const __m256i *const in,
out[7 + 8] = _mm256_permute2x128_si256(c[12 + 2], c[13 + 2], 0x31);
}
static INLINE void transpose_16bit_16x8_avx2(const __m256i *const in,
__m256i *const out) {
const __m256i a0 = _mm256_unpacklo_epi16(in[0], in[1]);
const __m256i a1 = _mm256_unpacklo_epi16(in[2], in[3]);
const __m256i a2 = _mm256_unpacklo_epi16(in[4], in[5]);
const __m256i a3 = _mm256_unpacklo_epi16(in[6], in[7]);
const __m256i a4 = _mm256_unpackhi_epi16(in[0], in[1]);
const __m256i a5 = _mm256_unpackhi_epi16(in[2], in[3]);
const __m256i a6 = _mm256_unpackhi_epi16(in[4], in[5]);
const __m256i a7 = _mm256_unpackhi_epi16(in[6], in[7]);
const __m256i b0 = _mm256_unpacklo_epi32(a0, a1);
const __m256i b1 = _mm256_unpacklo_epi32(a2, a3);
const __m256i b2 = _mm256_unpacklo_epi32(a4, a5);
const __m256i b3 = _mm256_unpacklo_epi32(a6, a7);
const __m256i b4 = _mm256_unpackhi_epi32(a0, a1);
const __m256i b5 = _mm256_unpackhi_epi32(a2, a3);
const __m256i b6 = _mm256_unpackhi_epi32(a4, a5);
const __m256i b7 = _mm256_unpackhi_epi32(a6, a7);
out[0] = _mm256_unpacklo_epi64(b0, b1);
out[1] = _mm256_unpackhi_epi64(b0, b1);
out[2] = _mm256_unpacklo_epi64(b4, b5);
out[3] = _mm256_unpackhi_epi64(b4, b5);
out[4] = _mm256_unpacklo_epi64(b2, b3);
out[5] = _mm256_unpackhi_epi64(b2, b3);
out[6] = _mm256_unpacklo_epi64(b6, b7);
out[7] = _mm256_unpackhi_epi64(b6, b7);
}
static INLINE void flip_buf_avx2(__m256i *in, __m256i *out, int size) {
for (int i = 0; i < size; ++i) {
out[size - i - 1] = in[i];
@ -236,6 +266,66 @@ static INLINE void av1_round_shift_rect_array_32_avx2(__m256i *input,
}
}
static INLINE __m256i scale_round_avx2(const __m256i a, const int scale) {
const __m256i scale_rounding =
pair_set_w16_epi16(scale, 1 << (NewSqrt2Bits - 1));
const __m256i b = _mm256_madd_epi16(a, scale_rounding);
return _mm256_srai_epi32(b, NewSqrt2Bits);
}
static INLINE void store_rect_16bit_to_32bit_w8_avx2(const __m256i a,
int32_t *const b) {
const __m256i one = _mm256_set1_epi16(1);
const __m256i a_lo = _mm256_unpacklo_epi16(a, one);
const __m256i a_hi = _mm256_unpackhi_epi16(a, one);
const __m256i b_lo = scale_round_avx2(a_lo, NewSqrt2);
const __m256i b_hi = scale_round_avx2(a_hi, NewSqrt2);
const __m256i temp = _mm256_permute2f128_si256(b_lo, b_hi, 0x31);
_mm_store_si128((__m128i *)b, _mm256_castsi256_si128(b_lo));
_mm_store_si128((__m128i *)(b + 4), _mm256_castsi256_si128(b_hi));
_mm256_store_si256((__m256i *)(b + 64), temp);
}
static INLINE void store_rect_buffer_16bit_to_32bit_w8_avx2(
const __m256i *const in, int32_t *const out, const int stride,
const int out_size) {
for (int i = 0; i < out_size; ++i) {
store_rect_16bit_to_32bit_w8_avx2(in[i], out + i * stride);
}
}
static INLINE void pack_reg(const __m128i *in1, const __m128i *in2,
__m256i *out) {
out[0] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[0]), in2[0], 0x1);
out[1] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[1]), in2[1], 0x1);
out[2] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[2]), in2[2], 0x1);
out[3] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[3]), in2[3], 0x1);
out[4] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[4]), in2[4], 0x1);
out[5] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[5]), in2[5], 0x1);
out[6] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[6]), in2[6], 0x1);
out[7] = _mm256_insertf128_si256(_mm256_castsi128_si256(in1[7]), in2[7], 0x1);
}
static INLINE void extract_reg(const __m256i *in, __m128i *out1) {
out1[0] = _mm256_castsi256_si128(in[0]);
out1[1] = _mm256_castsi256_si128(in[1]);
out1[2] = _mm256_castsi256_si128(in[2]);
out1[3] = _mm256_castsi256_si128(in[3]);
out1[4] = _mm256_castsi256_si128(in[4]);
out1[5] = _mm256_castsi256_si128(in[5]);
out1[6] = _mm256_castsi256_si128(in[6]);
out1[7] = _mm256_castsi256_si128(in[7]);
out1[8] = _mm256_extracti128_si256(in[0], 0x01);
out1[9] = _mm256_extracti128_si256(in[1], 0x01);
out1[10] = _mm256_extracti128_si256(in[2], 0x01);
out1[11] = _mm256_extracti128_si256(in[3], 0x01);
out1[12] = _mm256_extracti128_si256(in[4], 0x01);
out1[13] = _mm256_extracti128_si256(in[5], 0x01);
out1[14] = _mm256_extracti128_si256(in[6], 0x01);
out1[15] = _mm256_extracti128_si256(in[7], 0x01);
}
#ifdef __cplusplus
}
#endif

View file

@ -34,5 +34,9 @@ function(setup_aom_scale_targets)
"AOM_SCALE_INTRIN_DSPR2" "aom")
endif()
target_sources(aom PRIVATE $<TARGET_OBJECTS:aom_scale>)
# Pass the new lib targets up to the parent scope instance of
# $AOM_LIB_TARGETS.
set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} aom_scale PARENT_SCOPE)
endfunction()

View file

@ -26,6 +26,8 @@ if (aom_config("CONFIG_SPATIAL_RESAMPLING") eq "yes") {
add_proto qw/void aom_vertical_band_2_1_scale_i/, "unsigned char *source, int src_pitch, unsigned char *dest, int dest_pitch, unsigned int dest_width";
}
add_proto qw/int aom_yv12_realloc_with_new_border/, "struct yv12_buffer_config *ybf, int new_border, int byte_alignment, int num_planes";
add_proto qw/void aom_yv12_extend_frame_borders/, "struct yv12_buffer_config *ybf, const int num_planes";
add_proto qw/void aom_yv12_copy_frame/, "const struct yv12_buffer_config *src_bc, struct yv12_buffer_config *dst_bc, const int num_planes";

View file

@ -46,37 +46,16 @@ int aom_free_frame_buffer(YV12_BUFFER_CONFIG *ybf) {
return 0;
}
int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
int ss_x, int ss_y, int use_highbitdepth,
int border, int byte_alignment,
aom_codec_frame_buffer_t *fb,
aom_get_frame_buffer_cb_fn_t cb, void *cb_priv) {
#if CONFIG_SIZE_LIMIT
if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return -1;
#endif
/* Only support allocating buffers that have a border that's a multiple
* of 32. The border restriction is required to get 16-byte alignment of
* the start of the chroma rows without introducing an arbitrary gap
* between planes, which would break the semantics of things like
* aom_img_set_rect(). */
if (border & 0x1f) return -3;
static int realloc_frame_buffer_aligned(
YV12_BUFFER_CONFIG *ybf, int width, int height, int ss_x, int ss_y,
int use_highbitdepth, int border, int byte_alignment,
aom_codec_frame_buffer_t *fb, aom_get_frame_buffer_cb_fn_t cb,
void *cb_priv, const int y_stride, const uint64_t yplane_size,
const uint64_t uvplane_size, const int aligned_width,
const int aligned_height, const int uv_width, const int uv_height,
const int uv_stride, const int uv_border_w, const int uv_border_h) {
if (ybf) {
const int aom_byte_align = (byte_alignment == 0) ? 1 : byte_alignment;
const int aligned_width = (width + 7) & ~7;
const int aligned_height = (height + 7) & ~7;
const int y_stride = ((aligned_width + 2 * border) + 31) & ~31;
const uint64_t yplane_size =
(aligned_height + 2 * border) * (uint64_t)y_stride + byte_alignment;
const int uv_width = aligned_width >> ss_x;
const int uv_height = aligned_height >> ss_y;
const int uv_stride = y_stride >> ss_x;
const int uv_border_w = border >> ss_x;
const int uv_border_h = border >> ss_y;
const uint64_t uvplane_size =
(uv_height + 2 * uv_border_h) * (uint64_t)uv_stride + byte_alignment;
const uint64_t frame_size =
(1 + use_highbitdepth) * (yplane_size + 2 * uvplane_size);
@ -191,6 +170,111 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
return -2;
}
static int calc_stride_and_planesize(const int ss_x, const int ss_y,
const int aligned_width,
const int aligned_height, const int border,
const int byte_alignment, int *y_stride,
int *uv_stride, uint64_t *yplane_size,
uint64_t *uvplane_size,
const int uv_height) {
/* Only support allocating buffers that have a border that's a multiple
* of 32. The border restriction is required to get 16-byte alignment of
* the start of the chroma rows without introducing an arbitrary gap
* between planes, which would break the semantics of things like
* aom_img_set_rect(). */
if (border & 0x1f) return -3;
*y_stride = ((aligned_width + 2 * border) + 31) & ~31;
*yplane_size =
(aligned_height + 2 * border) * (uint64_t)(*y_stride) + byte_alignment;
*uv_stride = *y_stride >> ss_x;
*uvplane_size = (uv_height + 2 * (border >> ss_y)) * (uint64_t)(*uv_stride) +
byte_alignment;
return 0;
}
int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
int ss_x, int ss_y, int use_highbitdepth,
int border, int byte_alignment,
aom_codec_frame_buffer_t *fb,
aom_get_frame_buffer_cb_fn_t cb, void *cb_priv) {
#if CONFIG_SIZE_LIMIT
if (width > DECODE_WIDTH_LIMIT || height > DECODE_HEIGHT_LIMIT) return -1;
#endif
if (ybf) {
int y_stride = 0;
int uv_stride = 0;
uint64_t yplane_size = 0;
uint64_t uvplane_size = 0;
const int aligned_width = (width + 7) & ~7;
const int aligned_height = (height + 7) & ~7;
const int uv_width = aligned_width >> ss_x;
const int uv_height = aligned_height >> ss_y;
const int uv_border_w = border >> ss_x;
const int uv_border_h = border >> ss_y;
int error = calc_stride_and_planesize(
ss_x, ss_y, aligned_width, aligned_height, border, byte_alignment,
&y_stride, &uv_stride, &yplane_size, &uvplane_size, uv_height);
if (error) return error;
return realloc_frame_buffer_aligned(
ybf, width, height, ss_x, ss_y, use_highbitdepth, border,
byte_alignment, fb, cb, cb_priv, y_stride, yplane_size, uvplane_size,
aligned_width, aligned_height, uv_width, uv_height, uv_stride,
uv_border_w, uv_border_h);
}
return -2;
}
// TODO(anyone): This function allocates memory for
// lookahead buffer considering height and width is
// aligned to 128. Currently variance calculation of
// simple_motion_search_get_best_ref() function is done
// for full sb size (i.e integral multiple of max sb
// size = 128 or 64). Hence partial sbs need up to 127
// pixels beyond frame boundary. 128 aligned limitation of
// lookahead buffer can be removed if variance calculation
// is adjusted for partial sbs
// NOTE: Chroma width and height need not be aligned to
// 128 since variance calculation happens only for luma plane
int aom_realloc_lookahead_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
int ss_x, int ss_y, int use_highbitdepth,
int border, int byte_alignment,
aom_codec_frame_buffer_t *fb,
aom_get_frame_buffer_cb_fn_t cb,
void *cb_priv) {
if (ybf) {
int y_stride = 0;
int uv_stride = 0;
uint64_t yplane_size = 0;
uint64_t uvplane_size = 0;
const int aligned_128_width = (width + 127) & ~127;
const int aligned_128_height = (height + 127) & ~127;
const int aligned_width = (width + 7) & ~7;
const int aligned_height = (height + 7) & ~7;
const int uv_64_height = aligned_128_height >> ss_y;
const int uv_width = aligned_width >> ss_x;
const int uv_height = aligned_height >> ss_y;
const int uv_border_w = border >> ss_x;
const int uv_border_h = border >> ss_y;
int error = calc_stride_and_planesize(
ss_x, ss_y, aligned_128_width, aligned_128_height, border,
byte_alignment, &y_stride, &uv_stride, &yplane_size, &uvplane_size,
uv_64_height);
if (error) return error;
return realloc_frame_buffer_aligned(
ybf, width, height, ss_x, ss_y, use_highbitdepth, border,
byte_alignment, fb, cb, cb_priv, y_stride, yplane_size, uvplane_size,
aligned_width, aligned_height, uv_width, uv_height, uv_stride,
uv_border_w, uv_border_h);
}
return -2;
}
int aom_alloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
int ss_x, int ss_y, int use_highbitdepth, int border,
int byte_alignment) {

View file

@ -434,3 +434,28 @@ void aom_yv12_partial_coloc_copy_v_c(const YV12_BUFFER_CONFIG *src_bc,
aom_yv12_partial_copy_v_c(src_bc, hstart, hend, vstart, vend, dst_bc, hstart,
vstart);
}
int aom_yv12_realloc_with_new_border_c(YV12_BUFFER_CONFIG *ybf, int new_border,
int byte_alignment, int num_planes) {
if (ybf) {
if (new_border == ybf->border) return 0;
YV12_BUFFER_CONFIG new_buf;
memset(&new_buf, 0, sizeof(new_buf));
const int error = aom_alloc_frame_buffer(
&new_buf, ybf->y_crop_width, ybf->y_crop_height, ybf->subsampling_x,
ybf->subsampling_y, ybf->flags & YV12_FLAG_HIGHBITDEPTH, new_border,
byte_alignment);
if (error) return error;
// Copy image buffer
aom_yv12_copy_frame(ybf, &new_buf, num_planes);
// Extend up to new border
aom_extend_frame_borders(&new_buf, num_planes);
// Now free the old buffer and replace with the new
aom_free_frame_buffer(ybf);
memcpy(ybf, &new_buf, sizeof(new_buf));
return 0;
}
return -2;
}

View file

@ -26,6 +26,7 @@ extern "C" {
#define AOM_INTERP_EXTEND 4
#define AOM_BORDER_IN_PIXELS 288
#define AOM_ENC_NO_SCALE_BORDER 160
#define AOM_ENC_LOOKAHEAD_BORDER 64
#define AOM_DEC_BORDER_IN_PIXELS 64
typedef struct yv12_buffer_config {
@ -124,6 +125,14 @@ int aom_realloc_frame_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
int border, int byte_alignment,
aom_codec_frame_buffer_t *fb,
aom_get_frame_buffer_cb_fn_t cb, void *cb_priv);
int aom_realloc_lookahead_buffer(YV12_BUFFER_CONFIG *ybf, int width, int height,
int ss_x, int ss_y, int use_highbitdepth,
int border, int byte_alignment,
aom_codec_frame_buffer_t *fb,
aom_get_frame_buffer_cb_fn_t cb,
void *cb_priv);
int aom_free_frame_buffer(YV12_BUFFER_CONFIG *ybf);
#ifdef __cplusplus

View file

@ -851,7 +851,7 @@ static int main_loop(int argc, const char **argv_) {
}
// Default to codec bit depth if output bit depth not set
unsigned int output_bit_depth;
if (!fixed_output_bit_depth && single_file && !do_md5) {
if (!fixed_output_bit_depth && single_file) {
output_bit_depth = img->bit_depth;
} else {
output_bit_depth = fixed_output_bit_depth;

View file

@ -144,16 +144,14 @@ static const arg_def_t pass_arg =
ARG_DEF(NULL, "pass", 1, "Pass to execute (1/2)");
static const arg_def_t fpf_name =
ARG_DEF(NULL, "fpf", 1, "First pass statistics file name");
#if CONFIG_FP_MB_STATS
static const arg_def_t fpmbf_name =
ARG_DEF(NULL, "fpmbf", 1, "First pass block statistics file name");
#endif
static const arg_def_t limit =
ARG_DEF(NULL, "limit", 1, "Stop encoding after n input frames");
static const arg_def_t skip =
ARG_DEF(NULL, "skip", 1, "Skip the first n input frames");
static const arg_def_t good_dl =
ARG_DEF(NULL, "good", 0, "Use Good Quality Deadline");
static const arg_def_t rt_dl =
ARG_DEF(NULL, "rt", 0, "Use Realtime Quality Deadline");
static const arg_def_t quietarg =
ARG_DEF("q", "quiet", 0, "Do not print encode progress");
static const arg_def_t verbosearg =
@ -219,6 +217,7 @@ static const arg_def_t *main_args[] = { &help,
&limit,
&skip,
&good_dl,
&rt_dl,
&quietarg,
&verbosearg,
&psnrarg,
@ -441,6 +440,21 @@ static const arg_def_t enable_rect_partitions =
ARG_DEF(NULL, "enable-rect-partitions", 1,
"Enable rectangular partitions "
"(0: false, 1: true (default))");
static const arg_def_t enable_ab_partitions =
ARG_DEF(NULL, "enable-ab-partitions", 1,
"Enable ab partitions (0: false, 1: true (default))");
static const arg_def_t enable_1to4_partitions =
ARG_DEF(NULL, "enable-1to4-partitions", 1,
"Enable 1:4 and 4:1 partitions "
"(0: false, 1: true (default))");
static const arg_def_t min_partition_size =
ARG_DEF(NULL, "min-partition-size", 4,
"Set min partition size "
"(4:4x4, 8:8x8, 16:16x16, 32:32x32, 64:64x64, 128:128x128)");
static const arg_def_t max_partition_size =
ARG_DEF(NULL, "max-partition-size", 128,
"Set max partition size "
"(4:4x4, 8:8x8, 16:16x16, 32:32x32, 64:64x64, 128:128x128)");
static const arg_def_t enable_dual_filter =
ARG_DEF(NULL, "enable-dual-filter", 1,
"Enable dual filter "
@ -456,6 +470,16 @@ static const arg_def_t enable_order_hint =
static const arg_def_t enable_tx64 =
ARG_DEF(NULL, "enable-tx64", 1,
"Enable 64-pt transform (0: false, 1: true (default))");
static const arg_def_t tx_size_search_method =
ARG_DEF(NULL, "tx-size-search-method", 0,
"Set transform block size search method "
"(0: Full RD (default), 1: Fast RD, 2: use largest allowed)");
static const arg_def_t enable_flip_idtx =
ARG_DEF(NULL, "enable-flip-idtx", 1,
"Enable extended transform type (0: false, 1: true (default)) "
"including FLIPADST_DCT, DCT_FLIPADST, FLIPADST_FLIPADST, "
"ADST_FLIPADST, FLIPADST_ADST, IDTX, V_DCT, H_DCT, V_ADST, "
"H_ADST, V_FLIPADST, H_FLIPADST");
static const arg_def_t enable_dist_wtd_comp =
ARG_DEF(NULL, "enable-dist-wtd-comp", 1,
"Enable distance-weighted compound "
@ -464,6 +488,10 @@ static const arg_def_t enable_masked_comp =
ARG_DEF(NULL, "enable-masked-comp", 1,
"Enable masked (wedge/diff-wtd) compound "
"(0: false, 1: true (default))");
static const arg_def_t enable_onesided_comp =
ARG_DEF(NULL, "enable-onesided-comp", 1,
"Enable one sided compound "
"(0: false, 1: true (default))");
static const arg_def_t enable_interintra_comp =
ARG_DEF(NULL, "enable-interintra-comp", 1,
"Enable interintra compound "
@ -522,7 +550,7 @@ static const arg_def_t enable_angle_delta =
static const arg_def_t disable_trellis_quant =
ARG_DEF(NULL, "disable-trellis-quant", 1,
"Disable trellis optimization of quantized coefficients (0: false ("
"default) 1: true)");
"default) 1: true 2: partial true)");
static const arg_def_t enable_qm =
ARG_DEF(NULL, "enable-qm", 1,
"Enable quantisation matrices (0: false (default), 1: true)");
@ -536,8 +564,19 @@ static const arg_def_t use_intra_dct_only =
ARG_DEF(NULL, "use-intra-dct-only", 1, "Use DCT only for INTRA modes");
static const arg_def_t use_inter_dct_only =
ARG_DEF(NULL, "use-inter-dct-only", 1, "Use DCT only for INTER modes");
static const arg_def_t use_intra_default_tx_only =
ARG_DEF(NULL, "use-intra-default-tx-only", 1,
"Use Default-transform only for INTRA modes");
static const arg_def_t quant_b_adapt =
ARG_DEF(NULL, "quant-b-adapt", 1, "Use adaptive quantize_b");
static const arg_def_t coeff_cost_upd_freq =
ARG_DEF(NULL, "coeff-cost-upd-freq", 1,
"Update freq for coeff costs"
"0: SB, 1: SB Row per Tile, 2: Tile");
static const arg_def_t mode_cost_upd_freq =
ARG_DEF(NULL, "mode-cost-upd-freq", 1,
"Update freq for mode costs"
"0: SB, 1: SB Row per Tile, 2: Tile");
#if CONFIG_DIST_8X8
static const arg_def_t enable_dist_8x8 =
ARG_DEF(NULL, "enable-dist-8x8", 1,
@ -607,10 +646,23 @@ static const arg_def_t max_gf_interval = ARG_DEF(
"max gf/arf frame interval (default 0, indicating in-built behavior)");
static const arg_def_t gf_max_pyr_height =
ARG_DEF(NULL, "gf-max-pyr-height", 1,
"maximum height for GF group pyramid structure (1 to 4 (default))");
"maximum height for GF group pyramid structure (0 to 4 (default))");
static const arg_def_t max_reference_frames = ARG_DEF(
NULL, "max-reference-frames", 1,
"maximum number of reference frames allowed per frame (3 to 7 (default))");
static const arg_def_t reduced_reference_set =
ARG_DEF(NULL, "reduced-reference-set", 1,
"Use reduced set of single and compound references (0: off "
"(default), 1: on)");
static const arg_def_t target_seq_level_idx =
ARG_DEF(NULL, "target-seq-level-idx", 1,
"Target sequence level index. "
"Possible values are in the form of \"ABxy\"(pad leading zeros if "
"less than 4 digits). "
"AB: Operating point(OP) index; "
"xy: Target level index for the OP. "
"E.g. \"0\" means target level index 0 for the 0th OP; "
"\"1021\" means target level index 21 for the 10th OP.");
static const struct arg_enum_list color_primaries_enum[] = {
{ "bt709", AOM_CICP_CP_BT_709 },
@ -716,6 +768,12 @@ static const struct arg_enum_list superblock_size_enum[] = {
static const arg_def_t superblock_size = ARG_DEF_ENUM(
NULL, "sb-size", 1, "Superblock size to use", superblock_size_enum);
static const arg_def_t set_tier_mask =
ARG_DEF(NULL, "set-tier-mask", 1,
"Set bit mask to specify which tier each of the 32 possible "
"operating points conforms to. "
"Bit value 0(defualt): Main Tier; 1: High Tier.");
static const arg_def_t *av1_args[] = { &cpu_used_av1,
&auto_altref,
&sharpness,
@ -735,12 +793,19 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1,
&enable_cdef,
&enable_restoration,
&enable_rect_partitions,
&enable_ab_partitions,
&enable_1to4_partitions,
&min_partition_size,
&max_partition_size,
&enable_dual_filter,
&enable_intra_edge_filter,
&enable_order_hint,
&enable_tx64,
&tx_size_search_method,
&enable_flip_idtx,
&enable_dist_wtd_comp,
&enable_masked_comp,
&enable_onesided_comp,
&enable_interintra_comp,
&enable_smooth_interintra,
&enable_diff_wtd_comp,
@ -763,7 +828,10 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1,
&reduced_tx_type_set,
&use_intra_dct_only,
&use_inter_dct_only,
&use_intra_default_tx_only,
&quant_b_adapt,
&coeff_cost_upd_freq,
&mode_cost_upd_freq,
#if CONFIG_DIST_8X8
&enable_dist_8x8,
#endif
@ -793,7 +861,10 @@ static const arg_def_t *av1_args[] = { &cpu_used_av1,
&denoise_block_size,
#endif // CONFIG_DENOISE
&max_reference_frames,
&reduced_reference_set,
&enable_ref_frame_mvs,
&target_seq_level_idx,
&set_tier_mask,
&bitdeptharg,
&inbitdeptharg,
&input_chroma_subsampling_x,
@ -821,12 +892,19 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
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_INTRA_EDGE_FILTER,
AV1E_SET_ENABLE_ORDER_HINT,
AV1E_SET_ENABLE_TX64,
AV1E_SET_TX_SIZE_SEARCH_METHOD,
AV1E_SET_ENABLE_FLIP_IDTX,
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,
@ -849,7 +927,10 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
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,
#if CONFIG_DIST_8X8
AV1E_SET_ENABLE_DIST_8X8,
#endif
@ -879,7 +960,10 @@ static const int av1_arg_ctrl_map[] = { AOME_SET_CPUUSED,
AV1E_SET_DENOISE_BLOCK_SIZE,
#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,
0 };
#endif // CONFIG_AV1_ENCODER
@ -946,9 +1030,6 @@ struct stream_config {
struct aom_codec_enc_cfg cfg;
const char *out_fn;
const char *stats_fn;
#if CONFIG_FP_MB_STATS
const char *fpmb_stats_fn;
#endif
stereo_format_t stereo_fmt;
int arg_ctrls[ARG_CTRL_CNT_MAX][2];
int arg_ctrl_cnt;
@ -976,9 +1057,6 @@ struct stream_state {
uint64_t cx_time;
size_t nbytes;
stats_io_t stats;
#if CONFIG_FP_MB_STATS
stats_io_t fpmb_stats;
#endif
struct aom_image *img;
aom_codec_ctx_t decoder;
int mismatch_seen;
@ -1064,7 +1142,9 @@ static void parse_global_config(struct AvxEncoderConfig *global, int argc,
} else if (arg_match(&arg, &usage, argi))
global->usage = arg_parse_uint(&arg);
else if (arg_match(&arg, &good_dl, argi))
warn("Deprecated --good option! Ignoring\n");
global->usage = AOM_USAGE_GOOD_QUALITY; // Good quality usage
else if (arg_match(&arg, &rt_dl, argi))
global->usage = AOM_USAGE_REALTIME; // Real-time usage
else if (arg_match(&arg, &use_yv12, argi))
global->color_type = YV12;
else if (arg_match(&arg, &use_i420, argi))
@ -1117,11 +1197,19 @@ static void parse_global_config(struct AvxEncoderConfig *global, int argc,
// Make default AV1 passes = 2 until there is a better quality 1-pass
// encoder
if (global->codec != NULL && global->codec->name != NULL)
global->passes = (strcmp(global->codec->name, "av1") == 0) ? 2 : 1;
global->passes = (strcmp(global->codec->name, "av1") == 0 &&
global->usage != AOM_USAGE_REALTIME)
? 2
: 1;
#else
global->passes = 1;
#endif
}
if (global->usage == AOM_USAGE_REALTIME && global->passes > 1) {
warn("Enforcing one-pass encoding in realtime mode\n");
global->passes = 1;
}
}
static void open_input_file(struct AvxInputContext *input,
@ -1238,6 +1326,17 @@ static void set_config_arg_ctrls(struct stream_config *config, int key,
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 < (int)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.
*/
@ -1307,10 +1406,6 @@ static int parse_stream_params(struct AvxEncoderConfig *global,
}
} else if (arg_match(&arg, &fpf_name, argi)) {
config->stats_fn = arg.val;
#if CONFIG_FP_MB_STATS
} else if (arg_match(&arg, &fpmbf_name, argi)) {
config->fpmb_stats_fn = arg.val;
#endif
} else if (arg_match(&arg, &use_webm, argi)) {
#if CONFIG_WEBM_IO
config->write_webm = 1;
@ -1355,6 +1450,12 @@ static int parse_stream_params(struct AvxEncoderConfig *global,
config->cfg.g_error_resilient = arg_parse_uint(&arg);
} else if (arg_match(&arg, &lag_in_frames, argi)) {
config->cfg.g_lag_in_frames = arg_parse_uint(&arg);
if (global->usage == AOM_USAGE_REALTIME &&
config->cfg.rc_end_usage == AOM_CBR &&
config->cfg.g_lag_in_frames != 0) {
warn("non-zero %s option ignored in realtime CBR mode.\n", arg.name);
config->cfg.g_lag_in_frames = 0;
}
} else if (arg_match(&arg, &large_scale_tile, argi)) {
config->cfg.large_scale_tile = arg_parse_uint(&arg);
if (config->cfg.large_scale_tile) global->codec = get_aom_lst_encoder();
@ -1498,17 +1599,6 @@ static void validate_stream_config(const struct stream_state *stream,
fatal("Stream %d: duplicate stats file (from stream %d)",
streami->index, stream->index);
}
#if CONFIG_FP_MB_STATS
/* Check for two streams sharing a mb stats file. */
if (streami != stream) {
const char *a = stream->config.fpmb_stats_fn;
const char *b = streami->config.fpmb_stats_fn;
if (a && b && !strcmp(a, b))
fatal("Stream %d: duplicate mb stats file (from stream %d)",
streami->index, stream->index);
}
#endif
}
}
@ -1673,26 +1763,11 @@ static void setup_pass(struct stream_state *stream,
fatal("Failed to open statistics store");
}
#if CONFIG_FP_MB_STATS
if (stream->config.fpmb_stats_fn) {
if (!stats_open_file(&stream->fpmb_stats, stream->config.fpmb_stats_fn,
pass))
fatal("Failed to open mb statistics store");
} else {
if (!stats_open_mem(&stream->fpmb_stats, pass))
fatal("Failed to open mb statistics store");
}
#endif
stream->config.cfg.g_pass = global->passes == 2
? pass ? AOM_RC_LAST_PASS : AOM_RC_FIRST_PASS
: AOM_RC_ONE_PASS;
if (pass) {
stream->config.cfg.rc_twopass_stats_in = stats_get(&stream->stats);
#if CONFIG_FP_MB_STATS
stream->config.cfg.rc_firstpass_mb_stats_in =
stats_get(&stream->fpmb_stats);
#endif
}
stream->cx_time = 0;
@ -1921,13 +1996,6 @@ static void get_cx_data(struct stream_state *stream,
pkt->data.twopass_stats.sz);
stream->nbytes += pkt->data.raw.sz;
break;
#if CONFIG_FP_MB_STATS
case AOM_CODEC_FPMB_STATS_PKT:
stats_write(&stream->fpmb_stats, pkt->data.firstpass_mb_stats.buf,
pkt->data.firstpass_mb_stats.sz);
stream->nbytes += pkt->data.raw.sz;
break;
#endif
case AOM_CODEC_PSNR_PKT:
if (global->show_psnr) {
@ -2524,12 +2592,6 @@ int main(int argc, const char **argv_) {
stats_close(&stream->stats, global.passes - 1);
}
#if CONFIG_FP_MB_STATS
FOREACH_STREAM(stream, streams) {
stats_close(&stream->fpmb_stats, global.passes - 1);
}
#endif
if (global.pass) break;
}

View file

@ -151,6 +151,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES
"${AOM_ROOT}/av1/encoder/firstpass.h"
"${AOM_ROOT}/av1/encoder/global_motion.c"
"${AOM_ROOT}/av1/encoder/global_motion.h"
"${AOM_ROOT}/av1/encoder/gop_structure.c"
"${AOM_ROOT}/av1/encoder/gop_structure.h"
"${AOM_ROOT}/av1/encoder/grain_test_vectors.h"
"${AOM_ROOT}/av1/encoder/hash.c"
"${AOM_ROOT}/av1/encoder/hash.h"
@ -158,6 +160,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES
"${AOM_ROOT}/av1/encoder/hash_motion.h"
"${AOM_ROOT}/av1/encoder/hybrid_fwd_txfm.c"
"${AOM_ROOT}/av1/encoder/hybrid_fwd_txfm.h"
"${AOM_ROOT}/av1/encoder/level.c"
"${AOM_ROOT}/av1/encoder/level.h"
"${AOM_ROOT}/av1/encoder/lookahead.c"
"${AOM_ROOT}/av1/encoder/lookahead.h"
"${AOM_ROOT}/av1/encoder/mbgraph.c"
@ -168,6 +172,10 @@ list(APPEND AOM_AV1_ENCODER_SOURCES
"${AOM_ROOT}/av1/encoder/ml.h"
"${AOM_ROOT}/av1/encoder/palette.c"
"${AOM_ROOT}/av1/encoder/palette.h"
"${AOM_ROOT}/av1/encoder/partition_strategy.h"
"${AOM_ROOT}/av1/encoder/partition_strategy.c"
"${AOM_ROOT}/av1/encoder/pass2_strategy.h"
"${AOM_ROOT}/av1/encoder/pass2_strategy.c"
"${AOM_ROOT}/av1/encoder/pickcdef.c"
"${AOM_ROOT}/av1/encoder/picklpf.c"
"${AOM_ROOT}/av1/encoder/picklpf.h"
@ -194,6 +202,8 @@ list(APPEND AOM_AV1_ENCODER_SOURCES
"${AOM_ROOT}/av1/encoder/tpl_model.c"
"${AOM_ROOT}/av1/encoder/tpl_model.h"
"${AOM_ROOT}/av1/encoder/wedge_utils.c"
"${AOM_ROOT}/av1/encoder/var_based_part.c"
"${AOM_ROOT}/av1/encoder/var_based_part.h"
"${AOM_ROOT}/third_party/fastfeat/fast.c"
"${AOM_ROOT}/third_party/fastfeat/fast.h"
"${AOM_ROOT}/third_party/fastfeat/fast_9.c"
@ -257,8 +267,7 @@ list(APPEND AOM_AV1_COMMON_INTRIN_AVX2
"${AOM_ROOT}/av1/common/x86/wiener_convolve_avx2.c")
list(APPEND AOM_AV1_ENCODER_ASM_SSE2 "${AOM_ROOT}/av1/encoder/x86/dct_sse2.asm"
"${AOM_ROOT}/av1/encoder/x86/error_sse2.asm"
"${AOM_ROOT}/av1/encoder/x86/temporal_filter_apply_sse2.asm")
"${AOM_ROOT}/av1/encoder/x86/error_sse2.asm")
list(APPEND AOM_AV1_ENCODER_INTRIN_SSE2
"${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm_sse2.c"
@ -281,6 +290,9 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_SSE4_1
"${AOM_ROOT}/av1/encoder/x86/encodetxb_sse4.c"
"${AOM_ROOT}/av1/encoder/x86/highbd_fwd_txfm_sse4.c"
"${AOM_ROOT}/av1/encoder/x86/rdopt_sse4.c"
"${AOM_ROOT}/av1/encoder/x86/temporal_filter_constants.h"
"${AOM_ROOT}/av1/encoder/x86/temporal_filter_sse4.c"
"${AOM_ROOT}/av1/encoder/x86/highbd_temporal_filter_sse4.c"
"${AOM_ROOT}/av1/encoder/x86/pickrst_sse4.c")
list(APPEND AOM_AV1_ENCODER_INTRIN_AVX2
@ -288,6 +300,7 @@ list(APPEND AOM_AV1_ENCODER_INTRIN_AVX2
"${AOM_ROOT}/av1/encoder/x86/av1_highbd_quantize_avx2.c"
"${AOM_ROOT}/av1/encoder/x86/corner_match_avx2.c"
"${AOM_ROOT}/av1/encoder/x86/error_intrin_avx2.c"
"${AOM_ROOT}/av1/encoder/x86/highbd_block_error_intrin_avx2.c"
"${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm_avx2.h"
"${AOM_ROOT}/av1/encoder/x86/av1_fwd_txfm2d_avx2.c"
"${AOM_ROOT}/av1/encoder/x86/highbd_fwd_txfm_avx2.c"
@ -346,15 +359,7 @@ endif()
function(setup_av1_targets)
add_library(aom_av1_common OBJECT ${AOM_AV1_COMMON_SOURCES})
list(APPEND AOM_LIB_TARGETS aom_av1_common)
create_dummy_source_file("aom_av1" "c" "dummy_source_file")
add_library(aom_av1 OBJECT "${dummy_source_file}")
target_sources(aom PRIVATE $<TARGET_OBJECTS:aom_av1_common>)
list(APPEND AOM_LIB_TARGETS aom_av1)
# Not all generators support libraries consisting only of object files. Add a
# dummy source file to the aom_av1 target.
add_dummy_source_file_to_target("aom_av1" "c")
if(CONFIG_AV1_DECODER)
add_library(aom_av1_decoder OBJECT ${AOM_AV1_DECODER_SOURCES})
@ -452,13 +457,13 @@ function(setup_av1_targets)
if(HAVE_NEON)
if(AOM_AV1_COMMON_INTRIN_NEON)
add_intrinsics_object_library("${AOM_INTRIN_NEON_FLAG}" "neon"
add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon"
"aom_av1_common"
"AOM_AV1_COMMON_INTRIN_NEON" "aom")
endif()
if(AOM_AV1_ENCODER_INTRIN_NEON)
add_intrinsics_object_library("${AOM_INTRIN_NEON_FLAG}" "neon"
add_intrinsics_object_library("${AOM_NEON_INTRIN_FLAG}" "neon"
"aom_av1_encoder"
"AOM_AV1_ENCODER_INTRIN_NEON" "aom")
endif()
@ -476,13 +481,7 @@ function(setup_av1_targets)
"AOM_AV1_ENCODER_INTRIN_MSA" "aom")
endif()
target_sources(aom PRIVATE $<TARGET_OBJECTS:aom_dsp>)
target_sources(aom PRIVATE $<TARGET_OBJECTS:aom_scale>)
# Pass the new lib targets up to the parent scope instance of
# $AOM_LIB_TARGETS.
set(AOM_LIB_TARGETS ${AOM_LIB_TARGETS} PARENT_SCOPE)
endfunction()
function(setup_av1_test_targets)
endfunction()

View file

@ -92,26 +92,34 @@ struct av1_extracfg {
unsigned int motion_vector_unit_test;
unsigned int cdf_update_mode;
int enable_rect_partitions; // enable rectangular partitions for sequence
int enable_ab_partitions; // enable AB partitions for sequence
int enable_1to4_partitions; // enable 1:4 and 4:1 partitions for sequence
int min_partition_size; // min partition size [4,8,16,32,64,128]
int max_partition_size; // max partition size [4,8,16,32,64,128]
int enable_intra_edge_filter; // enable intra-edge filter for sequence
int enable_order_hint; // enable order hint for sequence
int enable_tx64; // enable 64-pt transform usage for sequence
int tx_size_search_method; // set transform block size search method
int enable_flip_idtx; // enable flip and identity transform types
int enable_dist_wtd_comp; // enable dist wtd compound for sequence
int max_reference_frames; // maximum number of references per frame
int enable_ref_frame_mvs; // sequence level
int allow_ref_frame_mvs; // frame level
int enable_masked_comp; // enable masked compound for sequence
int enable_interintra_comp; // enable interintra compound for sequence
int enable_smooth_interintra; // enable smooth interintra mode usage
int enable_diff_wtd_comp; // enable diff-wtd compound usage
int enable_interinter_wedge; // enable interinter-wedge compound usage
int enable_interintra_wedge; // enable interintra-wedge compound usage
int enable_global_motion; // enable global motion usage for sequence
int enable_warped_motion; // sequence level
int allow_warped_motion; // frame level
int enable_filter_intra; // enable filter intra for sequence
int enable_smooth_intra; // enable smooth intra modes for sequence
int enable_paeth_intra; // enable Peeth intra mode for sequence
int enable_cfl_intra; // enable CFL uv intra mode for sequence
int enable_reduced_reference_set; // enable reduced set of references
int enable_ref_frame_mvs; // sequence level
int allow_ref_frame_mvs; // frame level
int enable_masked_comp; // enable masked compound for sequence
int enable_onesided_comp; // enable one sided compound for sequence
int enable_interintra_comp; // enable interintra compound for sequence
int enable_smooth_interintra; // enable smooth interintra mode usage
int enable_diff_wtd_comp; // enable diff-wtd compound usage
int enable_interinter_wedge; // enable interinter-wedge compound usage
int enable_interintra_wedge; // enable interintra-wedge compound usage
int enable_global_motion; // enable global motion usage for sequence
int enable_warped_motion; // sequence level
int allow_warped_motion; // frame level
int enable_filter_intra; // enable filter intra for sequence
int enable_smooth_intra; // enable smooth intra modes for sequence
int enable_paeth_intra; // enable Paeth intra mode for sequence
int enable_cfl_intra; // enable CFL uv intra mode for sequence
int enable_superres;
int enable_palette;
int enable_intrabc;
@ -126,7 +134,14 @@ struct av1_extracfg {
int reduced_tx_type_set;
int use_intra_dct_only;
int use_inter_dct_only;
int use_intra_default_tx_only;
int quant_b_adapt;
AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS];
// Bit mask to specify which tier each of the 32 possible operating points
// conforms to.
unsigned int tier_mask;
COST_UPDATE_TYPE coeff_cost_upd_freq;
COST_UPDATE_TYPE mode_cost_upd_freq;
};
static struct av1_extracfg default_extra_cfg = {
@ -167,7 +182,7 @@ static struct av1_extracfg default_extra_cfg = {
1, // max number of tile groups
0, // mtu_size
AOM_TIMING_UNSPECIFIED, // No picture timing signaling in bitstream
1, // frame_parallel_decoding_mode
0, // frame_parallel_decoding_mode
1, // enable dual filter
NO_AQ, // aq_mode
NO_DELTA_Q, // deltaq_mode
@ -190,14 +205,22 @@ static struct av1_extracfg default_extra_cfg = {
0, // motion_vector_unit_test
1, // CDF update mode
1, // enable rectangular partitions
1, // enable ab shape partitions
1, // enable 1:4 and 4:1 partitions
4, // min_partition_size
128, // max_partition_size
1, // enable intra edge filter
1, // frame order hint
1, // enable 64-pt transform usage
0, // transform block size search method
1, // enable flip and identity transform
1, // dist-wtd compound
7, // max_reference_frames
0, // enable_reduced_reference_set
1, // enable_ref_frame_mvs sequence level
1, // allow ref_frame_mvs frame level
1, // enable masked compound at sequence level
1, // enable one sided compound at sequence level
1, // enable interintra compound at sequence level
1, // enable smooth interintra mode
1, // enable difference-weighted compound
@ -212,7 +235,7 @@ static struct av1_extracfg default_extra_cfg = {
1, // enable CFL uv intra mode usage for sequence
1, // superres
1, // enable palette
1, // enable intrabc
!CONFIG_SHARP_SETTINGS, // enable intrabc
1, // enable angle delta
#if CONFIG_DENOISE
0, // noise_level
@ -223,7 +246,15 @@ static struct av1_extracfg default_extra_cfg = {
0, // reduced_tx_type_set
0, // use_intra_dct_only
0, // use_inter_dct_only
0, // use_intra_default_tx_only
0, // quant_b_adapt
{
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
}, // target_seq_level_idx
0, // tier_mask
COST_UPD_SB, // coeff_cost_upd_freq
COST_UPD_SB, // mode_cost_upd_freq
};
struct aom_codec_alg_priv {
@ -295,6 +326,7 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
RANGE_CHECK_HI(extra_cfg, aq_mode, AQ_MODE_COUNT - 1);
RANGE_CHECK_HI(extra_cfg, deltaq_mode, DELTAQ_MODE_COUNT - 1);
RANGE_CHECK_HI(extra_cfg, frame_periodic_boost, 1);
RANGE_CHECK_HI(cfg, g_usage, 1);
RANGE_CHECK_HI(cfg, g_threads, MAX_NUM_THREADS);
RANGE_CHECK_HI(cfg, g_lag_in_frames, MAX_LAG_BUFFERS);
RANGE_CHECK(cfg, rc_end_usage, AOM_VBR, AOM_Q);
@ -310,7 +342,7 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
RANGE_CHECK(extra_cfg, max_gf_interval, MAX(2, extra_cfg->min_gf_interval),
(MAX_LAG_BUFFERS - 1));
}
RANGE_CHECK(extra_cfg, gf_max_pyr_height, 1, 4);
RANGE_CHECK_HI(extra_cfg, gf_max_pyr_height, 4);
RANGE_CHECK_HI(cfg, rc_resize_mode, RESIZE_MODES - 1);
RANGE_CHECK(cfg, rc_resize_denominator, SCALE_NUMERATOR,
@ -428,9 +460,25 @@ static aom_codec_err_t validate_config(aom_codec_alg_priv_t *ctx,
}
RANGE_CHECK(extra_cfg, max_reference_frames, 3, 7);
RANGE_CHECK(extra_cfg, enable_reduced_reference_set, 0, 1);
RANGE_CHECK_HI(extra_cfg, chroma_subsampling_x, 1);
RANGE_CHECK_HI(extra_cfg, chroma_subsampling_y, 1);
RANGE_CHECK_HI(extra_cfg, disable_trellis_quant, 3);
RANGE_CHECK(extra_cfg, coeff_cost_upd_freq, 0, 2);
RANGE_CHECK(extra_cfg, mode_cost_upd_freq, 0, 2);
RANGE_CHECK(extra_cfg, min_partition_size, 4, 128);
RANGE_CHECK(extra_cfg, max_partition_size, 4, 128);
RANGE_CHECK_HI(extra_cfg, min_partition_size, extra_cfg->max_partition_size);
RANGE_CHECK(extra_cfg, tx_size_search_method, 0, 2);
for (int i = 0; i < MAX_NUM_OPERATING_POINTS; ++i) {
if (!is_valid_seq_level_idx(extra_cfg->target_seq_level_idx[i]))
ERROR("Target sequence level index is invalid");
}
return AOM_CODEC_OK;
}
@ -498,6 +546,7 @@ static aom_codec_err_t set_encoder_config(
oxcf->profile = cfg->g_profile;
oxcf->fwd_kf_enabled = cfg->fwd_kf_enabled;
oxcf->max_threads = (int)cfg->g_threads;
oxcf->mode = (cfg->g_usage == 1) ? REALTIME : GOOD;
oxcf->width = cfg->g_w;
oxcf->height = cfg->g_h;
oxcf->forced_max_frame_width = cfg->g_forced_max_frame_width;
@ -540,7 +589,6 @@ static aom_codec_err_t set_encoder_config(
oxcf->init_framerate = 30;
oxcf->timing_info_present = 0;
}
oxcf->mode = GOOD;
oxcf->cfg = &cfg->cfg;
switch (cfg->g_pass) {
@ -582,7 +630,10 @@ static aom_codec_err_t set_encoder_config(
oxcf->reduced_tx_type_set = extra_cfg->reduced_tx_type_set;
oxcf->use_intra_dct_only = extra_cfg->use_intra_dct_only;
oxcf->use_inter_dct_only = extra_cfg->use_inter_dct_only;
oxcf->use_intra_default_tx_only = extra_cfg->use_intra_default_tx_only;
oxcf->quant_b_adapt = extra_cfg->quant_b_adapt;
oxcf->coeff_cost_upd_freq = (COST_UPDATE_TYPE)extra_cfg->coeff_cost_upd_freq;
oxcf->mode_cost_upd_freq = (COST_UPDATE_TYPE)extra_cfg->mode_cost_upd_freq;
#if CONFIG_DIST_8X8
oxcf->using_dist_8x8 = extra_cfg->enable_dist_8x8;
if (extra_cfg->tuning == AOM_TUNE_CDEF_DIST ||
@ -660,10 +711,6 @@ static aom_codec_err_t set_encoder_config(
oxcf->two_pass_stats_in = cfg->rc_twopass_stats_in;
#if CONFIG_FP_MB_STATS
oxcf->firstpass_mb_stats_in = cfg->rc_firstpass_mb_stats_in;
#endif
oxcf->color_primaries = extra_cfg->color_primaries;
oxcf->transfer_characteristics = extra_cfg->transfer_characteristics;
oxcf->matrix_coefficients = extra_cfg->matrix_coefficients;
@ -718,17 +765,21 @@ static aom_codec_err_t set_encoder_config(
oxcf->full_still_picture_hdr = cfg->full_still_picture_hdr;
oxcf->enable_dual_filter = extra_cfg->enable_dual_filter;
oxcf->enable_rect_partitions = extra_cfg->enable_rect_partitions;
oxcf->enable_ab_partitions = extra_cfg->enable_ab_partitions;
oxcf->enable_1to4_partitions = extra_cfg->enable_1to4_partitions;
oxcf->min_partition_size = extra_cfg->min_partition_size;
oxcf->max_partition_size = extra_cfg->max_partition_size;
oxcf->enable_intra_edge_filter = extra_cfg->enable_intra_edge_filter;
oxcf->enable_tx64 = extra_cfg->enable_tx64;
oxcf->tx_size_search_method = extra_cfg->tx_size_search_method;
oxcf->enable_flip_idtx = extra_cfg->enable_flip_idtx;
oxcf->enable_order_hint = extra_cfg->enable_order_hint;
oxcf->enable_dist_wtd_comp =
extra_cfg->enable_dist_wtd_comp & extra_cfg->enable_order_hint;
oxcf->max_reference_frames = extra_cfg->max_reference_frames;
if (oxcf->max_reference_frames > 3 && oxcf->max_reference_frames < 7) {
// TODO(urvang): Enable all possible values, after they work properly.
oxcf->max_reference_frames = 3;
}
oxcf->enable_reduced_reference_set = extra_cfg->enable_reduced_reference_set;
oxcf->enable_masked_comp = extra_cfg->enable_masked_comp;
oxcf->enable_onesided_comp = extra_cfg->enable_onesided_comp;
oxcf->enable_diff_wtd_comp =
extra_cfg->enable_masked_comp & extra_cfg->enable_diff_wtd_comp;
oxcf->enable_interinter_wedge =
@ -795,6 +846,9 @@ static aom_codec_err_t set_encoder_config(
oxcf->border_in_pixels = (oxcf->resize_mode || oxcf->superres_mode)
? AOM_BORDER_IN_PIXELS
: AOM_ENC_NO_SCALE_BORDER;
memcpy(oxcf->target_seq_level_idx, extra_cfg->target_seq_level_idx,
sizeof(oxcf->target_seq_level_idx));
oxcf->tier_mask = extra_cfg->tier_mask;
return AOM_CODEC_OK;
}
@ -1097,6 +1151,35 @@ static aom_codec_err_t ctrl_set_enable_rect_partitions(
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_ab_partitions(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.enable_ab_partitions = CAST(AV1E_SET_ENABLE_AB_PARTITIONS, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_1to4_partitions(
aom_codec_alg_priv_t *ctx, va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.enable_1to4_partitions =
CAST(AV1E_SET_ENABLE_1TO4_PARTITIONS, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_min_partition_size(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.min_partition_size = CAST(AV1E_SET_MIN_PARTITION_SIZE, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_max_partition_size(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.max_partition_size = CAST(AV1E_SET_MAX_PARTITION_SIZE, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_intra_edge_filter(
aom_codec_alg_priv_t *ctx, va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@ -1119,6 +1202,20 @@ static aom_codec_err_t ctrl_set_enable_tx64(aom_codec_alg_priv_t *ctx,
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_tx_size_search_method(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.tx_size_search_method = CAST(AV1E_SET_TX_SIZE_SEARCH_METHOD, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_flip_idtx(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.enable_flip_idtx = CAST(AV1E_SET_ENABLE_FLIP_IDTX, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_dist_wtd_comp(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@ -1133,6 +1230,14 @@ static aom_codec_err_t ctrl_set_max_reference_frames(aom_codec_alg_priv_t *ctx,
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_reduced_reference_set(
aom_codec_alg_priv_t *ctx, va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.enable_reduced_reference_set =
CAST(AV1E_SET_REDUCED_REFERENCE_SET, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_ref_frame_mvs(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@ -1154,6 +1259,13 @@ static aom_codec_err_t ctrl_set_enable_masked_comp(aom_codec_alg_priv_t *ctx,
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_onesided_comp(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.enable_onesided_comp = CAST(AV1E_SET_ENABLE_ONESIDED_COMP, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_enable_interintra_comp(
aom_codec_alg_priv_t *ctx, va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@ -1327,6 +1439,14 @@ static aom_codec_err_t ctrl_set_inter_dct_only(aom_codec_alg_priv_t *ctx,
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_intra_default_tx_only(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.use_intra_default_tx_only =
CAST(AV1E_SET_INTRA_DEFAULT_TX_ONLY, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_quant_b_adapt(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@ -1334,6 +1454,20 @@ static aom_codec_err_t ctrl_set_quant_b_adapt(aom_codec_alg_priv_t *ctx,
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_coeff_cost_upd_freq(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.coeff_cost_upd_freq = CAST(AV1E_SET_COEFF_COST_UPD_FREQ, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_mode_cost_upd_freq(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.mode_cost_upd_freq = CAST(AV1E_SET_MODE_COST_UPD_FREQ, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_film_grain_test_vector(
aom_codec_alg_priv_t *ctx, va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
@ -1409,6 +1543,26 @@ static aom_codec_err_t ctrl_enable_motion_vector_unit_test(
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_target_seq_level_idx(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
const int val = CAST(AV1E_SET_TARGET_SEQ_LEVEL_IDX, args);
const int level = val % 100;
const int operating_point_idx = val / 100;
if (operating_point_idx >= 0 &&
operating_point_idx < MAX_NUM_OPERATING_POINTS) {
extra_cfg.target_seq_level_idx[operating_point_idx] = (AV1_LEVEL)level;
}
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_set_tier_mask(aom_codec_alg_priv_t *ctx,
va_list args) {
struct av1_extracfg extra_cfg = ctx->extra_cfg;
extra_cfg.tier_mask = CAST(AV1E_SET_TIER_MASK, args);
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t encoder_init(aom_codec_ctx_t *ctx,
aom_codec_priv_enc_mr_cfg_t *data) {
aom_codec_err_t res = AOM_CODEC_OK;
@ -1511,8 +1665,7 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx,
}
}
}
if (ctx->oxcf.mode != GOOD) {
if (ctx->oxcf.mode != GOOD && ctx->oxcf.mode != REALTIME) {
ctx->oxcf.mode = GOOD;
av1_change_config(ctx->cpi, &ctx->oxcf);
}
@ -1570,6 +1723,8 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx,
unsigned char *cx_data = ctx->cx_data;
size_t cx_data_sz = ctx->cx_data_sz;
assert(!(cx_data == NULL && cx_data_sz != 0));
/* Any pending invisible frames? */
if (ctx->pending_cx_data) {
memmove(cx_data, ctx->pending_cx_data, ctx->pending_cx_data_sz);
@ -1616,8 +1771,8 @@ static aom_codec_err_t encoder_encode(aom_codec_alg_priv_t *ctx,
frame_size);
}
const uint32_t obu_header_offset = 0;
obu_header_size = write_obu_header(
OBU_TEMPORAL_DELIMITER, 0,
obu_header_size = av1_write_obu_header(
cpi, OBU_TEMPORAL_DELIMITER, 0,
(uint8_t *)(ctx->pending_cx_data + obu_header_offset));
// OBUs are preceded/succeeded by an unsigned leb128 coded integer.
@ -1978,6 +2133,13 @@ static aom_codec_err_t ctrl_set_chroma_subsampling_y(aom_codec_alg_priv_t *ctx,
return update_extra_cfg(ctx, &extra_cfg);
}
static aom_codec_err_t ctrl_get_seq_level_idx(aom_codec_alg_priv_t *ctx,
va_list args) {
int *const arg = va_arg(args, int *);
if (arg == NULL) return AOM_CODEC_INVALID_PARAM;
return av1_get_seq_level_idx(ctx->cpi, arg);
}
static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ AV1_COPY_REFERENCE, ctrl_copy_reference },
{ AOME_USE_REFERENCE, ctrl_use_reference },
@ -2027,15 +2189,23 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ AV1E_SET_ERROR_RESILIENT_MODE, ctrl_set_error_resilient_mode },
{ AV1E_SET_S_FRAME_MODE, ctrl_set_s_frame_mode },
{ AV1E_SET_ENABLE_RECT_PARTITIONS, ctrl_set_enable_rect_partitions },
{ AV1E_SET_ENABLE_AB_PARTITIONS, ctrl_set_enable_ab_partitions },
{ AV1E_SET_ENABLE_1TO4_PARTITIONS, ctrl_set_enable_1to4_partitions },
{ AV1E_SET_MIN_PARTITION_SIZE, ctrl_set_min_partition_size },
{ AV1E_SET_MAX_PARTITION_SIZE, ctrl_set_max_partition_size },
{ AV1E_SET_ENABLE_DUAL_FILTER, ctrl_set_enable_dual_filter },
{ AV1E_SET_ENABLE_INTRA_EDGE_FILTER, ctrl_set_enable_intra_edge_filter },
{ AV1E_SET_ENABLE_ORDER_HINT, ctrl_set_enable_order_hint },
{ AV1E_SET_ENABLE_TX64, ctrl_set_enable_tx64 },
{ AV1E_SET_TX_SIZE_SEARCH_METHOD, ctrl_set_tx_size_search_method },
{ AV1E_SET_ENABLE_FLIP_IDTX, ctrl_set_enable_flip_idtx },
{ AV1E_SET_ENABLE_DIST_WTD_COMP, ctrl_set_enable_dist_wtd_comp },
{ AV1E_SET_MAX_REFERENCE_FRAMES, ctrl_set_max_reference_frames },
{ AV1E_SET_REDUCED_REFERENCE_SET, ctrl_set_enable_reduced_reference_set },
{ AV1E_SET_ENABLE_REF_FRAME_MVS, ctrl_set_enable_ref_frame_mvs },
{ AV1E_SET_ALLOW_REF_FRAME_MVS, ctrl_set_allow_ref_frame_mvs },
{ AV1E_SET_ENABLE_MASKED_COMP, ctrl_set_enable_masked_comp },
{ AV1E_SET_ENABLE_ONESIDED_COMP, ctrl_set_enable_onesided_comp },
{ AV1E_SET_ENABLE_INTERINTRA_COMP, ctrl_set_enable_interintra_comp },
{ AV1E_SET_ENABLE_SMOOTH_INTERINTRA, ctrl_set_enable_smooth_interintra },
{ AV1E_SET_ENABLE_DIFF_WTD_COMP, ctrl_set_enable_diff_wtd_comp },
@ -2056,7 +2226,10 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ AV1E_SET_REDUCED_TX_TYPE_SET, ctrl_set_reduced_tx_type_set },
{ AV1E_SET_INTRA_DCT_ONLY, ctrl_set_intra_dct_only },
{ AV1E_SET_INTER_DCT_ONLY, ctrl_set_inter_dct_only },
{ AV1E_SET_INTRA_DEFAULT_TX_ONLY, ctrl_set_intra_default_tx_only },
{ AV1E_SET_QUANT_B_ADAPT, ctrl_set_quant_b_adapt },
{ AV1E_SET_COEFF_COST_UPD_FREQ, ctrl_set_coeff_cost_upd_freq },
{ AV1E_SET_MODE_COST_UPD_FREQ, ctrl_set_mode_cost_upd_freq },
{ AV1E_SET_DELTAQ_MODE, ctrl_set_deltaq_mode },
{ AV1E_SET_FRAME_PERIODIC_BOOST, ctrl_set_frame_periodic_boost },
{ AV1E_SET_TUNE_CONTENT, ctrl_set_tune_content },
@ -2080,6 +2253,8 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ AV1E_SET_DENOISE_BLOCK_SIZE, ctrl_set_denoise_block_size },
#endif // CONFIG_FILM_GRAIN
{ AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test },
{ AV1E_SET_TARGET_SEQ_LEVEL_IDX, ctrl_set_target_seq_level_idx },
{ AV1E_SET_TIER_MASK, ctrl_set_tier_mask },
// Getters
{ AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer },
@ -2090,6 +2265,7 @@ static aom_codec_ctrl_fn_map_t encoder_ctrl_maps[] = {
{ AV1_COPY_NEW_FRAME_IMAGE, ctrl_copy_new_frame_image },
{ AV1E_SET_CHROMA_SUBSAMPLING_X, ctrl_set_chroma_subsampling_x },
{ AV1E_SET_CHROMA_SUBSAMPLING_Y, ctrl_set_chroma_subsampling_y },
{ AV1E_GET_SEQ_LEVEL_IDX, ctrl_get_seq_level_idx },
{ -1, NULL },
};
@ -2097,7 +2273,7 @@ static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
{ 0,
{
// NOLINT
0, // g_usage
0, // g_usage - non-realtime usage
0, // g_threads
0, // g_profile
@ -2122,7 +2298,7 @@ static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
SCALE_NUMERATOR, // rc_resize_denominator
SCALE_NUMERATOR, // rc_resize_kf_denominator
0, // rc_superres_mode
SUPERRES_NONE, // rc_superres_mode
SCALE_NUMERATOR, // rc_superres_denominator
SCALE_NUMERATOR, // rc_superres_kf_denominator
63, // rc_superres_qthresh
@ -2145,6 +2321,74 @@ static aom_codec_enc_cfg_map_t encoder_usage_cfg_map[] = {
0, // rc_two_pass_vbrmin_section
2000, // rc_two_pass_vbrmax_section
// keyframing settings (kf)
0, // fwd_kf_enabled
AOM_KF_AUTO, // g_kfmode
0, // kf_min_dist
9999, // kf_max_dist
0, // sframe_dist
1, // sframe_mode
0, // large_scale_tile
0, // monochrome
0, // full_still_picture_hdr
0, // save_as_annexb
0, // tile_width_count
0, // tile_height_count
{ 0 }, // tile_widths
{ 0 }, // tile_heights
{ 1 }, // config file
} },
{ 1,
{
// NOLINT
1, // g_usage - real-time usage
0, // g_threads
0, // g_profile
320, // g_width
240, // g_height
0, // g_limit
0, // g_forced_max_frame_width
0, // g_forced_max_frame_height
AOM_BITS_8, // g_bit_depth
8, // g_input_bit_depth
{ 1, 30 }, // g_timebase
0, // g_error_resilient
AOM_RC_ONE_PASS, // g_pass
1, // g_lag_in_frames
0, // rc_dropframe_thresh
RESIZE_NONE, // rc_resize_mode
SCALE_NUMERATOR, // rc_resize_denominator
SCALE_NUMERATOR, // rc_resize_kf_denominator
0, // rc_superres_mode
SCALE_NUMERATOR, // rc_superres_denominator
SCALE_NUMERATOR, // rc_superres_kf_denominator
63, // rc_superres_qthresh
32, // rc_superres_kf_qthresh
AOM_CBR, // rc_end_usage
{ NULL, 0 }, // rc_twopass_stats_in
{ NULL, 0 }, // rc_firstpass_mb_stats_in
256, // rc_target_bandwidth
0, // rc_min_quantizer
63, // rc_max_quantizer
25, // rc_undershoot_pct
25, // rc_overshoot_pct
6000, // rc_max_buffer_size
4000, // rc_buffer_initial_size
5000, // rc_buffer_optimal_size
50, // rc_two_pass_vbrbias
0, // rc_two_pass_vbrmin_section
2000, // rc_two_pass_vbrmax_section
// keyframing settings (kf)
0, // fwd_kf_enabled
AOM_KF_AUTO, // g_kfmode
@ -2185,7 +2429,7 @@ CODEC_INTERFACE(aom_codec_av1_cx) = {
},
{
// NOLINT
1, // 1 cfg map
2, // 2 cfg map
encoder_usage_cfg_map, // aom_codec_enc_cfg_map_t
encoder_encode, // aom_codec_encode_fn_t
encoder_get_cxdata, // aom_codec_get_cx_data_fn_t

View file

@ -154,6 +154,49 @@ static aom_codec_err_t decoder_destroy(aom_codec_alg_priv_t *ctx) {
return AOM_CODEC_OK;
}
static aom_codec_err_t parse_timing_info(struct aom_read_bit_buffer *rb) {
const uint32_t num_units_in_display_tick =
aom_rb_read_unsigned_literal(rb, 32);
const uint32_t time_scale = aom_rb_read_unsigned_literal(rb, 32);
if (num_units_in_display_tick == 0 || time_scale == 0)
return AOM_CODEC_UNSUP_BITSTREAM;
const uint8_t equal_picture_interval = aom_rb_read_bit(rb);
if (equal_picture_interval) {
const uint32_t num_ticks_per_picture_minus_1 = aom_rb_read_uvlc(rb);
if (num_ticks_per_picture_minus_1 == UINT32_MAX) {
// num_ticks_per_picture_minus_1 cannot be (1 << 32) − 1.
return AOM_CODEC_UNSUP_BITSTREAM;
}
}
return AOM_CODEC_OK;
}
static aom_codec_err_t parse_decoder_model_info(
struct aom_read_bit_buffer *rb, int *buffer_delay_length_minus_1) {
*buffer_delay_length_minus_1 = aom_rb_read_literal(rb, 5);
const uint32_t num_units_in_decoding_tick =
aom_rb_read_unsigned_literal(rb, 32);
const uint8_t buffer_removal_time_length_minus_1 = aom_rb_read_literal(rb, 5);
const uint8_t frame_presentation_time_length_minus_1 =
aom_rb_read_literal(rb, 5);
(void)num_units_in_decoding_tick;
(void)buffer_removal_time_length_minus_1;
(void)frame_presentation_time_length_minus_1;
return AOM_CODEC_OK;
}
static aom_codec_err_t parse_op_parameters_info(
struct aom_read_bit_buffer *rb, int buffer_delay_length_minus_1) {
const int n = buffer_delay_length_minus_1 + 1;
const uint32_t decoder_buffer_delay = aom_rb_read_unsigned_literal(rb, n);
const uint32_t encoder_buffer_delay = aom_rb_read_unsigned_literal(rb, n);
const uint8_t low_delay_mode_flag = aom_rb_read_bit(rb);
(void)decoder_buffer_delay;
(void)encoder_buffer_delay;
(void)low_delay_mode_flag;
return AOM_CODEC_OK;
}
// Parses the operating points (including operating_point_idc, seq_level_idx,
// and seq_tier) and then sets si->number_spatial_layers and
// si->number_temporal_layers based on operating_point_idc[0].
@ -161,10 +204,23 @@ static aom_codec_err_t parse_operating_points(struct aom_read_bit_buffer *rb,
int is_reduced_header,
aom_codec_stream_info_t *si) {
int operating_point_idc0 = 0;
if (is_reduced_header) {
aom_rb_read_literal(rb, LEVEL_BITS); // level
} else {
uint8_t decoder_model_info_present_flag = 0;
int buffer_delay_length_minus_1 = 0;
aom_codec_err_t status;
const uint8_t timing_info_present_flag = aom_rb_read_bit(rb);
if (timing_info_present_flag) {
if ((status = parse_timing_info(rb)) != AOM_CODEC_OK) return status;
decoder_model_info_present_flag = aom_rb_read_bit(rb);
if (decoder_model_info_present_flag) {
if ((status = parse_decoder_model_info(
rb, &buffer_delay_length_minus_1)) != AOM_CODEC_OK)
return status;
}
}
const uint8_t initial_display_delay_present_flag = aom_rb_read_bit(rb);
const uint8_t operating_points_cnt_minus_1 =
aom_rb_read_literal(rb, OP_POINTS_CNT_MINUS_1_BITS);
for (int i = 0; i < operating_points_cnt_minus_1 + 1; i++) {
@ -173,6 +229,20 @@ static aom_codec_err_t parse_operating_points(struct aom_read_bit_buffer *rb,
if (i == 0) operating_point_idc0 = operating_point_idc;
int seq_level_idx = aom_rb_read_literal(rb, LEVEL_BITS); // level
if (seq_level_idx > 7) aom_rb_read_bit(rb); // tier
if (decoder_model_info_present_flag) {
const uint8_t decoder_model_present_for_this_op = aom_rb_read_bit(rb);
if (decoder_model_present_for_this_op) {
if ((status = parse_op_parameters_info(
rb, buffer_delay_length_minus_1)) != AOM_CODEC_OK)
return status;
}
}
if (initial_display_delay_present_flag) {
const uint8_t initial_display_delay_present_for_this_op =
aom_rb_read_bit(rb);
if (initial_display_delay_present_for_this_op)
aom_rb_read_literal(rb, 4); // initial_display_delay_minus_1
}
}
}

View file

@ -228,7 +228,7 @@ void av1_gen_inv_stage_range(int8_t *stage_range_col, int8_t *stage_range_row,
(void)real_range_row;
if (cfg->txfm_type_row == TXFM_TYPE_ADST4 && i == 1) {
// the adst4 may use 1 extra bit on top of opt_range_row at stage 1
// so opt_range_col >= real_range_col will not hold
// so opt_range_row >= real_range_row will not hold
stage_range_row[i] = opt_range_row;
} else {
assert(opt_range_row >= real_range_row);
@ -241,7 +241,7 @@ void av1_gen_inv_stage_range(int8_t *stage_range_col, int8_t *stage_range_row,
cfg->stage_range_col[i] + fwd_shift + shift[0] + bd + 1;
(void)real_range_col;
if (cfg->txfm_type_col == TXFM_TYPE_ADST4 && i == 1) {
// the adst4 may use 1 extra bit on top of opt_range_row at stage 1
// the adst4 may use 1 extra bit on top of opt_range_col at stage 1
// so opt_range_col >= real_range_col will not hold
stage_range_col[i] = opt_range_col;
} else {

View file

@ -111,10 +111,14 @@ specialize qw/av1_highbd_convolve8_vert/, "$sse2_x86_64";
#inv txfm
add_proto qw/void av1_inv_txfm_add/, "const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param";
specialize qw/av1_inv_txfm_add ssse3 avx2 neon/;
# TODO(http://crbug.com/aomedia/2350): avx2 is disabled due to test vector
# mismatches.
specialize qw/av1_inv_txfm_add ssse3 neon/;
add_proto qw/void av1_highbd_inv_txfm_add/, "const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param";
specialize qw/av1_highbd_inv_txfm_add sse4_1 avx2/;
# TODO(http://crbug.com/aomedia/2350): avx2 is disabled due to test vector
# mismatches.
specialize qw/av1_highbd_inv_txfm_add sse4_1/;
add_proto qw/void av1_highbd_inv_txfm_add_4x4/, "const tran_low_t *dqcoeff, uint8_t *dst, int stride, const TxfmParam *txfm_param";
specialize qw/av1_highbd_inv_txfm_add_4x4 sse4_1/;
@ -160,8 +164,9 @@ add_proto qw/void av1_inv_txfm2d_add_32x8/, "const int32_t *input, uint16_t *out
add_proto qw/void av1_highbd_dr_prediction_z1/, "uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, int upsample_above, int dx, int dy, int bd";
specialize qw/av1_highbd_dr_prediction_z1 avx2/;
add_proto qw/void av1_highbd_dr_prediction_z2/, "uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, int upsample_above, int upsample_left, int dx, int dy, int bd";
# TODO(https://crbug.com/aomedia/2288)
#specialize qw/av1_highbd_dr_prediction_z2 avx2/;
# TODO(niva213@gmail.com): Re-enable avx2 after fixing valgrind issue
# https://crbug.com/aomedia/2316
# specialize qw/av1_highbd_dr_prediction_z2 avx2/;
add_proto qw/void av1_highbd_dr_prediction_z3/, "uint16_t *dst, ptrdiff_t stride, int bw, int bh, const uint16_t *above, const uint16_t *left, int upsample_left, int dx, int dy, int bd";
specialize qw/av1_highbd_dr_prediction_z3 avx2/;
@ -255,18 +260,18 @@ if (aom_config("CONFIG_AV1_ENCODER") eq "yes") {
add_proto qw/int av1_full_range_search/, "const struct macroblock *x, const struct search_site_config *cfg, MV *ref_mv, MV *best_mv, int search_param, int sad_per_bit, int *num00, const struct aom_variance_vtable *fn_ptr, const MV *center_mv";
# TODO(yunqing): Add back the optimizations.
# add_proto qw/void av1_temporal_filter_apply/, "uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count";
# specialize qw/av1_temporal_filter_apply sse2 msa/;
add_proto qw/void av1_apply_temporal_filter/, "const uint8_t *y_frame1, int y_stride, const uint8_t *y_pred, int y_buf_stride, const uint8_t *u_frame1, const uint8_t *v_frame1, int uv_stride, const uint8_t *u_pred, const uint8_t *v_pred, int uv_buf_stride, unsigned int block_width, unsigned int block_height, int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, uint32_t *y_accumulator, uint16_t *y_count, uint32_t *u_accumulator, uint16_t *u_count, uint32_t *v_accumulator, uint16_t *v_count";
specialize qw/av1_apply_temporal_filter sse4_1/;
add_proto qw/void av1_quantize_b/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan, const qm_val_t * qm_ptr, const qm_val_t * iqm_ptr, int log_scale";
# ENCODEMB INVOKE
add_proto qw/int64_t av1_highbd_block_error/, "const tran_low_t *coeff, const tran_low_t *dqcoeff, intptr_t block_size, int64_t *ssz, int bd";
specialize qw/av1_highbd_block_error sse2/;
specialize qw/av1_highbd_block_error sse2 avx2/;
# add_proto qw/void av1_highbd_temporal_filter_apply/, "uint8_t *frame1, unsigned int stride, uint8_t *frame2, unsigned int block_width, unsigned int block_height, int strength, int filter_weight, unsigned int *accumulator, uint16_t *count";
add_proto qw/void av1_highbd_apply_temporal_filter/, "const uint8_t *yf, int y_stride, const uint8_t *yp, int y_buf_stride, const uint8_t *uf, const uint8_t *vf, int uv_stride, const uint8_t *up, const uint8_t *vp, int uv_buf_stride, unsigned int block_width, unsigned int block_height, int ss_x, int ss_y, int strength, const int *blk_fw, int use_32x32, uint32_t *y_accumulator, uint16_t *y_count, uint32_t *u_accumulator, uint16_t *u_count, uint32_t *v_accumulator, uint16_t *v_count";
specialize qw/av1_highbd_apply_temporal_filter sse4_1/;
add_proto qw/void av1_highbd_quantize_fp/, "const tran_low_t *coeff_ptr, intptr_t n_coeffs, const int16_t *zbin_ptr, const int16_t *round_ptr, const int16_t *quant_ptr, const int16_t *quant_shift_ptr, tran_low_t *qcoeff_ptr, tran_low_t *dqcoeff_ptr, const int16_t *dequant_ptr, uint16_t *eob_ptr, const int16_t *scan, const int16_t *iscan, int log_scale";
specialize qw/av1_highbd_quantize_fp sse4_1 avx2/;

View file

@ -59,7 +59,9 @@ static INLINE int32_t range_check_value(int32_t value, int8_t bit) {
const int64_t min_value = -(1LL << (bit - 1));
if (value < min_value || value > max_value) {
fprintf(stderr, "coeff out of bit range, value: %d bit %d\n", value, bit);
#if !CONFIG_AV1_ENCODER
assert(0);
#endif
}
#endif // CONFIG_COEFFICIENT_RANGE_CHECKING
#if DO_RANGE_CHECK_CLAMP

View file

@ -190,11 +190,6 @@ typedef struct RD_STATS {
int64_t ref_rdcost;
int zero_rate;
uint8_t invalid_rate;
#if CONFIG_ONE_PASS_SVM
int eob, eob_0, eob_1, eob_2, eob_3;
int64_t rd, rd_0, rd_1, rd_2, rd_3;
int64_t y_sse, sse_0, sse_1, sse_2, sse_3;
#endif
#if CONFIG_RD_DEBUG
int txb_coeff_cost[MAX_MB_PLANE];
int txb_coeff_cost_map[MAX_MB_PLANE][TXB_COEFF_COST_MAP_SIZE]

View file

@ -80,7 +80,6 @@ int sb_compute_cdef_list(const AV1_COMMON *const cm, int mi_row, int mi_col,
if (!is_8x8_block_skip(grid, mi_row + r, mi_col + c, cm->mi_stride)) {
dlist[count].by = r >> r_shift;
dlist[count].bx = c >> c_shift;
dlist[count].skip = 0;
count++;
}
}

View file

@ -232,8 +232,8 @@ void cdef_filter_fb(uint8_t *dst8, uint16_t *dst16, int dstride, uint16_t *in,
}
for (bi = 0; bi < cdef_count; bi++) {
int t = dlist[bi].skip ? 0 : pri_strength;
int s = dlist[bi].skip ? 0 : sec_strength;
int t = pri_strength;
int s = sec_strength;
by = dlist[bi].by;
bx = dlist[bi].bx;
if (dst8)

View file

@ -38,7 +38,6 @@ DECLARE_ALIGNED(16, extern const int, cdef_directions[8][2]);
typedef struct {
uint8_t by;
uint8_t bx;
uint8_t skip;
} cdef_list;
typedef void (*cdef_filter_block_func)(uint8_t *dst8, uint16_t *dst16,

View file

@ -101,7 +101,7 @@ void av1_reset_cdf_symbol_counters(FRAME_CONTEXT *fc) {
RESET_CDF_COUNTER(fc->refmv_cdf, 2);
RESET_CDF_COUNTER(fc->drl_cdf, 2);
RESET_CDF_COUNTER(fc->inter_compound_mode_cdf, INTER_COMPOUND_MODES);
RESET_CDF_COUNTER(fc->compound_type_cdf, COMPOUND_TYPES - 1);
RESET_CDF_COUNTER(fc->compound_type_cdf, MASKED_COMPOUND_TYPES);
RESET_CDF_COUNTER(fc->wedge_idx_cdf, 16);
RESET_CDF_COUNTER(fc->interintra_cdf, 2);
RESET_CDF_COUNTER(fc->wedge_interintra_cdf, 2);

View file

@ -488,17 +488,17 @@ static const aom_cdf_prob
{ AOM_CDF2(16384) }
};
static const aom_cdf_prob
default_compound_type_cdf[BLOCK_SIZES_ALL][CDF_SIZE(COMPOUND_TYPES - 1)] = {
{ AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(23431) }, { AOM_CDF2(13171) }, { AOM_CDF2(11470) },
{ AOM_CDF2(9770) }, { AOM_CDF2(9100) }, { AOM_CDF2(8233) },
{ AOM_CDF2(6172) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(11820) }, { AOM_CDF2(7701) }, { AOM_CDF2(16384) },
{ AOM_CDF2(16384) }
};
static const aom_cdf_prob default_compound_type_cdf[BLOCK_SIZES_ALL][CDF_SIZE(
MASKED_COMPOUND_TYPES)] = {
{ AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(23431) }, { AOM_CDF2(13171) }, { AOM_CDF2(11470) },
{ AOM_CDF2(9770) }, { AOM_CDF2(9100) }, { AOM_CDF2(8233) },
{ AOM_CDF2(6172) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(16384) }, { AOM_CDF2(16384) }, { AOM_CDF2(16384) },
{ AOM_CDF2(11820) }, { AOM_CDF2(7701) }, { AOM_CDF2(16384) },
{ AOM_CDF2(16384) }
};
static const aom_cdf_prob default_wedge_idx_cdf[BLOCK_SIZES_ALL][CDF_SIZE(16)] =
{ { AOM_CDF16(2048, 4096, 6144, 8192, 10240, 12288, 14336, 16384, 18432,

View file

@ -92,7 +92,8 @@ typedef struct frame_contexts {
aom_cdf_prob inter_compound_mode_cdf[INTER_MODE_CONTEXTS]
[CDF_SIZE(INTER_COMPOUND_MODES)];
aom_cdf_prob compound_type_cdf[BLOCK_SIZES_ALL][CDF_SIZE(COMPOUND_TYPES - 1)];
aom_cdf_prob compound_type_cdf[BLOCK_SIZES_ALL]
[CDF_SIZE(MASKED_COMPOUND_TYPES)];
aom_cdf_prob wedge_idx_cdf[BLOCK_SIZES_ALL][CDF_SIZE(16)];
aom_cdf_prob interintra_cdf[BLOCK_SIZE_GROUPS][CDF_SIZE(2)];
aom_cdf_prob wedge_interintra_cdf[BLOCK_SIZES_ALL][CDF_SIZE(2)];

View file

@ -92,15 +92,6 @@ enum {
MAX_PROFILES,
} SENUM1BYTE(BITSTREAM_PROFILE);
#define LEVEL_MAJOR_BITS 3
#define LEVEL_MINOR_BITS 2
#define LEVEL_BITS (LEVEL_MAJOR_BITS + LEVEL_MINOR_BITS)
#define LEVEL_MAJOR_MIN 2
#define LEVEL_MAJOR_MAX ((1 << LEVEL_MAJOR_BITS) - 1 + LEVEL_MAJOR_MIN)
#define LEVEL_MINOR_MIN 0
#define LEVEL_MINOR_MAX ((1 << LEVEL_MINOR_BITS) - 1)
#define OP_POINTS_CNT_MINUS_1_BITS 5
#define OP_POINTS_IDC_BITS 12
@ -455,9 +446,11 @@ enum {
enum {
COMPOUND_AVERAGE,
COMPOUND_DISTWTD,
COMPOUND_WEDGE,
COMPOUND_DIFFWTD,
COMPOUND_TYPES,
MASKED_COMPOUND_TYPES = 2,
} UENUM1BYTE(COMPOUND_TYPE);
enum {
@ -469,6 +462,37 @@ enum {
FILTER_INTRA_MODES,
} UENUM1BYTE(FILTER_INTRA_MODE);
enum {
SEQ_LEVEL_2_0,
SEQ_LEVEL_2_1,
SEQ_LEVEL_2_2,
SEQ_LEVEL_2_3,
SEQ_LEVEL_3_0,
SEQ_LEVEL_3_1,
SEQ_LEVEL_3_2,
SEQ_LEVEL_3_3,
SEQ_LEVEL_4_0,
SEQ_LEVEL_4_1,
SEQ_LEVEL_4_2,
SEQ_LEVEL_4_3,
SEQ_LEVEL_5_0,
SEQ_LEVEL_5_1,
SEQ_LEVEL_5_2,
SEQ_LEVEL_5_3,
SEQ_LEVEL_6_0,
SEQ_LEVEL_6_1,
SEQ_LEVEL_6_2,
SEQ_LEVEL_6_3,
SEQ_LEVEL_7_0,
SEQ_LEVEL_7_1,
SEQ_LEVEL_7_2,
SEQ_LEVEL_7_3,
SEQ_LEVELS,
SEQ_LEVEL_MAX = 31
} UENUM1BYTE(AV1_LEVEL);
#define LEVEL_BITS 5
#define DIRECTIONAL_MODES 8
#define MAX_ANGLE_DELTA 3
#define ANGLE_STEP 3

View file

@ -821,7 +821,7 @@ void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd,
MV_REFERENCE_FRAME rf[2];
av1_set_ref_frame(rf, ref_frame);
if (ref_frame < REF_FRAMES) {
if (global_mvs != NULL && ref_frame < REF_FRAMES) {
if (ref_frame != INTRA_FRAME) {
global_mvs[ref_frame] = gm_get_motion_vector(
&cm->global_motion[ref_frame], cm->allow_high_precision_mv, bsize,
@ -1362,15 +1362,15 @@ static int compare_ref_frame_info(const void *arg_a, const void *arg_b) {
return info_a->map_idx - info_b->map_idx;
}
static void set_ref_frame_info(AV1_COMMON *const cm, int frame_idx,
static void set_ref_frame_info(int *remapped_ref_idx, int frame_idx,
REF_FRAME_INFO *ref_info) {
assert(frame_idx >= 0 && frame_idx < INTER_REFS_PER_FRAME);
cm->remapped_ref_idx[frame_idx] = ref_info->map_idx;
remapped_ref_idx[frame_idx] = ref_info->map_idx;
}
void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
int gld_map_idx) {
void av1_set_frame_refs(AV1_COMMON *const cm, int *remapped_ref_idx,
int lst_map_idx, int gld_map_idx) {
int lst_frame_sort_idx = -1;
int gld_frame_sort_idx = -1;
@ -1395,8 +1395,6 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
if (buf == NULL) continue;
// If this assertion fails, there is a reference leak.
assert(buf->ref_count > 0);
// TODO(wtc@google.com): Remove the checking on ref_count after 2019-03-01.
if (buf->ref_count <= 0) continue;
const int offset = (int)buf->order_hint;
ref_frame_info[i].sort_idx =
@ -1449,7 +1447,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
// == ALTREF_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
set_ref_frame_info(cm, ALTREF_FRAME - LAST_FRAME,
set_ref_frame_info(remapped_ref_idx, ALTREF_FRAME - LAST_FRAME,
&ref_frame_info[bwd_end_idx]);
ref_flag_list[ALTREF_FRAME - LAST_FRAME] = 1;
bwd_end_idx--;
@ -1457,7 +1455,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
// == BWDREF_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
set_ref_frame_info(cm, BWDREF_FRAME - LAST_FRAME,
set_ref_frame_info(remapped_ref_idx, BWDREF_FRAME - LAST_FRAME,
&ref_frame_info[bwd_start_idx]);
ref_flag_list[BWDREF_FRAME - LAST_FRAME] = 1;
bwd_start_idx++;
@ -1465,7 +1463,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
// == ALTREF2_FRAME ==
if (bwd_start_idx <= bwd_end_idx) {
set_ref_frame_info(cm, ALTREF2_FRAME - LAST_FRAME,
set_ref_frame_info(remapped_ref_idx, ALTREF2_FRAME - LAST_FRAME,
&ref_frame_info[bwd_start_idx]);
ref_flag_list[ALTREF2_FRAME - LAST_FRAME] = 1;
}
@ -1475,13 +1473,15 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
for (int i = fwd_start_idx; i <= fwd_end_idx; ++i) {
// == LAST_FRAME ==
if (ref_frame_info[i].map_idx == lst_map_idx) {
set_ref_frame_info(cm, LAST_FRAME - LAST_FRAME, &ref_frame_info[i]);
set_ref_frame_info(remapped_ref_idx, LAST_FRAME - LAST_FRAME,
&ref_frame_info[i]);
ref_flag_list[LAST_FRAME - LAST_FRAME] = 1;
}
// == GOLDEN_FRAME ==
if (ref_frame_info[i].map_idx == gld_map_idx) {
set_ref_frame_info(cm, GOLDEN_FRAME - LAST_FRAME, &ref_frame_info[i]);
set_ref_frame_info(remapped_ref_idx, GOLDEN_FRAME - LAST_FRAME,
&ref_frame_info[i]);
ref_flag_list[GOLDEN_FRAME - LAST_FRAME] = 1;
}
}
@ -1513,7 +1513,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
}
if (fwd_start_idx > fwd_end_idx) break;
set_ref_frame_info(cm, ref_frame - LAST_FRAME,
set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME,
&ref_frame_info[fwd_end_idx]);
ref_flag_list[ref_frame - LAST_FRAME] = 1;
@ -1524,7 +1524,7 @@ void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx,
for (; ref_idx < (INTER_REFS_PER_FRAME - 2); ref_idx++) {
const MV_REFERENCE_FRAME ref_frame = ref_frame_list[ref_idx];
if (ref_flag_list[ref_frame - LAST_FRAME] == 1) continue;
set_ref_frame_info(cm, ref_frame - LAST_FRAME,
set_ref_frame_info(remapped_ref_idx, ref_frame - LAST_FRAME,
&ref_frame_info[fwd_start_idx]);
ref_flag_list[ref_frame - LAST_FRAME] = 1;
}

View file

@ -210,7 +210,8 @@ void av1_setup_frame_buf_refs(AV1_COMMON *cm);
void av1_setup_frame_sign_bias(AV1_COMMON *cm);
void av1_setup_skip_mode_allowed(AV1_COMMON *cm);
void av1_setup_motion_field(AV1_COMMON *cm);
void av1_set_frame_refs(AV1_COMMON *const cm, int lst_map_idx, int gld_map_idx);
void av1_set_frame_refs(AV1_COMMON *const cm, int *remapped_ref_idx,
int lst_map_idx, int gld_map_idx);
static INLINE void av1_collect_neighbors_ref_counts(MACROBLOCKD *const xd) {
av1_zero(xd->neighbors_ref_counts);
@ -243,6 +244,9 @@ void av1_copy_frame_mvs(const AV1_COMMON *const cm,
const MB_MODE_INFO *const mi, int mi_row, int mi_col,
int x_mis, int y_mis);
// The global_mvs output parameter points to an array of REF_FRAMES elements.
// The caller may pass a null global_mvs if it does not need the global_mvs
// output.
void av1_find_mv_refs(const AV1_COMMON *cm, const MACROBLOCKD *xd,
MB_MODE_INFO *mi, MV_REFERENCE_FRAME ref_frame,
uint8_t ref_mv_count[MODE_CTX_REF_FRAMES],

View file

@ -109,18 +109,6 @@ typedef struct {
MV_REFERENCE_FRAME ref_frame;
} MV_REF;
// FIXME(jack.haughton@argondesign.com): This enum was originally in
// encoder/ratectrl.h, and is encoder specific. When we move to C++, this
// should go back there and BufferPool should be templatized.
enum {
INTER_NORMAL = 0,
INTER_LOW = 1,
INTER_HIGH = 2,
GF_ARF_LOW = 3,
GF_ARF_STD = 4,
KF_STD = 5,
RATE_FACTOR_LEVELS = 6
} UENUM1BYTE(RATE_FACTOR_LEVEL);
typedef struct RefCntBuffer {
// For a RefCntBuffer, the following are reference-holding variables:
@ -136,8 +124,6 @@ typedef struct RefCntBuffer {
// - Total 'n' of the variables / array elements above have value 'k' (that
// is, they are pointing to buffer at index 'k').
// Then, pool->frame_bufs[k].ref_count = n.
// TODO(david.turner@argondesign.com) Check whether this helpful comment is
// still correct after we finish restructuring
int ref_count;
unsigned int order_hint;
@ -161,6 +147,10 @@ typedef struct RefCntBuffer {
hash_table hash_table;
FRAME_TYPE frame_type;
// This is only used in the encoder but needs to be indexed per ref frame
// so it's extremely convenient to keep it here.
int interp_filter_selected[SWITCHABLE];
// Inter frame reference frame delta for loop filter
int8_t ref_deltas[REF_FRAMES];
@ -168,7 +158,6 @@ typedef struct RefCntBuffer {
int8_t mode_deltas[MAX_MODE_LF_DELTAS];
FRAME_CONTEXT frame_context;
RATE_FACTOR_LEVEL frame_rf_level;
} RefCntBuffer;
typedef struct BufferPool {
@ -193,11 +182,6 @@ typedef struct BufferPool {
InternalFrameBufferList int_frame_buffers;
} BufferPool;
typedef struct BitstreamLevel {
uint8_t major;
uint8_t minor;
} BitstreamLevel;
typedef struct {
int cdef_pri_damping;
int cdef_sec_damping;
@ -279,7 +263,7 @@ typedef struct SequenceHeader {
int operating_point_idc[MAX_NUM_OPERATING_POINTS];
uint8_t display_model_info_present_flag;
uint8_t decoder_model_info_present_flag;
BitstreamLevel level[MAX_NUM_OPERATING_POINTS];
AV1_LEVEL seq_level_idx[MAX_NUM_OPERATING_POINTS];
uint8_t tier[MAX_NUM_OPERATING_POINTS]; // seq_tier in the spec. One bit: 0
// or 1.
@ -314,6 +298,7 @@ typedef struct {
unsigned int frame_number;
SkipModeInfo skip_mode_info;
int refresh_frame_flags; // Which ref frames are overwritten by this frame
int frame_refs_short_signaling;
} CurrentFrame;
typedef struct AV1Common {
@ -343,9 +328,9 @@ typedef struct AV1Common {
// For encoder, we have a two-level mapping from reference frame type to the
// corresponding buffer in the buffer pool:
// * 'remapped_ref_idx[i - 1]' maps reference type ‘i’ (range: LAST_FRAME ...
// EXTREF_FRAME) to a remapped index ‘j’ (in range: 0 ... REF_FRAMES - 1)
// * Later, 'cm->ref_frame_map[j]' maps the remapped index ‘j’ to a pointer to
// * 'remapped_ref_idx[i - 1]' maps reference type 'i' (range: LAST_FRAME ...
// EXTREF_FRAME) to a remapped index 'j' (in range: 0 ... REF_FRAMES - 1)
// * Later, 'cm->ref_frame_map[j]' maps the remapped index 'j' to a pointer to
// the reference counted buffer structure RefCntBuffer, taken from the buffer
// pool cm->buffer_pool->frame_bufs.
//
@ -364,10 +349,10 @@ typedef struct AV1Common {
struct scale_factors ref_scale_factors[REF_FRAMES];
// For decoder, ref_frame_map[i] maps reference type 'i' to a pointer to
// the buffer in the buffer pool ‘cm->buffer_pool.frame_bufs’.
// the buffer in the buffer pool 'cm->buffer_pool.frame_bufs'.
// For encoder, ref_frame_map[j] (where j = remapped_ref_idx[i]) maps
// remapped reference index 'j' (that is, original reference type 'i') to
// a pointer to the buffer in the buffer pool ‘cm->buffer_pool.frame_bufs’.
// a pointer to the buffer in the buffer pool 'cm->buffer_pool.frame_bufs'.
RefCntBuffer *ref_frame_map[REF_FRAMES];
// Prepare ref_frame_map for the next frame.
@ -517,6 +502,7 @@ typedef struct AV1Common {
int tile_col_start_sb[MAX_TILE_COLS + 1]; // valid for 0 <= i <= tile_cols
int tile_row_start_sb[MAX_TILE_ROWS + 1]; // valid for 0 <= i <= tile_rows
int tile_width, tile_height; // In MI units
int min_inner_tile_width; // min width of non-rightmost tile
unsigned int large_scale_tile;
unsigned int single_tile_decoding;
@ -642,6 +628,7 @@ static INLINE RefCntBuffer *assign_cur_frame_new_fb(AV1_COMMON *const cm) {
cm->cur_frame = &cm->buffer_pool->frame_bufs[new_fb_idx];
cm->cur_frame->buf.buf_8bit_valid = 0;
av1_zero(cm->cur_frame->interp_filter_selected);
return cm->cur_frame;
}
@ -1385,17 +1372,8 @@ static INLINE int is_coded_lossless(const AV1_COMMON *cm,
return coded_lossless;
}
static INLINE int is_valid_seq_level_idx(uint8_t seq_level_idx) {
return seq_level_idx < 24 || seq_level_idx == 31;
}
static INLINE uint8_t major_minor_to_seq_level_idx(BitstreamLevel bl) {
assert(bl.major >= LEVEL_MAJOR_MIN && bl.major <= LEVEL_MAJOR_MAX);
// Since bl.minor is unsigned a comparison will return a warning:
// comparison is always true due to limited range of data type
assert(LEVEL_MINOR_MIN == 0);
assert(bl.minor <= LEVEL_MINOR_MAX);
return ((bl.major - LEVEL_MAJOR_MIN) << LEVEL_MINOR_BITS) + bl.minor;
static INLINE int is_valid_seq_level_idx(AV1_LEVEL seq_level_idx) {
return seq_level_idx < SEQ_LEVELS || seq_level_idx == SEQ_LEVEL_MAX;
}
#ifdef __cplusplus

View file

@ -59,9 +59,13 @@ static INLINE int av1_get_spatial_seg_pred(const AV1_COMMON *const cm,
prev_l = get_segment_id(cm, cm->cur_frame->seg_map, BLOCK_4X4, mi_row - 0,
mi_col - 1);
}
// This property follows from the fact that get_segment_id() returns a
// nonnegative value. This allows us to test for all edge cases with a simple
// prev_ul < 0 check.
assert(IMPLIES(prev_ul >= 0, prev_u >= 0 && prev_l >= 0));
// Pick CDF index based on number of matching/out-of-bounds segment IDs.
if (prev_ul < 0 || prev_u < 0 || prev_l < 0) /* Edge case */
if (prev_ul < 0) /* Edge cases */
*cdf_index = 0;
else if ((prev_ul == prev_u) && (prev_ul == prev_l))
*cdf_index = 2;

View file

@ -167,6 +167,7 @@ static INLINE int is_interinter_compound_used(COMPOUND_TYPE type,
const int comp_allowed = is_comp_ref_allowed(sb_type);
switch (type) {
case COMPOUND_AVERAGE:
case COMPOUND_DISTWTD:
case COMPOUND_DIFFWTD: return comp_allowed;
case COMPOUND_WEDGE:
return comp_allowed && wedge_params_lookup[sb_type].bits > 0;
@ -245,13 +246,14 @@ static INLINE MV clamp_mv_to_umv_border_sb(const MACROBLOCKD *xd,
return clamped_mv;
}
static INLINE int scaled_buffer_offset(int x_offset, int y_offset, int stride,
const struct scale_factors *sf) {
static INLINE int64_t scaled_buffer_offset(int x_offset, int y_offset,
int stride,
const struct scale_factors *sf) {
const int x =
sf ? sf->scale_value_x(x_offset, sf) >> SCALE_EXTRA_BITS : x_offset;
const int y =
sf ? sf->scale_value_y(y_offset, sf) >> SCALE_EXTRA_BITS : y_offset;
return y * stride + x;
return (int64_t)y * stride + x;
}
static INLINE void setup_pred_plane(struct buf_2d *dst, BLOCK_SIZE bsize,

View file

@ -22,7 +22,7 @@
extern "C" {
#endif
// Boarder for Loop restoration buffer
// Border for Loop restoration buffer
#define AOM_RESTORATION_FRAME_BORDER 32
#define CLIP(x, lo, hi) ((x) < (lo) ? (lo) : (x) > (hi) ? (hi) : (x))
#define RINT(x) ((x) < 0 ? (int)((x)-0.5) : (int)((x) + 0.5))

View file

@ -51,6 +51,10 @@ void av1_calculate_tile_cols(AV1_COMMON *const cm) {
int sb_rows = mi_rows >> cm->seq_params.mib_size_log2;
int i;
// This will be overridden if there is at least two columns of tiles
// (otherwise there is no inner tile width)
cm->min_inner_tile_width = -1;
if (cm->uniform_tile_spacing_flag) {
int start_sb;
int size_sb = ALIGN_POWER_OF_TWO(sb_cols, cm->log2_tile_cols);
@ -67,18 +71,29 @@ void av1_calculate_tile_cols(AV1_COMMON *const cm) {
cm->tile_width = size_sb << cm->seq_params.mib_size_log2;
cm->tile_width = AOMMIN(cm->tile_width, cm->mi_cols);
if (cm->tile_cols > 1) {
cm->min_inner_tile_width = cm->tile_width;
}
} else {
int max_tile_area_sb = (sb_rows * sb_cols);
int widest_tile_sb = 1;
int narrowest_inner_tile_sb = 65536;
cm->log2_tile_cols = tile_log2(1, cm->tile_cols);
for (i = 0; i < cm->tile_cols; i++) {
int size_sb = cm->tile_col_start_sb[i + 1] - cm->tile_col_start_sb[i];
widest_tile_sb = AOMMAX(widest_tile_sb, size_sb);
// ignore the rightmost tile in frame for determining the narrowest
if (i < cm->tile_cols - 1)
narrowest_inner_tile_sb = AOMMIN(narrowest_inner_tile_sb, size_sb);
}
if (cm->min_log2_tiles) {
max_tile_area_sb >>= (cm->min_log2_tiles + 1);
}
cm->max_tile_height_sb = AOMMAX(max_tile_area_sb / widest_tile_sb, 1);
if (cm->tile_cols > 1) {
cm->min_inner_tile_width = narrowest_inner_tile_sb
<< cm->seq_params.mib_size_log2;
}
}
}
@ -204,3 +219,11 @@ void av1_get_uniform_tile_size(const AV1_COMMON *cm, int *w, int *h) {
}
}
}
int is_min_tile_width_satisfied(const AV1_COMMON *cm) {
// Disable check if there is a single tile col in the frame
if (cm->tile_cols == 1) return 1;
return ((cm->min_inner_tile_width << MI_SIZE_LOG2) >=
(64 << av1_superres_scaled(cm)));
}

View file

@ -59,6 +59,9 @@ void av1_get_tile_limits(struct AV1Common *const cm);
void av1_calculate_tile_cols(struct AV1Common *const cm);
void av1_calculate_tile_rows(struct AV1Common *const cm);
// Checks if the minimum tile_width requirement is satisfied
int is_min_tile_width_satisfied(const struct AV1Common *cm);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -2920,8 +2920,18 @@ void av1_inv_txfm_add_ssse3(const tran_low_t *dqcoeff, uint8_t *dst, int stride,
const TxfmParam *txfm_param) {
const TX_TYPE tx_type = txfm_param->tx_type;
if (!txfm_param->lossless) {
av1_lowbd_inv_txfm2d_add_ssse3(dqcoeff, dst, stride, tx_type,
txfm_param->tx_size, txfm_param->eob);
switch (txfm_param->tx_size) {
case TX_4X16:
case TX_16X4:
// TODO(http://crbug.com/aomedia/2350): the ssse3 versions cause test
// vector mismatches.
av1_inv_txfm_add_c(dqcoeff, dst, stride, txfm_param);
break;
default:
av1_lowbd_inv_txfm2d_add_ssse3(dqcoeff, dst, stride, tx_type,
txfm_param->tx_size, txfm_param->eob);
break;
}
} else {
av1_inv_txfm_add_c(dqcoeff, dst, stride, txfm_param);
}

View file

@ -27,31 +27,15 @@ void av1_convolve_2d_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst,
const int subpel_x_q4, const int subpel_y_q4,
ConvolveParams *conv_params) {
const int bd = 8;
DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * 8]);
int im_h = h + filter_params_y->taps - 1;
int im_stride = 8;
int i, j;
const int fo_vert = filter_params_y->taps / 2 - 1;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
int i, is_horiz_4tap = 0, is_vert_4tap = 0;
DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * 8]);
const int bits =
FILTER_BITS * 2 - conv_params->round_0 - conv_params->round_1;
const int offset_bits = bd + 2 * FILTER_BITS - conv_params->round_0;
__m256i filt[4], coeffs_h[4], coeffs_v[4];
assert(conv_params->round_0 > 0);
filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2);
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_h);
prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_v);
const __m256i round_const_h = _mm256_set1_epi16(
((1 << (conv_params->round_0 - 1)) >> 1) + (1 << (bd + FILTER_BITS - 2)));
const __m128i round_shift_h = _mm_cvtsi32_si128(conv_params->round_0 - 1);
@ -65,58 +49,96 @@ void av1_convolve_2d_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst,
((1 << (offset_bits - conv_params->round_1)) >> 1));
const __m128i round_shift_v = _mm_cvtsi32_si128(bits);
for (j = 0; j < w; j += 8) {
for (i = 0; i < im_h; i += 2) {
__m256i data = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j]));
__m256i filt[4], coeffs_h[4], coeffs_v[4];
// Load the next line
if (i + 1 < im_h)
filt[0] = _mm256_load_si256((__m256i const *)(filt_global_avx2));
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_h);
prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_v);
// Condition for checking valid horz_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_h[0], coeffs_h[3]), 0)))
is_horiz_4tap = 1;
// Condition for checking valid vert_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_v[0], coeffs_v[3]), 0)))
is_vert_4tap = 1;
// horz_filt as 4 tap and vert_filt as 8 tap
if (is_horiz_4tap) {
int im_h = h + filter_params_y->taps - 1;
const int fo_vert = filter_params_y->taps / 2 - 1;
const int fo_horiz = 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
// horz-filter
for (int j = 0; j < w; j += 8) {
for (i = 0; i < (im_h - 2); i += 2) {
__m256i data = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j]));
// Load the next line
data = _mm256_inserti128_si256(
data,
_mm_loadu_si128(
(__m128i *)&src_ptr[(i * src_stride) + j + src_stride]),
1);
__m256i res = convolve_lowbd_x_4tap(data, coeffs_h + 1, filt);
__m256i res = convolve_lowbd_x(data, coeffs_h, filt);
res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h),
round_shift_h);
_mm256_store_si256((__m256i *)&im_block[i * im_stride], res);
}
__m256i data_1 = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j]));
__m256i res = convolve_lowbd_x_4tap(data_1, coeffs_h + 1, filt);
res =
_mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h);
_mm256_store_si256((__m256i *)&im_block[i * im_stride], res);
}
/* Vertical filter */
{
// vert filter
CONVOLVE_SR_VERTICAL_FILTER_8TAP;
}
} else if (is_vert_4tap) {
int im_h = h + 3;
const int fo_vert = 1;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
for (int j = 0; j < w; j += 8) {
// horz_filter
CONVOLVE_SR_HORIZONTAL_FILTER_8TAP;
// vert_filter
__m256i s[6];
__m256i src_0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride));
__m256i src_1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride));
__m256i src_2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride));
__m256i src_3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride));
__m256i src_4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride));
__m256i src_5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride));
__m256i s[8];
s[0] = _mm256_unpacklo_epi16(src_0, src_1);
s[1] = _mm256_unpacklo_epi16(src_2, src_3);
s[2] = _mm256_unpacklo_epi16(src_4, src_5);
s[4] = _mm256_unpackhi_epi16(src_0, src_1);
s[5] = _mm256_unpackhi_epi16(src_2, src_3);
s[6] = _mm256_unpackhi_epi16(src_4, src_5);
s[3] = _mm256_unpackhi_epi16(src_0, src_1);
s[4] = _mm256_unpackhi_epi16(src_2, src_3);
for (i = 0; i < h; i += 2) {
const int16_t *data = &im_block[i * im_stride];
const __m256i s6 =
_mm256_loadu_si256((__m256i *)(data + 6 * im_stride));
const __m256i s7 =
_mm256_loadu_si256((__m256i *)(data + 7 * im_stride));
const __m256i s4 =
_mm256_loadu_si256((__m256i *)(data + 4 * im_stride));
const __m256i s5 =
_mm256_loadu_si256((__m256i *)(data + 5 * im_stride));
s[3] = _mm256_unpacklo_epi16(s6, s7);
s[7] = _mm256_unpackhi_epi16(s6, s7);
s[2] = _mm256_unpacklo_epi16(s4, s5);
s[5] = _mm256_unpackhi_epi16(s4, s5);
__m256i res_a = convolve(s, coeffs_v);
__m256i res_b = convolve(s + 4, coeffs_v);
__m256i res_a = convolve_4tap(s, coeffs_v + 1);
__m256i res_b = convolve_4tap(s + 3, coeffs_v + 1);
// Combine V round and 2F-H-V round into a single rounding
res_a =
@ -154,13 +176,25 @@ void av1_convolve_2d_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst,
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = s[4];
s[4] = s[5];
s[5] = s[6];
s[6] = s[7];
}
}
} else {
int j;
int im_h = h + filter_params_y->taps - 1;
const int fo_vert = filter_params_y->taps / 2 - 1;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
for (j = 0; j < w; j += 8) {
CONVOLVE_SR_HORIZONTAL_FILTER_8TAP;
CONVOLVE_SR_VERTICAL_FILTER_8TAP;
}
}
}

View file

@ -23,153 +23,239 @@ void av1_convolve_y_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst,
const InterpFilterParams *filter_params_y,
const int subpel_x_q4, const int subpel_y_q4,
ConvolveParams *conv_params) {
int i, j;
const int fo_vert = filter_params_y->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride;
int i, j, is_vert_4tap = 0;
// right shift is F-1 because we are already dividing
// filter co-efficients by 2
const int right_shift_bits = (FILTER_BITS - 1);
const __m128i right_shift = _mm_cvtsi32_si128(right_shift_bits);
const __m256i right_shift_const =
_mm256_set1_epi16((1 << right_shift_bits) >> 1);
__m256i coeffs[4], s[8];
assert(conv_params->round_0 <= FILTER_BITS);
assert(((conv_params->round_0 + conv_params->round_1) <= (FILTER_BITS + 1)) ||
((conv_params->round_0 + conv_params->round_1) == (2 * FILTER_BITS)));
prepare_coeffs_lowbd(filter_params_y, subpel_y_q4, coeffs);
(void)filter_params_x;
(void)subpel_x_q4;
(void)conv_params;
__m256i coeffs[4], s[8];
__m128i d[6];
for (j = 0; j < w; j += 16) {
const uint8_t *data = &src_ptr[j];
__m256i src6;
prepare_coeffs_lowbd(filter_params_y, subpel_y_q4, coeffs);
// Load lines a and b. Line a to lower 128, line b to upper 128
const __m256i src_01a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 0 * src_stride))),
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 1 * src_stride))),
0x20);
// Condition for checking valid vert_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0)))
is_vert_4tap = 1;
const __m256i src_12a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 1 * src_stride))),
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 2 * src_stride))),
0x20);
// vert_filt as 4 tap
if (is_vert_4tap) {
const int fo_vert = 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride;
for (j = 0; j < w; j += 16) {
const uint8_t *data = &src_ptr[j];
d[0] = _mm_loadu_si128((__m128i *)(data + 0 * src_stride));
d[1] = _mm_loadu_si128((__m128i *)(data + 1 * src_stride));
d[2] = _mm_loadu_si128((__m128i *)(data + 2 * src_stride));
d[3] = _mm_loadu_si128((__m128i *)(data + 3 * src_stride));
d[4] = _mm_loadu_si128((__m128i *)(data + 4 * src_stride));
const __m256i src_23a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 2 * src_stride))),
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 3 * src_stride))),
0x20);
// Load lines a and b. Line a to lower 128, line b to upper 128
const __m256i src_01a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[0]), _mm256_castsi128_si256(d[1]), 0x20);
const __m256i src_34a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 3 * src_stride))),
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 4 * src_stride))),
0x20);
const __m256i src_12a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[1]), _mm256_castsi128_si256(d[2]), 0x20);
const __m256i src_45a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 4 * src_stride))),
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 5 * src_stride))),
0x20);
const __m256i src_23a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[2]), _mm256_castsi128_si256(d[3]), 0x20);
src6 = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 6 * src_stride)));
const __m256i src_56a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 5 * src_stride))),
src6, 0x20);
const __m256i src_34a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[3]), _mm256_castsi128_si256(d[4]), 0x20);
s[0] = _mm256_unpacklo_epi8(src_01a, src_12a);
s[1] = _mm256_unpacklo_epi8(src_23a, src_34a);
s[2] = _mm256_unpacklo_epi8(src_45a, src_56a);
s[0] = _mm256_unpacklo_epi8(src_01a, src_12a);
s[1] = _mm256_unpacklo_epi8(src_23a, src_34a);
s[4] = _mm256_unpackhi_epi8(src_01a, src_12a);
s[5] = _mm256_unpackhi_epi8(src_23a, src_34a);
s[6] = _mm256_unpackhi_epi8(src_45a, src_56a);
s[3] = _mm256_unpackhi_epi8(src_01a, src_12a);
s[4] = _mm256_unpackhi_epi8(src_23a, src_34a);
for (i = 0; i < h; i += 2) {
data = &src_ptr[i * src_stride + j];
const __m256i src_67a = _mm256_permute2x128_si256(
src6,
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 7 * src_stride))),
0x20);
for (i = 0; i < h; i += 2) {
data = &src_ptr[i * src_stride + j];
d[5] = _mm_loadu_si128((__m128i *)(data + 5 * src_stride));
const __m256i src_45a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[4]), _mm256_castsi128_si256(d[5]), 0x20);
d[4] = _mm_loadu_si128((__m128i *)(data + 6 * src_stride));
const __m256i src_56a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[5]), _mm256_castsi128_si256(d[4]), 0x20);
s[2] = _mm256_unpacklo_epi8(src_45a, src_56a);
s[5] = _mm256_unpackhi_epi8(src_45a, src_56a);
const __m256i res_lo = convolve_lowbd_4tap(s, coeffs + 1);
/* rounding code */
// shift by F - 1
const __m256i res_16b_lo = _mm256_sra_epi16(
_mm256_add_epi16(res_lo, right_shift_const), right_shift);
// 8 bit conversion and saturation to uint8
__m256i res_8b_lo = _mm256_packus_epi16(res_16b_lo, res_16b_lo);
if (w - j > 8) {
const __m256i res_hi = convolve_lowbd_4tap(s + 3, coeffs + 1);
/* rounding code */
// shift by F - 1
const __m256i res_16b_hi = _mm256_sra_epi16(
_mm256_add_epi16(res_hi, right_shift_const), right_shift);
// 8 bit conversion and saturation to uint8
__m256i res_8b_hi = _mm256_packus_epi16(res_16b_hi, res_16b_hi);
__m256i res_a = _mm256_unpacklo_epi64(res_8b_lo, res_8b_hi);
const __m128i res_0 = _mm256_castsi256_si128(res_a);
const __m128i res_1 = _mm256_extracti128_si256(res_a, 1);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res_0);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride],
res_1);
} else {
const __m128i res_0 = _mm256_castsi256_si128(res_8b_lo);
const __m128i res_1 = _mm256_extracti128_si256(res_8b_lo, 1);
if (w - j > 4) {
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + j], res_0);
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride],
res_1);
} else if (w - j > 2) {
xx_storel_32(&dst[i * dst_stride + j], res_0);
xx_storel_32(&dst[i * dst_stride + j + dst_stride], res_1);
} else {
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j];
__m128i *const p_1 =
(__m128i *)&dst[i * dst_stride + j + dst_stride];
*(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0);
*(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1);
}
}
s[0] = s[1];
s[1] = s[2];
s[3] = s[4];
s[4] = s[5];
}
}
} else {
const int fo_vert = filter_params_y->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride;
for (j = 0; j < w; j += 16) {
const uint8_t *data = &src_ptr[j];
__m256i src6;
d[0] = _mm_loadu_si128((__m128i *)(data + 0 * src_stride));
d[1] = _mm_loadu_si128((__m128i *)(data + 1 * src_stride));
d[2] = _mm_loadu_si128((__m128i *)(data + 2 * src_stride));
d[3] = _mm_loadu_si128((__m128i *)(data + 3 * src_stride));
d[4] = _mm_loadu_si128((__m128i *)(data + 4 * src_stride));
d[5] = _mm_loadu_si128((__m128i *)(data + 5 * src_stride));
// Load lines a and b. Line a to lower 128, line b to upper 128
const __m256i src_01a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[0]), _mm256_castsi128_si256(d[1]), 0x20);
const __m256i src_12a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[1]), _mm256_castsi128_si256(d[2]), 0x20);
const __m256i src_23a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[2]), _mm256_castsi128_si256(d[3]), 0x20);
const __m256i src_34a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[3]), _mm256_castsi128_si256(d[4]), 0x20);
const __m256i src_45a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(d[4]), _mm256_castsi128_si256(d[5]), 0x20);
src6 = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 8 * src_stride)));
const __m256i src_78a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 7 * src_stride))),
src6, 0x20);
_mm_loadu_si128((__m128i *)(data + 6 * src_stride)));
const __m256i src_56a =
_mm256_permute2x128_si256(_mm256_castsi128_si256(d[5]), src6, 0x20);
s[3] = _mm256_unpacklo_epi8(src_67a, src_78a);
s[7] = _mm256_unpackhi_epi8(src_67a, src_78a);
s[0] = _mm256_unpacklo_epi8(src_01a, src_12a);
s[1] = _mm256_unpacklo_epi8(src_23a, src_34a);
s[2] = _mm256_unpacklo_epi8(src_45a, src_56a);
const __m256i res_lo = convolve_lowbd(s, coeffs);
s[4] = _mm256_unpackhi_epi8(src_01a, src_12a);
s[5] = _mm256_unpackhi_epi8(src_23a, src_34a);
s[6] = _mm256_unpackhi_epi8(src_45a, src_56a);
/* rounding code */
// shift by F - 1
const __m256i res_16b_lo = _mm256_sra_epi16(
_mm256_add_epi16(res_lo, right_shift_const), right_shift);
// 8 bit conversion and saturation to uint8
__m256i res_8b_lo = _mm256_packus_epi16(res_16b_lo, res_16b_lo);
for (i = 0; i < h; i += 2) {
data = &src_ptr[i * src_stride + j];
const __m256i src_67a = _mm256_permute2x128_si256(
src6,
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 7 * src_stride))),
0x20);
if (w - j > 8) {
const __m256i res_hi = convolve_lowbd(s + 4, coeffs);
src6 = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 8 * src_stride)));
const __m256i src_78a = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + 7 * src_stride))),
src6, 0x20);
s[3] = _mm256_unpacklo_epi8(src_67a, src_78a);
s[7] = _mm256_unpackhi_epi8(src_67a, src_78a);
const __m256i res_lo = convolve_lowbd(s, coeffs);
/* rounding code */
// shift by F - 1
const __m256i res_16b_hi = _mm256_sra_epi16(
_mm256_add_epi16(res_hi, right_shift_const), right_shift);
const __m256i res_16b_lo = _mm256_sra_epi16(
_mm256_add_epi16(res_lo, right_shift_const), right_shift);
// 8 bit conversion and saturation to uint8
__m256i res_8b_hi = _mm256_packus_epi16(res_16b_hi, res_16b_hi);
__m256i res_8b_lo = _mm256_packus_epi16(res_16b_lo, res_16b_lo);
__m256i res_a = _mm256_unpacklo_epi64(res_8b_lo, res_8b_hi);
if (w - j > 8) {
const __m256i res_hi = convolve_lowbd(s + 4, coeffs);
const __m128i res_0 = _mm256_castsi256_si128(res_a);
const __m128i res_1 = _mm256_extracti128_si256(res_a, 1);
/* rounding code */
// shift by F - 1
const __m256i res_16b_hi = _mm256_sra_epi16(
_mm256_add_epi16(res_hi, right_shift_const), right_shift);
// 8 bit conversion and saturation to uint8
__m256i res_8b_hi = _mm256_packus_epi16(res_16b_hi, res_16b_hi);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res_0);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride],
res_1);
} else {
const __m128i res_0 = _mm256_castsi256_si128(res_8b_lo);
const __m128i res_1 = _mm256_extracti128_si256(res_8b_lo, 1);
if (w - j > 4) {
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + j], res_0);
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride],
__m256i res_a = _mm256_unpacklo_epi64(res_8b_lo, res_8b_hi);
const __m128i res_0 = _mm256_castsi256_si128(res_a);
const __m128i res_1 = _mm256_extracti128_si256(res_a, 1);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res_0);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j + dst_stride],
res_1);
} else if (w - j > 2) {
xx_storel_32(&dst[i * dst_stride + j], res_0);
xx_storel_32(&dst[i * dst_stride + j + dst_stride], res_1);
} else {
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j];
__m128i *const p_1 = (__m128i *)&dst[i * dst_stride + j + dst_stride];
*(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0);
*(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1);
const __m128i res_0 = _mm256_castsi256_si128(res_8b_lo);
const __m128i res_1 = _mm256_extracti128_si256(res_8b_lo, 1);
if (w - j > 4) {
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + j], res_0);
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + j + dst_stride],
res_1);
} else if (w - j > 2) {
xx_storel_32(&dst[i * dst_stride + j], res_0);
xx_storel_32(&dst[i * dst_stride + j + dst_stride], res_1);
} else {
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j];
__m128i *const p_1 =
(__m128i *)&dst[i * dst_stride + j + dst_stride];
*(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0);
*(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1);
}
}
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[4] = s[5];
s[5] = s[6];
s[6] = s[7];
}
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[4] = s[5];
s[5] = s[6];
s[6] = s[7];
}
}
}
@ -180,26 +266,14 @@ void av1_convolve_x_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst,
const InterpFilterParams *filter_params_y,
const int subpel_x_q4, const int subpel_y_q4,
ConvolveParams *conv_params) {
int i, j;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_horiz;
const int bits = FILTER_BITS - conv_params->round_0;
__m256i filt[4], coeffs[4];
filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2);
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs);
const __m256i round_0_const =
_mm256_set1_epi16((1 << (conv_params->round_0 - 1)) >> 1);
const __m128i round_0_shift = _mm_cvtsi32_si128(conv_params->round_0 - 1);
const __m256i round_const = _mm256_set1_epi16((1 << bits) >> 1);
const __m128i round_shift = _mm_cvtsi32_si128(bits);
int i, is_horiz_4tap = 0;
(void)filter_params_y;
(void)subpel_y_q4;
@ -208,51 +282,101 @@ void av1_convolve_x_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst,
((conv_params->round_0 + conv_params->round_1) == 2 * FILTER_BITS));
assert(conv_params->round_0 > 0);
if (w <= 8) {
for (i = 0; i < h; i += 2) {
const __m256i data = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(&src_ptr[i * src_stride]))),
_mm256_castsi128_si256(_mm_loadu_si128(
(__m128i *)(&src_ptr[i * src_stride + src_stride]))),
0x20);
__m256i coeffs[4], filt[4];
filt[0] = _mm256_load_si256((__m256i const *)(filt_global_avx2));
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
__m256i res_16b = convolve_lowbd_x(data, coeffs, filt);
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs);
res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const),
round_0_shift);
// Condition for checking valid horz_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0)))
is_horiz_4tap = 1;
res_16b =
_mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const), round_shift);
// horz_filt as 4 tap
if (is_horiz_4tap) {
const int fo_horiz = 1;
const uint8_t *const src_ptr = src - fo_horiz;
if (w <= 8) {
for (i = 0; i < h; i += 2) {
const __m256i data = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(&src_ptr[i * src_stride]))),
_mm256_castsi128_si256(_mm_loadu_si128(
(__m128i *)(&src_ptr[i * src_stride + src_stride]))),
0x20);
/* rounding code */
// 8 bit conversion and saturation to uint8
__m256i res_8b = _mm256_packus_epi16(res_16b, res_16b);
__m256i res_16b = convolve_lowbd_x_4tap(data, coeffs + 1, filt);
const __m128i res_0 = _mm256_castsi256_si128(res_8b);
const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1);
if (w > 4) {
_mm_storel_epi64((__m128i *)&dst[i * dst_stride], res_0);
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + dst_stride], res_1);
} else if (w > 2) {
xx_storel_32(&dst[i * dst_stride], res_0);
xx_storel_32(&dst[i * dst_stride + dst_stride], res_1);
} else {
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride];
__m128i *const p_1 = (__m128i *)&dst[i * dst_stride + dst_stride];
*(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0);
*(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1);
res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const),
round_0_shift);
res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const),
round_shift);
/* rounding code */
// 8 bit conversion and saturation to uint8
__m256i res_8b = _mm256_packus_epi16(res_16b, res_16b);
const __m128i res_0 = _mm256_castsi256_si128(res_8b);
const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1);
if (w > 4) {
_mm_storel_epi64((__m128i *)&dst[i * dst_stride], res_0);
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + dst_stride], res_1);
} else if (w > 2) {
xx_storel_32(&dst[i * dst_stride], res_0);
xx_storel_32(&dst[i * dst_stride + dst_stride], res_1);
} else {
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride];
__m128i *const p_1 = (__m128i *)&dst[i * dst_stride + dst_stride];
*(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0);
*(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1);
}
}
} else {
for (i = 0; i < h; ++i) {
for (int j = 0; j < w; j += 16) {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 16 17
// 18 19 20 21 22 23
const __m256i data = _mm256_inserti128_si256(
_mm256_loadu_si256((__m256i *)&src_ptr[(i * src_stride) + j]),
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + (j + 8)]),
1);
__m256i res_16b = convolve_lowbd_x_4tap(data, coeffs + 1, filt);
res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const),
round_0_shift);
res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const),
round_shift);
/* rounding code */
// 8 bit conversion and saturation to uint8
__m256i res_8b = _mm256_packus_epi16(res_16b, res_16b);
// Store values into the destination buffer
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
res_8b = _mm256_permute4x64_epi64(res_8b, 216);
__m128i res = _mm256_castsi256_si128(res_8b);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res);
}
}
}
} else {
for (i = 0; i < h; ++i) {
for (j = 0; j < w; j += 16) {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 16 17 18
// 19 20 21 22 23
const __m256i data = _mm256_inserti128_si256(
_mm256_loadu_si256((__m256i *)&src_ptr[(i * src_stride) + j]),
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + (j + 8)]),
1);
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_horiz;
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
if (w <= 8) {
for (i = 0; i < h; i += 2) {
const __m256i data = _mm256_permute2x128_si256(
_mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(&src_ptr[i * src_stride]))),
_mm256_castsi128_si256(_mm_loadu_si128(
(__m128i *)(&src_ptr[i * src_stride + src_stride]))),
0x20);
__m256i res_16b = convolve_lowbd_x(data, coeffs, filt);
@ -266,11 +390,49 @@ void av1_convolve_x_sr_avx2(const uint8_t *src, int src_stride, uint8_t *dst,
// 8 bit conversion and saturation to uint8
__m256i res_8b = _mm256_packus_epi16(res_16b, res_16b);
// Store values into the destination buffer
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
res_8b = _mm256_permute4x64_epi64(res_8b, 216);
__m128i res = _mm256_castsi256_si128(res_8b);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res);
const __m128i res_0 = _mm256_castsi256_si128(res_8b);
const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1);
if (w > 4) {
_mm_storel_epi64((__m128i *)&dst[i * dst_stride], res_0);
_mm_storel_epi64((__m128i *)&dst[i * dst_stride + dst_stride], res_1);
} else if (w > 2) {
xx_storel_32(&dst[i * dst_stride], res_0);
xx_storel_32(&dst[i * dst_stride + dst_stride], res_1);
} else {
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride];
__m128i *const p_1 = (__m128i *)&dst[i * dst_stride + dst_stride];
*(uint16_t *)p_0 = _mm_cvtsi128_si32(res_0);
*(uint16_t *)p_1 = _mm_cvtsi128_si32(res_1);
}
}
} else {
for (i = 0; i < h; ++i) {
for (int j = 0; j < w; j += 16) {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 16 17
// 18 19 20 21 22 23
const __m256i data = _mm256_inserti128_si256(
_mm256_loadu_si256((__m256i *)&src_ptr[(i * src_stride) + j]),
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + (j + 8)]),
1);
__m256i res_16b = convolve_lowbd_x(data, coeffs, filt);
res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_0_const),
round_0_shift);
res_16b = _mm256_sra_epi16(_mm256_add_epi16(res_16b, round_const),
round_shift);
/* rounding code */
// 8 bit conversion and saturation to uint8
__m256i res_8b = _mm256_packus_epi16(res_16b, res_16b);
// Store values into the destination buffer
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
res_8b = _mm256_permute4x64_epi64(res_8b, 216);
__m128i res = _mm256_castsi256_si128(res_8b);
_mm_storeu_si128((__m128i *)&dst[i * dst_stride + j], res);
}
}
}
}

View file

@ -5926,28 +5926,16 @@ void av1_highbd_inv_txfm_add_sse4_1(const tran_low_t *input, uint8_t *dest,
assert(av1_ext_tx_used[txfm_param->tx_set_type][txfm_param->tx_type]);
const TX_SIZE tx_size = txfm_param->tx_size;
switch (tx_size) {
case TX_8X8:
av1_highbd_inv_txfm_add_8x8_sse4_1(input, dest, stride, txfm_param);
break;
case TX_4X8:
av1_highbd_inv_txfm_add_4x8_sse4_1(input, dest, stride, txfm_param);
break;
case TX_8X4:
av1_highbd_inv_txfm_add_8x4_sse4_1(input, dest, stride, txfm_param);
break;
case TX_4X4:
av1_highbd_inv_txfm_add_4x4_sse4_1(input, dest, stride, txfm_param);
break;
case TX_16X4:
av1_highbd_inv_txfm_add_16x4_sse4_1(input, dest, stride, txfm_param);
break;
case TX_4X16:
av1_highbd_inv_txfm_add_4x16_sse4_1(input, dest, stride, txfm_param);
break;
default:
av1_highbd_inv_txfm2d_add_universe_sse4_1(
input, dest, stride, txfm_param->tx_type, tx_size, txfm_param->eob,
txfm_param->bd);
// TODO(http://crbug.com/aomedia/2350): the remaining sse4_1 versions
// cause test vector mismatches.
av1_highbd_inv_txfm_add_c(input, dest, stride, txfm_param);
break;
}
}

View file

@ -44,9 +44,7 @@ void av1_dist_wtd_convolve_x_avx2(const uint8_t *src, int src_stride,
CONV_BUF_TYPE *dst = conv_params->dst;
int dst_stride = conv_params->dst_stride;
const int bd = 8;
int i, j;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_horiz;
int i, j, is_horiz_4tap = 0;
const int bits = FILTER_BITS - conv_params->round_1;
const __m256i wt = unpack_weights_avx2(conv_params);
const int do_average = conv_params->do_average;
@ -58,18 +56,10 @@ void av1_dist_wtd_convolve_x_avx2(const uint8_t *src, int src_stride,
const int rounding_shift =
2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1;
const __m256i rounding_const = _mm256_set1_epi16((1 << rounding_shift) >> 1);
__m256i filt[4], coeffs[4];
assert(bits >= 0);
assert(conv_params->round_0 > 0);
filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2);
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs);
const __m256i round_const =
_mm256_set1_epi16((1 << (conv_params->round_0 - 1)) >> 1);
const __m128i round_shift = _mm_cvtsi32_si128(conv_params->round_0 - 1);
@ -77,51 +67,121 @@ void av1_dist_wtd_convolve_x_avx2(const uint8_t *src, int src_stride,
(void)filter_params_y;
(void)subpel_y_q4;
for (i = 0; i < h; i += 2) {
const uint8_t *src_data = src_ptr + i * src_stride;
CONV_BUF_TYPE *dst_data = dst + i * dst_stride;
for (j = 0; j < w; j += 8) {
const __m256i data =
load_line2_avx2(&src_data[j], &src_data[j + src_stride]);
__m256i filt[4], coeffs[4];
__m256i res = convolve_lowbd_x(data, coeffs, filt);
filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2);
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const), round_shift);
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs);
res = _mm256_slli_epi16(res, bits);
// Condition for checking valid horz_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0)))
is_horiz_4tap = 1;
const __m256i res_unsigned = _mm256_add_epi16(res, offset_const);
// horz_filt as 4 tap
if (is_horiz_4tap) {
const int fo_horiz = 1;
const uint8_t *const src_ptr = src - fo_horiz;
for (i = 0; i < h; i += 2) {
const uint8_t *src_data = src_ptr + i * src_stride;
CONV_BUF_TYPE *dst_data = dst + i * dst_stride;
for (j = 0; j < w; j += 8) {
const __m256i data =
load_line2_avx2(&src_data[j], &src_data[j + src_stride]);
// Accumulate values into the destination buffer
if (do_average) {
const __m256i data_ref_0 =
load_line2_avx2(&dst_data[j], &dst_data[j + dst_stride]);
const __m256i comp_avg_res =
comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg);
__m256i res = convolve_lowbd_x_4tap(data, coeffs + 1, filt);
res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const), round_shift);
res = _mm256_slli_epi16(res, bits);
const __m256i round_result = convolve_rounding(
&comp_avg_res, &offset_const, &rounding_const, rounding_shift);
const __m256i res_unsigned = _mm256_add_epi16(res, offset_const);
const __m256i res_8 = _mm256_packus_epi16(round_result, round_result);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
// Accumulate values into the destination buffer
if (do_average) {
const __m256i data_ref_0 =
load_line2_avx2(&dst_data[j], &dst_data[j + dst_stride]);
const __m256i comp_avg_res =
comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg);
if (w > 4) {
_mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_storel_epi64(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1);
const __m256i round_result = convolve_rounding(
&comp_avg_res, &offset_const, &rounding_const, rounding_shift);
const __m256i res_8 = _mm256_packus_epi16(round_result, round_result);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
if (w > 4) {
_mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_storel_epi64(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1);
} else {
*(uint32_t *)(&dst0[i * dst_stride0 + j]) =
_mm_cvtsi128_si32(res_0);
*(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) =
_mm_cvtsi128_si32(res_1);
}
} else {
*(uint32_t *)(&dst0[i * dst_stride0 + j]) = _mm_cvtsi128_si32(res_0);
*(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) =
_mm_cvtsi128_si32(res_1);
}
} else {
const __m128i res_0 = _mm256_castsi256_si128(res_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0);
const __m128i res_0 = _mm256_castsi256_si128(res_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0);
const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_1);
const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_1);
}
}
}
} else {
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_horiz;
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
for (i = 0; i < h; i += 2) {
const uint8_t *src_data = src_ptr + i * src_stride;
CONV_BUF_TYPE *dst_data = dst + i * dst_stride;
for (j = 0; j < w; j += 8) {
const __m256i data =
load_line2_avx2(&src_data[j], &src_data[j + src_stride]);
__m256i res = convolve_lowbd_x(data, coeffs, filt);
res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const), round_shift);
res = _mm256_slli_epi16(res, bits);
const __m256i res_unsigned = _mm256_add_epi16(res, offset_const);
// Accumulate values into the destination buffer
if (do_average) {
const __m256i data_ref_0 =
load_line2_avx2(&dst_data[j], &dst_data[j + dst_stride]);
const __m256i comp_avg_res =
comp_avg(&data_ref_0, &res_unsigned, &wt, use_dist_wtd_comp_avg);
const __m256i round_result = convolve_rounding(
&comp_avg_res, &offset_const, &rounding_const, rounding_shift);
const __m256i res_8 = _mm256_packus_epi16(round_result, round_result);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
if (w > 4) {
_mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_storel_epi64(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1);
} else {
*(uint32_t *)(&dst0[i * dst_stride0 + j]) =
_mm_cvtsi128_si32(res_0);
*(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) =
_mm_cvtsi128_si32(res_1);
}
} else {
const __m128i res_0 = _mm256_castsi256_si128(res_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0);
const __m128i res_1 = _mm256_extracti128_si256(res_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_1);
}
}
}
}
@ -136,9 +196,7 @@ void av1_dist_wtd_convolve_y_avx2(const uint8_t *src, int src_stride,
CONV_BUF_TYPE *dst = conv_params->dst;
int dst_stride = conv_params->dst_stride;
const int bd = 8;
int i, j;
const int fo_vert = filter_params_y->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride;
int i, j, is_vert_4tap = 0;
// +1 to compensate for dividing the filter coeffs by 2
const int left_shift = FILTER_BITS - conv_params->round_0 + 1;
const __m256i round_const =
@ -168,171 +226,368 @@ void av1_dist_wtd_convolve_y_avx2(const uint8_t *src, int src_stride,
(void)filter_params_x;
(void)subpel_x_q4;
for (j = 0; j < w; j += 16) {
const uint8_t *data = &src_ptr[j];
__m256i src6;
// Load lines a and b. Line a to lower 128, line b to upper 128
{
__m256i src_ab[7];
__m256i src_a[7];
src_a[0] = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
for (int kk = 0; kk < 6; ++kk) {
data += src_stride;
src_a[kk + 1] =
_mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
src_ab[kk] = _mm256_permute2x128_si256(src_a[kk], src_a[kk + 1], 0x20);
// Condition for checking valid vert_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs[0], coeffs[3]), 0)))
is_vert_4tap = 1;
if (is_vert_4tap) {
const int fo_vert = 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride;
for (j = 0; j < w; j += 16) {
const uint8_t *data = &src_ptr[j];
__m256i src4;
// Load lines a and b. Line a to lower 128, line b to upper 128
{
__m256i src_ab[4];
__m256i src_a[5];
src_a[0] = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
for (int kk = 0; kk < 4; ++kk) {
data += src_stride;
src_a[kk + 1] =
_mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
src_ab[kk] =
_mm256_permute2x128_si256(src_a[kk], src_a[kk + 1], 0x20);
}
src4 = src_a[4];
s[0] = _mm256_unpacklo_epi8(src_ab[0], src_ab[1]);
s[1] = _mm256_unpacklo_epi8(src_ab[2], src_ab[3]);
s[3] = _mm256_unpackhi_epi8(src_ab[0], src_ab[1]);
s[4] = _mm256_unpackhi_epi8(src_ab[2], src_ab[3]);
}
src6 = src_a[6];
s[0] = _mm256_unpacklo_epi8(src_ab[0], src_ab[1]);
s[1] = _mm256_unpacklo_epi8(src_ab[2], src_ab[3]);
s[2] = _mm256_unpacklo_epi8(src_ab[4], src_ab[5]);
s[4] = _mm256_unpackhi_epi8(src_ab[0], src_ab[1]);
s[5] = _mm256_unpackhi_epi8(src_ab[2], src_ab[3]);
s[6] = _mm256_unpackhi_epi8(src_ab[4], src_ab[5]);
}
for (i = 0; i < h; i += 2) {
data = &src_ptr[(i + 7) * src_stride + j];
const __m256i src7 =
_mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
const __m256i src_67a = _mm256_permute2x128_si256(src6, src7, 0x20);
for (i = 0; i < h; i += 2) {
data = &src_ptr[(i + 5) * src_stride + j];
const __m256i src5 =
_mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
const __m256i src_45a = _mm256_permute2x128_si256(src4, src5, 0x20);
src6 = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + src_stride)));
const __m256i src_78a = _mm256_permute2x128_si256(src7, src6, 0x20);
src4 = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + src_stride)));
const __m256i src_56a = _mm256_permute2x128_si256(src5, src4, 0x20);
s[3] = _mm256_unpacklo_epi8(src_67a, src_78a);
s[7] = _mm256_unpackhi_epi8(src_67a, src_78a);
s[2] = _mm256_unpacklo_epi8(src_45a, src_56a);
s[5] = _mm256_unpackhi_epi8(src_45a, src_56a);
__m256i res_lo = convolve_lowbd(s, coeffs);
__m256i res_lo = convolve_lowbd_4tap(s, coeffs + 1);
res_lo = _mm256_add_epi16(res_lo, offset_const_1);
res_lo = _mm256_add_epi16(res_lo, offset_const_1);
const __m256i res_lo_0_32b = _mm256_unpacklo_epi16(res_lo, zero);
const __m256i res_lo_0_shift =
_mm256_slli_epi32(res_lo_0_32b, left_shift);
const __m256i res_lo_0_round = _mm256_sra_epi32(
_mm256_add_epi32(res_lo_0_shift, round_const), round_shift);
const __m256i res_lo_0_32b = _mm256_unpacklo_epi16(res_lo, zero);
const __m256i res_lo_0_shift =
_mm256_slli_epi32(res_lo_0_32b, left_shift);
const __m256i res_lo_0_round = _mm256_sra_epi32(
_mm256_add_epi32(res_lo_0_shift, round_const), round_shift);
const __m256i res_lo_1_32b = _mm256_unpackhi_epi16(res_lo, zero);
const __m256i res_lo_1_shift =
_mm256_slli_epi32(res_lo_1_32b, left_shift);
const __m256i res_lo_1_round = _mm256_sra_epi32(
_mm256_add_epi32(res_lo_1_shift, round_const), round_shift);
const __m256i res_lo_1_32b = _mm256_unpackhi_epi16(res_lo, zero);
const __m256i res_lo_1_shift =
_mm256_slli_epi32(res_lo_1_32b, left_shift);
const __m256i res_lo_1_round = _mm256_sra_epi32(
_mm256_add_epi32(res_lo_1_shift, round_const), round_shift);
const __m256i res_lo_round =
_mm256_packs_epi32(res_lo_0_round, res_lo_1_round);
const __m256i res_lo_round =
_mm256_packs_epi32(res_lo_0_round, res_lo_1_round);
const __m256i res_lo_unsigned =
_mm256_add_epi16(res_lo_round, offset_const_2);
const __m256i res_lo_unsigned =
_mm256_add_epi16(res_lo_round, offset_const_2);
if (w - j < 16) {
if (do_average) {
const __m256i data_ref_0 = load_line2_avx2(
&dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]);
const __m256i comp_avg_res = comp_avg(&data_ref_0, &res_lo_unsigned,
&wt, use_dist_wtd_comp_avg);
if (w - j < 16) {
if (do_average) {
const __m256i data_ref_0 =
load_line2_avx2(&dst[i * dst_stride + j],
&dst[i * dst_stride + j + dst_stride]);
const __m256i comp_avg_res = comp_avg(&data_ref_0, &res_lo_unsigned,
&wt, use_dist_wtd_comp_avg);
const __m256i round_result = convolve_rounding(
&comp_avg_res, &offset_const, &rounding_const, rounding_shift);
const __m256i round_result = convolve_rounding(
&comp_avg_res, &offset_const, &rounding_const, rounding_shift);
const __m256i res_8 = _mm256_packus_epi16(round_result, round_result);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
const __m256i res_8 =
_mm256_packus_epi16(round_result, round_result);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
if (w - j > 4) {
_mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_storel_epi64(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1);
if (w - j > 4) {
_mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_storel_epi64(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])),
res_1);
} else {
*(uint32_t *)(&dst0[i * dst_stride0 + j]) =
_mm_cvtsi128_si32(res_0);
*(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) =
_mm_cvtsi128_si32(res_1);
}
} else {
*(uint32_t *)(&dst0[i * dst_stride0 + j]) =
_mm_cvtsi128_si32(res_0);
*(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) =
_mm_cvtsi128_si32(res_1);
const __m128i res_0 = _mm256_castsi256_si128(res_lo_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0);
const __m128i res_1 = _mm256_extracti128_si256(res_lo_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_1);
}
} else {
const __m128i res_0 = _mm256_castsi256_si128(res_lo_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0);
__m256i res_hi = convolve_lowbd_4tap(s + 3, coeffs + 1);
const __m128i res_1 = _mm256_extracti128_si256(res_lo_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_1);
res_hi = _mm256_add_epi16(res_hi, offset_const_1);
const __m256i res_hi_0_32b = _mm256_unpacklo_epi16(res_hi, zero);
const __m256i res_hi_0_shift =
_mm256_slli_epi32(res_hi_0_32b, left_shift);
const __m256i res_hi_0_round = _mm256_sra_epi32(
_mm256_add_epi32(res_hi_0_shift, round_const), round_shift);
const __m256i res_hi_1_32b = _mm256_unpackhi_epi16(res_hi, zero);
const __m256i res_hi_1_shift =
_mm256_slli_epi32(res_hi_1_32b, left_shift);
const __m256i res_hi_1_round = _mm256_sra_epi32(
_mm256_add_epi32(res_hi_1_shift, round_const), round_shift);
const __m256i res_hi_round =
_mm256_packs_epi32(res_hi_0_round, res_hi_1_round);
const __m256i res_hi_unsigned =
_mm256_add_epi16(res_hi_round, offset_const_2);
if (do_average) {
const __m256i data_ref_0_lo =
load_line2_avx2(&dst[i * dst_stride + j],
&dst[i * dst_stride + j + dst_stride]);
const __m256i data_ref_0_hi =
load_line2_avx2(&dst[i * dst_stride + j + 8],
&dst[i * dst_stride + j + 8 + dst_stride]);
const __m256i comp_avg_res_lo = comp_avg(
&data_ref_0_lo, &res_lo_unsigned, &wt, use_dist_wtd_comp_avg);
const __m256i comp_avg_res_hi = comp_avg(
&data_ref_0_hi, &res_hi_unsigned, &wt, use_dist_wtd_comp_avg);
const __m256i round_result_lo =
convolve_rounding(&comp_avg_res_lo, &offset_const,
&rounding_const, rounding_shift);
const __m256i round_result_hi =
convolve_rounding(&comp_avg_res_hi, &offset_const,
&rounding_const, rounding_shift);
const __m256i res_8 =
_mm256_packus_epi16(round_result_lo, round_result_hi);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
_mm_store_si128((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_store_si128(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1);
} else {
const __m128i res_lo_0 = _mm256_castsi256_si128(res_lo_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_lo_0);
const __m128i res_lo_1 =
_mm256_extracti128_si256(res_lo_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_lo_1);
const __m128i res_hi_0 = _mm256_castsi256_si128(res_hi_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + 8]),
res_hi_0);
const __m128i res_hi_1 =
_mm256_extracti128_si256(res_hi_unsigned, 1);
_mm_store_si128(
(__m128i *)(&dst[i * dst_stride + j + 8 + dst_stride]),
res_hi_1);
}
}
} else {
__m256i res_hi = convolve_lowbd(s + 4, coeffs);
s[0] = s[1];
s[1] = s[2];
res_hi = _mm256_add_epi16(res_hi, offset_const_1);
const __m256i res_hi_0_32b = _mm256_unpacklo_epi16(res_hi, zero);
const __m256i res_hi_0_shift =
_mm256_slli_epi32(res_hi_0_32b, left_shift);
const __m256i res_hi_0_round = _mm256_sra_epi32(
_mm256_add_epi32(res_hi_0_shift, round_const), round_shift);
const __m256i res_hi_1_32b = _mm256_unpackhi_epi16(res_hi, zero);
const __m256i res_hi_1_shift =
_mm256_slli_epi32(res_hi_1_32b, left_shift);
const __m256i res_hi_1_round = _mm256_sra_epi32(
_mm256_add_epi32(res_hi_1_shift, round_const), round_shift);
const __m256i res_hi_round =
_mm256_packs_epi32(res_hi_0_round, res_hi_1_round);
const __m256i res_hi_unsigned =
_mm256_add_epi16(res_hi_round, offset_const_2);
if (do_average) {
const __m256i data_ref_0_lo = load_line2_avx2(
&dst[i * dst_stride + j], &dst[i * dst_stride + j + dst_stride]);
const __m256i data_ref_0_hi =
load_line2_avx2(&dst[i * dst_stride + j + 8],
&dst[i * dst_stride + j + 8 + dst_stride]);
const __m256i comp_avg_res_lo = comp_avg(
&data_ref_0_lo, &res_lo_unsigned, &wt, use_dist_wtd_comp_avg);
const __m256i comp_avg_res_hi = comp_avg(
&data_ref_0_hi, &res_hi_unsigned, &wt, use_dist_wtd_comp_avg);
const __m256i round_result_lo = convolve_rounding(
&comp_avg_res_lo, &offset_const, &rounding_const, rounding_shift);
const __m256i round_result_hi = convolve_rounding(
&comp_avg_res_hi, &offset_const, &rounding_const, rounding_shift);
const __m256i res_8 =
_mm256_packus_epi16(round_result_lo, round_result_hi);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
_mm_store_si128((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_store_si128(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1);
} else {
const __m128i res_lo_0 = _mm256_castsi256_si128(res_lo_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_lo_0);
const __m128i res_lo_1 = _mm256_extracti128_si256(res_lo_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_lo_1);
const __m128i res_hi_0 = _mm256_castsi256_si128(res_hi_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + 8]), res_hi_0);
const __m128i res_hi_1 = _mm256_extracti128_si256(res_hi_unsigned, 1);
_mm_store_si128(
(__m128i *)(&dst[i * dst_stride + j + 8 + dst_stride]), res_hi_1);
}
s[3] = s[4];
s[4] = s[5];
}
}
} else {
const int fo_vert = filter_params_y->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride;
for (j = 0; j < w; j += 16) {
const uint8_t *data = &src_ptr[j];
__m256i src6;
// Load lines a and b. Line a to lower 128, line b to upper 128
{
__m256i src_ab[7];
__m256i src_a[7];
src_a[0] = _mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
for (int kk = 0; kk < 6; ++kk) {
data += src_stride;
src_a[kk + 1] =
_mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
src_ab[kk] =
_mm256_permute2x128_si256(src_a[kk], src_a[kk + 1], 0x20);
}
src6 = src_a[6];
s[0] = _mm256_unpacklo_epi8(src_ab[0], src_ab[1]);
s[1] = _mm256_unpacklo_epi8(src_ab[2], src_ab[3]);
s[2] = _mm256_unpacklo_epi8(src_ab[4], src_ab[5]);
s[4] = _mm256_unpackhi_epi8(src_ab[0], src_ab[1]);
s[5] = _mm256_unpackhi_epi8(src_ab[2], src_ab[3]);
s[6] = _mm256_unpackhi_epi8(src_ab[4], src_ab[5]);
}
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[4] = s[5];
s[5] = s[6];
s[6] = s[7];
for (i = 0; i < h; i += 2) {
data = &src_ptr[(i + 7) * src_stride + j];
const __m256i src7 =
_mm256_castsi128_si256(_mm_loadu_si128((__m128i *)data));
const __m256i src_67a = _mm256_permute2x128_si256(src6, src7, 0x20);
src6 = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)(data + src_stride)));
const __m256i src_78a = _mm256_permute2x128_si256(src7, src6, 0x20);
s[3] = _mm256_unpacklo_epi8(src_67a, src_78a);
s[7] = _mm256_unpackhi_epi8(src_67a, src_78a);
__m256i res_lo = convolve_lowbd(s, coeffs);
res_lo = _mm256_add_epi16(res_lo, offset_const_1);
const __m256i res_lo_0_32b = _mm256_unpacklo_epi16(res_lo, zero);
const __m256i res_lo_0_shift =
_mm256_slli_epi32(res_lo_0_32b, left_shift);
const __m256i res_lo_0_round = _mm256_sra_epi32(
_mm256_add_epi32(res_lo_0_shift, round_const), round_shift);
const __m256i res_lo_1_32b = _mm256_unpackhi_epi16(res_lo, zero);
const __m256i res_lo_1_shift =
_mm256_slli_epi32(res_lo_1_32b, left_shift);
const __m256i res_lo_1_round = _mm256_sra_epi32(
_mm256_add_epi32(res_lo_1_shift, round_const), round_shift);
const __m256i res_lo_round =
_mm256_packs_epi32(res_lo_0_round, res_lo_1_round);
const __m256i res_lo_unsigned =
_mm256_add_epi16(res_lo_round, offset_const_2);
if (w - j < 16) {
if (do_average) {
const __m256i data_ref_0 =
load_line2_avx2(&dst[i * dst_stride + j],
&dst[i * dst_stride + j + dst_stride]);
const __m256i comp_avg_res = comp_avg(&data_ref_0, &res_lo_unsigned,
&wt, use_dist_wtd_comp_avg);
const __m256i round_result = convolve_rounding(
&comp_avg_res, &offset_const, &rounding_const, rounding_shift);
const __m256i res_8 =
_mm256_packus_epi16(round_result, round_result);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
if (w - j > 4) {
_mm_storel_epi64((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_storel_epi64(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])),
res_1);
} else {
*(uint32_t *)(&dst0[i * dst_stride0 + j]) =
_mm_cvtsi128_si32(res_0);
*(uint32_t *)(&dst0[i * dst_stride0 + j + dst_stride0]) =
_mm_cvtsi128_si32(res_1);
}
} else {
const __m128i res_0 = _mm256_castsi256_si128(res_lo_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_0);
const __m128i res_1 = _mm256_extracti128_si256(res_lo_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_1);
}
} else {
__m256i res_hi = convolve_lowbd(s + 4, coeffs);
res_hi = _mm256_add_epi16(res_hi, offset_const_1);
const __m256i res_hi_0_32b = _mm256_unpacklo_epi16(res_hi, zero);
const __m256i res_hi_0_shift =
_mm256_slli_epi32(res_hi_0_32b, left_shift);
const __m256i res_hi_0_round = _mm256_sra_epi32(
_mm256_add_epi32(res_hi_0_shift, round_const), round_shift);
const __m256i res_hi_1_32b = _mm256_unpackhi_epi16(res_hi, zero);
const __m256i res_hi_1_shift =
_mm256_slli_epi32(res_hi_1_32b, left_shift);
const __m256i res_hi_1_round = _mm256_sra_epi32(
_mm256_add_epi32(res_hi_1_shift, round_const), round_shift);
const __m256i res_hi_round =
_mm256_packs_epi32(res_hi_0_round, res_hi_1_round);
const __m256i res_hi_unsigned =
_mm256_add_epi16(res_hi_round, offset_const_2);
if (do_average) {
const __m256i data_ref_0_lo =
load_line2_avx2(&dst[i * dst_stride + j],
&dst[i * dst_stride + j + dst_stride]);
const __m256i data_ref_0_hi =
load_line2_avx2(&dst[i * dst_stride + j + 8],
&dst[i * dst_stride + j + 8 + dst_stride]);
const __m256i comp_avg_res_lo = comp_avg(
&data_ref_0_lo, &res_lo_unsigned, &wt, use_dist_wtd_comp_avg);
const __m256i comp_avg_res_hi = comp_avg(
&data_ref_0_hi, &res_hi_unsigned, &wt, use_dist_wtd_comp_avg);
const __m256i round_result_lo =
convolve_rounding(&comp_avg_res_lo, &offset_const,
&rounding_const, rounding_shift);
const __m256i round_result_hi =
convolve_rounding(&comp_avg_res_hi, &offset_const,
&rounding_const, rounding_shift);
const __m256i res_8 =
_mm256_packus_epi16(round_result_lo, round_result_hi);
const __m128i res_0 = _mm256_castsi256_si128(res_8);
const __m128i res_1 = _mm256_extracti128_si256(res_8, 1);
_mm_store_si128((__m128i *)(&dst0[i * dst_stride0 + j]), res_0);
_mm_store_si128(
(__m128i *)((&dst0[i * dst_stride0 + j + dst_stride0])), res_1);
} else {
const __m128i res_lo_0 = _mm256_castsi256_si128(res_lo_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j]), res_lo_0);
const __m128i res_lo_1 =
_mm256_extracti128_si256(res_lo_unsigned, 1);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + dst_stride]),
res_lo_1);
const __m128i res_hi_0 = _mm256_castsi256_si128(res_hi_unsigned);
_mm_store_si128((__m128i *)(&dst[i * dst_stride + j + 8]),
res_hi_0);
const __m128i res_hi_1 =
_mm256_extracti128_si256(res_hi_unsigned, 1);
_mm_store_si128(
(__m128i *)(&dst[i * dst_stride + j + 8 + dst_stride]),
res_hi_1);
}
}
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[4] = s[5];
s[5] = s[6];
s[6] = s[7];
}
}
}
}
@ -348,12 +603,9 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride,
const int bd = 8;
DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + MAX_FILTER_TAP) * 8]);
int im_h = h + filter_params_y->taps - 1;
int im_stride = 8;
int i, j;
const int fo_vert = filter_params_y->taps / 2 - 1;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
int i, is_horiz_4tap = 0, is_vert_4tap = 0;
const __m256i wt = unpack_weights_avx2(conv_params);
const int do_average = conv_params->do_average;
const int use_dist_wtd_comp_avg = conv_params->use_dist_wtd_comp_avg;
@ -364,18 +616,9 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride,
const int rounding_shift =
2 * FILTER_BITS - conv_params->round_0 - conv_params->round_1;
const __m256i rounding_const = _mm256_set1_epi16((1 << rounding_shift) >> 1);
__m256i filt[4], s[8], coeffs_x[4], coeffs_y[4];
assert(conv_params->round_0 > 0);
filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2);
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_x);
prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_y);
const __m256i round_const_h = _mm256_set1_epi16(
((1 << (conv_params->round_0 - 1)) >> 1) + (1 << (bd + FILTER_BITS - 2)));
const __m128i round_shift_h = _mm_cvtsi32_si128(conv_params->round_0 - 1);
@ -385,9 +628,29 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride,
(1 << (bd + 2 * FILTER_BITS - conv_params->round_0 - 1)));
const __m128i round_shift_v = _mm_cvtsi32_si128(conv_params->round_1);
for (j = 0; j < w; j += 8) {
/* Horizontal filter */
{
__m256i filt[4], coeffs_x[4], coeffs_y[4];
filt[0] = _mm256_load_si256((__m256i const *)filt_global_avx2);
filt[1] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32));
prepare_coeffs_lowbd(filter_params_x, subpel_x_q4, coeffs_x);
prepare_coeffs(filter_params_y, subpel_y_q4, coeffs_y);
// Condition for checking valid horz_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_x[0], coeffs_x[3]), 0)))
is_horiz_4tap = 1;
// Condition for checking valid vert_filt taps
if (!(_mm256_extract_epi32(_mm256_or_si256(coeffs_y[0], coeffs_y[3]), 0)))
is_vert_4tap = 1;
if (is_horiz_4tap) {
int im_h = h + filter_params_y->taps - 1;
const int fo_vert = filter_params_y->taps / 2 - 1;
const int fo_horiz = 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
for (int j = 0; j < w; j += 8) {
/* Horizontal filter */
const uint8_t *src_h = src_ptr + j;
for (i = 0; i < im_h; i += 2) {
__m256i data =
@ -396,49 +659,59 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride,
data = _mm256_inserti128_si256(
data, _mm_loadu_si128((__m128i *)(src_h + src_stride)), 1);
src_h += (src_stride << 1);
__m256i res = convolve_lowbd_x(data, coeffs_x, filt);
__m256i res = convolve_lowbd_x_4tap(data, coeffs_x + 1, filt);
res = _mm256_sra_epi16(_mm256_add_epi16(res, round_const_h),
round_shift_h);
_mm256_store_si256((__m256i *)&im_block[i * im_stride], res);
}
DIST_WTD_CONVOLVE_VERTICAL_FILTER_8TAP;
}
} else if (is_vert_4tap) {
int im_h = h + 3;
const int fo_vert = 1;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
/* Vertical filter */
{
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
for (int j = 0; j < w; j += 8) {
/* Horizontal filter */
const uint8_t *src_h = src_ptr + j;
DIST_WTD_CONVOLVE_HORIZONTAL_FILTER_8TAP;
/* Vertical filter */
__m256i s[6];
__m256i s0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride));
__m256i s1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride));
__m256i s2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride));
__m256i s3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride));
__m256i s4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride));
__m256i s5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride));
s[0] = _mm256_unpacklo_epi16(s0, s1);
s[1] = _mm256_unpacklo_epi16(s2, s3);
s[2] = _mm256_unpacklo_epi16(s4, s5);
s[4] = _mm256_unpackhi_epi16(s0, s1);
s[5] = _mm256_unpackhi_epi16(s2, s3);
s[6] = _mm256_unpackhi_epi16(s4, s5);
s[3] = _mm256_unpackhi_epi16(s0, s1);
s[4] = _mm256_unpackhi_epi16(s2, s3);
for (i = 0; i < h; i += 2) {
const int16_t *data = &im_block[i * im_stride];
const __m256i s6 =
_mm256_loadu_si256((__m256i *)(data + 6 * im_stride));
const __m256i s7 =
_mm256_loadu_si256((__m256i *)(data + 7 * im_stride));
const __m256i s4 =
_mm256_loadu_si256((__m256i *)(data + 4 * im_stride));
const __m256i s5 =
_mm256_loadu_si256((__m256i *)(data + 5 * im_stride));
s[3] = _mm256_unpacklo_epi16(s6, s7);
s[7] = _mm256_unpackhi_epi16(s6, s7);
s[2] = _mm256_unpacklo_epi16(s4, s5);
s[5] = _mm256_unpackhi_epi16(s4, s5);
const __m256i res_a = convolve(s, coeffs_y);
const __m256i res_a = convolve_4tap(s, coeffs_y + 1);
const __m256i res_a_round = _mm256_sra_epi32(
_mm256_add_epi32(res_a, round_const_v), round_shift_v);
if (w - j > 4) {
const __m256i res_b = convolve(s + 4, coeffs_y);
const __m256i res_b = convolve_4tap(s + 3, coeffs_y + 1);
const __m256i res_b_round = _mm256_sra_epi32(
_mm256_add_epi32(res_b, round_const_v), round_shift_v);
const __m256i res_16b = _mm256_packs_epi32(res_a_round, res_b_round);
@ -504,16 +777,28 @@ void av1_dist_wtd_convolve_2d_avx2(const uint8_t *src, int src_stride,
res_1);
}
}
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = s[4];
s[4] = s[5];
s[5] = s[6];
s[6] = s[7];
}
}
} else {
int im_h = h + filter_params_y->taps - 1;
const int fo_vert = filter_params_y->taps / 2 - 1;
const int fo_horiz = filter_params_x->taps / 2 - 1;
const uint8_t *const src_ptr = src - fo_vert * src_stride - fo_horiz;
filt[2] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 2));
filt[3] = _mm256_load_si256((__m256i const *)(filt_global_avx2 + 32 * 3));
for (int j = 0; j < w; j += 8) {
/* Horizontal filter */
const uint8_t *src_h = src_ptr + j;
DIST_WTD_CONVOLVE_HORIZONTAL_FILTER_8TAP;
DIST_WTD_CONVOLVE_VERTICAL_FILTER_8TAP;
}
}
}

View file

@ -17,7 +17,6 @@
#include "av1/common/convolve.h"
#include "aom_dsp/aom_dsp_common.h"
#include "aom_dsp/aom_filter.h"
#include "aom_dsp/x86/convolve_avx2.h"
#include "aom_dsp/x86/synonyms.h"
#include "aom_dsp/x86/synonyms_avx2.h"
@ -26,207 +25,236 @@
// on the left.
// A row of, say, 8-bit pixels with values p0, p1, p2, ..., p30, p31 will be
// loaded and stored as [ p31 ... p17 p16 ][ p15 ... p1 p0 ].
// Exploiting the range of wiener filter coefficients,
// horizontal filtering can be done in 16 bit intermediate precision.
// The details are as follows :
// Consider the horizontal wiener filter coefficients of the following form :
// [C0, C1, C2, 2^(FILTER_BITS) -2 * (C0 + C1 + C2), C2, C1, C0]
// Subtracting 2^(FILTER_BITS) from the centre tap we get the following :
// [C0, C1, C2, -2 * (C0 + C1 + C2), C2, C1, C0]
// The sum of the product "C0 * p0 + C1 * p1 + C2 * p2 -2 * (C0 + C1 + C2) * p3
// + C2 * p4 + C1 * p5 + C0 * p6" would be in the range of signed 16 bit
// precision. Finally, after rounding the above result by round_0, we multiply
// the centre pixel by 2^(FILTER_BITS - round_0) and add it to get the
// horizontal filter output.
void av1_wiener_convolve_add_src_avx2(const uint8_t *src, ptrdiff_t src_stride,
uint8_t *dst, ptrdiff_t dst_stride,
const int16_t *filter_x, int x_step_q4,
const int16_t *filter_y, int y_step_q4,
int w, int h,
const ConvolveParams *conv_params) {
const int bd = 8;
assert(x_step_q4 == 16 && y_step_q4 == 16);
assert(!(w & 7));
(void)x_step_q4;
(void)y_step_q4;
DECLARE_ALIGNED(32, int16_t, im_block[(MAX_SB_SIZE + SUBPEL_TAPS) * 8]);
int im_h = h + SUBPEL_TAPS - 2;
int im_stride = 8;
memset(im_block + (im_h * im_stride), 0, MAX_SB_SIZE);
int i, j;
const int center_tap = (SUBPEL_TAPS - 1) / 2;
DECLARE_ALIGNED(32, uint16_t,
temp[(MAX_SB_SIZE + SUBPEL_TAPS - 1) * MAX_SB_SIZE]);
int intermediate_height = h + SUBPEL_TAPS - 2;
memset(temp + (intermediate_height * MAX_SB_SIZE), 0, MAX_SB_SIZE);
const int center_tap = ((SUBPEL_TAPS - 1) / 2);
const uint8_t *const src_ptr = src - center_tap * src_stride - center_tap;
__m256i filt[4], coeffs_h[4], coeffs_v[4], filt_center;
assert(conv_params->round_0 > 0);
filt[0] = _mm256_load_si256((__m256i const *)filt1_global_avx2);
filt[1] = _mm256_load_si256((__m256i const *)filt2_global_avx2);
filt[2] = _mm256_load_si256((__m256i const *)filt3_global_avx2);
filt[3] = _mm256_load_si256((__m256i const *)filt4_global_avx2);
filt_center = _mm256_load_si256((__m256i const *)filt_center_global_avx2);
const __m128i coeffs_x = _mm_loadu_si128((__m128i *)filter_x);
const __m256i filter_coeffs_x = _mm256_broadcastsi128_si256(coeffs_x);
// coeffs 0 1 0 1 0 1 0 1
coeffs_h[0] =
_mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0200u));
// coeffs 2 3 2 3 2 3 2 3
coeffs_h[1] =
_mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0604u));
// coeffs 4 5 4 5 4 5 4 5
coeffs_h[2] =
_mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0a08u));
// coeffs 6 7 6 7 6 7 6 7
coeffs_h[3] =
_mm256_shuffle_epi8(filter_coeffs_x, _mm256_set1_epi16(0x0e0cu));
const __m256i round_const_h =
_mm256_set1_epi16((1 << (conv_params->round_0 - 1)));
const __m128i round_shift_h = _mm_cvtsi32_si128(conv_params->round_0);
const __m128i zero_128 = _mm_setzero_si128();
const __m256i zero_256 = _mm256_setzero_si256();
// Add an offset to account for the "add_src" part of the convolve function.
const __m128i zero_128 = _mm_setzero_si128();
const __m128i offset_0 = _mm_insert_epi16(zero_128, 1 << FILTER_BITS, 3);
const __m128i coeffs_y = _mm_add_epi16(xx_loadu_128(filter_y), offset_0);
const __m128i offset = _mm_insert_epi16(zero_128, 1 << FILTER_BITS, 3);
const __m256i filter_coeffs_y = _mm256_broadcastsi128_si256(coeffs_y);
const __m256i clamp_low = zero_256;
const __m256i clamp_high =
_mm256_set1_epi16(WIENER_CLAMP_LIMIT(conv_params->round_0, bd) - 1);
// coeffs 0 1 0 1 0 1 0 1
coeffs_v[0] = _mm256_shuffle_epi32(filter_coeffs_y, 0x00);
// coeffs 2 3 2 3 2 3 2 3
coeffs_v[1] = _mm256_shuffle_epi32(filter_coeffs_y, 0x55);
// coeffs 4 5 4 5 4 5 4 5
coeffs_v[2] = _mm256_shuffle_epi32(filter_coeffs_y, 0xaa);
// coeffs 6 7 6 7 6 7 6 7
coeffs_v[3] = _mm256_shuffle_epi32(filter_coeffs_y, 0xff);
/* Horizontal filter */
{
// coeffs [ f7 f6 f5 f4 f3 f2 f1 f0 ]
const __m128i coeffs_x = _mm_add_epi16(xx_loadu_128(filter_x), offset);
const __m256i round_const_v =
_mm256_set1_epi32((1 << (conv_params->round_1 - 1)));
const __m128i round_shift_v = _mm_cvtsi32_si128(conv_params->round_1);
// coeffs [ f3 f2 f3 f2 f1 f0 f1 f0 ]
const __m128i coeffs_0123 = _mm_unpacklo_epi32(coeffs_x, coeffs_x);
// coeffs [ f7 f6 f7 f6 f5 f4 f5 f4 ]
const __m128i coeffs_4567 = _mm_unpackhi_epi32(coeffs_x, coeffs_x);
for (j = 0; j < w; j += 8) {
for (i = 0; i < im_h; i += 2) {
__m256i data = _mm256_castsi128_si256(
_mm_loadu_si128((__m128i *)&src_ptr[(i * src_stride) + j]));
// coeffs [ f1 f0 f1 f0 f1 f0 f1 f0 ]
const __m128i coeffs_01_128 = _mm_unpacklo_epi64(coeffs_0123, coeffs_0123);
// coeffs [ f3 f2 f3 f2 f3 f2 f3 f2 ]
const __m128i coeffs_23_128 = _mm_unpackhi_epi64(coeffs_0123, coeffs_0123);
// coeffs [ f5 f4 f5 f4 f5 f4 f5 f4 ]
const __m128i coeffs_45_128 = _mm_unpacklo_epi64(coeffs_4567, coeffs_4567);
// coeffs [ f7 f6 f7 f6 f7 f6 f7 f6 ]
const __m128i coeffs_67_128 = _mm_unpackhi_epi64(coeffs_4567, coeffs_4567);
// Load the next line
if (i + 1 < im_h)
data = _mm256_inserti128_si256(
data,
_mm_loadu_si128(
(__m128i *)&src_ptr[(i * src_stride) + j + src_stride]),
1);
// coeffs [ f1 f0 f1 f0 f1 f0 f1 f0 ][ f1 f0 f1 f0 f1 f0 f1 f0 ]
const __m256i coeffs_01 = yy_set_m128i(coeffs_01_128, coeffs_01_128);
// coeffs [ f3 f2 f3 f2 f3 f2 f3 f2 ][ f3 f2 f3 f2 f3 f2 f3 f2 ]
const __m256i coeffs_23 = yy_set_m128i(coeffs_23_128, coeffs_23_128);
// coeffs [ f5 f4 f5 f4 f5 f4 f5 f4 ][ f5 f4 f5 f4 f5 f4 f5 f4 ]
const __m256i coeffs_45 = yy_set_m128i(coeffs_45_128, coeffs_45_128);
// coeffs [ f7 f6 f7 f6 f7 f6 f7 f6 ][ f7 f6 f7 f6 f7 f6 f7 f6 ]
const __m256i coeffs_67 = yy_set_m128i(coeffs_67_128, coeffs_67_128);
__m256i res = convolve_lowbd_x(data, coeffs_h, filt);
const __m256i round_const = _mm256_set1_epi32(
(1 << (conv_params->round_0 - 1)) + (1 << (bd + FILTER_BITS - 1)));
res =
_mm256_sra_epi16(_mm256_add_epi16(res, round_const_h), round_shift_h);
for (int i = 0; i < intermediate_height; ++i) {
for (int j = 0; j < w; j += 16) {
const uint8_t *data_ij = src_ptr + i * src_stride + j;
__m256i data_0 = _mm256_shuffle_epi8(data, filt_center);
// Load 8-bit src data
const __m128i data_0 = xx_loadu_128(data_ij + 0);
const __m128i data_1 = xx_loadu_128(data_ij + 1);
const __m128i data_2 = xx_loadu_128(data_ij + 2);
const __m128i data_3 = xx_loadu_128(data_ij + 3);
const __m128i data_4 = xx_loadu_128(data_ij + 4);
const __m128i data_5 = xx_loadu_128(data_ij + 5);
const __m128i data_6 = xx_loadu_128(data_ij + 6);
const __m128i data_7 = xx_loadu_128(data_ij + 7);
// multiply the center pixel by 2^(FILTER_BITS - round_0) and add it to
// the result
data_0 = _mm256_slli_epi16(data_0, FILTER_BITS - conv_params->round_0);
res = _mm256_add_epi16(res, data_0);
// (Zero-)Extend 8-bit data to 16-bit data
const __m256i src_0 = _mm256_cvtepu8_epi16(data_0);
const __m256i src_1 = _mm256_cvtepu8_epi16(data_1);
const __m256i src_2 = _mm256_cvtepu8_epi16(data_2);
const __m256i src_3 = _mm256_cvtepu8_epi16(data_3);
const __m256i src_4 = _mm256_cvtepu8_epi16(data_4);
const __m256i src_5 = _mm256_cvtepu8_epi16(data_5);
const __m256i src_6 = _mm256_cvtepu8_epi16(data_6);
const __m256i src_7 = _mm256_cvtepu8_epi16(data_7);
_mm256_store_si256((__m256i *)&im_block[i * im_stride], res);
}
// Multiply src data by filter coeffs and sum pairs
const __m256i res_0 = _mm256_madd_epi16(src_0, coeffs_01);
const __m256i res_1 = _mm256_madd_epi16(src_1, coeffs_01);
const __m256i res_2 = _mm256_madd_epi16(src_2, coeffs_23);
const __m256i res_3 = _mm256_madd_epi16(src_3, coeffs_23);
const __m256i res_4 = _mm256_madd_epi16(src_4, coeffs_45);
const __m256i res_5 = _mm256_madd_epi16(src_5, coeffs_45);
const __m256i res_6 = _mm256_madd_epi16(src_6, coeffs_67);
const __m256i res_7 = _mm256_madd_epi16(src_7, coeffs_67);
/* Vertical filter */
{
__m256i src_0 = _mm256_loadu_si256((__m256i *)(im_block + 0 * im_stride));
__m256i src_1 = _mm256_loadu_si256((__m256i *)(im_block + 1 * im_stride));
__m256i src_2 = _mm256_loadu_si256((__m256i *)(im_block + 2 * im_stride));
__m256i src_3 = _mm256_loadu_si256((__m256i *)(im_block + 3 * im_stride));
__m256i src_4 = _mm256_loadu_si256((__m256i *)(im_block + 4 * im_stride));
__m256i src_5 = _mm256_loadu_si256((__m256i *)(im_block + 5 * im_stride));
// Calculate scalar product for even- and odd-indices separately,
// increasing to 32-bit precision
const __m256i res_even_sum = _mm256_add_epi32(
_mm256_add_epi32(res_0, res_4), _mm256_add_epi32(res_2, res_6));
const __m256i res_odd_sum = _mm256_add_epi32(
_mm256_add_epi32(res_1, res_5), _mm256_add_epi32(res_3, res_7));
__m256i s[8];
s[0] = _mm256_unpacklo_epi16(src_0, src_1);
s[1] = _mm256_unpacklo_epi16(src_2, src_3);
s[2] = _mm256_unpacklo_epi16(src_4, src_5);
const __m256i res_even = _mm256_srai_epi32(
_mm256_add_epi32(res_even_sum, round_const), conv_params->round_0);
const __m256i res_odd = _mm256_srai_epi32(
_mm256_add_epi32(res_odd_sum, round_const), conv_params->round_0);
s[4] = _mm256_unpackhi_epi16(src_0, src_1);
s[5] = _mm256_unpackhi_epi16(src_2, src_3);
s[6] = _mm256_unpackhi_epi16(src_4, src_5);
// Reduce to 16-bit precision and pack even- and odd-index results
// back into one register. The _mm256_packs_epi32 intrinsic returns
// a register with the pixels ordered as follows:
// [ 15 13 11 9 14 12 10 8 ] [ 7 5 3 1 6 4 2 0 ]
const __m256i res = _mm256_packs_epi32(res_even, res_odd);
const __m256i res_clamped =
_mm256_min_epi16(_mm256_max_epi16(res, clamp_low), clamp_high);
for (i = 0; i < h - 1; i += 2) {
const int16_t *data = &im_block[i * im_stride];
const __m256i s6 =
_mm256_loadu_si256((__m256i *)(data + 6 * im_stride));
const __m256i s7 =
_mm256_loadu_si256((__m256i *)(data + 7 * im_stride));
s[3] = _mm256_unpacklo_epi16(s6, s7);
s[7] = _mm256_unpackhi_epi16(s6, s7);
__m256i res_a = convolve(s, coeffs_v);
__m256i res_b = convolve(s + 4, coeffs_v);
const __m256i res_a_round = _mm256_sra_epi32(
_mm256_add_epi32(res_a, round_const_v), round_shift_v);
const __m256i res_b_round = _mm256_sra_epi32(
_mm256_add_epi32(res_b, round_const_v), round_shift_v);
/* rounding code */
// 16 bit conversion
const __m256i res_16bit = _mm256_packs_epi32(res_a_round, res_b_round);
// 8 bit conversion and saturation to uint8
const __m256i res_8b = _mm256_packus_epi16(res_16bit, res_16bit);
const __m128i res_0 = _mm256_castsi256_si128(res_8b);
const __m128i res_1 = _mm256_extracti128_si256(res_8b, 1);
// Store values into the destination buffer
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j];
__m128i *const p_1 = (__m128i *)&dst[i * dst_stride + j + dst_stride];
_mm_storel_epi64(p_0, res_0);
_mm_storel_epi64(p_1, res_1);
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[4] = s[5];
s[5] = s[6];
s[6] = s[7];
// Store in a temporary array
yy_storeu_256(temp + i * MAX_SB_SIZE + j, res_clamped);
}
if (h - i) {
s[0] = _mm256_permute2x128_si256(s[0], s[4], 0x20);
s[1] = _mm256_permute2x128_si256(s[1], s[5], 0x20);
s[2] = _mm256_permute2x128_si256(s[2], s[6], 0x20);
}
}
const int16_t *data = &im_block[i * im_stride];
const __m128i s6_ = _mm_loadu_si128((__m128i *)(data + 6 * im_stride));
const __m128i s7_ = _mm_loadu_si128((__m128i *)(data + 7 * im_stride));
/* Vertical filter */
{
// coeffs [ g7 g6 g5 g4 g3 g2 g1 g0 ]
const __m128i coeffs_y = _mm_add_epi16(xx_loadu_128(filter_y), offset);
__m128i s3 = _mm_unpacklo_epi16(s6_, s7_);
__m128i s7 = _mm_unpackhi_epi16(s6_, s7_);
// coeffs [ g3 g2 g3 g2 g1 g0 g1 g0 ]
const __m128i coeffs_0123 = _mm_unpacklo_epi32(coeffs_y, coeffs_y);
// coeffs [ g7 g6 g7 g6 g5 g4 g5 g4 ]
const __m128i coeffs_4567 = _mm_unpackhi_epi32(coeffs_y, coeffs_y);
s[3] = _mm256_inserti128_si256(_mm256_castsi128_si256(s3), s7, 1);
__m256i convolveres = convolve(s, coeffs_v);
// coeffs [ g1 g0 g1 g0 g1 g0 g1 g0 ]
const __m128i coeffs_01_128 = _mm_unpacklo_epi64(coeffs_0123, coeffs_0123);
// coeffs [ g3 g2 g3 g2 g3 g2 g3 g2 ]
const __m128i coeffs_23_128 = _mm_unpackhi_epi64(coeffs_0123, coeffs_0123);
// coeffs [ g5 g4 g5 g4 g5 g4 g5 g4 ]
const __m128i coeffs_45_128 = _mm_unpacklo_epi64(coeffs_4567, coeffs_4567);
// coeffs [ g7 g6 g7 g6 g7 g6 g7 g6 ]
const __m128i coeffs_67_128 = _mm_unpackhi_epi64(coeffs_4567, coeffs_4567);
const __m256i res_round = _mm256_sra_epi32(
_mm256_add_epi32(convolveres, round_const_v), round_shift_v);
// coeffs [ g1 g0 g1 g0 g1 g0 g1 g0 ][ g1 g0 g1 g0 g1 g0 g1 g0 ]
const __m256i coeffs_01 = yy_set_m128i(coeffs_01_128, coeffs_01_128);
// coeffs [ g3 g2 g3 g2 g3 g2 g3 g2 ][ g3 g2 g3 g2 g3 g2 g3 g2 ]
const __m256i coeffs_23 = yy_set_m128i(coeffs_23_128, coeffs_23_128);
// coeffs [ g5 g4 g5 g4 g5 g4 g5 g4 ][ g5 g4 g5 g4 g5 g4 g5 g4 ]
const __m256i coeffs_45 = yy_set_m128i(coeffs_45_128, coeffs_45_128);
// coeffs [ g7 g6 g7 g6 g7 g6 g7 g6 ][ g7 g6 g7 g6 g7 g6 g7 g6 ]
const __m256i coeffs_67 = yy_set_m128i(coeffs_67_128, coeffs_67_128);
/* rounding code */
// 16 bit conversion
__m128i reslo = _mm256_castsi256_si128(res_round);
__m128i reshi = _mm256_extracti128_si256(res_round, 1);
const __m128i res_16bit = _mm_packus_epi32(reslo, reshi);
const __m256i round_const =
_mm256_set1_epi32((1 << (conv_params->round_1 - 1)) -
(1 << (bd + conv_params->round_1 - 1)));
// 8 bit conversion and saturation to uint8
const __m128i res_8b = _mm_packus_epi16(res_16bit, res_16bit);
__m128i *const p_0 = (__m128i *)&dst[i * dst_stride + j];
_mm_storel_epi64(p_0, res_8b);
for (int i = 0; i < h; ++i) {
for (int j = 0; j < w; j += 16) {
const uint16_t *data_ij = temp + i * MAX_SB_SIZE + j;
// Load 16-bit data from the output of the horizontal filter in
// which the pixels are ordered as follows:
// [ 15 13 11 9 14 12 10 8 ] [ 7 5 3 1 6 4 2 0 ]
const __m256i data_0 = yy_loadu_256(data_ij + 0 * MAX_SB_SIZE);
const __m256i data_1 = yy_loadu_256(data_ij + 1 * MAX_SB_SIZE);
const __m256i data_2 = yy_loadu_256(data_ij + 2 * MAX_SB_SIZE);
const __m256i data_3 = yy_loadu_256(data_ij + 3 * MAX_SB_SIZE);
const __m256i data_4 = yy_loadu_256(data_ij + 4 * MAX_SB_SIZE);
const __m256i data_5 = yy_loadu_256(data_ij + 5 * MAX_SB_SIZE);
const __m256i data_6 = yy_loadu_256(data_ij + 6 * MAX_SB_SIZE);
const __m256i data_7 = yy_loadu_256(data_ij + 7 * MAX_SB_SIZE);
// Filter the even-indices, increasing to 32-bit precision
const __m256i src_0 = _mm256_unpacklo_epi16(data_0, data_1);
const __m256i src_2 = _mm256_unpacklo_epi16(data_2, data_3);
const __m256i src_4 = _mm256_unpacklo_epi16(data_4, data_5);
const __m256i src_6 = _mm256_unpacklo_epi16(data_6, data_7);
const __m256i res_0 = _mm256_madd_epi16(src_0, coeffs_01);
const __m256i res_2 = _mm256_madd_epi16(src_2, coeffs_23);
const __m256i res_4 = _mm256_madd_epi16(src_4, coeffs_45);
const __m256i res_6 = _mm256_madd_epi16(src_6, coeffs_67);
const __m256i res_even = _mm256_add_epi32(
_mm256_add_epi32(res_0, res_2), _mm256_add_epi32(res_4, res_6));
// Filter the odd-indices, increasing to 32-bit precision
const __m256i src_1 = _mm256_unpackhi_epi16(data_0, data_1);
const __m256i src_3 = _mm256_unpackhi_epi16(data_2, data_3);
const __m256i src_5 = _mm256_unpackhi_epi16(data_4, data_5);
const __m256i src_7 = _mm256_unpackhi_epi16(data_6, data_7);
const __m256i res_1 = _mm256_madd_epi16(src_1, coeffs_01);
const __m256i res_3 = _mm256_madd_epi16(src_3, coeffs_23);
const __m256i res_5 = _mm256_madd_epi16(src_5, coeffs_45);
const __m256i res_7 = _mm256_madd_epi16(src_7, coeffs_67);
const __m256i res_odd = _mm256_add_epi32(
_mm256_add_epi32(res_1, res_3), _mm256_add_epi32(res_5, res_7));
// Pixels are currently in the following order:
// res_even order: [ 14 12 10 8 ] [ 6 4 2 0 ]
// res_odd order: [ 15 13 11 9 ] [ 7 5 3 1 ]
//
// Rearrange the pixels into the following order:
// res_lo order: [ 11 10 9 8 ] [ 3 2 1 0 ]
// res_hi order: [ 15 14 13 12 ] [ 7 6 5 4 ]
const __m256i res_lo = _mm256_unpacklo_epi32(res_even, res_odd);
const __m256i res_hi = _mm256_unpackhi_epi32(res_even, res_odd);
const __m256i res_lo_round = _mm256_srai_epi32(
_mm256_add_epi32(res_lo, round_const), conv_params->round_1);
const __m256i res_hi_round = _mm256_srai_epi32(
_mm256_add_epi32(res_hi, round_const), conv_params->round_1);
// Reduce to 16-bit precision and pack into the correct order:
// [ 15 14 13 12 11 10 9 8 ][ 7 6 5 4 3 2 1 0 ]
const __m256i res_16bit =
_mm256_packs_epi32(res_lo_round, res_hi_round);
// Reduce to 8-bit precision. This messes up the order:
// [ - - - - - - - - 15 14 13 12 11 10 9 8 ]
// [ - - - - - - - - 7 6 5 4 3 2 1 0 ]
const __m256i res_8bit =
_mm256_packus_epi16(res_16bit, zero_256 /* don't care value */);
// Swap the two central 32-bit values to get the order:
// [ - - - - - - - - - - - - - - - - ]
// [ 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ]
const __m256i res_8bit2 = _mm256_permute4x64_epi64(res_8bit, 0xd8);
// Store the lower 128-bit lane in the dst array
xx_storeu_128(dst + i * dst_stride + j,
_mm256_castsi256_si128(res_8bit2));
}
}
}

View file

@ -781,7 +781,7 @@ static INLINE void dec_build_inter_predictors(const AV1_COMMON *cm,
dec_calc_subpel_params(xd, sf, mv, plane, pre_x, pre_y, 0, 0, pre_buf,
&subpel_params[ref], bw, bh, &block, mi_x, mi_y,
&scaled_mv, &subpel_x_mv, &subpel_y_mv);
pre[ref] = pre_buf->buf0 + block.y0 * pre_buf->stride + block.x0;
pre[ref] = pre_buf->buf0 + (int64_t)block.y0 * pre_buf->stride + block.x0;
src_stride[ref] = pre_buf->stride;
highbd = is_cur_buf_hbd(xd);
@ -4240,6 +4240,25 @@ void av1_read_film_grain_params(AV1_COMMON *cm,
if (!pars->update_parameters) {
// inherit parameters from a previous reference frame
int film_grain_params_ref_idx = aom_rb_read_literal(rb, 3);
// Section 6.8.20: It is a requirement of bitstream conformance that
// film_grain_params_ref_idx is equal to ref_frame_idx[ j ] for some value
// of j in the range 0 to REFS_PER_FRAME - 1.
int found = 0;
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
if (film_grain_params_ref_idx == cm->remapped_ref_idx[i]) {
found = 1;
break;
}
}
if (!found) {
aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
"Invalid film grain reference idx %d. ref_frame_idx = "
"{%d, %d, %d, %d, %d, %d, %d}",
film_grain_params_ref_idx, cm->remapped_ref_idx[0],
cm->remapped_ref_idx[1], cm->remapped_ref_idx[2],
cm->remapped_ref_idx[3], cm->remapped_ref_idx[4],
cm->remapped_ref_idx[5], cm->remapped_ref_idx[6]);
}
RefCntBuffer *const buf = cm->ref_frame_map[film_grain_params_ref_idx];
if (buf == NULL) {
aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
@ -4468,13 +4487,13 @@ void av1_read_timing_info_header(AV1_COMMON *cm,
cm->timing_info.equal_picture_interval =
aom_rb_read_bit(rb); // Equal picture interval bit
if (cm->timing_info.equal_picture_interval) {
cm->timing_info.num_ticks_per_picture =
aom_rb_read_uvlc(rb) + 1; // ticks per picture
if (cm->timing_info.num_ticks_per_picture == 0) {
const uint32_t num_ticks_per_picture_minus_1 = aom_rb_read_uvlc(rb);
if (num_ticks_per_picture_minus_1 == UINT32_MAX) {
aom_internal_error(
&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
"num_ticks_per_picture_minus_1 cannot be (1 << 32) − 1.");
}
cm->timing_info.num_ticks_per_picture = num_ticks_per_picture_minus_1 + 1;
}
}
@ -5179,7 +5198,7 @@ static int read_uncompressed_header(AV1Decoder *pbi,
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Inter frame requests nonexistent reference");
av1_set_frame_refs(cm, lst_ref, gld_ref);
av1_set_frame_refs(cm, cm->remapped_ref_idx, lst_ref, gld_ref);
}
for (int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
@ -5189,7 +5208,7 @@ static int read_uncompressed_header(AV1Decoder *pbi,
// Most of the time, streams start with a keyframe. In that case,
// ref_frame_map will have been filled in at that point and will not
// contain any -1's. However, streams are explicitly allowed to start
// contain any NULLs. However, streams are explicitly allowed to start
// with an intra-only frame, so long as they don't then signal a
// reference to a slot that hasn't been set yet. That's what we are
// checking here.
@ -5319,6 +5338,11 @@ static int read_uncompressed_header(AV1Decoder *pbi,
}
read_tile_info(pbi, rb);
if (!is_min_tile_width_satisfied(cm)) {
aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
"Minimum tile width requirement not satisfied");
}
setup_quantization(cm, rb);
xd->bd = (int)seq_params->bit_depth;

View file

@ -678,11 +678,10 @@ static void read_intrabc_info(AV1_COMMON *const cm, MACROBLOCKD *const xd,
int16_t inter_mode_ctx[MODE_CTX_REF_FRAMES];
int_mv ref_mvs[INTRA_FRAME + 1][MAX_MV_REF_CANDIDATES];
int_mv global_mvs[REF_FRAMES];
av1_find_mv_refs(cm, xd, mbmi, INTRA_FRAME, xd->ref_mv_count,
xd->ref_mv_stack, ref_mvs, global_mvs, mi_row, mi_col,
inter_mode_ctx);
xd->ref_mv_stack, ref_mvs, /*global_mvs=*/NULL, mi_row,
mi_col, inter_mode_ctx);
int_mv nearestmv, nearmv;
@ -1271,9 +1270,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi,
const int is_compound = has_second_ref(mbmi);
MV_REFERENCE_FRAME ref_frame = av1_ref_frame_type(mbmi->ref_frame);
int_mv global_mvs[REF_FRAMES];
av1_find_mv_refs(cm, xd, mbmi, ref_frame, xd->ref_mv_count, xd->ref_mv_stack,
ref_mvs, global_mvs, mi_row, mi_col, inter_mode_ctx);
ref_mvs, /*global_mvs=*/NULL, mi_row, mi_col,
inter_mode_ctx);
int mode_ctx = av1_mode_context_analyzer(inter_mode_ctx, mbmi->ref_frame);
mbmi->ref_mv_idx = 0;
@ -1421,9 +1420,12 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi,
const int comp_index_ctx = get_comp_index_context(cm, xd);
mbmi->compound_idx = aom_read_symbol(
r, ec_ctx->compound_index_cdf[comp_index_ctx], 2, ACCT_STR);
mbmi->interinter_comp.type =
mbmi->compound_idx ? COMPOUND_AVERAGE : COMPOUND_DISTWTD;
} else {
// Distance-weighted compound is disabled, so always use average
mbmi->compound_idx = 1;
mbmi->interinter_comp.type = COMPOUND_AVERAGE;
}
} else {
assert(cm->current_frame.reference_mode != SINGLE_REFERENCE &&
@ -1434,8 +1436,9 @@ static void read_inter_block_mode_info(AV1Decoder *const pbi,
// compound_diffwtd, wedge
if (is_interinter_compound_used(COMPOUND_WEDGE, bsize))
mbmi->interinter_comp.type =
1 + aom_read_symbol(r, ec_ctx->compound_type_cdf[bsize],
COMPOUND_TYPES - 1, ACCT_STR);
COMPOUND_WEDGE + aom_read_symbol(r,
ec_ctx->compound_type_cdf[bsize],
MASKED_COMPOUND_TYPES, ACCT_STR);
else
mbmi->interinter_comp.type = COMPOUND_DIFFWTD;

View file

@ -48,9 +48,9 @@ typedef void (*cfl_store_inter_block_visitor_fn_t)(AV1_COMMON *const cm,
MACROBLOCKD *const xd);
typedef struct ThreadData {
aom_reader *bit_reader;
DECLARE_ALIGNED(32, MACROBLOCKD, xd);
CB_BUFFER cb_buffer_base;
aom_reader *bit_reader;
uint8_t *mc_buf[2];
int32_t mc_buf_size;
int mc_buf_use_highbd; // Boolean: whether the byte pointers stored in

View file

@ -1,192 +0,0 @@
/*
* 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 "config/aom_config.h"
#include "aom_mem/aom_mem.h"
#include "av1/common/reconinter.h"
#include "av1/decoder/dthread.h"
#include "av1/decoder/decoder.h"
// #define DEBUG_THREAD
// TODO(hkuang): Clean up all the #ifdef in this file.
void av1_frameworker_lock_stats(AVxWorker *const worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const worker_data = worker->data1;
pthread_mutex_lock(&worker_data->stats_mutex);
#else
(void)worker;
#endif
}
void av1_frameworker_unlock_stats(AVxWorker *const worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const worker_data = worker->data1;
pthread_mutex_unlock(&worker_data->stats_mutex);
#else
(void)worker;
#endif
}
void av1_frameworker_signal_stats(AVxWorker *const worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const worker_data = worker->data1;
// TODO(hkuang): Fix the pthread_cond_broadcast in windows wrapper.
#if defined(_WIN32) && !HAVE_PTHREAD_H
pthread_cond_signal(&worker_data->stats_cond);
#else
pthread_cond_broadcast(&worker_data->stats_cond);
#endif
#else
(void)worker;
#endif
}
// This macro prevents thread_sanitizer from reporting known concurrent writes.
#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define BUILDING_WITH_TSAN
#endif
#endif
// TODO(hkuang): Remove worker parameter as it is only used in debug code.
void av1_frameworker_wait(AVxWorker *const worker, RefCntBuffer *const ref_buf,
int row) {
#if CONFIG_MULTITHREAD
if (!ref_buf) return;
#ifndef BUILDING_WITH_TSAN
// The following line of code will get harmless tsan error but it is the key
// to get best performance.
if (ref_buf->row >= row && ref_buf->buf.corrupted != 1) return;
#endif
{
// Find the worker thread that owns the reference frame. If the reference
// frame has been fully decoded, it may not have owner.
AVxWorker *const ref_worker = ref_buf->frame_worker_owner;
FrameWorkerData *const ref_worker_data =
(FrameWorkerData *)ref_worker->data1;
const AV1Decoder *const pbi = ref_worker_data->pbi;
#ifdef DEBUG_THREAD
{
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
printf("%d %p worker is waiting for %d %p worker (%d) ref %d \r\n",
worker_data->worker_id, worker, ref_worker_data->worker_id,
ref_buf->frame_worker_owner, row, ref_buf->row);
}
#endif
av1_frameworker_lock_stats(ref_worker);
while (ref_buf->row < row && pbi->cur_buf == ref_buf &&
ref_buf->buf.corrupted != 1) {
pthread_cond_wait(&ref_worker_data->stats_cond,
&ref_worker_data->stats_mutex);
}
if (ref_buf->buf.corrupted == 1) {
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
av1_frameworker_unlock_stats(ref_worker);
aom_internal_error(&worker_data->pbi->common.error,
AOM_CODEC_CORRUPT_FRAME,
"Worker %p failed to decode frame", worker);
}
av1_frameworker_unlock_stats(ref_worker);
}
#else
(void)worker;
(void)ref_buf;
(void)row;
(void)ref_buf;
#endif // CONFIG_MULTITHREAD
}
void av1_frameworker_broadcast(RefCntBuffer *const buf, int row) {
#if CONFIG_MULTITHREAD
AVxWorker *worker = buf->frame_worker_owner;
#ifdef DEBUG_THREAD
{
FrameWorkerData *const worker_data = (FrameWorkerData *)worker->data1;
printf("%d %p worker decode to (%d) \r\n", worker_data->worker_id,
buf->frame_worker_owner, row);
}
#endif
av1_frameworker_lock_stats(worker);
buf->row = row;
av1_frameworker_signal_stats(worker);
av1_frameworker_unlock_stats(worker);
#else
(void)buf;
(void)row;
#endif // CONFIG_MULTITHREAD
}
void av1_frameworker_copy_context(AVxWorker *const dst_worker,
AVxWorker *const src_worker) {
#if CONFIG_MULTITHREAD
FrameWorkerData *const src_worker_data = (FrameWorkerData *)src_worker->data1;
FrameWorkerData *const dst_worker_data = (FrameWorkerData *)dst_worker->data1;
AV1_COMMON *const src_cm = &src_worker_data->pbi->common;
AV1_COMMON *const dst_cm = &dst_worker_data->pbi->common;
int i;
// Wait until source frame's context is ready.
av1_frameworker_lock_stats(src_worker);
while (!src_worker_data->frame_context_ready) {
pthread_cond_wait(&src_worker_data->stats_cond,
&src_worker_data->stats_mutex);
}
dst_cm->last_frame_seg_map = src_cm->seg.enabled
? src_cm->current_frame_seg_map
: src_cm->last_frame_seg_map;
dst_worker_data->pbi->need_resync = src_worker_data->pbi->need_resync;
av1_frameworker_unlock_stats(src_worker);
dst_cm->seq_params.bit_depth = src_cm->seq_params.bit_depth;
dst_cm->seq_params.use_highbitdepth = src_cm->seq_params.use_highbitdepth;
// TODO(zoeliu): To handle parallel decoding
dst_cm->prev_frame =
src_cm->show_existing_frame ? src_cm->prev_frame : src_cm->cur_frame;
dst_cm->last_width =
!src_cm->show_existing_frame ? src_cm->width : src_cm->last_width;
dst_cm->last_height =
!src_cm->show_existing_frame ? src_cm->height : src_cm->last_height;
dst_cm->seq_params.subsampling_x = src_cm->seq_params.subsampling_x;
dst_cm->seq_params.subsampling_y = src_cm->seq_params.subsampling_y;
dst_cm->frame_type = src_cm->frame_type;
dst_cm->last_show_frame = !src_cm->show_existing_frame
? src_cm->show_frame
: src_cm->last_show_frame;
for (i = 0; i < REF_FRAMES; ++i)
dst_cm->ref_frame_map[i] = src_cm->next_ref_frame_map[i];
memcpy(dst_cm->lf_info.lfthr, src_cm->lf_info.lfthr,
(MAX_LOOP_FILTER + 1) * sizeof(loop_filter_thresh));
dst_cm->lf.sharpness_level = src_cm->lf.sharpness_level;
dst_cm->lf.filter_level[0] = src_cm->lf.filter_level[0];
dst_cm->lf.filter_level[1] = src_cm->lf.filter_level[1];
memcpy(dst_cm->lf.ref_deltas, src_cm->lf.ref_deltas, REF_FRAMES);
memcpy(dst_cm->lf.mode_deltas, src_cm->lf.mode_deltas, MAX_MODE_LF_DELTAS);
dst_cm->seg = src_cm->seg;
memcpy(dst_cm->frame_contexts, src_cm->frame_contexts,
FRAME_CONTEXTS * sizeof(dst_cm->frame_contexts[0]));
#else
(void)dst_worker;
(void)src_worker;
#endif // CONFIG_MULTITHREAD
}

View file

@ -82,6 +82,9 @@ int ifd_inspect(insp_frame_data *fd, void *decoder, int skip_not_transform) {
mi->ref_frame[1] = mbmi->ref_frame[1];
// Prediction Mode
mi->mode = mbmi->mode;
mi->intrabc = (int16_t)mbmi->use_intrabc;
mi->palette = (int16_t)mbmi->palette_mode_info.palette_size[0];
mi->uv_palette = (int16_t)mbmi->palette_mode_info.palette_size[1];
// Prediction Mode for Chromatic planes
if (mi->mode < INTRA_MODES) {
mi->uv_mode = mbmi->uv_mode;

View file

@ -52,6 +52,9 @@ struct insp_mi_data {
int16_t current_qindex;
int16_t compound_type;
int16_t motion_mode;
int16_t intrabc;
int16_t palette;
int16_t uv_palette;
};
typedef struct insp_frame_data insp_frame_data;

View file

@ -98,12 +98,10 @@ static int byte_alignment(AV1_COMMON *const cm,
static uint32_t read_temporal_delimiter_obu() { return 0; }
// Returns a boolean that indicates success.
static int read_bitstream_level(BitstreamLevel *bl,
static int read_bitstream_level(AV1_LEVEL *seq_level_idx,
struct aom_read_bit_buffer *rb) {
const uint8_t seq_level_idx = aom_rb_read_literal(rb, LEVEL_BITS);
if (!is_valid_seq_level_idx(seq_level_idx)) return 0;
bl->major = (seq_level_idx >> LEVEL_MINOR_BITS) + LEVEL_MAJOR_MIN;
bl->minor = seq_level_idx & ((1 << LEVEL_MINOR_BITS) - 1);
*seq_level_idx = aom_rb_read_literal(rb, LEVEL_BITS);
if (!is_valid_seq_level_idx(*seq_level_idx)) return 0;
return 1;
}
@ -151,7 +149,7 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi,
seq_params->display_model_info_present_flag = 0;
seq_params->operating_points_cnt_minus_1 = 0;
seq_params->operating_point_idc[0] = 0;
if (!read_bitstream_level(&seq_params->level[0], rb)) {
if (!read_bitstream_level(&seq_params->seq_level_idx[0], rb)) {
cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
return 0;
}
@ -175,13 +173,13 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi,
for (int i = 0; i < seq_params->operating_points_cnt_minus_1 + 1; i++) {
seq_params->operating_point_idc[i] =
aom_rb_read_literal(rb, OP_POINTS_IDC_BITS);
if (!read_bitstream_level(&seq_params->level[i], rb)) {
if (!read_bitstream_level(&seq_params->seq_level_idx[i], rb)) {
cm->error.error_code = AOM_CODEC_UNSUP_BITSTREAM;
return 0;
}
// This is the seq_level_idx[i] > 7 check in the spec. seq_level_idx 7
// is equivalent to level 3.3.
if (seq_params->level[i].major > 3)
if (seq_params->seq_level_idx[i] >= SEQ_LEVEL_4_0)
seq_params->tier[i] = aom_rb_read_bit(rb);
else
seq_params->tier[i] = 0;
@ -195,10 +193,9 @@ static uint32_t read_sequence_header_obu(AV1Decoder *pbi,
if (cm->timing_info_present &&
(cm->timing_info.equal_picture_interval ||
cm->op_params[i].decoder_model_param_present_flag)) {
cm->op_params[i].bitrate = max_level_bitrate(
seq_params->profile,
major_minor_to_seq_level_idx(seq_params->level[i]),
seq_params->tier[i]);
cm->op_params[i].bitrate =
max_level_bitrate(seq_params->profile, seq_params->seq_level_idx[i],
seq_params->tier[i]);
// Level with seq_level_idx = 31 returns a high "dummy" bitrate to pass
// the check
if (cm->op_params[i].bitrate == 0)

View file

@ -31,9 +31,9 @@ struct CYCLIC_REFRESH {
// excess of the cycle time, i.e., in the case of all zero motion, block
// will be refreshed every (100/percent_refresh + time_for_refresh) frames.
int time_for_refresh;
// Target number of (8x8) blocks that are set for delta-q.
// Target number of (4x4) blocks that are set for delta-q.
int target_num_seg_blocks;
// Actual number of (8x8) blocks that were applied delta-q.
// Actual number of (4x4) blocks that were applied delta-q.
int actual_num_seg1_blocks;
int actual_num_seg2_blocks;
// RD mult. parameters for segment 1.
@ -55,6 +55,8 @@ struct CYCLIC_REFRESH {
int rate_boost_fac;
double low_content_avg;
int qindex_delta[3];
double weight_segment;
int apply_cyclic_refresh;
};
CYCLIC_REFRESH *av1_cyclic_refresh_alloc(int mi_rows, int mi_cols) {
@ -87,27 +89,6 @@ void av1_cyclic_refresh_free(CYCLIC_REFRESH *cr) {
}
}
// Check if we should turn off cyclic refresh based on bitrate condition.
static int apply_cyclic_refresh_bitrate(const AV1_COMMON *cm,
const RATE_CONTROL *rc) {
// Turn off cyclic refresh if bits available per frame is not sufficiently
// larger than bit cost of segmentation. Segment map bit cost should scale
// with number of seg blocks, so compare available bits to number of blocks.
// Average bits available per frame = avg_frame_bandwidth
// Number of (8x8) blocks in frame = mi_rows * mi_cols;
const float factor = 0.25;
const int number_blocks = cm->mi_rows * cm->mi_cols;
// The condition below corresponds to turning off at target bitrates:
// (at 30fps), ~12kbps for CIF, 36kbps for VGA, 100kps for HD/720p.
// Also turn off at very small frame sizes, to avoid too large fraction of
// superblocks to be refreshed per frame. Threshold below is less than QCIF.
if (rc->avg_frame_bandwidth < factor * number_blocks ||
number_blocks / 64 < 5)
return 0;
else
return 1;
}
// Check if this coding block, of size bsize, should be considered for refresh
// (lower-qp coding). Decision can be based on various factors, such as
// size of the coding block (i.e., below min_block size rejected), coding
@ -158,11 +139,11 @@ int av1_cyclic_refresh_estimate_bits_at_q(const AV1_COMP *cpi,
const CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
int estimated_bits;
int mbs = cm->MBs;
int num8x8bl = mbs << 2;
int num4x4bl = mbs << 4;
// Weight for non-base segments: use actual number of blocks refreshed in
// previous/just encoded frame. Note number of blocks here is in 8x8 units.
double weight_segment1 = (double)cr->actual_num_seg1_blocks / num8x8bl;
double weight_segment2 = (double)cr->actual_num_seg2_blocks / num8x8bl;
// previous/just encoded frame. Note number of blocks here is in 4x4 units.
double weight_segment1 = (double)cr->actual_num_seg1_blocks / num4x4bl;
double weight_segment2 = (double)cr->actual_num_seg2_blocks / num4x4bl;
// Take segment weighted average for estimated bits.
estimated_bits =
(int)((1.0 - weight_segment1 - weight_segment2) *
@ -190,14 +171,14 @@ int av1_cyclic_refresh_rc_bits_per_mb(const AV1_COMP *cpi, int i,
const AV1_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
int bits_per_mb;
int num8x8bl = cm->MBs << 2;
int num4x4bl = cm->MBs << 4;
// Weight for segment prior to encoding: take the average of the target
// number for the frame to be encoded and the actual from the previous frame.
double weight_segment =
(double)((cr->target_num_seg_blocks + cr->actual_num_seg1_blocks +
cr->actual_num_seg2_blocks) >>
1) /
num8x8bl;
num4x4bl;
// Compute delta-q corresponding to qindex i.
int deltaq = compute_deltaq(cpi, i, cr->rate_ratio_qdelta);
// Take segment weighted average for bits per mb.
@ -264,21 +245,6 @@ void av1_cyclic_refresh_update_segment(const AV1_COMP *cpi,
int map_offset = block_index + y * cm->mi_cols + x;
cr->map[map_offset] = new_map_value;
cpi->segmentation_map[map_offset] = mbmi->segment_id;
// Inter skip blocks were clearly not coded at the current qindex, so
// don't update the map for them. For cases where motion is non-zero or
// the reference frame isn't the previous frame, the previous value in
// the map for this spatial location is not entirely correct.
if ((!is_inter_block(mbmi) || !skip) &&
mbmi->segment_id <= CR_SEGMENT_ID_BOOST2) {
cr->last_coded_q_map[map_offset] = clamp(
cm->base_qindex + cr->qindex_delta[mbmi->segment_id], 0, MAXQ);
} else if (is_inter_block(mbmi) && skip &&
mbmi->segment_id <= CR_SEGMENT_ID_BOOST2) {
cr->last_coded_q_map[map_offset] =
AOMMIN(clamp(cm->base_qindex + cr->qindex_delta[mbmi->segment_id],
0, MAXQ),
cr->last_coded_q_map[map_offset]);
}
}
}
@ -315,73 +281,6 @@ void av1_cyclic_refresh_set_golden_update(AV1_COMP *const cpi) {
rc->baseline_gf_interval = 40;
}
// Update some encoding stats (from the just encoded frame). If this frame's
// background has high motion, refresh the golden frame. Otherwise, if the
// golden reference is to be updated check if we should NOT update the golden
// ref.
void av1_cyclic_refresh_check_golden_update(AV1_COMP *const cpi) {
AV1_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
int mi_row, mi_col;
double fraction_low = 0.0;
int low_content_frame = 0;
MB_MODE_INFO **mi;
RATE_CONTROL *const rc = &cpi->rc;
const int rows = cm->mi_rows, cols = cm->mi_cols;
int cnt1 = 0, cnt2 = 0;
int force_gf_refresh = 0;
for (mi_row = 0; mi_row < rows; mi_row++) {
mi = cm->mi_grid_visible + mi_row * cm->mi_stride;
for (mi_col = 0; mi_col < cols; mi_col++) {
int16_t abs_mvr = mi[0]->mv[0].as_mv.row >= 0
? mi[0]->mv[0].as_mv.row
: -1 * mi[0]->mv[0].as_mv.row;
int16_t abs_mvc = mi[0]->mv[0].as_mv.col >= 0
? mi[0]->mv[0].as_mv.col
: -1 * mi[0]->mv[0].as_mv.col;
// Calculate the motion of the background.
if (abs_mvr <= 16 && abs_mvc <= 16) {
cnt1++;
if (abs_mvr == 0 && abs_mvc == 0) cnt2++;
}
mi++;
// Accumulate low_content_frame.
if (cr->map[mi_row * cols + mi_col] < 1) low_content_frame++;
}
}
// For video conference clips, if the background has high motion in current
// frame because of the camera movement, set this frame as the golden frame.
// Use 70% and 5% as the thresholds for golden frame refreshing.
if (cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1) {
av1_cyclic_refresh_set_golden_update(cpi);
rc->frames_till_gf_update_due = rc->baseline_gf_interval;
if (rc->frames_till_gf_update_due > rc->frames_to_key)
rc->frames_till_gf_update_due = rc->frames_to_key;
cpi->refresh_golden_frame = 1;
force_gf_refresh = 1;
}
fraction_low = (double)low_content_frame / (rows * cols);
// Update average.
cr->low_content_avg = (fraction_low + 3 * cr->low_content_avg) / 4;
if (!force_gf_refresh && cpi->refresh_golden_frame == 1) {
// Don't update golden reference if the amount of low_content for the
// current encoded frame is small, or if the recursive average of the
// low_content over the update interval window falls below threshold.
if (fraction_low < 0.8 || cr->low_content_avg < 0.7)
cpi->refresh_golden_frame = 0;
// Reset for next internal.
cr->low_content_avg = fraction_low;
}
}
// Update the segmentation map, and related quantities: cyclic refresh map,
// refresh sb_index, and target number of blocks to be refreshed.
// The map is set to either 0/CR_SEGMENT_ID_BASE (no refresh) or to
@ -458,26 +357,70 @@ static void cyclic_refresh_update_map(AV1_COMP *const cpi) {
// Set cyclic refresh parameters.
void av1_cyclic_refresh_update_parameters(AV1_COMP *const cpi) {
// TODO(marpan): Parameters need to be tuned.
const RATE_CONTROL *const rc = &cpi->rc;
const AV1_COMMON *const cm = &cpi->common;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
int num4x4bl = cm->MBs << 4;
int target_refresh = 0;
double weight_segment_target = 0;
double weight_segment = 0;
int qp_thresh = AOMMIN(20, rc->best_quality << 1);
cr->apply_cyclic_refresh = 1;
if (frame_is_intra_only(cm) || is_lossless_requested(&cpi->oxcf) ||
rc->avg_frame_qindex[INTER_FRAME] < qp_thresh) {
cr->apply_cyclic_refresh = 0;
return;
}
cr->percent_refresh = 10;
cr->max_qdelta_perc = 50;
cr->max_qdelta_perc = 60;
cr->time_for_refresh = 0;
cr->motion_thresh = 32;
cr->rate_boost_fac = 15;
// Use larger delta-qp (increase rate_ratio_qdelta) for first few (~4)
// periods of the refresh cycle, after a key frame.
if (rc->frames_since_key < 4 * cr->percent_refresh)
// Account for larger interval on base layer for temporal layers.
if (cr->percent_refresh > 0 &&
rc->frames_since_key < 400 / cr->percent_refresh) {
cr->rate_ratio_qdelta = 3.0;
else
cr->rate_ratio_qdelta = 2.0;
// Adjust some parameters for low resolutions at low bitrates.
if (cm->width <= 352 && cm->height <= 288 && rc->avg_frame_bandwidth < 3400) {
cr->motion_thresh = 4;
cr->rate_boost_fac = 10;
} else {
cr->motion_thresh = 32;
cr->rate_boost_fac = 17;
cr->rate_ratio_qdelta = 2.0;
}
// Adjust some parameters for low resolutions.
if (cm->width <= 352 && cm->height <= 288) {
if (rc->avg_frame_bandwidth < 3000) {
cr->motion_thresh = 16;
cr->rate_boost_fac = 13;
} else {
cr->max_qdelta_perc = 70;
cr->rate_ratio_qdelta = AOMMAX(cr->rate_ratio_qdelta, 2.5);
}
}
if (cpi->oxcf.rc_mode == AOM_VBR) {
// To be adjusted for VBR mode, e.g., based on gf period and boost.
// For now use smaller qp-delta (than CBR), no second boosted seg, and
// turn-off (no refresh) on golden refresh (since it's already boosted).
cr->percent_refresh = 10;
cr->rate_ratio_qdelta = 1.5;
cr->rate_boost_fac = 10;
if (cpi->refresh_golden_frame == 1) {
cr->percent_refresh = 0;
cr->rate_ratio_qdelta = 1.0;
}
}
// Weight for segment prior to encoding: take the average of the target
// number for the frame to be encoded and the actual from the previous frame.
// Use the target if its less. To be used for setting the base qp for the
// frame in vp9_rc_regulate_q.
target_refresh = cr->percent_refresh * cm->mi_rows * cm->mi_cols / 100;
weight_segment_target = (double)(target_refresh) / num4x4bl;
weight_segment = (double)((target_refresh + cr->actual_num_seg1_blocks +
cr->actual_num_seg2_blocks) >>
1) /
num4x4bl;
if (weight_segment_target < 7 * weight_segment / 8)
weight_segment = weight_segment_target;
cr->weight_segment = weight_segment;
}
// Setup cyclic background refresh: set delta q and segmentation map.
@ -486,7 +429,6 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) {
const RATE_CONTROL *const rc = &cpi->rc;
CYCLIC_REFRESH *const cr = cpi->cyclic_refresh;
struct segmentation *const seg = &cm->seg;
const int apply_cyclic_refresh = apply_cyclic_refresh_bitrate(cm, rc);
int resolution_change =
cm->prev_frame && (cm->width != cm->prev_frame->width ||
cm->height != cm->prev_frame->height);
@ -498,8 +440,7 @@ void av1_cyclic_refresh_setup(AV1_COMP *const cpi) {
return;
}
if (cm->current_frame.frame_number == 0) cr->low_content_avg = 0.0;
// Don't apply refresh on key frame or enhancement layer frames.
if (!apply_cyclic_refresh || cm->current_frame.frame_type == KEY_FRAME) {
if (!cr->apply_cyclic_refresh) {
// Set segmentation map to 0 and disable.
unsigned char *const seg_map = cpi->segmentation_map;
memset(seg_map, 0, cm->mi_rows * cm->mi_cols);

View file

@ -54,19 +54,12 @@ void av1_cyclic_refresh_update_segment(const struct AV1_COMP *cpi,
int mi_col, BLOCK_SIZE bsize,
int64_t rate, int64_t dist, int skip);
// Update the segmentation map, and related quantities: cyclic refresh map,
// refresh sb_index, and target number of blocks to be refreshed.
void av1_cyclic_refresh_update__map(struct AV1_COMP *const cpi);
// Update the actual number of blocks that were applied the segment delta q.
void av1_cyclic_refresh_postencode(struct AV1_COMP *const cpi);
// Set golden frame update interval, for 1 pass CBR mode.
void av1_cyclic_refresh_set_golden_update(struct AV1_COMP *const cpi);
// Check if we should not update golden reference, based on past refresh stats.
void av1_cyclic_refresh_check_golden_update(struct AV1_COMP *const cpi);
// Set/update global/frame level refresh parameters.
void av1_cyclic_refresh_update_parameters(struct AV1_COMP *const cpi);

View file

@ -276,13 +276,13 @@ void av1_quantize_b_facade(const tran_low_t *coeff_ptr, intptr_t n_coeffs,
} else {
switch (qparam->log_scale) {
case 0:
aom_quantize_b_adaptive_c(
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
eob_ptr, sc->scan, sc->iscan);
aom_quantize_b_adaptive(coeff_ptr, n_coeffs, p->zbin_QTX,
p->round_QTX, p->quant_QTX,
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr,
p->dequant_QTX, eob_ptr, sc->scan, sc->iscan);
break;
case 1:
aom_quantize_b_32x32_adaptive_c(
aom_quantize_b_32x32_adaptive(
coeff_ptr, n_coeffs, p->zbin_QTX, p->round_QTX, p->quant_QTX,
p->quant_shift_QTX, qcoeff_ptr, dqcoeff_ptr, p->dequant_QTX,
eob_ptr, sc->scan, sc->iscan);

View file

@ -22,6 +22,9 @@
extern "C" {
#endif
#define EOB_FACTOR 325
#define SKIP_EOB_FACTOR_ADJUST 200
typedef struct QUANT_PARAM {
int log_scale;
TX_SIZE tx_size;

View file

@ -369,10 +369,18 @@ static void pack_txb_tokens(aom_writer *w, AV1_COMMON *cm, MACROBLOCK *const x,
blk_col)];
if (tx_size == plane_tx_size || plane) {
tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block);
const uint16_t eob = x->mbmi_ext->eobs[plane][block];
TXB_CTX txb_ctx = { x->mbmi_ext->txb_skip_ctx[plane][block],
x->mbmi_ext->dc_sign_ctx[plane][block] };
const int txb_offset =
x->mbmi_ext->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
tran_low_t *tcoeff_txb =
x->mbmi_ext->cb_coef_buff->tcoeff[plane] + x->mbmi_ext->cb_offset;
uint16_t *eob_txb = x->mbmi_ext->cb_coef_buff->eobs[plane] + txb_offset;
uint8_t *txb_skip_ctx_txb =
x->mbmi_ext->cb_coef_buff->txb_skip_ctx[plane] + txb_offset;
int *dc_sign_ctx_txb =
x->mbmi_ext->cb_coef_buff->dc_sign_ctx[plane] + txb_offset;
tran_low_t *tcoeff = BLOCK_OFFSET(tcoeff_txb, block);
const uint16_t eob = eob_txb[block];
TXB_CTX txb_ctx = { txb_skip_ctx_txb[block], dc_sign_ctx_txb[block] };
av1_write_coeffs_txb(cm, xd, w, blk_row, blk_col, plane, tx_size, tcoeff,
eob, &txb_ctx);
#if CONFIG_RD_DEBUG
@ -627,7 +635,7 @@ static void write_mb_interp_filter(AV1_COMP *cpi, const MACROBLOCKD *xd,
av1_extract_interp_filter(mbmi->interp_filters, dir);
aom_write_symbol(w, filter, ec_ctx->switchable_interp_cdf[ctx],
SWITCHABLE_FILTERS);
++cpi->interp_filter_selected[0][filter];
++cm->cur_frame->interp_filter_selected[filter];
if (cm->seq_params.enable_dual_filter == 0) return;
}
}
@ -1162,9 +1170,9 @@ static void pack_inter_mode_mvs(AV1_COMP *cpi, const int mi_row,
mbmi->interinter_comp.type == COMPOUND_DIFFWTD);
if (is_interinter_compound_used(COMPOUND_WEDGE, bsize))
aom_write_symbol(w, mbmi->interinter_comp.type - 1,
aom_write_symbol(w, mbmi->interinter_comp.type - COMPOUND_WEDGE,
ec_ctx->compound_type_cdf[bsize],
COMPOUND_TYPES - 1);
MASKED_COMPOUND_TYPES);
if (mbmi->interinter_comp.type == COMPOUND_WEDGE) {
assert(is_interinter_compound_used(COMPOUND_WEDGE, bsize));
@ -1288,7 +1296,7 @@ static void enc_dump_logs(AV1_COMP *cpi, int mi_row, int mi_col) {
}
const int16_t mode_ctx =
is_comp_ref ? mbmi_ext->compound_mode_context[mbmi->ref_frame[0]]
is_comp_ref ? 0
: av1_mode_context_analyzer(mbmi_ext->mode_context,
mbmi->ref_frame);
@ -2743,21 +2751,14 @@ static int check_frame_refs_short_signaling(AV1_COMMON *const cm) {
// Check whether the encoder side ref frame choices are aligned with that to
// be derived at the decoder side.
int remapped_ref_idx_copy[REF_FRAMES];
struct scale_factors ref_scale_factors_copy[REF_FRAMES];
// Backup the frame refs info
memcpy(remapped_ref_idx_copy, cm->remapped_ref_idx,
REF_FRAMES * sizeof(*remapped_ref_idx_copy));
memcpy(ref_scale_factors_copy, cm->ref_scale_factors,
REF_FRAMES * sizeof(*ref_scale_factors_copy));
int remapped_ref_idx_decoder[REF_FRAMES];
const int lst_map_idx = get_ref_frame_map_idx(cm, LAST_FRAME);
const int gld_map_idx = get_ref_frame_map_idx(cm, GOLDEN_FRAME);
// Set up the frame refs mapping indexes according to the
// frame_refs_short_signaling policy.
av1_set_frame_refs(cm, lst_map_idx, gld_map_idx);
av1_set_frame_refs(cm, remapped_ref_idx_decoder, lst_map_idx, gld_map_idx);
// We only turn on frame_refs_short_signaling when the encoder side decision
// on ref frames is identical to that at the decoder side.
@ -2765,10 +2766,11 @@ static int check_frame_refs_short_signaling(AV1_COMMON *const cm) {
for (int ref_idx = 0; ref_idx < INTER_REFS_PER_FRAME; ++ref_idx) {
// Compare the buffer index between two reference frames indexed
// respectively by the encoder and the decoder side decisions.
RefCntBuffer *ref_frame_buf_copy = NULL;
if (remapped_ref_idx_copy[ref_idx] != INVALID_IDX)
ref_frame_buf_copy = cm->ref_frame_map[remapped_ref_idx_copy[ref_idx]];
if (get_ref_frame_buf(cm, LAST_FRAME + ref_idx) != ref_frame_buf_copy) {
RefCntBuffer *ref_frame_buf_new = NULL;
if (remapped_ref_idx_decoder[ref_idx] != INVALID_IDX) {
ref_frame_buf_new = cm->ref_frame_map[remapped_ref_idx_decoder[ref_idx]];
}
if (get_ref_frame_buf(cm, LAST_FRAME + ref_idx) != ref_frame_buf_new) {
frame_refs_short_signaling = 0;
break;
}
@ -2786,13 +2788,6 @@ static int check_frame_refs_short_signaling(AV1_COMMON *const cm) {
}
#endif // 0
// Restore the frame refs info if frame_refs_short_signaling is off.
if (!frame_refs_short_signaling) {
memcpy(cm->remapped_ref_idx, remapped_ref_idx_copy,
REF_FRAMES * sizeof(*remapped_ref_idx_copy));
memcpy(cm->ref_scale_factors, ref_scale_factors_copy,
REF_FRAMES * sizeof(*ref_scale_factors_copy));
}
return frame_refs_short_signaling;
}
@ -2805,6 +2800,8 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi,
MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
CurrentFrame *const current_frame = &cm->current_frame;
current_frame->frame_refs_short_signaling = 0;
if (seq_params->still_picture) {
assert(cm->show_existing_frame == 0);
assert(cm->show_frame == 1);
@ -2867,24 +2864,25 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi,
int frame_size_override_flag = 0;
if (seq_params->reduced_still_picture_hdr) {
assert(cm->width == seq_params->max_frame_width &&
cm->height == seq_params->max_frame_height);
assert(cm->superres_upscaled_width == seq_params->max_frame_width &&
cm->superres_upscaled_height == seq_params->max_frame_height);
} else {
if (seq_params->frame_id_numbers_present_flag) {
int frame_id_len = seq_params->frame_id_length;
aom_wb_write_literal(wb, cm->current_frame_id, frame_id_len);
}
if (cm->width > seq_params->max_frame_width ||
cm->height > seq_params->max_frame_height) {
if (cm->superres_upscaled_width > seq_params->max_frame_width ||
cm->superres_upscaled_height > seq_params->max_frame_height) {
aom_internal_error(&cm->error, AOM_CODEC_UNSUP_BITSTREAM,
"Frame dimensions are larger than the maximum values");
}
frame_size_override_flag =
frame_is_sframe(cm) ? 1
: (cm->width != seq_params->max_frame_width ||
cm->height != seq_params->max_frame_height);
frame_is_sframe(cm)
? 1
: (cm->superres_upscaled_width != seq_params->max_frame_width ||
cm->superres_upscaled_height != seq_params->max_frame_height);
if (!frame_is_sframe(cm)) aom_wb_write_bit(wb, frame_size_override_flag);
if (seq_params->order_hint_info.enable_order_hint)
@ -2960,25 +2958,25 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi,
// NOTE: Error resilient mode turns off frame_refs_short_signaling
// automatically.
int frame_refs_short_signaling = 0;
#define FRAME_REFS_SHORT_SIGNALING 0
#if FRAME_REFS_SHORT_SIGNALING
frame_refs_short_signaling =
current_frame->frame_refs_short_signaling =
seq_params->order_hint_info.enable_order_hint;
#endif // FRAME_REFS_SHORT_SIGNALING
if (frame_refs_short_signaling) {
if (current_frame->frame_refs_short_signaling) {
// NOTE(zoeliu@google.com):
// An example solution for encoder-side implementation on frame refs
// short signaling, which is only turned on when the encoder side
// decision on ref frames is identical to that at the decoder side.
frame_refs_short_signaling = check_frame_refs_short_signaling(cm);
current_frame->frame_refs_short_signaling =
check_frame_refs_short_signaling(cm);
}
if (seq_params->order_hint_info.enable_order_hint)
aom_wb_write_bit(wb, frame_refs_short_signaling);
aom_wb_write_bit(wb, current_frame->frame_refs_short_signaling);
if (frame_refs_short_signaling) {
if (current_frame->frame_refs_short_signaling) {
const int lst_ref = get_ref_frame_map_idx(cm, LAST_FRAME);
aom_wb_write_literal(wb, lst_ref, REF_FRAMES_LOG2);
@ -2988,7 +2986,7 @@ static void write_uncompressed_header_obu(AV1_COMP *cpi,
for (ref_frame = LAST_FRAME; ref_frame <= ALTREF_FRAME; ++ref_frame) {
assert(get_ref_frame_map_idx(cm, ref_frame) != INVALID_IDX);
if (!frame_refs_short_signaling)
if (!current_frame->frame_refs_short_signaling)
aom_wb_write_literal(wb, get_ref_frame_map_idx(cm, ref_frame),
REF_FRAMES_LOG2);
if (seq_params->frame_id_numbers_present_flag) {
@ -3236,8 +3234,12 @@ static int remux_tiles(const AV1_COMMON *const cm, uint8_t *dst,
return wpos;
}
uint32_t write_obu_header(OBU_TYPE obu_type, int obu_extension,
uint8_t *const dst) {
uint32_t av1_write_obu_header(AV1_COMP *const cpi, OBU_TYPE obu_type,
int obu_extension, uint8_t *const dst) {
if (cpi->keep_level_stats &&
(obu_type == OBU_FRAME || obu_type == OBU_FRAME_HEADER))
++cpi->frame_header_count;
struct aom_write_bit_buffer wb = { dst, 0 };
uint32_t size = 0;
@ -3289,9 +3291,8 @@ static void add_trailing_bits(struct aom_write_bit_buffer *wb) {
}
}
static void write_bitstream_level(BitstreamLevel bl,
static void write_bitstream_level(AV1_LEVEL seq_level_idx,
struct aom_write_bit_buffer *wb) {
uint8_t seq_level_idx = major_minor_to_seq_level_idx(bl);
assert(is_valid_seq_level_idx(seq_level_idx));
aom_wb_write_literal(wb, seq_level_idx, LEVEL_BITS);
}
@ -3314,7 +3315,7 @@ uint32_t write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst) {
assert(cm->timing_info_present == 0);
assert(cm->seq_params.decoder_model_info_present_flag == 0);
assert(cm->seq_params.display_model_info_present_flag == 0);
write_bitstream_level(cm->seq_params.level[0], &wb);
write_bitstream_level(cm->seq_params.seq_level_idx[0], &wb);
} else {
aom_wb_write_bit(&wb, cm->timing_info_present); // timing info present flag
@ -3333,8 +3334,8 @@ uint32_t write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst) {
for (i = 0; i < cm->seq_params.operating_points_cnt_minus_1 + 1; i++) {
aom_wb_write_literal(&wb, cm->seq_params.operating_point_idc[i],
OP_POINTS_IDC_BITS);
write_bitstream_level(cm->seq_params.level[i], &wb);
if (cm->seq_params.level[i].major > 3)
write_bitstream_level(cm->seq_params.seq_level_idx[i], &wb);
if (cm->seq_params.seq_level_idx[i] >= SEQ_LEVEL_4_0)
aom_wb_write_bit(&wb, cm->seq_params.tier[i]);
if (cm->seq_params.decoder_model_info_present_flag) {
aom_wb_write_bit(&wb,
@ -3436,7 +3437,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst,
// For large_scale_tile case, we always have only one tile group, so it can
// be written as an OBU_FRAME.
const OBU_TYPE obu_type = OBU_FRAME;
const uint32_t tg_hdr_size = write_obu_header(obu_type, 0, data);
const uint32_t tg_hdr_size = av1_write_obu_header(cpi, obu_type, 0, data);
data += tg_hdr_size;
const uint32_t frame_header_size =
@ -3591,7 +3592,7 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst,
const OBU_TYPE obu_type =
(num_tg_hdrs == 1) ? OBU_FRAME : OBU_TILE_GROUP;
curr_tg_data_size =
write_obu_header(obu_type, obu_extension_header, data);
av1_write_obu_header(cpi, obu_type, obu_extension_header, data);
obu_header_size = curr_tg_data_size;
if (num_tg_hdrs == 1) {
@ -3677,8 +3678,9 @@ static uint32_t write_tiles_in_tg_obus(AV1_COMP *const cpi, uint8_t *const dst,
// Rewrite the OBU header to change the OBU type to Redundant Frame
// Header.
write_obu_header(OBU_REDUNDANT_FRAME_HEADER, obu_extension_header,
&data[fh_info->obu_header_byte_offset]);
av1_write_obu_header(cpi, OBU_REDUNDANT_FRAME_HEADER,
obu_extension_header,
&data[fh_info->obu_header_byte_offset]);
data += fh_info->total_length;
@ -3757,11 +3759,13 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size,
bitstream_queue_reset_write();
#endif
cpi->frame_header_count = 0;
// The TD is now written outside the frame encode loop
// write sequence header obu if KEY_FRAME, preceded by 4-byte size
if (cm->current_frame.frame_type == KEY_FRAME && cm->show_frame) {
obu_header_size = write_obu_header(OBU_SEQUENCE_HEADER, 0, data);
obu_header_size = av1_write_obu_header(cpi, OBU_SEQUENCE_HEADER, 0, data);
obu_payload_size = write_sequence_header_obu(cpi, data + obu_header_size);
const size_t length_field_size =
@ -3781,7 +3785,7 @@ int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size,
// Write Frame Header OBU.
fh_info.frame_header = data;
obu_header_size =
write_obu_header(OBU_FRAME_HEADER, obu_extension_header, data);
av1_write_obu_header(cpi, OBU_FRAME_HEADER, obu_extension_header, data);
obu_payload_size =
write_frame_header_obu(cpi, &saved_wb, data + obu_header_size, 1);

View file

@ -27,8 +27,8 @@ uint32_t write_sequence_header_obu(AV1_COMP *cpi, uint8_t *const dst);
// Writes the OBU header byte, and the OBU header extension byte when
// 'obu_extension' is non-zero. Returns number of bytes written to 'dst'.
uint32_t write_obu_header(OBU_TYPE obu_type, int obu_extension,
uint8_t *const dst);
uint32_t av1_write_obu_header(AV1_COMP *const cpi, OBU_TYPE obu_type,
int obu_extension, uint8_t *const dst);
int write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size,
uint8_t *dest);
@ -36,11 +36,6 @@ int write_uleb_obu_size(uint32_t obu_header_size, uint32_t obu_payload_size,
int av1_pack_bitstream(AV1_COMP *const cpi, uint8_t *dst, size_t *size,
int *const largest_tile_id);
static INLINE int av1_preserve_existing_gf(const AV1_COMP *const cpi) {
// Do not swap gf and arf indices for internal overlay frames
return cpi->rc.is_src_frame_alt_ref && !cpi->rc.is_src_frame_ext_arf;
}
void av1_write_tx_type(const AV1_COMMON *const cm, const MACROBLOCKD *xd,
int blk_row, int blk_col, int plane, TX_SIZE tx_size,
aom_writer *w);

View file

@ -75,13 +75,10 @@ typedef struct {
typedef struct {
// TODO(angiebird): Reduce the buffer size according to sb_type
tran_low_t *tcoeff[MAX_MB_PLANE];
uint16_t *eobs[MAX_MB_PLANE];
uint8_t *txb_skip_ctx[MAX_MB_PLANE];
int *dc_sign_ctx[MAX_MB_PLANE];
CB_COEFF_BUFFER *cb_coef_buff;
CANDIDATE_MV ref_mv_stack[MODE_CTX_REF_FRAMES][MAX_REF_MV_STACK_SIZE];
int_mv global_mvs[REF_FRAMES];
int16_t compound_mode_context[MODE_CTX_REF_FRAMES];
int cb_offset;
int16_t mode_context[MODE_CTX_REF_FRAMES];
uint8_t ref_mv_count[MODE_CTX_REF_FRAMES];
} MB_MODE_INFO_EXT;
@ -156,7 +153,7 @@ typedef struct {
// Region size for mode decision sampling in the first pass of partition
// search(two_pass_partition_search speed feature), in units of mi size(4).
// Used by the mode_pruning_based_on_two_pass_partition_search speed feature.
// Used by the mode pruning in two_pass_partition_search feature.
#define FIRST_PARTITION_PASS_SAMPLE_REGION 8
#define FIRST_PARTITION_PASS_SAMPLE_REGION_LOG2 3
#define FIRST_PARTITION_PASS_STATS_TABLES \
@ -177,6 +174,8 @@ typedef struct {
uint8_t ref0_counts[REF_FRAMES]; // Counters for ref_frame[0].
uint8_t ref1_counts[REF_FRAMES]; // Counters for ref_frame[1].
int sample_counts; // Number of samples collected.
uint8_t interintra_motion_mode_count[REF_FRAMES]; // Counter for interintra
// motion mode
} FIRST_PARTITION_PASS_STATS;
#define MAX_INTERP_FILTER_STATS 64
@ -185,12 +184,17 @@ typedef struct {
int_mv mv[2];
int8_t ref_frames[2];
COMPOUND_TYPE comp_type;
int64_t rd;
int skip_txfm_sb;
int64_t skip_sse_sb;
unsigned int pred_sse;
} INTERPOLATION_FILTER_STATS;
#define MAX_COMP_RD_STATS 64
typedef struct {
int32_t rate[COMPOUND_TYPES];
int64_t dist[COMPOUND_TYPES];
int64_t comp_model_rd[COMPOUND_TYPES];
int_mv mv[2];
MV_REFERENCE_FRAME ref_frames[2];
PREDICTION_MODE mode;
@ -272,6 +276,7 @@ struct macroblock {
unsigned int max_mv_context[REF_FRAMES];
unsigned int source_variance;
unsigned int simple_motion_pred_sse;
unsigned int pred_sse[REF_FRAMES];
int pred_mv_sad[REF_FRAMES];
@ -351,7 +356,7 @@ struct macroblock {
// BWDREF_FRAME) in bidir-comp mode.
int comp_bwdref_cost[REF_CONTEXTS][BWD_REFS - 1][2];
int inter_compound_mode_cost[INTER_MODE_CONTEXTS][INTER_COMPOUND_MODES];
int compound_type_cost[BLOCK_SIZES_ALL][COMPOUND_TYPES - 1];
int compound_type_cost[BLOCK_SIZES_ALL][MASKED_COMPOUND_TYPES];
int wedge_idx_cost[BLOCK_SIZES_ALL][16];
int interintra_cost[BLOCK_SIZE_GROUPS][2];
int wedge_interintra_cost[BLOCK_SIZES_ALL][2];
@ -396,6 +401,11 @@ struct macroblock {
// Store the fractional best motion vector during sub/Qpel-pixel motion search
int_mv fractional_best_mv[3];
// Ref frames that are selected by square partition blocks within a super-
// block, in MI resolution. They can be used to prune ref frames for
// rectangular blocks.
int picked_ref_frames_mask[32 * 32];
// use default transform and skip transform type search for intra modes
int use_default_intra_tx_type;
// use default transform and skip transform type search for inter modes
@ -416,6 +426,9 @@ struct macroblock {
// detection). For reference, 556 is the value returned for a solid
// vertical black/white edge.
uint16_t edge_strength;
// The strongest edge strength seen along the x/y axis.
uint16_t edge_strength_x;
uint16_t edge_strength_y;
// [Saved stat index]
COMP_RD_STATS comp_rd_stats[MAX_COMP_RD_STATS];

View file

@ -58,8 +58,6 @@ typedef struct {
int hybrid_pred_diff;
int comp_pred_diff;
int single_pred_diff;
// Skip certain ref frames during RD search of rectangular partitions.
int skip_ref_frame_mask;
// TODO(jingning) Use RD_COST struct here instead. This involves a boarder
// scope of refactoring.
@ -67,26 +65,12 @@ typedef struct {
int rd_mode_is_ready; // Flag to indicate whether rd pick mode decision has
// been made.
int mode_selected;
#if CONFIG_ONE_PASS_SVM
// Features for one pass svm early term
int seg_feat;
#endif
// motion vector cache for adaptive motion search control in partition
// search loop
MV pred_mv[REF_FRAMES];
InterpFilter pred_interp_filter;
PARTITION_TYPE partition;
// Reference and prediction mode cache for ref/mode speedup
// TODO(zoeliu@gmail.com): The values of ref_selected and mode_selected will
// be explored for further encoder speedup, to differentiate this approach for
// setting skip_ref_frame_mask from others. For instance, it is possible that
// the underlying square block(s) share the same SIMPLE_TRANSLATION motion
// mode as well as the mode of GLOBALMV, more ref/mode combos could be
// skipped.
MV_REFERENCE_FRAME ref_selected[2];
} PICK_MODE_CONTEXT;
typedef struct {

File diff suppressed because it is too large Load diff

View file

@ -31,9 +31,13 @@ int av1_encode_strategy(AV1_COMP *const cpi, size_t *const size,
int64_t *const time_stamp, int64_t *const time_end,
const aom_rational_t *const timebase, int flush);
// Set individual buffer update flags based on frame reference type
// Set individual buffer update flags based on frame reference type.
// force_refresh_all is used when we have a KEY_FRAME or S_FRAME. It forces all
// refresh_*_frame flags to be set, because we refresh all buffers in this case.
void av1_configure_buffer_updates(AV1_COMP *const cpi,
const FRAME_UPDATE_TYPE type);
EncodeFrameParams *const frame_params,
const FRAME_UPDATE_TYPE type,
int force_refresh_all);
#ifdef __cplusplus
} // extern "C"

File diff suppressed because it is too large Load diff

View file

@ -111,9 +111,8 @@ int av1_optimize_b(const struct AV1_COMP *cpi, MACROBLOCK *mb, int plane,
return eob;
}
(void)fast_mode;
return av1_optimize_txb_new(cpi, mb, plane, block, tx_size, tx_type, txb_ctx,
rate_cost, cpi->oxcf.sharpness);
rate_cost, cpi->oxcf.sharpness, fast_mode);
}
enum {
@ -185,7 +184,7 @@ void av1_xform_quant(const AV1_COMMON *cm, MACROBLOCK *x, int plane, int block,
av1_quantize_skip(n_coeffs, qcoeff, dqcoeff, eob);
}
}
// NOTE: optimize_b_following is ture means av1_optimze_b will be called
// NOTE: optimize_b_following is true means av1_optimze_b will be called
// When the condition of doing optimize_b is changed,
// this flag need update simultaneously
const int optimize_b_following =
@ -228,12 +227,16 @@ static void encode_block(int plane, int block, int blk_row, int blk_col,
TX_TYPE tx_type = av1_get_tx_type(pd->plane_type, xd, blk_row, blk_col,
tx_size, cm->reduced_tx_set_used);
if (args->enable_optimize_b != NO_TRELLIS_OPT) {
av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize,
tx_size, tx_type, AV1_XFORM_QUANT_FP);
av1_xform_quant(
cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type,
USE_B_QUANT_NO_TRELLIS &&
(args->enable_optimize_b == FINAL_PASS_TRELLIS_OPT)
? AV1_XFORM_QUANT_B
: AV1_XFORM_QUANT_FP);
TXB_CTX txb_ctx;
get_txb_ctx(plane_bsize, tx_size, plane, a, l, &txb_ctx);
av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx, 1,
&dummy_rate_cost);
av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx,
args->cpi->sf.trellis_eob_fast, &dummy_rate_cost);
} else {
av1_xform_quant(
cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type,
@ -256,12 +259,12 @@ static void encode_block(int plane, int block, int blk_row, int blk_col,
cm->reduced_tx_set_used);
}
// TODO(debargha, jingning): Temporarily disable txk_type check for eob=0
// case. It is possible that certain collision in hash index would cause
// the assertion failure. To further optimize the rate-distortion
// performance, we need to re-visit this part and enable this assert
// again.
if (p->eobs[block] == 0 && plane == 0) {
// TODO(debargha, jingning): Temporarily disable txk_type check for eob=0
// case. It is possible that certain collision in hash index would cause
// the assertion failure. To further optimize the rate-distortion
// performance, we need to re-visit this part and enable this assert
// again.
#if 0
if (args->cpi->oxcf.aq_mode == NO_AQ &&
args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) {
@ -580,12 +583,16 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col,
const ENTROPY_CONTEXT *a = &args->ta[blk_col];
const ENTROPY_CONTEXT *l = &args->tl[blk_row];
if (args->enable_optimize_b != NO_TRELLIS_OPT) {
av1_xform_quant(cm, x, plane, block, blk_row, blk_col, plane_bsize,
tx_size, tx_type, AV1_XFORM_QUANT_FP);
av1_xform_quant(
cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type,
USE_B_QUANT_NO_TRELLIS &&
(args->enable_optimize_b == FINAL_PASS_TRELLIS_OPT)
? AV1_XFORM_QUANT_B
: AV1_XFORM_QUANT_FP);
TXB_CTX txb_ctx;
get_txb_ctx(plane_bsize, tx_size, plane, a, l, &txb_ctx);
av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx, 1,
&dummy_rate_cost);
av1_optimize_b(args->cpi, x, plane, block, tx_size, tx_type, &txb_ctx,
args->cpi->sf.trellis_eob_fast, &dummy_rate_cost);
} else {
av1_xform_quant(
cm, x, plane, block, blk_row, blk_col, plane_bsize, tx_size, tx_type,
@ -598,12 +605,12 @@ void av1_encode_block_intra(int plane, int block, int blk_row, int blk_col,
dst_stride, *eob, cm->reduced_tx_set_used);
}
// TODO(jingning): Temporarily disable txk_type check for eob=0 case.
// It is possible that certain collision in hash index would cause
// the assertion failure. To further optimize the rate-distortion
// performance, we need to re-visit this part and enable this assert
// again.
if (*eob == 0 && plane == 0) {
// TODO(jingning): Temporarily disable txk_type check for eob=0 case.
// It is possible that certain collision in hash index would cause
// the assertion failure. To further optimize the rate-distortion
// performance, we need to re-visit this part and enable this assert
// again.
#if 0
if (args->cpi->oxcf.aq_mode == NO_AQ
&& args->cpi->oxcf.deltaq_mode == NO_DELTA_Q) {

File diff suppressed because it is too large Load diff

View file

@ -12,6 +12,7 @@
#ifndef AOM_AV1_ENCODER_ENCODER_H_
#define AOM_AV1_ENCODER_ENCODER_H_
#include <stdbool.h>
#include <stdio.h>
#include "config/aom_config.h"
@ -24,11 +25,14 @@
#include "av1/common/onyxc_int.h"
#include "av1/common/resize.h"
#include "av1/common/timing.h"
#include "av1/common/blockd.h"
#include "av1/common/enums.h"
#include "av1/encoder/aq_cyclicrefresh.h"
#include "av1/encoder/av1_quantize.h"
#include "av1/encoder/context_tree.h"
#include "av1/encoder/encodemb.h"
#include "av1/encoder/firstpass.h"
#include "av1/encoder/level.h"
#include "av1/encoder/lookahead.h"
#include "av1/encoder/mbgraph.h"
#include "av1/encoder/mcomp.h"
@ -36,6 +40,7 @@
#include "av1/encoder/rd.h"
#include "av1/encoder/speed_features.h"
#include "av1/encoder/tokenize.h"
#include "av1/encoder/block.h"
#if CONFIG_INTERNAL_STATS
#include "aom_dsp/ssim.h"
@ -60,18 +65,12 @@ typedef struct {
} CODING_CONTEXT;
enum {
// regular inter frame
REGULAR_FRAME = 0,
// alternate reference frame
ARF_FRAME = 1,
// overlay frame
OVERLAY_FRAME = 2,
// golden frame
GLD_FRAME = 3,
// backward reference frame
BRF_FRAME = 4,
// extra alternate reference frame
EXT_ARF_FRAME = 5,
REGULAR_FRAME, // regular inter frame
ARF_FRAME, // alternate reference frame
OVERLAY_FRAME, // overlay frame
GLD_FRAME, // golden frame
BRF_FRAME, // backward reference frame
INTERNAL_ARF_FRAME, // internal alternate reference frame
FRAME_CONTEXT_INDEXES
} UENUM1BYTE(FRAME_CONTEXT_INDEX);
@ -85,7 +84,10 @@ enum {
enum {
// Good Quality Fast Encoding. The encoder balances quality with the amount of
// time it takes to encode the output. Speed setting controls how fast.
GOOD
GOOD,
// Realtime Fast Encoding. Will force some restrictions on bitrate
// constraints.
REALTIME
} UENUM1BYTE(MODE);
enum {
@ -121,22 +123,38 @@ enum {
} UENUM1BYTE(RESIZE_MODE);
enum {
SUPERRES_NONE = 0, // No frame superres allowed
SUPERRES_FIXED = 1, // All frames are coded at the specified scale,
// and super-resolved.
SUPERRES_RANDOM = 2, // All frames are coded at a random scale,
// and super-resolved.
SUPERRES_QTHRESH = 3, // Superres scale for a frame is determined based on
// q_index
SUPERRES_NONE, // No frame superres allowed.
SUPERRES_FIXED, // All frames are coded at the specified scale,
// and super-resolved.
SUPERRES_RANDOM, // All frames are coded at a random scale,
// and super-resolved.
SUPERRES_QTHRESH, // Superres scale for a frame is determined based on
// q_index.
SUPERRES_AUTO, // Automatically select superres for appropriate frames.
SUPERRES_MODES
} UENUM1BYTE(SUPERRES_MODE);
typedef enum {
kInvalid = 0,
kLowSadLowSumdiff = 1,
kLowSadHighSumdiff = 2,
kHighSadLowSumdiff = 3,
kHighSadHighSumdiff = 4,
kLowVarHighSumdiff = 5,
kVeryHighSad = 6,
} CONTENT_STATE_SB;
enum {
SS_CFG_SRC = 0,
SS_CFG_LOOKAHEAD = 1,
SS_CFG_TOTAL = 2
} UENUM1BYTE(SS_CFG_OFFSET);
typedef struct TplDepStats {
int64_t intra_cost;
int64_t inter_cost;
int64_t mc_flow;
int64_t mc_dep_cost;
int64_t mc_ref_cost;
int ref_frame_index;
int_mv mv;
@ -153,6 +171,12 @@ typedef struct TplDepFrame {
int base_qindex;
} TplDepFrame;
typedef enum {
COST_UPD_SB,
COST_UPD_SBROW,
COST_UPD_TILE,
} COST_UPDATE_TYPE;
#define TPL_DEP_COST_SCALE_LOG2 4
typedef struct AV1EncoderConfig {
@ -291,10 +315,6 @@ typedef struct AV1EncoderConfig {
aom_fixed_buf_t two_pass_stats_in;
#if CONFIG_FP_MB_STATS
aom_fixed_buf_t firstpass_mb_stats_in;
#endif
aom_tune_metric tuning;
aom_tune_content content;
int use_highbitdepth;
@ -324,14 +344,22 @@ typedef struct AV1EncoderConfig {
unsigned int motion_vector_unit_test;
const cfg_options_t *cfg;
int enable_rect_partitions;
int enable_ab_partitions;
int enable_1to4_partitions;
int min_partition_size;
int max_partition_size;
int enable_intra_edge_filter;
int enable_tx64;
int tx_size_search_method;
int enable_flip_idtx;
int enable_order_hint;
int enable_dist_wtd_comp;
int enable_ref_frame_mvs;
unsigned int max_reference_frames;
int enable_reduced_reference_set;
unsigned int allow_ref_frame_mvs;
int enable_masked_comp;
int enable_onesided_comp;
int enable_interintra_comp;
int enable_smooth_interintra;
int enable_diff_wtd_comp;
@ -360,8 +388,15 @@ typedef struct AV1EncoderConfig {
int reduced_tx_type_set;
int use_intra_dct_only;
int use_inter_dct_only;
int use_intra_default_tx_only;
int quant_b_adapt;
COST_UPDATE_TYPE coeff_cost_upd_freq;
COST_UPDATE_TYPE mode_cost_upd_freq;
int border_in_pixels;
AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS];
// Bit mask to specify which tier each of the 32 possible operating points
// conforms to.
unsigned int tier_mask;
} AV1EncoderConfig;
static INLINE int is_lossless_requested(const AV1EncoderConfig *cfg) {
@ -418,7 +453,7 @@ typedef struct FRAME_COUNTS {
unsigned int interintra[BLOCK_SIZE_GROUPS][2];
unsigned int interintra_mode[BLOCK_SIZE_GROUPS][INTERINTRA_MODES];
unsigned int wedge_interintra[BLOCK_SIZES_ALL][2];
unsigned int compound_type[BLOCK_SIZES_ALL][COMPOUND_TYPES - 1];
unsigned int compound_type[BLOCK_SIZES_ALL][MASKED_COMPOUND_TYPES];
unsigned int motion_mode[BLOCK_SIZES_ALL][MOTION_MODES];
unsigned int obmc[BLOCK_SIZES_ALL][2];
unsigned int intra_inter[INTRA_INTER_CONTEXTS][2];
@ -487,6 +522,11 @@ typedef struct inter_modes_info {
int64_t sse_arr[MAX_INTER_MODES];
int64_t est_rd_arr[MAX_INTER_MODES];
RdIdxPair rd_idx_pair_arr[MAX_INTER_MODES];
bool true_rd_arr[MAX_INTER_MODES];
uint8_t blk_skip_arr[MAX_INTER_MODES][MAX_MIB_SIZE * MAX_MIB_SIZE];
RD_STATS rd_cost_arr[MAX_INTER_MODES];
RD_STATS rd_cost_y_arr[MAX_INTER_MODES];
RD_STATS rd_cost_uv_arr[MAX_INTER_MODES];
} InterModesInfo;
// Encoder row synchronization
@ -593,15 +633,84 @@ typedef struct {
YV12_BUFFER_CONFIG buf;
} EncRefCntBuffer;
#if CONFIG_COLLECT_PARTITION_STATS
#if CONFIG_COLLECT_PARTITION_STATS == 2
typedef struct PartitionStats {
int partition_decisions[6][EXT_PARTITION_TYPES];
int partition_attempts[6][EXT_PARTITION_TYPES];
int64_t partition_times[6][EXT_PARTITION_TYPES];
int partition_redo;
} PartitionStats;
#endif
#if CONFIG_COLLECT_COMPONENT_TIMING
#include "aom_ports/aom_timer.h"
// Adjust the following to add new components.
enum {
encode_frame_to_data_rate_time,
encode_with_recode_loop_time,
loop_filter_time,
cdef_time,
loop_restoration_time,
av1_pack_bitstream_final_time,
av1_encode_frame_time,
av1_compute_global_motion_time,
av1_setup_motion_field_time,
encode_sb_time,
first_partition_search_pass_time,
rd_pick_partition_time,
rd_pick_sb_modes_time,
av1_rd_pick_intra_mode_sb_time,
av1_rd_pick_inter_mode_sb_time,
handle_intra_mode_time,
handle_inter_mode_time,
do_tx_search_time,
handle_newmv_time,
compound_type_rd_time,
interpolation_filter_search_time,
motion_mode_rd_time,
kTimingComponents,
} UENUM1BYTE(TIMING_COMPONENT);
static INLINE char const *get_component_name(int index) {
switch (index) {
case encode_frame_to_data_rate_time:
return "encode_frame_to_data_rate_time";
case encode_with_recode_loop_time: return "encode_with_recode_loop_time";
case loop_filter_time: return "loop_filter_time";
case cdef_time: return "cdef_time";
case loop_restoration_time: return "loop_restoration_time";
case av1_pack_bitstream_final_time: return "av1_pack_bitstream_final_time";
case av1_encode_frame_time: return "av1_encode_frame_time";
case av1_compute_global_motion_time:
return "av1_compute_global_motion_time";
case av1_setup_motion_field_time: return "av1_setup_motion_field_time";
case encode_sb_time: return "encode_sb_time";
case first_partition_search_pass_time:
return "first_partition_search_pass_time";
case rd_pick_partition_time: return "rd_pick_partition_time";
case rd_pick_sb_modes_time: return "rd_pick_sb_modes_time";
case av1_rd_pick_intra_mode_sb_time:
return "av1_rd_pick_intra_mode_sb_time";
case av1_rd_pick_inter_mode_sb_time:
return "av1_rd_pick_inter_mode_sb_time";
case handle_intra_mode_time: return "handle_intra_mode_time";
case handle_inter_mode_time: return "handle_inter_mode_time";
case do_tx_search_time: return "do_tx_search_time";
case handle_newmv_time: return "handle_newmv_time";
case compound_type_rd_time: return "compound_type_rd_time";
case interpolation_filter_search_time:
return "interpolation_filter_search_time";
case motion_mode_rd_time: return "motion_mode_rd_time";
default: assert(0);
}
return "error";
}
#endif
// The maximum number of internal ARFs except ALTREF_FRAME
#define MAX_INTERNAL_ARFS (REF_FRAMES - BWDREF_FRAME - 1)
typedef struct AV1_COMP {
QUANTS quants;
ThreadData td;
@ -615,7 +724,6 @@ typedef struct AV1_COMP {
struct lookahead_entry *alt_ref_source;
int no_show_kf;
int optimize_speed_feature;
int optimize_seg_arr[MAX_SEGMENTS];
YV12_BUFFER_CONFIG *source;
@ -630,6 +738,9 @@ typedef struct AV1_COMP {
// For a still frame, this flag is set to 1 to skip partition search.
int partition_search_skippable_frame;
// The following item corresponds to two_pass_partition_search speed features.
int two_pass_partition_search;
double csm_rate_array[32];
double m_rate_array[32];
int rate_size;
@ -665,13 +776,6 @@ typedef struct AV1_COMP {
// frame of the same type as the current frame).
int fb_of_context_type[REF_FRAMES];
// When true, a new rule for backward (future) reference frames is in effect:
// - BWDREF_FRAME is always the closest future frame available
// - ALTREF2_FRAME is always the 2nd closest future frame available
// - 'refresh_bwd_ref_frame' flag is used for updating both the BWDREF_FRAME
// and ALTREF2_FRAME. ('refresh_alt2_ref_frame' flag is irrelevant).
int new_bwdref_update_rule;
int ext_refresh_frame_flags_pending;
int ext_refresh_last_frame;
int ext_refresh_golden_frame;
@ -709,12 +813,6 @@ typedef struct AV1_COMP {
RATE_CONTROL rc;
double framerate;
// Relevant for an inter frame.
// - Index '0' corresponds to the values for the currently coded frame.
// - Indices LAST_FRAME ... EXTREF_FRAMES are used to store values for all the
// possible inter reference frames.
int interp_filter_selected[REF_FRAMES + 1][SWITCHABLE];
struct aom_codec_pkt_list *output_pkt_list;
MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS];
@ -741,12 +839,10 @@ typedef struct AV1_COMP {
fractional_mv_step_fp *find_fractional_mv_step;
av1_diamond_search_fn_t diamond_search_sad;
aom_variance_fn_ptr_t fn_ptr[BLOCK_SIZES_ALL];
#if CONFIG_INTERNAL_STATS
uint64_t time_receive_data;
uint64_t time_compress_data;
uint64_t time_pick_lpf;
#if CONFIG_FP_MB_STATS
int use_fp_mb_stats;
#endif
TWO_PASS twopass;
@ -802,9 +898,11 @@ typedef struct AV1_COMP {
int resize_pending_width;
int resize_pending_height;
int frame_flags;
search_site_config ss_cfg;
// ss_cfg[SS_CFG_LOOKAHEAD] : used in following cases
// -> temporal filtering
// -> intrabc
// ss_cfg[SS_CFG_SRC] : used everywhere except above mentioned cases
search_site_config ss_cfg[SS_CFG_TOTAL];
TileDataEnc *tile_data;
int allocated_tiles; // Keep track of memory allocated for tiles.
@ -824,17 +922,24 @@ typedef struct AV1_COMP {
// VARIANCE_AQ segment map refresh
int vaq_refresh;
// VAR_BASED_PARTITION thresholds
// 0 - threshold_128x128; 1 - threshold_64x64;
// 2 - threshold_32x32; 3 - threshold_16x16;
// 4 - vbp_threshold_8x8;
int64_t vbp_thresholds[5];
int64_t vbp_threshold_minmax;
int64_t vbp_threshold_sad;
int64_t vbp_threshold_copy;
BLOCK_SIZE vbp_bsize_min;
// Multi-threading
int num_workers;
AVxWorker *workers;
struct EncWorkerData *tile_thr_data;
int existing_fb_idx_to_show;
int is_arf_filter_off[MAX_EXT_ARFS + 1];
int num_extra_arfs;
int arf_pos_in_gf[MAX_EXT_ARFS + 1];
int arf_pos_for_ovrly[MAX_EXT_ARFS + 1];
int is_arf_filter_off[MAX_INTERNAL_ARFS + 1];
int global_motion_search_done;
int extra_arf_allowed;
int internal_altref_allowed;
// A flag to indicate if intrabc is ever used in current frame.
int intrabc_used;
int dv_cost[2][MV_VALS];
@ -873,9 +978,25 @@ typedef struct AV1_COMP {
#endif
// Set if screen content is set or relevant tools are enabled
int is_screen_content_type;
#if CONFIG_COLLECT_PARTITION_STATS
#if CONFIG_COLLECT_PARTITION_STATS == 2
PartitionStats partition_stats;
#endif
#if CONFIG_COLLECT_COMPONENT_TIMING
// component_time[] are initialized to zero while encoder starts.
uint64_t component_time[kTimingComponents];
struct aom_usec_timer component_timer[kTimingComponents];
// frame_component_time[] are initialized to zero at beginning of each frame.
uint64_t frame_component_time[kTimingComponents];
#endif
// The following data are for AV1 bitstream levels.
AV1_LEVEL target_seq_level_idx[MAX_NUM_OPERATING_POINTS];
int keep_level_stats;
AV1LevelInfo level_info[MAX_NUM_OPERATING_POINTS];
// Count the number of OBU_FRAME and OBU_FRAME_HEADER for level calculation.
int frame_header_count;
FrameWindowBuffer frame_window_buffer;
} AV1_COMP;
typedef struct {
@ -892,14 +1013,26 @@ struct EncodeFrameParams {
int primary_ref_frame;
int order_offset;
int show_frame;
int refresh_frame_flags;
// This is a bitmask of which reference slots can be used in this frame
int show_existing_frame;
int existing_fb_idx_to_show;
// Bitmask of which reference buffers may be referenced by this frame
int ref_frame_flags;
// Reference buffer assignment for this frame.
int remapped_ref_idx[REF_FRAMES];
// Flags which determine which reference buffers are refreshed by this frame
int refresh_last_frame;
int refresh_golden_frame;
int refresh_bwd_ref_frame;
int refresh_alt2_ref_frame;
int refresh_alt_ref_frame;
// Speed level to use for this frame: Bigger number means faster.
int speed;
unsigned int *frame_flags;
};
typedef struct EncodeFrameParams EncodeFrameParams;
@ -1112,6 +1245,48 @@ static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) {
cm->current_frame.frame_type == KEY_FRAME);
}
// Lighter version of set_offsets that only sets the mode info
// pointers.
static INLINE void set_mode_info_offsets(const AV1_COMP *const cpi,
MACROBLOCK *const x,
MACROBLOCKD *const xd, int mi_row,
int mi_col) {
const AV1_COMMON *const cm = &cpi->common;
const int idx_str = xd->mi_stride * mi_row + mi_col;
xd->mi = cm->mi_grid_visible + idx_str;
xd->mi[0] = cm->mi + idx_str;
x->mbmi_ext = cpi->mbmi_ext_base + (mi_row * cm->mi_cols + mi_col);
}
// Check to see if the given partition size is allowed for a specified number
// of mi block rows and columns remaining in the image.
// If not then return the largest allowed partition size
static INLINE BLOCK_SIZE find_partition_size(BLOCK_SIZE bsize, int rows_left,
int cols_left, int *bh, int *bw) {
int int_size = (int)bsize;
if (rows_left <= 0 || cols_left <= 0) {
return AOMMIN(bsize, BLOCK_8X8);
} else {
for (; int_size > 0; int_size -= 3) {
*bh = mi_size_high[int_size];
*bw = mi_size_wide[int_size];
if ((*bh <= rows_left) && (*bw <= cols_left)) {
break;
}
}
}
return (BLOCK_SIZE)int_size;
}
static const uint8_t av1_ref_frame_flag_list[REF_FRAMES] = { 0,
AOM_LAST_FLAG,
AOM_LAST2_FLAG,
AOM_LAST3_FLAG,
AOM_GOLD_FLAG,
AOM_BWD_FLAG,
AOM_ALT2_FLAG,
AOM_ALT_FLAG };
// Returns a Sequence Header OBU stored in an aom_fixed_buf_t, or NULL upon
// failure. When a non-NULL aom_fixed_buf_t pointer is returned by this
// function, the memory must be freed by the caller. Both the buf member of the
@ -1123,7 +1298,7 @@ static INLINE int encode_show_existing_frame(const AV1_COMMON *cm) {
// field.
aom_fixed_buf_t *av1_get_global_headers(AV1_COMP *cpi);
#if CONFIG_COLLECT_PARTITION_STATS
#if CONFIG_COLLECT_PARTITION_STATS == 2
static INLINE void av1_print_partition_stats(PartitionStats *part_stats) {
FILE *f = fopen("partition_stats.csv", "w");
if (!f) {
@ -1137,6 +1312,9 @@ static INLINE void av1_print_partition_stats(PartitionStats *part_stats) {
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
fprintf(f, "attempt_%d,", part);
}
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
fprintf(f, "time_%d,", part);
}
fprintf(f, "\n");
const int bsizes[6] = { 128, 64, 32, 16, 8, 4 };
@ -1149,6 +1327,9 @@ static INLINE void av1_print_partition_stats(PartitionStats *part_stats) {
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
fprintf(f, "%d,", part_stats->partition_attempts[bsize_idx][part]);
}
for (int part = 0; part < EXT_PARTITION_TYPES; part++) {
fprintf(f, "%ld,", part_stats->partition_times[bsize_idx][part]);
}
fprintf(f, "\n");
}
fclose(f);
@ -1156,7 +1337,8 @@ static INLINE void av1_print_partition_stats(PartitionStats *part_stats) {
static INLINE int av1_get_bsize_idx_for_part_stats(BLOCK_SIZE bsize) {
assert(bsize == BLOCK_128X128 || bsize == BLOCK_64X64 ||
bsize == BLOCK_32X32 || bsize == BLOCK_16X16 || bsize == BLOCK_8X8);
bsize == BLOCK_32X32 || bsize == BLOCK_16X16 || bsize == BLOCK_8X8 ||
bsize == BLOCK_4X4);
switch (bsize) {
case BLOCK_128X128: return 0;
case BLOCK_64X64: return 1;
@ -1169,6 +1351,27 @@ static INLINE int av1_get_bsize_idx_for_part_stats(BLOCK_SIZE bsize) {
}
#endif
#if CONFIG_COLLECT_COMPONENT_TIMING
static INLINE void start_timing(AV1_COMP *cpi, int component) {
aom_usec_timer_start(&cpi->component_timer[component]);
}
static INLINE void end_timing(AV1_COMP *cpi, int component) {
aom_usec_timer_mark(&cpi->component_timer[component]);
cpi->frame_component_time[component] +=
aom_usec_timer_elapsed(&cpi->component_timer[component]);
}
static INLINE char const *get_frame_type_enum(int type) {
switch (type) {
case 0: return "KEY_FRAME";
case 1: return "INTER_FRAME";
case 2: return "INTRA_ONLY_FRAME";
case 3: return "S_FRAME";
default: assert(0);
}
return "error";
}
#endif
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -76,21 +76,12 @@ void av1_free_txb_buf(AV1_COMP *cpi) { aom_free(cpi->coeff_buffer_base); }
void av1_set_coeff_buffer(const AV1_COMP *const cpi, MACROBLOCK *const x,
int mi_row, int mi_col) {
const AV1_COMMON *const cm = &cpi->common;
const int num_planes = av1_num_planes(cm);
int mib_size_log2 = cm->seq_params.mib_size_log2;
int stride = (cm->mi_cols >> mib_size_log2) + 1;
int offset = (mi_row >> mib_size_log2) * stride + (mi_col >> mib_size_log2);
CB_COEFF_BUFFER *coeff_buf = &cpi->coeff_buffer_base[offset];
const int txb_offset = x->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
x->mbmi_ext->cb_coef_buff = &cpi->coeff_buffer_base[offset];
x->mbmi_ext->cb_offset = x->cb_offset;
assert(x->cb_offset < (1 << num_pels_log2_lookup[cm->seq_params.sb_size]));
for (int plane = 0; plane < num_planes; ++plane) {
x->mbmi_ext->tcoeff[plane] = coeff_buf->tcoeff[plane] + x->cb_offset;
x->mbmi_ext->eobs[plane] = coeff_buf->eobs[plane] + txb_offset;
x->mbmi_ext->txb_skip_ctx[plane] =
coeff_buf->txb_skip_ctx[plane] + txb_offset;
x->mbmi_ext->dc_sign_ctx[plane] =
coeff_buf->dc_sign_ctx[plane] + txb_offset;
}
}
static void write_golomb(aom_writer *w, int level) {
@ -647,10 +638,18 @@ static void write_coeffs_txb_wrap(const AV1_COMMON *cm, MACROBLOCK *x,
aom_writer *w, int plane, int block,
int blk_row, int blk_col, TX_SIZE tx_size) {
MACROBLOCKD *xd = &x->e_mbd;
tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block);
uint16_t eob = x->mbmi_ext->eobs[plane][block];
TXB_CTX txb_ctx = { x->mbmi_ext->txb_skip_ctx[plane][block],
x->mbmi_ext->dc_sign_ctx[plane][block] };
const int txb_offset =
x->mbmi_ext->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
tran_low_t *tcoeff_txb =
x->mbmi_ext->cb_coef_buff->tcoeff[plane] + x->mbmi_ext->cb_offset;
uint16_t *eob_txb = x->mbmi_ext->cb_coef_buff->eobs[plane] + txb_offset;
uint8_t *txb_skip_ctx_txb =
x->mbmi_ext->cb_coef_buff->txb_skip_ctx[plane] + txb_offset;
int *dc_sign_ctx_txb =
x->mbmi_ext->cb_coef_buff->dc_sign_ctx[plane] + txb_offset;
tran_low_t *tcoeff = BLOCK_OFFSET(tcoeff_txb, block);
uint16_t eob = eob_txb[block];
TXB_CTX txb_ctx = { txb_skip_ctx_txb[block], dc_sign_ctx_txb[block] };
av1_write_coeffs_txb(cm, xd, w, blk_row, blk_col, plane, tx_size, tcoeff, eob,
&txb_ctx);
}
@ -1489,6 +1488,36 @@ static AOM_FORCE_INLINE void update_coeff_simple(
}
}
static INLINE void update_coeff_eob_fast(int *eob, int shift,
const int16_t *dequant_ptr,
const int16_t *scan,
const tran_low_t *coeff_ptr,
tran_low_t *qcoeff_ptr,
tran_low_t *dqcoeff_ptr) {
// TODO(sarahparker) make this work for aomqm
int eob_out = *eob;
int zbin[2] = { dequant_ptr[0] + ROUND_POWER_OF_TWO(dequant_ptr[0] * 70, 7),
dequant_ptr[1] + ROUND_POWER_OF_TWO(dequant_ptr[1] * 70, 7) };
for (int i = *eob - 1; i >= 0; i--) {
const int rc = scan[i];
const int qcoeff = qcoeff_ptr[rc];
const int coeff = coeff_ptr[rc];
const int coeff_sign = (coeff >> 31);
int64_t abs_coeff = (coeff ^ coeff_sign) - coeff_sign;
if (((abs_coeff << (1 + shift)) < zbin[rc != 0]) || (qcoeff == 0)) {
eob_out--;
qcoeff_ptr[rc] = 0;
dqcoeff_ptr[rc] = 0;
} else {
break;
}
}
*eob = eob_out;
}
static AOM_FORCE_INLINE void update_coeff_eob(
int *accu_rate, int64_t *accu_dist, int *eob, int *nz_num, int *nz_ci,
int si, TX_SIZE tx_size, TX_CLASS tx_class, int bwl, int height,
@ -1624,35 +1653,44 @@ static INLINE void update_skip(int *accu_rate, int64_t accu_dist, int *eob,
int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
int block, TX_SIZE tx_size, TX_TYPE tx_type,
const TXB_CTX *const txb_ctx, int *rate_cost,
int sharpness) {
const AV1_COMMON *cm = &cpi->common;
int sharpness, int fast_mode) {
MACROBLOCKD *xd = &x->e_mbd;
struct macroblockd_plane *pd = &xd->plane[plane];
const struct macroblock_plane *p = &x->plane[plane];
const SCAN_ORDER *scan_order = get_scan(tx_size, tx_type);
const int16_t *scan = scan_order->scan;
const int shift = av1_get_tx_scale(tx_size);
int eob = p->eobs[block];
const int16_t *dequant = p->dequant_QTX;
tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
tran_low_t *dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
const tran_low_t *tcoeff = BLOCK_OFFSET(p->coeff, block);
if (fast_mode) {
update_coeff_eob_fast(&eob, shift, dequant, scan, tcoeff, qcoeff, dqcoeff);
p->eobs[block] = eob;
if (eob == 0) {
*rate_cost = av1_cost_skip_txb(x, txb_ctx, plane, tx_size);
return eob;
}
}
const AV1_COMMON *cm = &cpi->common;
const PLANE_TYPE plane_type = get_plane_type(plane);
const TX_SIZE txs_ctx = get_txsize_entropy_ctx(tx_size);
const TX_CLASS tx_class = tx_type_to_class[tx_type];
const MB_MODE_INFO *mbmi = xd->mi[0];
const struct macroblock_plane *p = &x->plane[plane];
struct macroblockd_plane *pd = &xd->plane[plane];
tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
tran_low_t *dqcoeff = BLOCK_OFFSET(pd->dqcoeff, block);
const tran_low_t *tcoeff = BLOCK_OFFSET(p->coeff, block);
const int16_t *dequant = p->dequant_QTX;
const int bwl = get_txb_bwl(tx_size);
const int width = get_txb_wide(tx_size);
const int height = get_txb_high(tx_size);
assert(width == (1 << bwl));
const int is_inter = is_inter_block(mbmi);
const SCAN_ORDER *scan_order = get_scan(tx_size, tx_type);
const int16_t *scan = scan_order->scan;
const LV_MAP_COEFF_COST *txb_costs = &x->coeff_costs[txs_ctx][plane_type];
const int eob_multi_size = txsize_log2_minus4[tx_size];
const LV_MAP_EOB_COST *txb_eob_costs =
&x->eob_costs[eob_multi_size][plane_type];
const int shift = av1_get_tx_scale(tx_size);
const int64_t rdmult =
((x->rdmult * plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8))) +
2) >>
const int rshift =
(sharpness +
(cpi->oxcf.aq_mode == VARIANCE_AQ && mbmi->segment_id < 4
? 7 - mbmi->segment_id
@ -1661,10 +1699,14 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
cpi->oxcf.deltaq_mode > NO_DELTA_Q && x->sb_energy_level < 0
? (3 - x->sb_energy_level)
: 0));
const int64_t rdmult =
(((int64_t)x->rdmult *
(plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8)))) +
2) >>
rshift;
uint8_t levels_buf[TX_PAD_2D];
uint8_t *const levels = set_levels(levels_buf, width);
int eob = p->eobs[block];
if (eob > 1) av1_txb_init_levels(qcoeff, width, height, levels);
@ -1705,7 +1747,7 @@ int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
#define UPDATE_COEFF_EOB_CASE(tx_class_literal) \
case tx_class_literal: \
for (; si >= 0 && nz_num <= max_nz_num; --si) { \
for (; si >= 0 && nz_num <= max_nz_num && !fast_mode; --si) { \
update_coeff_eob(&accu_rate, &accu_dist, &eob, &nz_num, nz_ci, si, \
tx_size, tx_class_literal, bwl, height, \
txb_ctx->dc_sign_ctx, rdmult, shift, dequant, scan, \
@ -1798,7 +1840,8 @@ int av1_optimize_txb(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
const int shift = av1_get_tx_scale(tx_size);
const int64_t rdmult =
((x->rdmult * plane_rd_mult[is_inter][plane_type] << (2 * (xd->bd - 8))) +
(((int64_t)x->rdmult * plane_rd_mult[is_inter][plane_type]
<< (2 * (xd->bd - 8))) +
2) >>
2;
uint8_t levels_buf[TX_PAD_2D];
@ -1965,15 +2008,22 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row,
2);
}
x->mbmi_ext->txb_skip_ctx[plane][block] = txb_ctx.txb_skip_ctx;
x->mbmi_ext->eobs[plane][block] = eob;
const int txb_offset =
x->mbmi_ext->cb_offset / (TX_SIZE_W_MIN * TX_SIZE_H_MIN);
uint16_t *eob_txb = x->mbmi_ext->cb_coef_buff->eobs[plane] + txb_offset;
uint8_t *txb_skip_ctx_txb =
x->mbmi_ext->cb_coef_buff->txb_skip_ctx[plane] + txb_offset;
txb_skip_ctx_txb[block] = txb_ctx.txb_skip_ctx;
eob_txb[block] = eob;
if (eob == 0) {
av1_set_contexts(xd, pd, plane, plane_bsize, tx_size, 0, blk_col, blk_row);
return;
}
tran_low_t *tcoeff = BLOCK_OFFSET(x->mbmi_ext->tcoeff[plane], block);
tran_low_t *tcoeff_txb =
x->mbmi_ext->cb_coef_buff->tcoeff[plane] + x->mbmi_ext->cb_offset;
tran_low_t *tcoeff = BLOCK_OFFSET(tcoeff_txb, block);
const int segment_id = mbmi->segment_id;
const int seg_eob = av1_get_tx_eob(&cpi->common.seg, segment_id, tx_size);
const tran_low_t *qcoeff = BLOCK_OFFSET(p->qcoeff, block);
@ -2066,7 +2116,9 @@ void av1_update_and_record_txb_context(int plane, int block, int blk_row,
#endif // CONFIG_ENTROPY_STATS
if (allow_update_cdf)
update_cdf(ec_ctx->dc_sign_cdf[plane_type][dc_sign_ctx], dc_sign, 2);
x->mbmi_ext->dc_sign_ctx[plane][block] = dc_sign_ctx;
int *dc_sign_ctx_txb =
x->mbmi_ext->cb_coef_buff->dc_sign_ctx[plane] + txb_offset;
dc_sign_ctx_txb[block] = dc_sign_ctx;
}
const int cul_level = av1_get_txb_entropy_context(tcoeff, scan_order, eob);

View file

@ -78,7 +78,7 @@ void hbt_destroy();
int av1_optimize_txb_new(const struct AV1_COMP *cpi, MACROBLOCK *x, int plane,
int block, TX_SIZE tx_size, TX_TYPE tx_type,
const TXB_CTX *const txb_ctx, int *rate_cost,
int sharpness);
int sharpness, int fast_mode);
// These numbers are empirically obtained.
static const int plane_rd_mult[REF_TYPES][PLANE_TYPES] = {

View file

@ -236,26 +236,34 @@ static void switch_tile_and_get_next_job(AV1_COMP *const cpi, int *cur_tile_id,
int tile_index = tile_row * tile_cols + tile_col;
TileDataEnc *this_tile = &cpi->tile_data[tile_index];
AV1RowMTInfo *row_mt_info = &this_tile->row_mt_info;
int num_mis_to_encode =
this_tile->tile_info.mi_row_end - row_mt_info->current_mi_row;
int num_sb_rows_in_tile =
av1_get_sb_rows_in_tile(cm, this_tile->tile_info);
int num_sb_cols_in_tile =
av1_get_sb_cols_in_tile(cm, this_tile->tile_info);
int theoretical_limit_on_threads =
AOMMIN((num_sb_cols_in_tile + 1) >> 1, num_sb_rows_in_tile);
int num_threads_working = row_mt_info->num_threads_working;
if (num_threads_working < theoretical_limit_on_threads) {
int num_mis_to_encode =
this_tile->tile_info.mi_row_end - row_mt_info->current_mi_row;
// Tile to be processed by this thread is selected on the basis of
// availability of jobs:
// 1) If jobs are available, tile to be processed is chosen on the
// basis of minimum number of threads working for that tile. If two or
// more tiles have same number of threads working for them, then the tile
// with maximum number of jobs available will be chosen.
// 2) If no jobs are available, then end_of_frame is reached.
if (num_mis_to_encode > 0) {
int num_threads_working = row_mt_info->num_threads_working;
if (num_threads_working < min_num_threads_working) {
min_num_threads_working = num_threads_working;
max_mis_to_encode = 0;
}
if (num_threads_working == min_num_threads_working &&
num_mis_to_encode > max_mis_to_encode) {
tile_id = tile_index;
max_mis_to_encode = num_mis_to_encode;
// Tile to be processed by this thread is selected on the basis of
// availability of jobs:
// 1) If jobs are available, tile to be processed is chosen on the
// basis of minimum number of threads working for that tile. If two or
// more tiles have same number of threads working for them, then the
// tile with maximum number of jobs available will be chosen.
// 2) If no jobs are available, then end_of_frame is reached.
if (num_mis_to_encode > 0) {
if (num_threads_working < min_num_threads_working) {
min_num_threads_working = num_threads_working;
max_mis_to_encode = 0;
}
if (num_threads_working == min_num_threads_working &&
num_mis_to_encode > max_mis_to_encode) {
tile_id = tile_index;
max_mis_to_encode = num_mis_to_encode;
}
}
}
}
@ -616,7 +624,7 @@ void av1_encode_tiles_row_mt(AV1_COMP *cpi) {
const int tile_rows = cm->tile_rows;
MultiThreadHandle *multi_thread_ctxt = &cpi->multi_thread_ctxt;
int num_workers = 0;
int total_num_sb_rows = 0;
int total_num_threads_row_mt = 0;
int max_sb_rows = 0;
if (cpi->tile_data == NULL || cpi->allocated_tiles < tile_cols * tile_rows) {
@ -631,11 +639,19 @@ void av1_encode_tiles_row_mt(AV1_COMP *cpi) {
TileDataEnc *tile_data = &cpi->tile_data[row * cm->tile_cols + col];
int num_sb_rows_in_tile =
av1_get_sb_rows_in_tile(cm, tile_data->tile_info);
total_num_sb_rows += num_sb_rows_in_tile;
int num_sb_cols_in_tile =
av1_get_sb_cols_in_tile(cm, tile_data->tile_info);
total_num_threads_row_mt +=
AOMMIN((num_sb_cols_in_tile + 1) >> 1, num_sb_rows_in_tile);
max_sb_rows = AOMMAX(max_sb_rows, num_sb_rows_in_tile);
}
}
num_workers = AOMMIN(cpi->oxcf.max_threads, total_num_sb_rows);
// TODO(ravi.chaudhary@ittiam.com): Currently the percentage of
// post-processing stages in encoder is quiet low, so limiting the number of
// threads to the theoretical limit in row-mt does not have much impact on
// post-processing multi-threading stage. Need to revisit this when
// post-processing time starts shooting up.
num_workers = AOMMIN(cpi->oxcf.max_threads, total_num_threads_row_mt);
if (multi_thread_ctxt->allocated_tile_cols != tile_cols ||
multi_thread_ctxt->allocated_tile_rows != tile_rows ||

File diff suppressed because it is too large Load diff

View file

@ -21,35 +21,7 @@
extern "C" {
#endif
#if CONFIG_FP_MB_STATS
#define FPMB_DCINTRA_MASK 0x01
#define FPMB_MOTION_ZERO_MASK 0x02
#define FPMB_MOTION_LEFT_MASK 0x04
#define FPMB_MOTION_RIGHT_MASK 0x08
#define FPMB_MOTION_UP_MASK 0x10
#define FPMB_MOTION_DOWN_MASK 0x20
#define FPMB_ERROR_SMALL_MASK 0x40
#define FPMB_ERROR_LARGE_MASK 0x80
#define FPMB_ERROR_SMALL_TH 2000
#define FPMB_ERROR_LARGE_TH 48000
typedef struct {
uint8_t *mb_stats_start;
uint8_t *mb_stats_end;
} FIRSTPASS_MB_STATS;
#endif
// Length of the bi-predictive frame group (BFG)
// NOTE: Currently each BFG contains one backward ref (BWF) frame plus a certain
// number of bi-predictive frames.
#define BFG_INTERVAL 2
// The maximum number of extra ALTREF's except ALTREF_FRAME
#define MAX_EXT_ARFS (REF_FRAMES - BWDREF_FRAME - 1)
#define MIN_EXT_ARF_INTERVAL 4
#define DOUBLE_DIVIDE_CHECK(x) ((x) < 0 ? (x)-0.000001 : (x) + 0.000001)
#define MIN_ZERO_MOTION 0.95
#define MAX_SR_CODED_ERROR 40
@ -59,45 +31,79 @@ typedef struct {
#define VLOW_MOTION_THRESHOLD 950
typedef struct {
// Frame number in display order, if stats are for a single frame.
// No real meaning for a collection of frames.
double frame;
// Weight assigned to this frame (or total weight for the collection of
// frames) currently based on intra factor and brightness factor. This is used
// to distribute bits betweeen easier and harder frames.
double weight;
// Intra prediction error.
double intra_error;
// Average wavelet energy computed using Discrete Wavelet Transform (DWT).
double frame_avg_wavelet_energy;
// Best of intra pred error and inter pred error using last frame as ref.
double coded_error;
// Best of intra pred error and inter pred error using golden frame as ref.
double sr_coded_error;
// Percentage of blocks with inter pred error < intra pred error.
double pcnt_inter;
// Percentage of blocks using (inter prediction and) non-zero motion vectors.
double pcnt_motion;
// Percentage of blocks where golden frame was the best reference. That is:
// inter pred error using golden frame < inter pred error using last frame and
// inter pred error using golden frame < intra pred error
double pcnt_second_ref;
// Percentage of blocks where intra and inter prediction errors were very
// close. Note that this is a 'weighted count', that is, the so blocks may be
// weighted by how close the two errors were.
double pcnt_neutral;
// Percentage of blocks that have almost no intra error residual
// (i.e. are in effect completely flat and untextured in the intra
// domain). In natural videos this is uncommon, but it is much more
// common in animations, graphics and screen content, so may be used
// as a signal to detect these types of content.
double intra_skip_pct;
double inactive_zone_rows; // Image mask rows top and bottom.
double inactive_zone_cols; // Image mask columns at left and right edges.
// Image mask rows top and bottom.
double inactive_zone_rows;
// Image mask columns at left and right edges.
double inactive_zone_cols;
// Average of row motion vectors.
double MVr;
// Mean of absolute value of row motion vectors.
double mvr_abs;
// Mean of column motion vectors.
double MVc;
// Mean of absolute value of column motion vectors.
double mvc_abs;
// Variance of row motion vectors.
double MVrv;
// Variance of column motion vectors.
double MVcv;
// Value in range [-1,1] indicating fraction of row and column motion vectors
// that point inwards (negative MV value) or outwards (positive MV value).
// For example, value of 1 indicates, all row/column MVs are inwards.
double mv_in_out_count;
// Count of unique non-zero motion vectors.
double new_mv_count;
// Duration of the frame / collection of frames.
double duration;
// 1.0 if stats are for a single frame, OR
// Number of frames in this collection for which the stats are accumulated.
double count;
// standard deviation for (0, 0) motion prediction error
double raw_error_stdev;
} FIRSTPASS_STATS;
enum {
KF_UPDATE = 0,
LF_UPDATE = 1,
GF_UPDATE = 2,
ARF_UPDATE = 3,
OVERLAY_UPDATE = 4,
BRF_UPDATE = 5, // Backward Reference Frame
LAST_BIPRED_UPDATE = 6, // Last Bi-predictive Frame
BIPRED_UPDATE = 7, // Bi-predictive Frame, but not the last one
INTNL_OVERLAY_UPDATE = 8, // Internal Overlay Frame
INTNL_ARF_UPDATE = 9, // Internal Altref Frame (candidate for ALTREF2)
FRAME_UPDATE_TYPES = 10
KF_UPDATE,
LF_UPDATE,
GF_UPDATE,
ARF_UPDATE,
OVERLAY_UPDATE,
INTNL_OVERLAY_UPDATE, // Internal Overlay Frame
INTNL_ARF_UPDATE, // Internal Altref Frame
FRAME_UPDATE_TYPES
} UENUM1BYTE(FRAME_UPDATE_TYPE);
#define FC_ANIMATION_THRESH 0.15
@ -109,18 +115,15 @@ enum {
typedef struct {
unsigned char index;
RATE_FACTOR_LEVEL rf_level[MAX_STATIC_GF_GROUP_LENGTH + 1];
FRAME_UPDATE_TYPE update_type[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char arf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char arf_update_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char arf_ref_idx[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char arf_pos_in_gf[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char pyramid_level[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char pyramid_height;
unsigned char pyramid_lvl_nodes[MAX_PYRAMID_LVL];
unsigned char brf_src_offset[MAX_STATIC_GF_GROUP_LENGTH + 1];
unsigned char bidir_pred_enabled[MAX_STATIC_GF_GROUP_LENGTH + 1];
int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH + 1];
int size;
} GF_GROUP;
typedef struct {
@ -139,11 +142,6 @@ typedef struct {
double mb_av_energy;
double frame_avg_haar_energy;
#if CONFIG_FP_MB_STATS
uint8_t *frame_mb_stats_buf;
uint8_t *this_frame_mb_stats;
FIRSTPASS_MB_STATS firstpass_mb_stats;
#endif
// An indication of the content type of the current frame
FRAME_CONTENT_TYPE fr_content_type;
@ -160,7 +158,6 @@ typedef struct {
int kf_zeromotion_pct;
int last_kfgroup_zeromotion_pct;
int gf_zeromotion_pct;
int active_worst_quality;
int baseline_active_worst_quality;
int extend_minq;
@ -172,37 +169,14 @@ typedef struct {
struct AV1_COMP;
struct EncodeFrameParams;
struct AV1EncoderConfig;
void av1_init_first_pass(struct AV1_COMP *cpi);
void av1_rc_get_first_pass_params(struct AV1_COMP *cpi);
void av1_first_pass(struct AV1_COMP *cpi, const int64_t ts_duration);
void av1_end_first_pass(struct AV1_COMP *cpi);
void av1_init_second_pass(struct AV1_COMP *cpi);
void av1_rc_get_second_pass_params(
struct AV1_COMP *cpi, struct EncodeFrameParams *const frame_params);
// Post encode update of the rate control parameters for 2-pass
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
static INLINE int get_number_of_extra_arfs(int interval, int arf_pending,
int max_pyr_height) {
// Max extra (internal) alt-refs allowed based on interval.
int extra_arfs_from_interval = 0;
if (arf_pending && MAX_EXT_ARFS > 0) {
extra_arfs_from_interval =
(interval >= MIN_EXT_ARF_INTERVAL * (MAX_EXT_ARFS + 1))
? MAX_EXT_ARFS
: (interval >= MIN_EXT_ARF_INTERVAL * MAX_EXT_ARFS)
? MAX_EXT_ARFS - 1
: 0;
}
// Max extra (internal) alt-refs allowed based on max pyramid height.
assert(max_pyr_height >= 1);
const int ext_arfs_from_max_height = max_pyr_height - 1;
// Finally, min of the two above is our actual max allowance.
return AOMMIN(extra_arfs_from_interval, ext_arfs_from_max_height);
}
void av1_twopass_zero_stats(FIRSTPASS_STATS *section);
#ifdef __cplusplus
} // extern "C"

View file

@ -32,7 +32,6 @@
#define MIN_INLIER_PROB 0.1
#define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
#define USE_GM_FEATURE_BASED 1
// Border over which to compute the global motion
#define ERRORADV_BORDER 0
@ -276,7 +275,6 @@ static unsigned char *downconvert_frame(YV12_BUFFER_CONFIG *frm,
return buf_8bit;
}
#if USE_GM_FEATURE_BASED
static int compute_global_motion_feature_based(
TransformationType type, YV12_BUFFER_CONFIG *frm, YV12_BUFFER_CONFIG *ref,
int bit_depth, int *num_inliers_by_motion, double *params_by_motion,
@ -331,7 +329,7 @@ static int compute_global_motion_feature_based(
}
return 0;
}
#else
static INLINE RansacFuncDouble
get_ransac_double_prec_type(TransformationType type) {
switch (type) {
@ -543,6 +541,7 @@ static INLINE void solve_2x2_system(const double *M, const double *b,
output_vec[1] = -M[2] * mult_b0 + M_0 * mult_b1;
}
/*
static INLINE void image_difference(const uint8_t *src, int src_stride,
const uint8_t *ref, int ref_stride,
int16_t *dst, int dst_stride, int height,
@ -557,6 +556,7 @@ static INLINE void image_difference(const uint8_t *src, int src_stride,
}
}
}
*/
// Compute an image gradient using a sobel filter.
// If dir == 1, compute the x gradient. If dir == 0, compute y. This function
@ -869,19 +869,22 @@ static int compute_global_motion_disflow_based(
}
return 0;
}
#endif
int av1_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *frm,
YV12_BUFFER_CONFIG *ref, int bit_depth,
GlobalMotionEstimationType gm_estimation_type,
int *num_inliers_by_motion,
double *params_by_motion, int num_motions) {
#if USE_GM_FEATURE_BASED
return compute_global_motion_feature_based(type, frm, ref, bit_depth,
num_inliers_by_motion,
params_by_motion, num_motions);
#else
return compute_global_motion_disflow_based(type, frm, ref, bit_depth,
num_inliers_by_motion,
params_by_motion, num_motions);
#endif
switch (gm_estimation_type) {
case GLOBAL_MOTION_FEATURE_BASED:
return compute_global_motion_feature_based(type, frm, ref, bit_depth,
num_inliers_by_motion,
params_by_motion, num_motions);
case GLOBAL_MOTION_DISFLOW_BASED:
return compute_global_motion_disflow_based(type, frm, ref, bit_depth,
num_inliers_by_motion,
params_by_motion, num_motions);
default: assert(0 && "Unknown global motion estimation type");
}
return 0;
}

View file

@ -22,6 +22,11 @@ extern "C" {
#define RANSAC_NUM_MOTIONS 1
typedef enum {
GLOBAL_MOTION_FEATURE_BASED,
GLOBAL_MOTION_DISFLOW_BASED,
} GlobalMotionEstimationType;
void av1_convert_model_to_params(const double *params,
WarpedMotionParams *model);
@ -56,6 +61,7 @@ int64_t av1_refine_integerized_param(WarpedMotionParams *wm,
*/
int av1_compute_global_motion(TransformationType type, YV12_BUFFER_CONFIG *frm,
YV12_BUFFER_CONFIG *ref, int bit_depth,
GlobalMotionEstimationType gm_estimation_type,
int *num_inliers_by_motion,
double *params_by_motion, int num_motions);
#ifdef __cplusplus

View file

@ -0,0 +1,192 @@
/*
* 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 "config/aom_config.h"
#include "config/aom_scale_rtcd.h"
#include "aom/aom_codec.h"
#include "aom/aom_encoder.h"
#include "aom_ports/system_state.h"
#include "av1/common/onyxc_int.h"
#include "av1/encoder/encoder.h"
#include "av1/encoder/firstpass.h"
#include "av1/encoder/gop_structure.h"
// Set parameters for frames between 'start' and 'end' (excluding both).
static void set_multi_layer_params(GF_GROUP *const gf_group, int start, int end,
int *frame_ind, int arf_ind, int level) {
assert(level >= MIN_PYRAMID_LVL);
const int num_frames_to_process = end - start - 1;
assert(num_frames_to_process >= 0);
if (num_frames_to_process == 0) return;
// Either we are at the last level of the pyramid, or we don't have enough
// frames between 'l' and 'r' to create one more level.
if (level == MIN_PYRAMID_LVL || num_frames_to_process < 3) {
// Leaf nodes.
while (++start < end) {
gf_group->update_type[*frame_ind] = LF_UPDATE;
gf_group->arf_src_offset[*frame_ind] = 0;
gf_group->arf_pos_in_gf[*frame_ind] = 0;
gf_group->arf_update_idx[*frame_ind] = arf_ind;
gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL;
++gf_group->pyramid_lvl_nodes[MIN_PYRAMID_LVL];
++(*frame_ind);
}
} else {
const int m = (start + end) / 2;
const int arf_pos_in_gf = *frame_ind;
// Internal ARF.
gf_group->update_type[*frame_ind] = INTNL_ARF_UPDATE;
gf_group->arf_src_offset[*frame_ind] = m - start - 1;
gf_group->arf_pos_in_gf[*frame_ind] = 0;
gf_group->arf_update_idx[*frame_ind] = 1; // mark all internal ARF 1
gf_group->pyramid_level[*frame_ind] = level;
++gf_group->pyramid_lvl_nodes[level];
++(*frame_ind);
// Frames displayed before this internal ARF.
set_multi_layer_params(gf_group, start, m, frame_ind, 1, level - 1);
// Overlay for internal ARF.
gf_group->update_type[*frame_ind] = INTNL_OVERLAY_UPDATE;
gf_group->arf_src_offset[*frame_ind] = 0;
gf_group->arf_pos_in_gf[*frame_ind] = arf_pos_in_gf; // For bit allocation.
gf_group->arf_update_idx[*frame_ind] = 1;
gf_group->pyramid_level[*frame_ind] = MIN_PYRAMID_LVL;
++(*frame_ind);
// Frames displayed after this internal ARF.
set_multi_layer_params(gf_group, m, end, frame_ind, arf_ind, level - 1);
}
}
static int construct_multi_layer_gf_structure(
GF_GROUP *const gf_group, int gf_interval, int pyr_height,
FRAME_UPDATE_TYPE first_frame_update_type) {
gf_group->pyramid_height = pyr_height;
av1_zero_array(gf_group->pyramid_lvl_nodes, MAX_PYRAMID_LVL);
int frame_index = 0;
// Keyframe / Overlay frame / Golden frame.
assert(gf_interval >= 1);
assert(first_frame_update_type == KF_UPDATE ||
first_frame_update_type == OVERLAY_UPDATE ||
first_frame_update_type == GF_UPDATE);
gf_group->update_type[frame_index] = first_frame_update_type;
gf_group->arf_src_offset[frame_index] = 0;
gf_group->arf_pos_in_gf[frame_index] = 0;
gf_group->arf_update_idx[frame_index] = 0;
gf_group->pyramid_level[frame_index] = MIN_PYRAMID_LVL;
++frame_index;
// ALTREF.
const int use_altref = (gf_group->pyramid_height > 0);
if (use_altref) {
gf_group->update_type[frame_index] = ARF_UPDATE;
gf_group->arf_src_offset[frame_index] = gf_interval - 1;
gf_group->arf_pos_in_gf[frame_index] = 0;
gf_group->arf_update_idx[frame_index] = 0;
gf_group->pyramid_level[frame_index] = gf_group->pyramid_height;
++frame_index;
}
// Rest of the frames.
const int next_height =
use_altref ? gf_group->pyramid_height - 1 : gf_group->pyramid_height;
assert(next_height >= MIN_PYRAMID_LVL);
set_multi_layer_params(gf_group, 0, gf_interval, &frame_index, 0,
next_height);
return frame_index;
}
#define CHECK_GF_PARAMETER 0
#if CHECK_GF_PARAMETER
void check_frame_params(GF_GROUP *const gf_group, int gf_interval) {
static const char *update_type_strings[FRAME_UPDATE_TYPES] = {
"KF_UPDATE", "LF_UPDATE", "GF_UPDATE",
"ARF_UPDATE", "OVERLAY_UPDATE", "INTNL_OVERLAY_UPDATE",
"INTNL_ARF_UPDATE"
};
FILE *fid = fopen("GF_PARAMS.txt", "a");
fprintf(fid, "\ngf_interval = {%d}\n", gf_interval);
for (int i = 0; i <= gf_group->size; ++i) {
fprintf(fid, "#%2d : %s %d %d %d %d\n", i,
update_type_strings[gf_group->update_type[i]],
gf_group->arf_src_offset[i], gf_group->arf_pos_in_gf[i],
gf_group->arf_update_idx[i], gf_group->pyramid_level[i]);
}
fprintf(fid, "number of nodes in each level: \n");
for (int i = 0; i < gf_group->pyramid_height; ++i) {
fprintf(fid, "lvl %d: %d ", i, gf_group->pyramid_lvl_nodes[i]);
}
fprintf(fid, "\n");
fclose(fid);
}
#endif // CHECK_GF_PARAMETER
static INLINE int max_pyramid_height_from_width(int pyramid_width) {
if (pyramid_width > 12) return 4;
if (pyramid_width > 6) return 3;
if (pyramid_width > 3) return 2;
if (pyramid_width > 1) return 1;
return 0;
}
static int get_pyramid_height(const AV1_COMP *const cpi) {
const RATE_CONTROL *const rc = &cpi->rc;
assert(IMPLIES(cpi->oxcf.gf_max_pyr_height == MIN_PYRAMID_LVL,
!rc->source_alt_ref_pending)); // define_gf_group() enforced.
if (!rc->source_alt_ref_pending) {
return MIN_PYRAMID_LVL;
}
assert(cpi->oxcf.gf_max_pyr_height > MIN_PYRAMID_LVL);
if (!cpi->internal_altref_allowed) {
assert(MIN_PYRAMID_LVL + 1 <= cpi->oxcf.gf_max_pyr_height);
return MIN_PYRAMID_LVL + 1;
}
return AOMMIN(max_pyramid_height_from_width(rc->baseline_gf_interval),
cpi->oxcf.gf_max_pyr_height);
}
void av1_gop_setup_structure(AV1_COMP *cpi,
const EncodeFrameParams *const frame_params) {
RATE_CONTROL *const rc = &cpi->rc;
TWO_PASS *const twopass = &cpi->twopass;
GF_GROUP *const gf_group = &twopass->gf_group;
const int key_frame = (frame_params->frame_type == KEY_FRAME);
const FRAME_UPDATE_TYPE first_frame_update_type =
key_frame ? KF_UPDATE
: rc->source_alt_ref_active ? OVERLAY_UPDATE : GF_UPDATE;
gf_group->size = construct_multi_layer_gf_structure(
gf_group, rc->baseline_gf_interval, get_pyramid_height(cpi),
first_frame_update_type);
// We need to configure the frame at the end of the sequence + 1 that
// will be the start frame for the next group. Otherwise prior to the
// call to av1_get_second_pass_params(), the data will be undefined.
gf_group->update_type[gf_group->size] =
(rc->source_alt_ref_pending) ? OVERLAY_UPDATE : GF_UPDATE;
gf_group->arf_update_idx[gf_group->size] = 0;
gf_group->arf_pos_in_gf[gf_group->size] = 0;
#if CHECK_GF_PARAMETER
check_frame_params(gf_group, rc->baseline_gf_interval);
#endif
}

View file

@ -0,0 +1,36 @@
/*
* 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.
*/
#ifndef AOM_AV1_ENCODER_GOP_STRUCTURE_H_
#define AOM_AV1_ENCODER_GOP_STRUCTURE_H_
#include "av1/common/onyxc_int.h"
#include "av1/encoder/ratectrl.h"
#ifdef __cplusplus
extern "C" {
#endif
struct AV1_COMP;
struct EncodeFrameParams;
// Set up the Group-Of-Pictures structure for this GF_GROUP. This involves
// deciding where to place the various FRAME_UPDATE_TYPEs in the group. It does
// this primarily by setting the contents of
// cpi->twopass.gf_group.update_type[].
void av1_gop_setup_structure(
struct AV1_COMP *cpi, const struct EncodeFrameParams *const frame_params);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AOM_AV1_ENCODER_GOP_STRUCTURE_H_

View file

@ -393,8 +393,9 @@ void av1_get_block_hash_value(uint8_t *y_src, int stride, int block_size,
uint32_t *hash_value1, uint32_t *hash_value2,
int use_highbitdepth, MACROBLOCK *x) {
uint32_t to_hash[4];
const int add_value = hash_block_size_to_index(block_size) << crc_bits;
int add_value = hash_block_size_to_index(block_size);
assert(add_value >= 0);
add_value <<= crc_bits;
const int crc_mask = (1 << crc_bits) - 1;
// 2x2 subblock hash values in current CU

599
third_party/aom/av1/encoder/level.c vendored Normal file
View file

@ -0,0 +1,599 @@
/*
* 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 "aom_ports/system_state.h"
#include "av1/encoder/encoder.h"
#include "av1/encoder/level.h"
#define UNDEFINED_LEVEL \
{ \
.level = SEQ_LEVEL_MAX, .max_picture_size = 0, .max_h_size = 0, \
.max_v_size = 0, .max_display_rate = 0, .max_decode_rate = 0, \
.max_header_rate = 0, .main_mbps = 0, .high_mbps = 0, .main_cr = 0, \
.high_cr = 0, .max_tiles = 0, .max_tile_cols = 0 \
}
static const AV1LevelSpec av1_level_defs[SEQ_LEVELS] = {
{ .level = SEQ_LEVEL_2_0,
.max_picture_size = 147456,
.max_h_size = 2048,
.max_v_size = 1152,
.max_display_rate = 4423680L,
.max_decode_rate = 5529600L,
.max_header_rate = 150,
.main_mbps = 1.5,
.high_mbps = 0,
.main_cr = 2.0,
.high_cr = 0,
.max_tiles = 8,
.max_tile_cols = 4 },
{ .level = SEQ_LEVEL_2_1,
.max_picture_size = 278784,
.max_h_size = 2816,
.max_v_size = 1584,
.max_display_rate = 8363520L,
.max_decode_rate = 10454400L,
.max_header_rate = 150,
.main_mbps = 3.0,
.high_mbps = 0,
.main_cr = 2.0,
.high_cr = 0,
.max_tiles = 8,
.max_tile_cols = 4 },
UNDEFINED_LEVEL,
UNDEFINED_LEVEL,
{ .level = SEQ_LEVEL_3_0,
.max_picture_size = 665856,
.max_h_size = 4352,
.max_v_size = 2448,
.max_display_rate = 19975680L,
.max_decode_rate = 24969600L,
.max_header_rate = 150,
.main_mbps = 6.0,
.high_mbps = 0,
.main_cr = 2.0,
.high_cr = 0,
.max_tiles = 16,
.max_tile_cols = 6 },
{ .level = SEQ_LEVEL_3_1,
.max_picture_size = 1065024,
.max_h_size = 5504,
.max_v_size = 3096,
.max_display_rate = 31950720L,
.max_decode_rate = 39938400L,
.max_header_rate = 150,
.main_mbps = 10.0,
.high_mbps = 0,
.main_cr = 2.0,
.high_cr = 0,
.max_tiles = 16,
.max_tile_cols = 6 },
UNDEFINED_LEVEL,
UNDEFINED_LEVEL,
{ .level = SEQ_LEVEL_4_0,
.max_picture_size = 2359296,
.max_h_size = 6144,
.max_v_size = 3456,
.max_display_rate = 70778880L,
.max_decode_rate = 77856768L,
.max_header_rate = 300,
.main_mbps = 12.0,
.high_mbps = 30.0,
.main_cr = 4.0,
.high_cr = 4.0,
.max_tiles = 32,
.max_tile_cols = 8 },
{ .level = SEQ_LEVEL_4_1,
.max_picture_size = 2359296,
.max_h_size = 6144,
.max_v_size = 3456,
.max_display_rate = 141557760L,
.max_decode_rate = 155713536L,
.max_header_rate = 300,
.main_mbps = 20.0,
.high_mbps = 50.0,
.main_cr = 4.0,
.high_cr = 4.0,
.max_tiles = 32,
.max_tile_cols = 8 },
UNDEFINED_LEVEL,
UNDEFINED_LEVEL,
{ .level = SEQ_LEVEL_5_0,
.max_picture_size = 8912896,
.max_h_size = 8192,
.max_v_size = 4352,
.max_display_rate = 267386880L,
.max_decode_rate = 273715200L,
.max_header_rate = 300,
.main_mbps = 30.0,
.high_mbps = 100.0,
.main_cr = 6.0,
.high_cr = 4.0,
.max_tiles = 64,
.max_tile_cols = 8 },
{ .level = SEQ_LEVEL_5_1,
.max_picture_size = 8912896,
.max_h_size = 8192,
.max_v_size = 4352,
.max_display_rate = 534773760L,
.max_decode_rate = 547430400L,
.max_header_rate = 300,
.main_mbps = 40.0,
.high_mbps = 160.0,
.main_cr = 8.0,
.high_cr = 4.0,
.max_tiles = 64,
.max_tile_cols = 8 },
{ .level = SEQ_LEVEL_5_2,
.max_picture_size = 8912896,
.max_h_size = 8192,
.max_v_size = 4352,
.max_display_rate = 1069547520L,
.max_decode_rate = 1094860800L,
.max_header_rate = 300,
.main_mbps = 60.0,
.high_mbps = 240.0,
.main_cr = 8.0,
.high_cr = 4.0,
.max_tiles = 64,
.max_tile_cols = 8 },
{ .level = SEQ_LEVEL_5_3,
.max_picture_size = 8912896,
.max_h_size = 8192,
.max_v_size = 4352,
.max_display_rate = 1069547520L,
.max_decode_rate = 1176502272L,
.max_header_rate = 300,
.main_mbps = 60.0,
.high_mbps = 240.0,
.main_cr = 8.0,
.high_cr = 4.0,
.max_tiles = 64,
.max_tile_cols = 8 },
{ .level = SEQ_LEVEL_6_0,
.max_picture_size = 35651584,
.max_h_size = 16384,
.max_v_size = 8704,
.max_display_rate = 1069547520L,
.max_decode_rate = 1176502272L,
.max_header_rate = 300,
.main_mbps = 60.0,
.high_mbps = 240.0,
.main_cr = 8.0,
.high_cr = 4.0,
.max_tiles = 128,
.max_tile_cols = 16 },
{ .level = SEQ_LEVEL_6_1,
.max_picture_size = 35651584,
.max_h_size = 16384,
.max_v_size = 8704,
.max_display_rate = 2139095040L,
.max_decode_rate = 2189721600L,
.max_header_rate = 300,
.main_mbps = 100.0,
.high_mbps = 480.0,
.main_cr = 8.0,
.high_cr = 4.0,
.max_tiles = 128,
.max_tile_cols = 16 },
{ .level = SEQ_LEVEL_6_2,
.max_picture_size = 35651584,
.max_h_size = 16384,
.max_v_size = 8704,
.max_display_rate = 4278190080L,
.max_decode_rate = 4379443200L,
.max_header_rate = 300,
.main_mbps = 160.0,
.high_mbps = 800.0,
.main_cr = 8.0,
.high_cr = 4.0,
.max_tiles = 128,
.max_tile_cols = 16 },
{ .level = SEQ_LEVEL_6_3,
.max_picture_size = 35651584,
.max_h_size = 16384,
.max_v_size = 8704,
.max_display_rate = 4278190080L,
.max_decode_rate = 4706009088L,
.max_header_rate = 300,
.main_mbps = 160.0,
.high_mbps = 800.0,
.main_cr = 8.0,
.high_cr = 4.0,
.max_tiles = 128,
.max_tile_cols = 16 },
UNDEFINED_LEVEL,
UNDEFINED_LEVEL,
UNDEFINED_LEVEL,
UNDEFINED_LEVEL,
};
typedef enum {
LUMA_PIC_SIZE_TOO_LARGE,
LUMA_PIC_H_SIZE_TOO_LARGE,
LUMA_PIC_V_SIZE_TOO_LARGE,
TOO_MANY_TILE_COLUMNS,
TOO_MANY_TILES,
TILE_TOO_LARGE,
CROPPED_TILE_WIDTH_TOO_SMALL,
CROPPED_TILE_HEIGHT_TOO_SMALL,
TILE_WIDTH_INVALID,
FRAME_HEADER_RATE_TOO_HIGH,
DISPLAY_RATE_TOO_HIGH,
DECODE_RATE_TOO_HIGH,
CR_TOO_SMALL,
TARGET_LEVEL_FAIL_IDS,
TARGET_LEVEL_OK,
} TARGET_LEVEL_FAIL_ID;
static const char *level_fail_messages[TARGET_LEVEL_FAIL_IDS] = {
"The picture size is too large.",
"The picture width is too large.",
"The picture height is too large.",
"Too many tile columns are used.",
"Too many tiles are used.",
"The tile size is too large.",
"The cropped tile width is less than 8",
"The cropped tile height is less than 8",
"The tile width is invalid",
"The frame header rate is too high",
"The display luma sample rate is too high",
"The decoded luma sample rate is too high",
"The compression ratio is too small",
};
static double get_min_cr(const AV1LevelSpec *const level_spec, int tier,
int is_still_picture, int64_t decoded_sample_rate) {
if (is_still_picture) return 0.8;
const double min_cr_basis = tier ? level_spec->high_cr : level_spec->main_cr;
const double speed_adj =
(double)decoded_sample_rate / level_spec->max_display_rate;
return AOMMAX(min_cr_basis * speed_adj, 0.8);
}
static TARGET_LEVEL_FAIL_ID check_level_constraints(
const AV1LevelSpec *const target_level_spec,
const AV1LevelSpec *const level_spec,
const AV1LevelStats *const level_stats, int tier, int is_still_picture) {
const double min_cr = get_min_cr(target_level_spec, tier, is_still_picture,
level_spec->max_decode_rate);
TARGET_LEVEL_FAIL_ID fail_id = TARGET_LEVEL_OK;
do {
if (level_spec->max_picture_size > target_level_spec->max_picture_size) {
fail_id = LUMA_PIC_SIZE_TOO_LARGE;
break;
}
if (level_spec->max_h_size > target_level_spec->max_h_size) {
fail_id = LUMA_PIC_H_SIZE_TOO_LARGE;
break;
}
if (level_spec->max_v_size > target_level_spec->max_v_size) {
fail_id = LUMA_PIC_V_SIZE_TOO_LARGE;
break;
}
if (level_spec->max_tile_cols > target_level_spec->max_tile_cols) {
fail_id = TOO_MANY_TILE_COLUMNS;
break;
}
if (level_spec->max_tiles > target_level_spec->max_tiles) {
fail_id = TOO_MANY_TILES;
break;
}
if (level_spec->max_header_rate > target_level_spec->max_header_rate) {
fail_id = FRAME_HEADER_RATE_TOO_HIGH;
break;
}
if (level_spec->max_display_rate > target_level_spec->max_display_rate) {
fail_id = DISPLAY_RATE_TOO_HIGH;
break;
}
if (level_spec->max_decode_rate > target_level_spec->max_decode_rate) {
fail_id = DECODE_RATE_TOO_HIGH;
break;
}
if (level_stats->max_tile_size > 4096 * 2304) {
fail_id = TILE_TOO_LARGE;
break;
}
if (level_stats->min_cropped_tile_width < 8) {
fail_id = CROPPED_TILE_WIDTH_TOO_SMALL;
break;
}
if (level_stats->min_cropped_tile_height < 8) {
fail_id = CROPPED_TILE_HEIGHT_TOO_SMALL;
break;
}
if (!level_stats->tile_width_is_valid) {
fail_id = TILE_WIDTH_INVALID;
break;
}
if (level_stats->min_cr < min_cr) {
fail_id = CR_TOO_SMALL;
break;
}
} while (0);
return fail_id;
}
static INLINE int is_in_operating_point(int operating_point,
int temporal_layer_id,
int spatial_layer_id) {
if (!operating_point) return 1;
return ((operating_point >> temporal_layer_id) & 1) &&
((operating_point >> (spatial_layer_id + 8)) & 1);
}
static void get_tile_stats(const AV1_COMP *const cpi, int *max_tile_size,
int *min_cropped_tile_width,
int *min_cropped_tile_height,
int *tile_width_valid) {
const AV1_COMMON *const cm = &cpi->common;
const int tile_cols = cm->tile_cols;
const int tile_rows = cm->tile_rows;
*max_tile_size = 0;
*min_cropped_tile_width = INT_MAX;
*min_cropped_tile_height = INT_MAX;
*tile_width_valid = 1;
for (int tile_row = 0; tile_row < tile_rows; ++tile_row) {
for (int tile_col = 0; tile_col < tile_cols; ++tile_col) {
const TileInfo *const tile_info =
&cpi->tile_data[tile_row * cm->tile_cols + tile_col].tile_info;
const int tile_width =
(tile_info->mi_col_end - tile_info->mi_col_start) * MI_SIZE;
const int tile_height =
(tile_info->mi_row_end - tile_info->mi_row_start) * MI_SIZE;
const int tile_size = tile_width * tile_height;
*max_tile_size = AOMMAX(*max_tile_size, tile_size);
const int cropped_tile_width =
cm->width - tile_info->mi_col_start * MI_SIZE;
const int cropped_tile_height =
cm->height - tile_info->mi_row_start * MI_SIZE;
*min_cropped_tile_width =
AOMMIN(*min_cropped_tile_width, cropped_tile_width);
*min_cropped_tile_height =
AOMMIN(*min_cropped_tile_height, cropped_tile_height);
const int is_right_most_tile = tile_info->mi_col_end == cm->mi_cols;
if (!is_right_most_tile) {
if (av1_superres_scaled(cm))
*tile_width_valid &= tile_width >= 128;
else
*tile_width_valid &= tile_width >= 64;
}
}
}
}
static int store_frame_record(int64_t ts_start, int64_t ts_end, int pic_size,
int frame_header_count, int show_frame,
int show_existing_frame,
FrameWindowBuffer *const buffer) {
if (buffer->num < FRAME_WINDOW_SIZE) {
++buffer->num;
} else {
buffer->start = (buffer->start + 1) % FRAME_WINDOW_SIZE;
}
const int new_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE;
FrameRecord *const record = &buffer->buf[new_idx];
record->ts_start = ts_start;
record->ts_end = ts_end;
record->pic_size = pic_size;
record->frame_header_count = frame_header_count;
record->show_frame = show_frame;
record->show_existing_frame = show_existing_frame;
return new_idx;
}
// Count the number of frames encoded in the last "duration" ticks, in display
// time.
static int count_frames(const FrameWindowBuffer *const buffer,
int64_t duration) {
const int current_idx = (buffer->start + buffer->num - 1) % FRAME_WINDOW_SIZE;
// Assume current frame is shown frame.
assert(buffer->buf[current_idx].show_frame);
const int64_t current_time = buffer->buf[current_idx].ts_end;
const int64_t time_limit = AOMMAX(current_time - duration, 0);
int num_frames = 1;
int index = current_idx - 1;
for (int i = buffer->num - 2; i >= 0; --i, --index, ++num_frames) {
if (index < 0) index = FRAME_WINDOW_SIZE - 1;
const FrameRecord *const record = &buffer->buf[index];
if (!record->show_frame) continue;
const int64_t ts_start = record->ts_start;
if (ts_start < time_limit) break;
}
return num_frames;
}
// Scan previously encoded frames and update level metrics accordingly.
static void scan_past_frames(const FrameWindowBuffer *const buffer,
int num_frames_to_scan,
AV1LevelSpec *const level_spec) {
const int num_frames_in_buffer = buffer->num;
int index = (buffer->start + num_frames_in_buffer - 1) % FRAME_WINDOW_SIZE;
int frame_headers = 0;
int64_t display_samples = 0;
int64_t decoded_samples = 0;
for (int i = 0; i < AOMMIN(num_frames_in_buffer, num_frames_to_scan); ++i) {
const FrameRecord *const record = &buffer->buf[index];
if (!record->show_existing_frame) {
frame_headers += record->frame_header_count;
decoded_samples += record->pic_size;
}
if (record->show_frame) {
display_samples += record->pic_size;
}
--index;
if (index < 0) index = FRAME_WINDOW_SIZE - 1;
}
level_spec->max_header_rate =
AOMMAX(level_spec->max_header_rate, frame_headers);
level_spec->max_display_rate =
AOMMAX(level_spec->max_display_rate, display_samples);
level_spec->max_decode_rate =
AOMMAX(level_spec->max_decode_rate, decoded_samples);
}
void av1_update_level_info(AV1_COMP *cpi, size_t size, int64_t ts_start,
int64_t ts_end) {
AV1_COMMON *const cm = &cpi->common;
const int upscaled_width = cm->superres_upscaled_width;
const int height = cm->height;
const int tile_cols = cm->tile_cols;
const int tile_rows = cm->tile_rows;
const int tiles = tile_cols * tile_rows;
const int luma_pic_size = upscaled_width * height;
const int frame_header_count = cpi->frame_header_count;
const int show_frame = cm->show_frame;
const int show_existing_frame = cm->show_existing_frame;
// Store info. of current frame into FrameWindowBuffer.
FrameWindowBuffer *const buffer = &cpi->frame_window_buffer;
store_frame_record(ts_start, ts_end, luma_pic_size, frame_header_count,
show_frame, show_existing_frame, buffer);
// Count the number of frames encoded in the past 1 second.
const int encoded_frames_in_last_second =
show_frame ? count_frames(buffer, TICKS_PER_SEC) : 0;
int max_tile_size;
int min_cropped_tile_width;
int min_cropped_tile_height;
int tile_width_is_valid;
get_tile_stats(cpi, &max_tile_size, &min_cropped_tile_width,
&min_cropped_tile_height, &tile_width_is_valid);
const SequenceHeader *const seq_params = &cm->seq_params;
const BITSTREAM_PROFILE profile = seq_params->profile;
const int pic_size_profile_factor =
profile == PROFILE_0 ? 15 : (profile == PROFILE_1 ? 30 : 36);
const size_t frame_compressed_size = (size > 129 ? size - 128 : 1);
const size_t frame_uncompressed_size =
(luma_pic_size * pic_size_profile_factor) >> 3;
aom_clear_system_state();
const double compression_ratio =
frame_uncompressed_size / (double)frame_compressed_size;
const double total_time_encoded =
(cpi->last_end_time_stamp_seen - cpi->first_time_stamp_ever) /
(double)TICKS_PER_SEC;
const int temporal_layer_id = cm->temporal_layer_id;
const int spatial_layer_id = cm->spatial_layer_id;
const int is_still_picture = seq_params->still_picture;
// update level_stats
// TODO(kyslov@) fix the implementation according to buffer model
for (int i = 0; i < seq_params->operating_points_cnt_minus_1 + 1; ++i) {
if (!is_in_operating_point(seq_params->operating_point_idc[i],
temporal_layer_id, spatial_layer_id)) {
continue;
}
AV1LevelInfo *const level_info = &cpi->level_info[i];
AV1LevelStats *const level_stats = &level_info->level_stats;
level_stats->max_tile_size =
AOMMAX(level_stats->max_tile_size, max_tile_size);
level_stats->min_cropped_tile_width =
AOMMIN(level_stats->min_cropped_tile_width, min_cropped_tile_width);
level_stats->min_cropped_tile_height =
AOMMIN(level_stats->min_cropped_tile_height, min_cropped_tile_height);
level_stats->tile_width_is_valid &= tile_width_is_valid;
level_stats->total_compressed_size += frame_compressed_size;
if (show_frame) level_stats->total_time_encoded = total_time_encoded;
level_stats->min_cr = AOMMIN(level_stats->min_cr, compression_ratio);
// update level_spec
// TODO(kyslov@) update all spec fields
AV1LevelSpec *const level_spec = &level_info->level_spec;
level_spec->max_picture_size =
AOMMAX(level_spec->max_picture_size, luma_pic_size);
level_spec->max_h_size =
AOMMAX(level_spec->max_h_size, cm->superres_upscaled_width);
level_spec->max_v_size = AOMMAX(level_spec->max_v_size, height);
level_spec->max_tile_cols = AOMMAX(level_spec->max_tile_cols, tile_cols);
level_spec->max_tiles = AOMMAX(level_spec->max_tiles, tiles);
if (show_frame) {
scan_past_frames(buffer, encoded_frames_in_last_second, level_spec);
}
// Check whether target level is met.
const AV1_LEVEL target_seq_level_idx = cpi->target_seq_level_idx[i];
if (target_seq_level_idx < SEQ_LEVELS) {
const AV1LevelSpec *const target_level_spec =
av1_level_defs + target_seq_level_idx;
const int tier = seq_params->tier[i];
const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints(
target_level_spec, level_spec, level_stats, tier, is_still_picture);
if (fail_id != TARGET_LEVEL_OK) {
const int target_level_major = 2 + (target_seq_level_idx >> 2);
const int target_level_minor = target_seq_level_idx & 3;
aom_internal_error(&cm->error, AOM_CODEC_ERROR,
"Failed to encode to the target level %d_%d. %s",
target_level_major, target_level_minor,
level_fail_messages[fail_id]);
}
}
}
}
aom_codec_err_t av1_get_seq_level_idx(const AV1_COMP *cpi, int *seq_level_idx) {
const SequenceHeader *const seq_params = &cpi->common.seq_params;
if (!cpi->keep_level_stats) {
for (int op = 0; op < seq_params->operating_points_cnt_minus_1 + 1; ++op) {
seq_level_idx[op] = (int)SEQ_LEVEL_MAX;
}
return AOM_CODEC_OK;
}
const int is_still_picture = seq_params->still_picture;
for (int op = 0; op < seq_params->operating_points_cnt_minus_1 + 1; ++op) {
seq_level_idx[op] = (int)SEQ_LEVEL_MAX;
const int tier = seq_params->tier[op];
const AV1LevelInfo *const level_info = &cpi->level_info[op];
const AV1LevelStats *const level_stats = &level_info->level_stats;
const AV1LevelSpec *const level_spec = &level_info->level_spec;
for (int level = 0; level < SEQ_LEVELS; ++level) {
const AV1LevelSpec *const target_level_spec = av1_level_defs + level;
const TARGET_LEVEL_FAIL_ID fail_id = check_level_constraints(
target_level_spec, level_spec, level_stats, tier, is_still_picture);
if (fail_id == TARGET_LEVEL_OK) {
seq_level_idx[op] = level;
break;
}
}
}
return AOM_CODEC_OK;
}

76
third_party/aom/av1/encoder/level.h vendored Normal file
View file

@ -0,0 +1,76 @@
/*
* 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.
*/
#ifndef AOM_AV1_ENCODER_LEVEL_H_
#define AOM_AV1_ENCODER_LEVEL_H_
#include "av1/common/enums.h"
struct AV1_COMP;
// AV1 Level Specifications
typedef struct {
AV1_LEVEL level;
int max_picture_size;
int max_h_size;
int max_v_size;
int max_header_rate;
int max_tiles;
int max_tile_cols;
int64_t max_display_rate;
int64_t max_decode_rate;
double main_mbps;
double high_mbps;
double main_cr;
double high_cr;
} AV1LevelSpec;
typedef struct {
int64_t ts_start;
int64_t ts_end;
int pic_size;
int frame_header_count;
int show_frame;
int show_existing_frame;
} FrameRecord;
// Record frame info. in a rolling window.
#define FRAME_WINDOW_SIZE 256
typedef struct {
FrameRecord buf[FRAME_WINDOW_SIZE];
int num; // Number of FrameRecord stored in the buffer.
int start; // Buffer index of the first FrameRecord.
} FrameWindowBuffer;
// Used to keep track of AV1 Level Stats. Currently unimplemented.
typedef struct {
uint64_t total_compressed_size;
int max_tile_size;
int min_cropped_tile_width;
int min_cropped_tile_height;
int tile_width_is_valid;
double total_time_encoded;
double min_cr;
} AV1LevelStats;
typedef struct {
AV1LevelStats level_stats;
AV1LevelSpec level_spec;
} AV1LevelInfo;
void av1_update_level_info(struct AV1_COMP *cpi, size_t size, int64_t ts_start,
int64_t ts_end);
// Return sequence level indices in seq_level_idx[MAX_NUM_OPERATING_POINTS].
aom_codec_err_t av1_get_seq_level_idx(const struct AV1_COMP *cpi,
int *seq_level_idx);
#endif // AOM_AV1_ENCODER_LEVEL_H_

View file

@ -44,7 +44,7 @@ void av1_lookahead_destroy(struct lookahead_ctx *ctx) {
struct lookahead_ctx *av1_lookahead_init(
unsigned int width, unsigned int height, unsigned int subsampling_x,
unsigned int subsampling_y, int use_highbitdepth, unsigned int depth,
const int border_in_pixels) {
const int border_in_pixels, int is_scale) {
struct lookahead_ctx *ctx = NULL;
// Clamp the lookahead queue depth
@ -62,10 +62,19 @@ struct lookahead_ctx *av1_lookahead_init(
ctx->buf = calloc(depth, sizeof(*ctx->buf));
if (!ctx->buf) goto bail;
for (i = 0; i < depth; i++)
if (aom_alloc_frame_buffer(&ctx->buf[i].img, width, height, subsampling_x,
subsampling_y, use_highbitdepth,
border_in_pixels, legacy_byte_alignment))
goto bail;
if (is_scale) {
if (aom_alloc_frame_buffer(
&ctx->buf[i].img, width, height, subsampling_x, subsampling_y,
use_highbitdepth, border_in_pixels, legacy_byte_alignment))
goto bail;
} else {
aom_free_frame_buffer(&ctx->buf[i].img);
if (aom_realloc_lookahead_buffer(
&ctx->buf[i].img, width, height, subsampling_x, subsampling_y,
use_highbitdepth, AOM_ENC_LOOKAHEAD_BORDER,
legacy_byte_alignment, NULL, NULL, NULL))
goto bail;
}
}
return ctx;
bail:

View file

@ -47,7 +47,7 @@ struct lookahead_ctx {
struct lookahead_ctx *av1_lookahead_init(
unsigned int width, unsigned int height, unsigned int subsampling_x,
unsigned int subsampling_y, int use_highbitdepth, unsigned int depth,
const int border_in_pixels);
const int border_in_pixels, int is_scale);
/**\brief Destroys the lookahead stage
*/

View file

@ -19,6 +19,7 @@
#include "aom_dsp/aom_dsp_common.h"
#include "aom_mem/aom_mem.h"
#include "aom_ports/mem.h"
#include "aom_ports/system_state.h"
#include "av1/common/common.h"
#include "av1/common/mvref_common.h"
@ -28,6 +29,7 @@
#include "av1/encoder/encoder.h"
#include "av1/encoder/encodemv.h"
#include "av1/encoder/mcomp.h"
#include "av1/encoder/partition_strategy.h"
#include "av1/encoder/rdopt.h"
#include "av1/encoder/reconinter_enc.h"
@ -1798,11 +1800,11 @@ static int full_pixel_diamond(const AV1_COMP *const cpi, MACROBLOCK *x,
MV *mvp_full, int step_param, int sadpb,
int further_steps, int do_refine, int *cost_list,
const aom_variance_fn_ptr_t *fn_ptr,
const MV *ref_mv) {
const MV *ref_mv, const search_site_config *cfg) {
MV temp_mv;
int thissme, n, num00 = 0;
int bestsme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
step_param, sadpb, &n, fn_ptr, ref_mv);
int bestsme = cpi->diamond_search_sad(x, cfg, mvp_full, &temp_mv, step_param,
sadpb, &n, fn_ptr, ref_mv);
if (bestsme < INT_MAX)
bestsme = av1_get_mvpred_var(x, &temp_mv, ref_mv, fn_ptr, 1);
x->best_mv.as_mv = temp_mv;
@ -1817,9 +1819,9 @@ static int full_pixel_diamond(const AV1_COMP *const cpi, MACROBLOCK *x,
if (num00) {
num00--;
} else {
thissme = cpi->diamond_search_sad(x, &cpi->ss_cfg, mvp_full, &temp_mv,
step_param + n, sadpb, &num00, fn_ptr,
ref_mv);
thissme =
cpi->diamond_search_sad(x, cfg, mvp_full, &temp_mv, step_param + n,
sadpb, &num00, fn_ptr, ref_mv);
if (thissme < INT_MAX)
thissme = av1_get_mvpred_var(x, &temp_mv, ref_mv, fn_ptr, 1);
@ -2095,11 +2097,222 @@ static int is_exhaustive_allowed(const AV1_COMP *const cpi, MACROBLOCK *x) {
return is_allowed;
}
static int vector_match(int16_t *ref, int16_t *src, int bwl) {
int best_sad = INT_MAX;
int this_sad;
int d;
int center, offset = 0;
int bw = 4 << bwl; // redundant variable, to be changed in the experiments.
for (d = 0; d <= bw; d += 16) {
this_sad = aom_vector_var(&ref[d], src, bwl);
if (this_sad < best_sad) {
best_sad = this_sad;
offset = d;
}
}
center = offset;
for (d = -8; d <= 8; d += 16) {
int this_pos = offset + d;
// check limit
if (this_pos < 0 || this_pos > bw) continue;
this_sad = aom_vector_var(&ref[this_pos], src, bwl);
if (this_sad < best_sad) {
best_sad = this_sad;
center = this_pos;
}
}
offset = center;
for (d = -4; d <= 4; d += 8) {
int this_pos = offset + d;
// check limit
if (this_pos < 0 || this_pos > bw) continue;
this_sad = aom_vector_var(&ref[this_pos], src, bwl);
if (this_sad < best_sad) {
best_sad = this_sad;
center = this_pos;
}
}
offset = center;
for (d = -2; d <= 2; d += 4) {
int this_pos = offset + d;
// check limit
if (this_pos < 0 || this_pos > bw) continue;
this_sad = aom_vector_var(&ref[this_pos], src, bwl);
if (this_sad < best_sad) {
best_sad = this_sad;
center = this_pos;
}
}
offset = center;
for (d = -1; d <= 1; d += 2) {
int this_pos = offset + d;
// check limit
if (this_pos < 0 || this_pos > bw) continue;
this_sad = aom_vector_var(&ref[this_pos], src, bwl);
if (this_sad < best_sad) {
best_sad = this_sad;
center = this_pos;
}
}
return (center - (bw >> 1));
}
static const MV search_pos[4] = {
{ -1, 0 },
{ 0, -1 },
{ 0, 1 },
{ 1, 0 },
};
unsigned int av1_int_pro_motion_estimation(const AV1_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, int mi_row,
int mi_col, const MV *ref_mv) {
MACROBLOCKD *xd = &x->e_mbd;
MB_MODE_INFO *mi = xd->mi[0];
struct buf_2d backup_yv12[MAX_MB_PLANE] = { { 0, 0, 0, 0, 0 } };
DECLARE_ALIGNED(16, int16_t, hbuf[256]);
DECLARE_ALIGNED(16, int16_t, vbuf[256]);
DECLARE_ALIGNED(16, int16_t, src_hbuf[128]);
DECLARE_ALIGNED(16, int16_t, src_vbuf[128]);
int idx;
const int bw = 4 << mi_size_wide_log2[bsize];
const int bh = 4 << mi_size_high_log2[bsize];
const int search_width = bw << 1;
const int search_height = bh << 1;
const int src_stride = x->plane[0].src.stride;
const int ref_stride = xd->plane[0].pre[0].stride;
uint8_t const *ref_buf, *src_buf;
MV *tmp_mv = &xd->mi[0]->mv[0].as_mv;
unsigned int best_sad, tmp_sad, this_sad[4];
MV this_mv;
const int norm_factor = 3 + (bw >> 5);
const YV12_BUFFER_CONFIG *scaled_ref_frame =
av1_get_scaled_ref_frame(cpi, mi->ref_frame[0]);
MvLimits subpel_mv_limits;
if (scaled_ref_frame) {
int i;
// Swap out the reference frame for a version that's been scaled to
// match the resolution of the current frame, allowing the existing
// motion search code to be used without additional modifications.
for (i = 0; i < MAX_MB_PLANE; i++) backup_yv12[i] = xd->plane[i].pre[0];
av1_setup_pre_planes(xd, 0, scaled_ref_frame, mi_row, mi_col, NULL,
MAX_MB_PLANE);
}
if (xd->bd != 8) {
unsigned int sad;
tmp_mv->row = 0;
tmp_mv->col = 0;
sad = cpi->fn_ptr[bsize].sdf(x->plane[0].src.buf, src_stride,
xd->plane[0].pre[0].buf, ref_stride);
if (scaled_ref_frame) {
int i;
for (i = 0; i < MAX_MB_PLANE; i++) xd->plane[i].pre[0] = backup_yv12[i];
}
return sad;
}
// Set up prediction 1-D reference set
ref_buf = xd->plane[0].pre[0].buf - (bw >> 1);
for (idx = 0; idx < search_width; idx += 16) {
aom_int_pro_row(&hbuf[idx], ref_buf, ref_stride, bh);
ref_buf += 16;
}
ref_buf = xd->plane[0].pre[0].buf - (bh >> 1) * ref_stride;
for (idx = 0; idx < search_height; ++idx) {
vbuf[idx] = aom_int_pro_col(ref_buf, bw) >> norm_factor;
ref_buf += ref_stride;
}
// Set up src 1-D reference set
for (idx = 0; idx < bw; idx += 16) {
src_buf = x->plane[0].src.buf + idx;
aom_int_pro_row(&src_hbuf[idx], src_buf, src_stride, bh);
}
src_buf = x->plane[0].src.buf;
for (idx = 0; idx < bh; ++idx) {
src_vbuf[idx] = aom_int_pro_col(src_buf, bw) >> norm_factor;
src_buf += src_stride;
}
// Find the best match per 1-D search
tmp_mv->col = vector_match(hbuf, src_hbuf, mi_size_wide_log2[bsize]);
tmp_mv->row = vector_match(vbuf, src_vbuf, mi_size_high_log2[bsize]);
this_mv = *tmp_mv;
src_buf = x->plane[0].src.buf;
ref_buf = xd->plane[0].pre[0].buf + this_mv.row * ref_stride + this_mv.col;
best_sad = cpi->fn_ptr[bsize].sdf(src_buf, src_stride, ref_buf, ref_stride);
{
const uint8_t *const pos[4] = {
ref_buf - ref_stride,
ref_buf - 1,
ref_buf + 1,
ref_buf + ref_stride,
};
cpi->fn_ptr[bsize].sdx4df(src_buf, src_stride, pos, ref_stride, this_sad);
}
for (idx = 0; idx < 4; ++idx) {
if (this_sad[idx] < best_sad) {
best_sad = this_sad[idx];
tmp_mv->row = search_pos[idx].row + this_mv.row;
tmp_mv->col = search_pos[idx].col + this_mv.col;
}
}
if (this_sad[0] < this_sad[3])
this_mv.row -= 1;
else
this_mv.row += 1;
if (this_sad[1] < this_sad[2])
this_mv.col -= 1;
else
this_mv.col += 1;
ref_buf = xd->plane[0].pre[0].buf + this_mv.row * ref_stride + this_mv.col;
tmp_sad = cpi->fn_ptr[bsize].sdf(src_buf, src_stride, ref_buf, ref_stride);
if (best_sad > tmp_sad) {
*tmp_mv = this_mv;
best_sad = tmp_sad;
}
tmp_mv->row *= 8;
tmp_mv->col *= 8;
set_subpel_mv_search_range(
&x->mv_limits, &subpel_mv_limits.col_min, &subpel_mv_limits.col_max,
&subpel_mv_limits.row_min, &subpel_mv_limits.row_max, ref_mv);
clamp_mv(tmp_mv, subpel_mv_limits.col_min, subpel_mv_limits.col_max,
subpel_mv_limits.row_min, subpel_mv_limits.row_max);
if (scaled_ref_frame) {
int i;
for (i = 0; i < MAX_MB_PLANE; i++) xd->plane[i].pre[0] = backup_yv12[i];
}
return best_sad;
}
int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
MV *mvp_full, int step_param, int method,
int run_mesh_search, int error_per_bit,
int *cost_list, const MV *ref_mv, int var_max, int rd,
int x_pos, int y_pos, int intra) {
int x_pos, int y_pos, int intra,
const search_site_config *cfg) {
const SPEED_FEATURES *const sf = &cpi->sf;
const aom_variance_fn_ptr_t *fn_ptr = &cpi->fn_ptr[bsize];
int var = 0;
@ -2139,7 +2352,7 @@ int av1_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize,
case NSTEP:
var = full_pixel_diamond(cpi, x, mvp_full, step_param, error_per_bit,
MAX_MVSEARCH_STEPS - 1 - step_param, 1,
cost_list, fn_ptr, ref_mv);
cost_list, fn_ptr, ref_mv, cfg);
// Should we allow a follow on exhaustive search?
if (is_exhaustive_allowed(cpi, x)) {
@ -2676,14 +2889,15 @@ static int obmc_full_pixel_diamond(const AV1_COMP *cpi, MACROBLOCK *x,
MV *mvp_full, int step_param, int sadpb,
int further_steps, int do_refine,
const aom_variance_fn_ptr_t *fn_ptr,
const MV *ref_mv, MV *dst_mv,
int is_second) {
const MV *ref_mv, MV *dst_mv, int is_second,
const search_site_config *cfg) {
(void)cpi; // to silence compiler warning
const int32_t *wsrc = x->wsrc_buf;
const int32_t *mask = x->mask_buf;
MV temp_mv;
int thissme, n, num00 = 0;
int bestsme =
obmc_diamond_search_sad(x, &cpi->ss_cfg, wsrc, mask, mvp_full, &temp_mv,
obmc_diamond_search_sad(x, cfg, wsrc, mask, mvp_full, &temp_mv,
step_param, sadpb, &n, fn_ptr, ref_mv, is_second);
if (bestsme < INT_MAX)
bestsme = get_obmc_mvpred_var(x, wsrc, mask, &temp_mv, ref_mv, fn_ptr, 1,
@ -2700,9 +2914,9 @@ static int obmc_full_pixel_diamond(const AV1_COMP *cpi, MACROBLOCK *x,
if (num00) {
num00--;
} else {
thissme = obmc_diamond_search_sad(x, &cpi->ss_cfg, wsrc, mask, mvp_full,
&temp_mv, step_param + n, sadpb, &num00,
fn_ptr, ref_mv, is_second);
thissme = obmc_diamond_search_sad(x, cfg, wsrc, mask, mvp_full, &temp_mv,
step_param + n, sadpb, &num00, fn_ptr,
ref_mv, is_second);
if (thissme < INT_MAX)
thissme = get_obmc_mvpred_var(x, wsrc, mask, &temp_mv, ref_mv, fn_ptr,
1, is_second);
@ -2738,11 +2952,12 @@ int av1_obmc_full_pixel_search(const AV1_COMP *cpi, MACROBLOCK *x, MV *mvp_full,
int step_param, int sadpb, int further_steps,
int do_refine,
const aom_variance_fn_ptr_t *fn_ptr,
const MV *ref_mv, MV *dst_mv, int is_second) {
const MV *ref_mv, MV *dst_mv, int is_second,
const search_site_config *cfg) {
if (cpi->sf.obmc_full_pixel_search_level == 0) {
return obmc_full_pixel_diamond(cpi, x, mvp_full, step_param, sadpb,
further_steps, do_refine, fn_ptr, ref_mv,
dst_mv, is_second);
dst_mv, is_second, cfg);
} else {
const int32_t *wsrc = x->wsrc_buf;
const int32_t *mask = x->mask_buf;
@ -2851,3 +3066,117 @@ int av1_return_min_sub_pixel_mv(
lower_mv_precision(bestmv, allow_hp, 0);
return besterr;
}
void av1_simple_motion_search(AV1_COMP *const cpi, MACROBLOCK *x, int mi_row,
int mi_col, BLOCK_SIZE bsize, int ref,
MV ref_mv_full, int num_planes,
int use_subpixel) {
assert(num_planes == 1 &&
"Currently simple_motion_search only supports luma plane");
assert(!frame_is_intra_only(&cpi->common) &&
"Simple motion search only enabled for non-key frames");
AV1_COMMON *const cm = &cpi->common;
MACROBLOCKD *xd = &x->e_mbd;
set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize);
MB_MODE_INFO *mbmi = xd->mi[0];
mbmi->sb_type = bsize;
mbmi->ref_frame[0] = ref;
mbmi->ref_frame[1] = NONE_FRAME;
mbmi->motion_mode = SIMPLE_TRANSLATION;
const YV12_BUFFER_CONFIG *yv12 = get_ref_frame_yv12_buf(cm, ref);
const YV12_BUFFER_CONFIG *scaled_ref_frame =
av1_get_scaled_ref_frame(cpi, ref);
struct buf_2d backup_yv12;
// ref_mv is used to code the motion vector. ref_mv_full is the initial point.
// ref_mv is in units of 1/8 pel whereas ref_mv_full is in units of pel.
MV ref_mv = { 0, 0 };
const int step_param = cpi->mv_step_param;
const MvLimits tmp_mv_limits = x->mv_limits;
const SEARCH_METHODS search_methods = NSTEP;
const int do_mesh_search = 0;
const int sadpb = x->sadperbit16;
int cost_list[5];
const int ref_idx = 0;
int var;
if (scaled_ref_frame) {
backup_yv12 = xd->plane[AOM_PLANE_Y].pre[ref_idx];
av1_setup_pre_planes(xd, ref_idx, scaled_ref_frame, mi_row, mi_col, NULL,
num_planes);
} else {
av1_setup_pre_planes(xd, ref_idx, yv12, mi_row, mi_col,
get_ref_scale_factors(cm, ref), num_planes);
}
// This overwrites the mv_limits so we will need to restore it later.
av1_set_mv_search_range(&x->mv_limits, &ref_mv);
var = av1_full_pixel_search(
cpi, x, bsize, &ref_mv_full, step_param, search_methods, do_mesh_search,
sadpb, cond_cost_list(cpi, cost_list), &ref_mv, INT_MAX, 1,
mi_col * MI_SIZE, mi_row * MI_SIZE, 0, &cpi->ss_cfg[SS_CFG_SRC]);
// Restore
x->mv_limits = tmp_mv_limits;
const int use_subpel_search =
var < INT_MAX && !cpi->common.cur_frame_force_integer_mv && use_subpixel;
if (use_subpel_search) {
int not_used = 0;
if (cpi->sf.use_accurate_subpel_search) {
const int pw = block_size_wide[bsize];
const int ph = block_size_high[bsize];
cpi->find_fractional_mv_step(
x, cm, mi_row, mi_col, &ref_mv, cm->allow_high_precision_mv,
x->errorperbit, &cpi->fn_ptr[bsize], cpi->sf.mv.subpel_force_stop,
cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list),
x->nmv_vec_cost, x->mv_cost_stack, &not_used, &x->pred_sse[ref], NULL,
NULL, 0, 0, pw, ph, cpi->sf.use_accurate_subpel_search, 1);
} else {
cpi->find_fractional_mv_step(
x, cm, mi_row, mi_col, &ref_mv, cm->allow_high_precision_mv,
x->errorperbit, &cpi->fn_ptr[bsize], cpi->sf.mv.subpel_force_stop,
cpi->sf.mv.subpel_iters_per_step, cond_cost_list(cpi, cost_list),
x->nmv_vec_cost, x->mv_cost_stack, &not_used, &x->pred_sse[ref], NULL,
NULL, 0, 0, 0, 0, 0, 1);
}
} else {
// Manually convert from units of pixel to 1/8-pixels if we are not doing
// subpel search
x->best_mv.as_mv.row *= 8;
x->best_mv.as_mv.col *= 8;
}
mbmi->mv[0].as_mv = x->best_mv.as_mv;
// Get a copy of the prediction output
set_ref_ptrs(cm, xd, mbmi->ref_frame[0], mbmi->ref_frame[1]);
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
AOM_PLANE_Y, AOM_PLANE_Y);
aom_clear_system_state();
if (scaled_ref_frame) {
xd->plane[AOM_PLANE_Y].pre[ref_idx] = backup_yv12;
}
}
void av1_simple_motion_sse_var(AV1_COMP *cpi, MACROBLOCK *x, int mi_row,
int mi_col, BLOCK_SIZE bsize,
const MV ref_mv_full, int use_subpixel,
unsigned int *sse, unsigned int *var) {
MACROBLOCKD *xd = &x->e_mbd;
const MV_REFERENCE_FRAME ref =
cpi->rc.is_src_frame_alt_ref ? ALTREF_FRAME : LAST_FRAME;
av1_simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref, ref_mv_full, 1,
use_subpixel);
const uint8_t *src = x->plane[0].src.buf;
const int src_stride = x->plane[0].src.stride;
const uint8_t *dst = xd->plane[0].dst.buf;
const int dst_stride = xd->plane[0].dst.stride;
*var = cpi->fn_ptr[bsize].vf(src, src_stride, dst, dst_stride, sse);
}

View file

@ -13,6 +13,7 @@
#define AOM_AV1_ENCODER_MCOMP_H_
#include "av1/encoder/block.h"
#include "aom_dsp/variance.h"
#ifdef __cplusplus
@ -83,6 +84,11 @@ int av1_refining_search_sad(struct macroblock *x, MV *ref_mv, int sad_per_bit,
int distance, const aom_variance_fn_ptr_t *fn_ptr,
const MV *center_mv);
unsigned int av1_int_pro_motion_estimation(const struct AV1_COMP *cpi,
MACROBLOCK *x, BLOCK_SIZE bsize,
int mi_row, int mi_col,
const MV *ref_mv);
// Runs sequence of diamond searches in smaller steps for RD.
int av1_full_pixel_diamond(const struct AV1_COMP *cpi, MACROBLOCK *x,
MV *mvp_full, int step_param, int sadpb,
@ -132,13 +138,15 @@ int av1_full_pixel_search(const struct AV1_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, MV *mvp_full, int step_param,
int method, int run_mesh_search, int error_per_bit,
int *cost_list, const MV *ref_mv, int var_max, int rd,
int x_pos, int y_pos, int intra);
int x_pos, int y_pos, int intra,
const search_site_config *cfg);
int av1_obmc_full_pixel_search(const struct AV1_COMP *cpi, MACROBLOCK *x,
MV *mvp_full, int step_param, int sadpb,
int further_steps, int do_refine,
const aom_variance_fn_ptr_t *fn_ptr,
const MV *ref_mv, MV *dst_mv, int is_second);
const MV *ref_mv, MV *dst_mv, int is_second,
const search_site_config *cfg);
int av1_find_best_obmc_sub_pixel_tree_up(
MACROBLOCK *x, const AV1_COMMON *const cm, int mi_row, int mi_col,
MV *bestmv, const MV *ref_mv, int allow_hp, int error_per_bit,
@ -154,6 +162,19 @@ unsigned int av1_refine_warped_mv(const struct AV1_COMP *cpi,
int mi_row, int mi_col, int *pts0,
int *pts_inref0, int total_samples);
// Performs a motion search in SIMPLE_TRANSLATION mode using reference frame
// ref. Note that this sets the offset of mbmi, so we will need to reset it
// after calling this function.
void av1_simple_motion_search(struct AV1_COMP *const cpi, MACROBLOCK *x,
int mi_row, int mi_col, BLOCK_SIZE bsize, int ref,
MV ref_mv_full, int num_planes, int use_subpixel);
// Performs a simple motion search to calculate the sse and var of the residue
void av1_simple_motion_sse_var(struct AV1_COMP *cpi, MACROBLOCK *x, int mi_row,
int mi_col, BLOCK_SIZE bsize,
const MV ref_mv_full, int use_subpixel,
unsigned int *sse, unsigned int *var);
static INLINE void av1_set_fractional_mv(int_mv *fractional_best_mv) {
for (int z = 0; z < 3; z++) {
fractional_best_mv[z].as_int = INVALID_MV;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,722 @@
/*
* 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 <float.h>
#include "aom_ports/system_state.h"
#include "av1/common/enums.h"
#include "av1/common/reconinter.h"
#include "av1/encoder/encoder.h"
#include "av1/encoder/partition_model_weights.h"
#include "av1/encoder/partition_strategy.h"
#include "av1/encoder/rdopt.h"
// Performs a simple_motion_search with a single reference frame and extract
// the variance of residues. Here features is assumed to be a length 6 array.
// After this function is called, we will store the following in to features:
// features[0] = log(1 + dc_q**2/256)
// features[1] = log(1 + variance_of_residue)
// for i in [2, 3, 4, 5]:
// features[i] = log(1 + variance_of_residue_in_block[i]/variance_of_residue)
static void get_res_var_features(AV1_COMP *const cpi, MACROBLOCK *x, int mi_row,
int mi_col, BLOCK_SIZE bsize,
float *features) {
// TODO(chiyotsai@google.com): The data this model trained on did not also use
// SIMPLE_TRANSLATION to build the inter_predictor. Retraining and tuning the
// model with the correct data should give better performance.
assert(mi_size_wide[bsize] == mi_size_high[bsize]);
MACROBLOCKD *xd = &x->e_mbd;
// Perform a single motion search in Y_PLANE to make a prediction
const int use_subpixel = 0;
// Start getting the features
int f_idx = 0;
// Q_INDEX
const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8);
aom_clear_system_state();
features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f);
// VARIANCE
unsigned int sse = 0;
unsigned int var = 0;
const MV ref_mv_full = { .row = 0, .col = 0 };
av1_simple_motion_sse_var(cpi, x, mi_row, mi_col, bsize, ref_mv_full,
use_subpixel, &sse, &var);
aom_clear_system_state();
features[f_idx++] = logf(1.0f + (float)var);
// Regional
const uint8_t *src = x->plane[0].src.buf;
const int src_stride = x->plane[0].src.stride;
const uint8_t *dst = xd->plane[0].dst.buf;
const int dst_stride = xd->plane[0].dst.stride;
const int bw = block_size_wide[bsize];
const int bh = block_size_high[bsize];
const BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT);
int r_idx = 0;
for (r_idx = 0; r_idx < 4; r_idx++) {
const int x_idx = (r_idx & 1) * bw / 2;
const int y_idx = (r_idx >> 1) * bh / 2;
const int src_offset = y_idx * src_stride + x_idx;
const int dst_offset = y_idx * dst_stride + x_idx;
const unsigned int sub_var = cpi->fn_ptr[subsize].vf(
src + src_offset, src_stride, dst + dst_offset, dst_stride, &sse);
aom_clear_system_state();
const float var_ratio = (1.0f + (float)sub_var) / (4.0f + (float)var);
features[f_idx++] = var_ratio;
}
}
void av1_simple_motion_search_based_split(
AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, int mi_col,
BLOCK_SIZE bsize, int *partition_none_allowed, int *partition_horz_allowed,
int *partition_vert_allowed, int *do_rectangular_split,
int *do_square_split) {
const NN_CONFIG *nn_config = NULL;
float split_only_thresh = 0.0f;
if (bsize == BLOCK_128X128) {
nn_config = &av1_simple_motion_search_based_split_nn_config_128;
split_only_thresh = av1_simple_motion_search_based_split_thresh_128;
} else if (bsize == BLOCK_64X64) {
nn_config = &av1_simple_motion_search_based_split_nn_config_64;
split_only_thresh = av1_simple_motion_search_based_split_thresh_64;
} else if (bsize == BLOCK_32X32) {
nn_config = &av1_simple_motion_search_based_split_nn_config_32;
split_only_thresh = av1_simple_motion_search_based_split_thresh_32;
} else if (bsize == BLOCK_16X16) {
nn_config = &av1_simple_motion_search_based_split_nn_config_16;
split_only_thresh = av1_simple_motion_search_based_split_thresh_16;
} else if (bsize == BLOCK_8X8) {
// Disable BLOCK_8X8 for now
#if !CONFIG_DISABLE_FULL_PIXEL_SPLIT_8X8
nn_config = &av1_simple_motion_search_based_split_nn_config_8;
split_only_thresh = av1_simple_motion_search_based_split_thresh_8;
#endif
} else {
assert(0 && "Unexpected block size in simple_motion_based_split");
}
if (nn_config) {
float features[6] = { 0 };
float score = 0;
get_res_var_features(cpi, x, mi_row, mi_col, bsize, features);
av1_nn_predict(features, nn_config, &score);
if (score > split_only_thresh) {
*partition_none_allowed = 0;
*partition_horz_allowed = 0;
*partition_vert_allowed = 0;
*do_rectangular_split = 0;
}
// TODO(Venkat): Experiment to skip only rectangular/extended parititions
if (cpi->sf.simple_motion_search_split_only >= 2) {
if (score < -split_only_thresh) *do_square_split = 0;
}
}
}
// Given a list of ref frames in refs, performs simple_motion_search on each of
// the refs and returns the ref with the smallest sse. Returns -1 if none of the
// ref in the list is available. Also stores the best sse and var in best_sse,
// best_var, respectively. If save_mv_code is -1, don't update mv_ref_fulls in
// pc_tree. If save_mv_code is between 0 and 3, update mv_ref_fulls under
// pc_tree->split[i]. If save_mv_code is 4, update mv_ref_fulls under pc_tree.
static int simple_motion_search_get_best_ref(
AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize, const int *const refs, int num_refs,
int use_subpixel, int save_mv_code, unsigned int *best_sse,
unsigned int *best_var) {
// TODO(chiyotsai@google.com): The calculation of variance currently uses
// bsize, so we might take area outside of the image into account. We need to
// modify the SIMD functions to fix this later.
const AV1_COMMON *const cm = &cpi->common;
int best_ref = -1;
if (mi_col >= cm->mi_cols || mi_row >= cm->mi_rows) {
// If the whole block is outside of the image, set the var and sse to 0.
*best_var = 0;
*best_sse = 0;
return best_ref;
}
// Otherwise do loop through the reference frames and find the one with the
// minimum SSE
const MACROBLOCKD *xd = &x->e_mbd;
const MV *mv_ref_fulls = pc_tree->mv_ref_fulls;
const int num_planes = 1;
*best_sse = INT_MAX;
for (int ref_idx = 0; ref_idx < num_refs; ref_idx++) {
const int ref = refs[ref_idx];
if (cpi->ref_frame_flags & av1_ref_frame_flag_list[ref]) {
unsigned int curr_sse = 0, curr_var = 0;
av1_simple_motion_search(cpi, x, mi_row, mi_col, bsize, ref,
mv_ref_fulls[ref], num_planes, use_subpixel);
curr_var = cpi->fn_ptr[bsize].vf(
x->plane[0].src.buf, x->plane[0].src.stride, xd->plane[0].dst.buf,
xd->plane[0].dst.stride, &curr_sse);
if (curr_sse < *best_sse) {
*best_sse = curr_sse;
*best_var = curr_var;
best_ref = ref;
}
const int new_mv_row = x->best_mv.as_mv.row / 8;
const int new_mv_col = x->best_mv.as_mv.col / 8;
if (save_mv_code == 4) {
pc_tree->mv_ref_fulls[ref].row = new_mv_row;
pc_tree->mv_ref_fulls[ref].col = new_mv_col;
} else if (save_mv_code >= 0 && save_mv_code < 4) {
// Propagate the new motion vectors to a lower level
pc_tree->split[save_mv_code]->mv_ref_fulls[ref].row = new_mv_row;
pc_tree->split[save_mv_code]->mv_ref_fulls[ref].col = new_mv_col;
} else {
assert(save_mv_code == -1 &&
"Unknown code in simple_motion_search_get_best_ref.");
}
}
}
return best_ref;
}
// Performs fullpixel simple_motion_search with LAST_FRAME and ALTREF_FRAME on
// each subblock and extract the variance and sse of residues. Then store the
// var and sse from each partition subblock to features. The DC qindex is also
// stored in features.
// Here features is assumed to be a length 19 array.
// After this function is called, we will store the following to features:
// features[0:17] = var and sse from subblocks
// features[18] = DC q_index
static void simple_motion_search_prune_part_features(
AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize, float *features) {
// TODO(chiyotsai@google.com): Cache the result of the motion search from the
// larger bsize.
const int w_mi = mi_size_wide[bsize];
const int h_mi = mi_size_high[bsize];
int f_idx = 0;
assert(mi_size_wide[bsize] == mi_size_high[bsize]);
assert(cpi->ref_frame_flags & av1_ref_frame_flag_list[LAST_FRAME] ||
cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]);
// Setting up motion search
const int ref_list[] = { LAST_FRAME, ALTREF_FRAME };
const int num_refs = 2;
const int use_subpixel = 1;
unsigned int int_features[FEATURE_SIZE_SMS_PRUNE_PART - 1];
// Doing whole block first to update the mv
simple_motion_search_get_best_ref(
cpi, x, pc_tree, mi_row, mi_col, bsize, ref_list, num_refs, use_subpixel,
4, &int_features[f_idx], &int_features[f_idx + 1]);
f_idx += 2;
// Split subblocks
BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT);
int r_idx = 0;
for (r_idx = 0; r_idx < 4; r_idx++) {
const int sub_mi_col = mi_col + (r_idx & 1) * w_mi / 2;
const int sub_mi_row = mi_row + (r_idx >> 1) * h_mi / 2;
simple_motion_search_get_best_ref(
cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs,
use_subpixel, r_idx, &int_features[f_idx], &int_features[f_idx + 1]);
f_idx += 2;
}
// Horz subblocks
subsize = get_partition_subsize(bsize, PARTITION_HORZ);
for (r_idx = 0; r_idx < 2; r_idx++) {
const int sub_mi_col = mi_col + 0;
const int sub_mi_row = mi_row + r_idx * h_mi / 2;
simple_motion_search_get_best_ref(
cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs,
use_subpixel, -1, &int_features[f_idx], &int_features[f_idx + 1]);
f_idx += 2;
}
// Vert subblock
subsize = get_partition_subsize(bsize, PARTITION_VERT);
for (r_idx = 0; r_idx < 2; r_idx++) {
const int sub_mi_col = mi_col + r_idx * w_mi / 2;
const int sub_mi_row = mi_row + 0;
simple_motion_search_get_best_ref(
cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs,
use_subpixel, -1, &int_features[f_idx], &int_features[f_idx + 1]);
f_idx += 2;
}
aom_clear_system_state();
for (int idx = 0; idx < f_idx; idx++) {
features[idx] = logf(1.0f + (float)int_features[idx]);
}
const MACROBLOCKD *xd = &x->e_mbd;
set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize);
// Q_INDEX
const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8);
features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f);
// Neighbor stuff
const int has_above = !!xd->above_mbmi;
const int has_left = !!xd->left_mbmi;
const BLOCK_SIZE above_bsize = has_above ? xd->above_mbmi->sb_type : bsize;
const BLOCK_SIZE left_bsize = has_left ? xd->left_mbmi->sb_type : bsize;
features[f_idx++] = (float)has_above;
features[f_idx++] = (float)mi_size_wide_log2[above_bsize];
features[f_idx++] = (float)mi_size_high_log2[above_bsize];
features[f_idx++] = (float)has_left;
features[f_idx++] = (float)mi_size_wide_log2[left_bsize];
features[f_idx++] = (float)mi_size_high_log2[left_bsize];
assert(f_idx == FEATURE_SIZE_SMS_PRUNE_PART);
}
void av1_simple_motion_search_prune_part(
AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize, int *partition_none_allowed,
int *partition_horz_allowed, int *partition_vert_allowed,
int *do_square_split, int *do_rectangular_split, int *prune_horz,
int *prune_vert, float *features, int *valid) {
const AV1_COMMON *const cm = &cpi->common;
// Get model parameters
const NN_CONFIG *nn_config = NULL;
const float *prune_thresh = NULL, *only_thresh = NULL;
const float *ml_mean = NULL, *ml_std = NULL;
float normalized_features[FEATURE_SIZE_SMS_PRUNE_PART] = { 0.0f };
if (bsize == BLOCK_128X128) {
nn_config = &av1_simple_motion_search_prune_part_nn_config_128;
ml_mean = av1_simple_motion_search_prune_part_mean_128;
ml_std = av1_simple_motion_search_prune_part_std_128;
prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_128;
only_thresh = av1_simple_motion_search_prune_part_only_thresh_128;
} else if (bsize == BLOCK_64X64) {
nn_config = &av1_simple_motion_search_prune_part_nn_config_64;
ml_mean = av1_simple_motion_search_prune_part_mean_64;
ml_std = av1_simple_motion_search_prune_part_std_64;
prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_64;
only_thresh = av1_simple_motion_search_prune_part_only_thresh_64;
} else if (bsize == BLOCK_32X32) {
nn_config = &av1_simple_motion_search_prune_part_nn_config_32;
ml_mean = av1_simple_motion_search_prune_part_mean_32;
ml_std = av1_simple_motion_search_prune_part_std_32;
prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_32;
only_thresh = av1_simple_motion_search_prune_part_only_thresh_32;
} else if (bsize == BLOCK_16X16) {
nn_config = &av1_simple_motion_search_prune_part_nn_config_16;
ml_mean = av1_simple_motion_search_prune_part_mean_16;
ml_std = av1_simple_motion_search_prune_part_std_16;
prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_16;
only_thresh = av1_simple_motion_search_prune_part_only_thresh_16;
} else if (bsize == BLOCK_8X8) {
nn_config = &av1_simple_motion_search_prune_part_nn_config_8;
ml_mean = av1_simple_motion_search_prune_part_mean_8;
ml_std = av1_simple_motion_search_prune_part_std_8;
prune_thresh = av1_simple_motion_search_prune_part_prune_thresh_8;
only_thresh = av1_simple_motion_search_prune_part_only_thresh_8;
} else {
assert(0 && "Unexpected block size in simple_motion_prune_part");
}
// If there is no valid threshold, return immediately.
if (!nn_config || (prune_thresh[PARTITION_HORZ] == 0.0f &&
prune_thresh[PARTITION_VERT] == 0.0f)) {
return;
}
if (bsize < BLOCK_8X8) {
return;
}
// Get features
simple_motion_search_prune_part_features(cpi, x, pc_tree, mi_row, mi_col,
bsize, features);
*valid = 1;
for (int f_idx = 0; f_idx < FEATURE_SIZE_SMS_PRUNE_PART; f_idx++) {
normalized_features[f_idx] =
(features[f_idx] - ml_mean[f_idx]) / ml_std[f_idx];
}
// Get probabilities
float scores[EXT_PARTITION_TYPES] = { 0.0f },
probs[EXT_PARTITION_TYPES] = { 0.0f };
const int num_classes = (bsize == BLOCK_128X128 || bsize == BLOCK_8X8)
? PARTITION_TYPES
: EXT_PARTITION_TYPES;
av1_nn_predict(normalized_features, nn_config, scores);
aom_clear_system_state();
av1_nn_softmax(scores, probs, num_classes);
// Determine if we should prune rectangular partitions.
if (cpi->sf.simple_motion_search_prune_rect && !frame_is_intra_only(cm) &&
(*partition_horz_allowed || *partition_vert_allowed) &&
bsize >= BLOCK_8X8 && !av1_superres_scaled(cm)) {
*prune_horz = probs[PARTITION_HORZ] <= prune_thresh[PARTITION_HORZ];
*prune_vert = probs[PARTITION_VERT] <= prune_thresh[PARTITION_VERT];
}
// Silence compiler warnings
(void)only_thresh;
(void)partition_none_allowed;
(void)do_square_split;
(void)do_rectangular_split;
}
// Early terminates PARTITION_NONE using simple_motion_search features and the
// rate, distortion, and rdcost of PARTITION_NONE. This is only called when:
// - The frame is a show frame
// - The frame is not intra only
// - The current bsize is > BLOCK_8X8
// - blk_row + blk_height/2 < total_rows and blk_col + blk_width/2 < total_cols
void av1_simple_motion_search_early_term_none(
AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize, const RD_STATS *none_rdc,
int *early_terminate, float *simple_motion_features,
int *simple_motion_features_are_valid) {
// TODO(chiyotsai@google.com): There are other features we can extract from
// PARTITION_NONE. Play with this later.
int f_idx = 0;
if (!*simple_motion_features_are_valid) {
simple_motion_search_prune_part_features(cpi, x, pc_tree, mi_row, mi_col,
bsize, simple_motion_features);
*simple_motion_features_are_valid = 1;
}
f_idx = 25;
simple_motion_features[f_idx++] = logf(1.0f + (float)none_rdc->rate);
simple_motion_features[f_idx++] = logf(1.0f + (float)none_rdc->dist);
simple_motion_features[f_idx++] = logf(1.0f + (float)none_rdc->rdcost);
assert(f_idx == FEATURE_SIZE_SMS_TERM_NONE);
const float *ml_mean = NULL;
const float *ml_std = NULL;
const float *ml_model = NULL;
if (bsize == BLOCK_128X128) {
ml_mean = av1_simple_motion_search_term_none_mean_128;
ml_std = av1_simple_motion_search_term_none_std_128;
ml_model = av1_simple_motion_search_term_none_model_128;
} else if (bsize == BLOCK_64X64) {
ml_mean = av1_simple_motion_search_term_none_mean_64;
ml_std = av1_simple_motion_search_term_none_std_64;
ml_model = av1_simple_motion_search_term_none_model_64;
} else if (bsize == BLOCK_32X32) {
ml_mean = av1_simple_motion_search_term_none_mean_32;
ml_std = av1_simple_motion_search_term_none_std_32;
ml_model = av1_simple_motion_search_term_none_model_32;
} else if (bsize == BLOCK_16X16) {
ml_mean = av1_simple_motion_search_term_none_mean_16;
ml_std = av1_simple_motion_search_term_none_std_16;
ml_model = av1_simple_motion_search_term_none_model_16;
} else {
assert(0 && "Unexpected block size in simple_motion_term_none");
}
if (ml_model) {
float score = 0.0f;
for (f_idx = 0; f_idx < FEATURE_SIZE_SMS_TERM_NONE; f_idx++) {
score += ml_model[f_idx] *
(simple_motion_features[f_idx] - ml_mean[f_idx]) / ml_std[f_idx];
}
score += ml_model[FEATURE_SIZE_SMS_TERM_NONE];
if (score >= 0.0f) {
*early_terminate = 1;
}
}
}
static void firstpass_simple_motion_search_features(
AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize, float *features) {
assert(mi_size_wide[bsize] == mi_size_high[bsize]);
assert(cpi->ref_frame_flags & av1_ref_frame_flag_list[LAST_FRAME] ||
cpi->ref_frame_flags & av1_ref_frame_flag_list[ALTREF_FRAME]);
// Setting up motion search
const int ref_list[] = { LAST_FRAME, ALTREF_FRAME };
const int num_refs = 2;
const int use_subpixel = 0;
unsigned int int_features[10] = { 0 };
int f_idx = 0;
// Doing whole block first to update the mv
simple_motion_search_get_best_ref(
cpi, x, pc_tree, mi_row, mi_col, bsize, ref_list, num_refs, use_subpixel,
4, &int_features[f_idx], &int_features[f_idx + 1]);
f_idx += 2;
// Split subblocks
const BLOCK_SIZE subsize = get_partition_subsize(bsize, PARTITION_SPLIT);
const int w_mi = mi_size_wide[bsize];
const int h_mi = mi_size_high[bsize];
for (int r_idx = 0; r_idx < 4; r_idx++) {
const int sub_mi_col = mi_col + (r_idx & 1) * w_mi / 2;
const int sub_mi_row = mi_row + (r_idx >> 1) * h_mi / 2;
simple_motion_search_get_best_ref(
cpi, x, pc_tree, sub_mi_row, sub_mi_col, subsize, ref_list, num_refs,
use_subpixel, r_idx, &int_features[f_idx], &int_features[f_idx + 1]);
f_idx += 2;
}
aom_clear_system_state();
for (int idx = 0; idx < f_idx; idx++) {
features[idx] = logf(1.0f + (float)int_features[idx]);
}
const MACROBLOCKD *xd = &x->e_mbd;
set_offsets_for_motion_search(cpi, x, mi_row, mi_col, bsize);
// Q_INDEX
const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8);
features[f_idx++] = logf(1.0f + (float)(dc_q * dc_q) / 256.0f);
// Neighbor stuff
const int has_above = !!xd->above_mbmi;
const int has_left = !!xd->left_mbmi;
const BLOCK_SIZE above_bsize = has_above ? xd->above_mbmi->sb_type : bsize;
const BLOCK_SIZE left_bsize = has_left ? xd->left_mbmi->sb_type : bsize;
features[f_idx++] = (float)has_above;
features[f_idx++] = (float)mi_size_wide_log2[above_bsize];
features[f_idx++] = (float)mi_size_high_log2[above_bsize];
features[f_idx++] = (float)has_left;
features[f_idx++] = (float)mi_size_wide_log2[left_bsize];
features[f_idx++] = (float)mi_size_high_log2[left_bsize];
}
void av1_firstpass_simple_motion_search_early_term(AV1_COMP *const cpi,
MACROBLOCK *x,
PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize,
const RD_STATS *none_rdc,
int *do_square_split) {
const NN_CONFIG *nn_config = NULL;
float thresh = 0.0f;
const float *ml_mean = NULL, *ml_std = NULL;
if (bsize == BLOCK_32X32) {
nn_config = &av1_fp_simple_motion_search_term_none_nn_config_32;
ml_mean = av1_fp_simple_motion_search_term_none_mean_32;
ml_std = av1_fp_simple_motion_search_term_none_std_32;
thresh = av1_fp_simple_motion_search_term_none_thresh_32;
} else if (bsize == BLOCK_16X16) {
nn_config = &av1_fp_simple_motion_search_term_none_nn_config_16;
ml_mean = av1_fp_simple_motion_search_term_none_mean_16;
ml_std = av1_fp_simple_motion_search_term_none_std_16;
thresh = av1_fp_simple_motion_search_term_none_thresh_16;
} else if (bsize == BLOCK_8X8) {
nn_config = &av1_fp_simple_motion_search_term_none_nn_config_8;
ml_mean = av1_fp_simple_motion_search_term_none_mean_8;
ml_std = av1_fp_simple_motion_search_term_none_std_8;
thresh = av1_fp_simple_motion_search_term_none_thresh_8;
} else {
assert(0 &&
"Unexpected bsize in firstpass_simple_motion_search_early_term");
return;
}
float ml_features[FEATURE_SIZE_FP_SMS_TERM_NONE] = { 0.0f };
firstpass_simple_motion_search_features(cpi, x, pc_tree, mi_row, mi_col,
bsize, ml_features);
int f_idx = 17;
ml_features[f_idx++] = logf(1.0f + (float)none_rdc->rate);
ml_features[f_idx++] = logf(1.0f + (float)none_rdc->dist);
ml_features[f_idx++] = logf(1.0f + (float)none_rdc->rdcost);
for (f_idx = 0; f_idx < 20; f_idx++) {
ml_features[f_idx] = (ml_features[f_idx] - ml_mean[f_idx]) / ml_std[f_idx];
}
// Get probabilities
float score = 0.0f;
av1_nn_predict(ml_features, nn_config, &score);
aom_clear_system_state();
// Determine if we should prune square partitions.
if (score < thresh) {
*do_square_split = 0;
}
}
void av1_get_max_min_partition_features(AV1_COMP *const cpi, MACROBLOCK *x,
int mi_row, int mi_col,
float *features) {
AV1_COMMON *const cm = &cpi->common;
MACROBLOCKD *xd = &x->e_mbd;
const BLOCK_SIZE sb_size = cm->seq_params.sb_size;
assert(sb_size == BLOCK_128X128);
int f_idx = 0;
const int dc_q = av1_dc_quant_QTX(x->qindex, 0, xd->bd) >> (xd->bd - 8);
aom_clear_system_state();
const float log_q_sq = logf(1.0f + (float)(dc_q * dc_q) / 256.0f);
// Perform full-pixel single motion search in Y plane of 16x16 mbs in the sb
float sum_mv_row_sq = 0;
float sum_mv_row = 0;
float min_abs_mv_row = FLT_MAX;
float max_abs_mv_row = 0;
float sum_mv_col_sq = 0;
float sum_mv_col = 0;
float min_abs_mv_col = FLT_MAX;
float max_abs_mv_col = 0;
float sum_log_sse_sq = 0;
float sum_log_sse = 0;
float min_log_sse = FLT_MAX;
float max_log_sse = 0;
const BLOCK_SIZE mb_size = BLOCK_16X16;
const int mb_rows = block_size_high[sb_size] / block_size_high[mb_size];
const int mb_cols = block_size_wide[sb_size] / block_size_wide[mb_size];
const int mb_in_mi_size_high_log2 = mi_size_high_log2[mb_size];
const int mb_in_mi_size_wide_log2 = mi_size_wide_log2[mb_size];
for (int mb_row = 0; mb_row < mb_rows; mb_row++)
for (int mb_col = 0; mb_col < mb_cols; mb_col++) {
const int this_mi_row = mi_row + (mb_row << mb_in_mi_size_high_log2);
const int this_mi_col = mi_col + (mb_col << mb_in_mi_size_wide_log2);
unsigned int sse = 0;
unsigned int var = 0;
const MV ref_mv_full = { .row = 0, .col = 0 };
av1_simple_motion_sse_var(cpi, x, this_mi_row, this_mi_col, mb_size,
ref_mv_full, 0, &sse, &var);
aom_clear_system_state();
const float mv_row = (float)(x->best_mv.as_mv.row / 8);
const float mv_col = (float)(x->best_mv.as_mv.col / 8);
const float log_sse = logf(1.0f + (float)sse);
const float abs_mv_row = fabsf(mv_row);
const float abs_mv_col = fabsf(mv_col);
sum_mv_row_sq += mv_row * mv_row;
sum_mv_row += mv_row;
sum_mv_col_sq += mv_col * mv_col;
sum_mv_col += mv_col;
if (abs_mv_row < min_abs_mv_row) min_abs_mv_row = abs_mv_row;
if (abs_mv_row > max_abs_mv_row) max_abs_mv_row = abs_mv_row;
if (abs_mv_col < min_abs_mv_col) min_abs_mv_col = abs_mv_col;
if (abs_mv_col > max_abs_mv_col) max_abs_mv_col = abs_mv_col;
sum_log_sse_sq += log_sse * log_sse;
sum_log_sse += log_sse;
if (log_sse < min_log_sse) min_log_sse = log_sse;
if (log_sse > max_log_sse) max_log_sse = log_sse;
}
aom_clear_system_state();
const float avg_mv_row = sum_mv_row / 64.0f;
const float var_mv_row = sum_mv_row_sq / 64.0f - avg_mv_row * avg_mv_row;
const float avg_mv_col = sum_mv_col / 64.0f;
const float var_mv_col = sum_mv_col_sq / 64.0f - avg_mv_col * avg_mv_col;
const float avg_log_sse = sum_log_sse / 64.0f;
const float var_log_sse = sum_log_sse_sq / 64.0f - avg_log_sse * avg_log_sse;
features[f_idx++] = avg_log_sse;
features[f_idx++] = avg_mv_col;
features[f_idx++] = avg_mv_row;
features[f_idx++] = log_q_sq;
features[f_idx++] = max_abs_mv_col;
features[f_idx++] = max_abs_mv_row;
features[f_idx++] = max_log_sse;
features[f_idx++] = min_abs_mv_col;
features[f_idx++] = min_abs_mv_row;
features[f_idx++] = min_log_sse;
features[f_idx++] = var_log_sse;
features[f_idx++] = var_mv_col;
features[f_idx++] = var_mv_row;
assert(f_idx == FEATURE_SIZE_MAX_MIN_PART_PRED);
}
BLOCK_SIZE av1_predict_max_partition(AV1_COMP *const cpi, MACROBLOCK *const x,
const float *features) {
float scores[MAX_NUM_CLASSES_MAX_MIN_PART_PRED] = { 0.0f },
probs[MAX_NUM_CLASSES_MAX_MIN_PART_PRED] = { 0.0f };
const NN_CONFIG *nn_config = &av1_max_part_pred_nn_config;
assert(cpi->sf.auto_max_partition_based_on_simple_motion != NOT_IN_USE);
aom_clear_system_state();
av1_nn_predict(features, nn_config, scores);
av1_nn_softmax(scores, probs, MAX_NUM_CLASSES_MAX_MIN_PART_PRED);
int result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1;
if (cpi->sf.auto_max_partition_based_on_simple_motion == DIRECT_PRED) {
result = 0;
float max_prob = probs[0];
for (int i = 1; i < MAX_NUM_CLASSES_MAX_MIN_PART_PRED; ++i) {
if (probs[i] > max_prob) {
max_prob = probs[i];
result = i;
}
}
} else if (cpi->sf.auto_max_partition_based_on_simple_motion ==
RELAXED_PRED) {
for (result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; result >= 0;
--result) {
if (result < MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1) {
probs[result] += probs[result + 1];
}
if (probs[result] > 0.2) break;
}
} else if (cpi->sf.auto_max_partition_based_on_simple_motion == ADAPT_PRED) {
const BLOCK_SIZE sb_size = cpi->common.seq_params.sb_size;
MACROBLOCKD *const xd = &x->e_mbd;
// TODO(debargha): x->source_variance is unavailable at this point,
// so compute. The redundant recomputation later can be removed.
const unsigned int source_variance =
is_cur_buf_hbd(xd)
? av1_high_get_sby_perpixel_variance(cpi, &x->plane[0].src, sb_size,
xd->bd)
: av1_get_sby_perpixel_variance(cpi, &x->plane[0].src, sb_size);
if (source_variance > 16) {
const double thresh = source_variance < 128 ? 0.05 : 0.1;
for (result = MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1; result >= 0;
--result) {
if (result < MAX_NUM_CLASSES_MAX_MIN_PART_PRED - 1) {
probs[result] += probs[result + 1];
}
if (probs[result] > thresh) break;
}
}
}
return (BLOCK_SIZE)((result + 2) * 3);
}

View file

@ -0,0 +1,154 @@
/*
* 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.
*/
#ifndef AOM_AV1_ENCODER_PARTITION_STRATEGY_H_
#define AOM_AV1_ENCODER_PARTITION_STRATEGY_H_
#include "av1/encoder/encodeframe.h"
#include "av1/encoder/encodemb.h"
#include "av1/encoder/encoder.h"
#define FEATURE_SIZE_SMS_PRUNE_PART 25
#define FEATURE_SIZE_SMS_TERM_NONE 28
#define FEATURE_SIZE_FP_SMS_TERM_NONE 20
#define FEATURE_SIZE_MAX_MIN_PART_PRED 13
#define MAX_NUM_CLASSES_MAX_MIN_PART_PRED 4
// Performs a simple_motion_search with a single reference frame and extract
// the variance of residues. Then use the features to determine whether we want
// to go straight to splitting without trying PARTITION_NONE
void av1_simple_motion_search_based_split(
AV1_COMP *const cpi, MACROBLOCK *x, int mi_row, int mi_col,
BLOCK_SIZE bsize, int *partition_none_allowed, int *partition_horz_allowed,
int *partition_vert_allowed, int *do_rectangular_split,
int *do_square_split);
// Performs a simple_motion_search with two reference frames and extract
// the variance of residues. Then use the features to determine whether we want
// to prune some partitions.
void av1_simple_motion_search_prune_part(
AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize, int *partition_none_allowed,
int *partition_horz_allowed, int *partition_vert_allowed,
int *do_square_split, int *do_rectangular_split, int *prune_horz,
int *prune_vert, float *features, int *valid);
// Early terminates PARTITION_NONE using simple_motion_search features and the
// rate, distortion, and rdcost of PARTITION_NONE. This is only called when:
// - The frame is a show frame
// - The frame is not intra only
// - The current bsize is > BLOCK_8X8
// - blk_row + blk_height/2 < total_rows and blk_col + blk_width/2 < total_cols
void av1_simple_motion_search_early_term_none(
AV1_COMP *const cpi, MACROBLOCK *x, PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize, const RD_STATS *none_rdc,
int *early_terminate, float *simple_motion_features,
int *simple_motion_features_are_valid);
// Early terminates after PARTITION_NONE in firstpass of two pass partition
// search.
void av1_firstpass_simple_motion_search_early_term(AV1_COMP *const cpi,
MACROBLOCK *x,
PC_TREE *pc_tree, int mi_row,
int mi_col, BLOCK_SIZE bsize,
const RD_STATS *none_rdc,
int *do_square_split);
// Get the features for selecting the max and min partition size. Currently this
// performs simple_motion_search on 16X16 subblocks of the currnet superblock,
// and then extract the statistics of sse and motion vectors as features.
void av1_get_max_min_partition_features(AV1_COMP *const cpi, MACROBLOCK *x,
int mi_row, int mi_col,
float *features);
// Predict the maximum BLOCK_SIZE to be used to encoder the current superblock.
BLOCK_SIZE av1_predict_max_partition(AV1_COMP *const cpi, MACROBLOCK *const x,
const float *features);
// A simplified version of set_offsets meant to be used for
// simple_motion_search.
static INLINE void set_offsets_for_motion_search(const AV1_COMP *const cpi,
MACROBLOCK *const x,
int mi_row, int mi_col,
BLOCK_SIZE bsize) {
const AV1_COMMON *const cm = &cpi->common;
const int num_planes = av1_num_planes(cm);
MACROBLOCKD *const xd = &x->e_mbd;
const int mi_width = mi_size_wide[bsize];
const int mi_height = mi_size_high[bsize];
set_mode_info_offsets(cpi, x, xd, mi_row, mi_col);
// Set up destination pointers.
av1_setup_dst_planes(xd->plane, bsize, &cm->cur_frame->buf, mi_row, mi_col, 0,
num_planes);
// Set up limit values for MV components.
// Mv beyond the range do not produce new/different prediction block.
x->mv_limits.row_min =
-(((mi_row + mi_height) * MI_SIZE) + AOM_INTERP_EXTEND);
x->mv_limits.col_min = -(((mi_col + mi_width) * MI_SIZE) + AOM_INTERP_EXTEND);
x->mv_limits.row_max = (cm->mi_rows - mi_row) * MI_SIZE + AOM_INTERP_EXTEND;
x->mv_limits.col_max = (cm->mi_cols - mi_col) * MI_SIZE + AOM_INTERP_EXTEND;
set_plane_n4(xd, mi_width, mi_height, num_planes);
// Set up distance of MB to edge of frame in 1/8th pel units.
assert(!(mi_col & (mi_width - 1)) && !(mi_row & (mi_height - 1)));
xd->mb_to_top_edge = -((mi_row * MI_SIZE) * 8);
xd->mb_to_bottom_edge = ((cm->mi_rows - mi_height - mi_row) * MI_SIZE) * 8;
xd->mb_to_left_edge = -((mi_col * MI_SIZE) * 8);
xd->mb_to_right_edge = ((cm->mi_cols - mi_width - mi_col) * MI_SIZE) * 8;
// Set up source buffers.
av1_setup_src_planes(x, cpi->source, mi_row, mi_col, num_planes, bsize);
// R/D setup.
x->rdmult = cpi->rd.RDMULT;
}
static INLINE void init_simple_motion_search_mvs(PC_TREE *pc_tree) {
for (int idx = 0; idx < REF_FRAMES; idx++) {
pc_tree->mv_ref_fulls[idx].row = 0;
pc_tree->mv_ref_fulls[idx].col = 0;
}
if (pc_tree->block_size >= BLOCK_8X8) {
init_simple_motion_search_mvs(pc_tree->split[0]);
init_simple_motion_search_mvs(pc_tree->split[1]);
init_simple_motion_search_mvs(pc_tree->split[2]);
init_simple_motion_search_mvs(pc_tree->split[3]);
}
}
static INLINE int is_full_sb(AV1_COMMON *const cm, int mi_row, int mi_col,
BLOCK_SIZE sb_size) {
const int sb_mi_wide = mi_size_wide[sb_size];
const int sb_mi_high = mi_size_high[sb_size];
return (mi_row + sb_mi_high) <= cm->mi_rows &&
(mi_col + sb_mi_wide) <= cm->mi_cols;
}
static INLINE int use_auto_max_partition(AV1_COMP *const cpi,
BLOCK_SIZE sb_size, int mi_row,
int mi_col) {
AV1_COMMON *const cm = &cpi->common;
return !frame_is_intra_only(cm) &&
cpi->sf.auto_max_partition_based_on_simple_motion != NOT_IN_USE &&
sb_size == BLOCK_128X128 && is_full_sb(cm, mi_row, mi_col, sb_size) &&
cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index] !=
OVERLAY_UPDATE &&
cpi->twopass.gf_group.update_type[cpi->twopass.gf_group.index] !=
INTNL_OVERLAY_UPDATE;
}
#endif // AOM_AV1_ENCODER_PARTITION_STRATEGY_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
/*
* 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.
*/
#ifndef AOM_AV1_ENCODER_PASS2_STRATEGY_H_
#define AOM_AV1_ENCODER_PASS2_STRATEGY_H_
#ifdef __cplusplus
extern "C" {
#endif
struct AV1_COMP;
struct EncodeFrameParams;
void av1_init_second_pass(struct AV1_COMP *cpi);
void av1_get_second_pass_params(struct AV1_COMP *cpi,
struct EncodeFrameParams *const frame_params,
unsigned int frame_flags);
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // AOM_AV1_ENCODER_PASS2_STRATEGY_H_

View file

@ -213,19 +213,25 @@ void av1_pick_filter_level(const YV12_BUFFER_CONFIG *sd, AV1_COMP *cpi,
const int min_filter_level = 0;
const int max_filter_level = av1_get_max_filter_level(cpi);
const int q = av1_ac_quant_Q3(cm->base_qindex, 0, cm->seq_params.bit_depth);
// based on tests result for rtc test set
// 0.04590 boosted or 0.02295 non-booseted in 18-bit fixed point
const int strength_boost_q_treshold = 700;
const int inter_frame_multiplier =
q > strength_boost_q_treshold ? 12034 : 6017;
// These values were determined by linear fitting the result of the
// searched level for 8 bit depth:
// Keyframes: filt_guess = q * 0.06699 - 1.60817
// Other frames: filt_guess = q * 0.02295 + 2.48225
// Other frames: filt_guess = q * inter_frame_multiplier + 2.48225
//
// And high bit depth separately:
// filt_guess = q * 0.316206 + 3.87252
int filt_guess;
switch (cm->seq_params.bit_depth) {
case AOM_BITS_8:
filt_guess = (cm->current_frame.frame_type == KEY_FRAME)
? ROUND_POWER_OF_TWO(q * 17563 - 421574, 18)
: ROUND_POWER_OF_TWO(q * 6017 + 650707, 18);
filt_guess =
(cm->current_frame.frame_type == KEY_FRAME)
? ROUND_POWER_OF_TWO(q * 17563 - 421574, 18)
: ROUND_POWER_OF_TWO(q * inter_frame_multiplier + 650707, 18);
break;
case AOM_BITS_10:
filt_guess = ROUND_POWER_OF_TWO(q * 20723 + 4060632, 20);

View file

@ -1413,20 +1413,22 @@ void av1_pick_filter_restoration(const YV12_BUFFER_CONFIG *src, AV1_COMP *cpi) {
RestorationType best_rtype = RESTORE_NONE;
const int highbd = rsc.cm->seq_params.use_highbitdepth;
extend_frame(rsc.dgd_buffer, rsc.plane_width, rsc.plane_height,
rsc.dgd_stride, RESTORATION_BORDER, RESTORATION_BORDER,
highbd);
if (!cpi->sf.disable_loop_restoration_chroma || !plane) {
extend_frame(rsc.dgd_buffer, rsc.plane_width, rsc.plane_height,
rsc.dgd_stride, RESTORATION_BORDER, RESTORATION_BORDER,
highbd);
for (RestorationType r = 0; r < num_rtypes; ++r) {
if ((force_restore_type != RESTORE_TYPES) && (r != RESTORE_NONE) &&
(r != force_restore_type))
continue;
for (RestorationType r = 0; r < num_rtypes; ++r) {
if ((force_restore_type != RESTORE_TYPES) && (r != RESTORE_NONE) &&
(r != force_restore_type))
continue;
double cost = search_rest_type(&rsc, r);
double cost = search_rest_type(&rsc, r);
if (r == 0 || cost < best_cost) {
best_cost = cost;
best_rtype = r;
if (r == 0 || cost < best_cost) {
best_cost = cost;
best_rtype = r;
}
}
}

Some files were not shown because too many files have changed in this diff Show more