...
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
clean::
|
||||
$(RM) $(CLEANSUFFIXES:%=libavcodec/vvc/%)
|
||||
|
||||
OBJS-$(CONFIG_VVC_DECODER) += vvc/dec.o \
|
||||
vvc/dsp.o \
|
||||
vvc/cabac.o \
|
||||
vvc/ctu.o \
|
||||
vvc/data.o \
|
||||
vvc/filter.o \
|
||||
vvc/inter.o \
|
||||
vvc/intra.o \
|
||||
vvc/intra_utils.o \
|
||||
vvc/itx_1d.o \
|
||||
vvc/mvs.o \
|
||||
vvc/ps.o \
|
||||
vvc/refs.o \
|
||||
vvc/sei.o \
|
||||
vvc/thread.o \
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* VVC CABAC decoder
|
||||
*
|
||||
* Copyright (C) 2022 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_CABAC_H
|
||||
#define AVCODEC_VVC_CABAC_H
|
||||
|
||||
#include "ctu.h"
|
||||
|
||||
int ff_vvc_cabac_init(VVCLocalContext *lc, int ctu_idx, int rx, int ry);
|
||||
|
||||
//sao
|
||||
int ff_vvc_sao_merge_flag_decode(VVCLocalContext *lc);
|
||||
int ff_vvc_sao_type_idx_decode(VVCLocalContext *lc);
|
||||
int ff_vvc_sao_band_position_decode(VVCLocalContext *lc);
|
||||
int ff_vvc_sao_offset_abs_decode(VVCLocalContext *lc);
|
||||
int ff_vvc_sao_offset_sign_decode(VVCLocalContext *lc);
|
||||
int ff_vvc_sao_eo_class_decode(VVCLocalContext *lc);
|
||||
|
||||
//alf
|
||||
int ff_vvc_alf_ctb_flag(VVCLocalContext *lc, int rx, int ry, int c_idx);
|
||||
int ff_vvc_alf_use_aps_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_alf_luma_prev_filter_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_alf_luma_fixed_filter_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_alf_ctb_filter_alt_idx(VVCLocalContext *lc, int c_idx, int num_chroma_filters);
|
||||
int ff_vvc_alf_ctb_cc_idc(VVCLocalContext *lc, int rx, int ry, int idx, int cc_filters_signalled);
|
||||
|
||||
//coding_tree
|
||||
int ff_vvc_split_cu_flag(VVCLocalContext* lc, int x0, int y0, int cb_width, int cb_height,
|
||||
int ch_type, const VVCAllowedSplit *a);
|
||||
VVCSplitMode ff_vvc_split_mode(VVCLocalContext *lc, int x0, int y0, int cb_width, int cb_height,
|
||||
int cqt_depth, int mtt_depth, int ch_type, const VVCAllowedSplit *a);
|
||||
int ff_vvc_non_inter_flag(VVCLocalContext *lc, int x0, int y0, int ch_type);
|
||||
|
||||
//coding unit
|
||||
int ff_vvc_pred_mode_flag(VVCLocalContext *lc, int is_chroma);
|
||||
int ff_vvc_pred_mode_plt_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_bdpcm_luma_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_bdpcm_luma_dir_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_bdpcm_chroma_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_bdpcm_chroma_dir_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_cu_skip_flag(VVCLocalContext *lc, const uint8_t *cu_skip_flag);
|
||||
int ff_vvc_pred_mode_ibc_flag(VVCLocalContext *lc, int ch_type);
|
||||
int ff_vvc_cu_coded_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_cu_qp_delta_abs(VVCLocalContext *lc);
|
||||
int ff_vvc_cu_qp_delta_sign_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_sbt_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_sbt_quad_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_sbt_horizontal_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_sbt_pos_flag(VVCLocalContext *lc);
|
||||
|
||||
//intra
|
||||
int ff_vvc_intra_mip_flag(VVCLocalContext *lc, const uint8_t *intra_mip_flag);
|
||||
int ff_vvc_intra_mip_transposed_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_mip_mode(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_luma_ref_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_subpartitions_mode_flag(VVCLocalContext *lc);
|
||||
enum IspType ff_vvc_isp_split_type(VVCLocalContext *lc, int intra_subpartitions_mode_flag);
|
||||
int ff_vvc_intra_luma_mpm_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_luma_not_planar_flag(VVCLocalContext *lc, int intra_subpartitions_mode_flag);
|
||||
int ff_vvc_intra_luma_mpm_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_luma_mpm_remainder(VVCLocalContext *lc);
|
||||
int ff_vvc_cclm_mode_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_cclm_mode_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_intra_chroma_pred_mode(VVCLocalContext *lc);
|
||||
int ff_vvc_palette_predictor_run(VVCLocalContext *lc, const int max);
|
||||
int ff_vvc_num_signalled_palette_entries(VVCLocalContext *lc, const int max);
|
||||
int ff_vvc_new_palette_entries(VVCLocalContext *lc, int bit_dpeth);
|
||||
bool ff_vvc_palette_escape_val_present_flag(VVCLocalContext *lc);
|
||||
bool ff_vvc_palette_transpose_flag(VVCLocalContext *lc);
|
||||
bool ff_vvc_run_copy_flag(VVCLocalContext *lc, int prev_run_type, int prev_run_position, int cur_pos);
|
||||
bool ff_vvc_copy_above_palette_indices_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_palette_idx_idc(VVCLocalContext *lc, int max_palette_index, bool adjust);
|
||||
int ff_vvc_palette_escape_val(VVCLocalContext *lc, const int max);
|
||||
|
||||
//inter
|
||||
int ff_vvc_general_merge_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_merge_subblock_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_merge_subblock_idx(VVCLocalContext *lc, int max_num_subblock_merge_cand);
|
||||
int ff_vvc_regular_merge_flag(VVCLocalContext *lc, int cu_skip_flag);
|
||||
int ff_vvc_merge_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_mmvd_merge_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_mmvd_cand_flag(VVCLocalContext *lc);
|
||||
void ff_vvc_mmvd_offset_coding(VVCLocalContext *lc, Mv *mvd_offset, int ph_mmvd_fullpel_only_flag);
|
||||
int ff_vvc_ciip_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_merge_gpm_partition_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_merge_gpm_idx(VVCLocalContext *lc, int idx);
|
||||
PredFlag ff_vvc_pred_flag(VVCLocalContext *lc, int is_b);
|
||||
int ff_vvc_inter_affine_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_cu_affine_type_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_sym_mvd_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_ref_idx_lx(VVCLocalContext *lc, uint8_t nb_refs);
|
||||
int ff_vvc_abs_mvd_greater0_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_abs_mvd_greater1_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_abs_mvd_minus2(VVCLocalContext *lc);
|
||||
int ff_vvc_mvd_sign_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_mvp_lx_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_amvr_shift(VVCLocalContext *lc, int inter_affine_flag, PredMode pred_mode, int has_amvr_flag);
|
||||
int ff_vvc_bcw_idx(VVCLocalContext *lc, int no_backward_pred_flag);
|
||||
|
||||
//transform
|
||||
int ff_vvc_tu_cb_coded_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_tu_cr_coded_flag(VVCLocalContext *lc, int tu_cb_coded_flag);
|
||||
int ff_vvc_tu_y_coded_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_cu_act_enabled_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_cu_chroma_qp_offset_flag(VVCLocalContext *lc);
|
||||
int ff_vvc_cu_chroma_qp_offset_idx(VVCLocalContext *lc);
|
||||
int ff_vvc_tu_joint_cbcr_residual_flag(VVCLocalContext *lc, int tu_cb_coded_flag, int tu_cr_coded_flag);
|
||||
int ff_vvc_transform_skip_flag(VVCLocalContext *lc, int ctx);
|
||||
int ff_vvc_residual_coding(VVCLocalContext *lc, TransformBlock *tb);
|
||||
int ff_vvc_lfnst_idx(VVCLocalContext *lc, int inc);
|
||||
int ff_vvc_mts_idx(VVCLocalContext *lc);
|
||||
|
||||
int ff_vvc_end_of_slice_flag_decode(VVCLocalContext *lc);
|
||||
int ff_vvc_end_of_tile_one_bit(VVCLocalContext *lc);
|
||||
int ff_vvc_end_of_subset_one_bit(VVCLocalContext *lc);
|
||||
|
||||
#endif //AVCODEC_VVC_CABAC_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,505 @@
|
||||
/*
|
||||
* VVC CTU(Coding Tree Unit) parser
|
||||
*
|
||||
* Copyright (C) 2022 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_CTU_H
|
||||
#define AVCODEC_VVC_CTU_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libavcodec/cabac.h"
|
||||
#include "libavutil/mem_internal.h"
|
||||
|
||||
#include "dec.h"
|
||||
|
||||
#define MAX_CTU_SIZE 128
|
||||
|
||||
#define MAX_CU_SIZE MAX_CTU_SIZE
|
||||
#define MIN_CU_SIZE 4
|
||||
#define MIN_CU_LOG2 2
|
||||
#define MAX_CU_DEPTH 7
|
||||
#define MAX_PALETTE_CU_SIZE 64
|
||||
|
||||
#define MAX_PARTS_IN_CTU ((MAX_CTU_SIZE >> MIN_CU_LOG2) * (MAX_CTU_SIZE >> MIN_CU_LOG2))
|
||||
|
||||
#define MIN_PU_SIZE 4
|
||||
|
||||
#define MAX_TB_SIZE 64
|
||||
#define MIN_TU_SIZE 4
|
||||
#define MAX_TUS_IN_CU 64
|
||||
|
||||
#define MAX_QP 63
|
||||
|
||||
#define MAX_PB_SIZE 128
|
||||
#define MAX_SCALING_RATIO 8
|
||||
#define EDGE_EMU_BUFFER_STRIDE ((MAX_PB_SIZE + 32) * MAX_SCALING_RATIO)
|
||||
|
||||
#define CHROMA_EXTRA_BEFORE 1
|
||||
#define CHROMA_EXTRA_AFTER 2
|
||||
#define CHROMA_EXTRA 3
|
||||
#define LUMA_EXTRA_BEFORE 3
|
||||
#define LUMA_EXTRA_AFTER 4
|
||||
#define LUMA_EXTRA 7
|
||||
#define BILINEAR_EXTRA_BEFORE 0
|
||||
#define BILINEAR_EXTRA_AFTER 1
|
||||
#define BILINEAR_EXTRA 1
|
||||
|
||||
#define SCALED_INT(pos) ((pos) >> 10)
|
||||
|
||||
#define MAX_CONTROL_POINTS 3
|
||||
|
||||
#define AFFINE_MIN_BLOCK_SIZE 4
|
||||
|
||||
#define MRG_MAX_NUM_CANDS 6
|
||||
#define MAX_NUM_HMVP_CANDS 5
|
||||
|
||||
#define SAO_PADDING_SIZE 1
|
||||
|
||||
#define ALF_PADDING_SIZE 8
|
||||
#define ALF_BLOCK_SIZE 4
|
||||
|
||||
#define ALF_BORDER_LUMA 3
|
||||
#define ALF_BORDER_CHROMA 2
|
||||
|
||||
#define ALF_VB_POS_ABOVE_LUMA 4
|
||||
#define ALF_VB_POS_ABOVE_CHROMA 2
|
||||
|
||||
#define ALF_GRADIENT_STEP 2
|
||||
#define ALF_GRADIENT_BORDER 2
|
||||
#define ALF_GRADIENT_SIZE ((MAX_CU_SIZE + ALF_GRADIENT_BORDER * 2) / ALF_GRADIENT_STEP)
|
||||
#define ALF_NUM_DIR 4
|
||||
|
||||
|
||||
/**
|
||||
* Value of the luma sample at position (x, y) in the 2D array tab.
|
||||
*/
|
||||
#define SAMPLE(tab, x, y) ((tab)[(y) * s->pps->width + (x)])
|
||||
#define SAMPLE_CTB(tab, x, y) ((tab)[(y) * min_cb_width + (x)])
|
||||
#define CTB(tab, x, y) ((tab)[(y) * fc->ps.pps->ctb_width + (x)])
|
||||
|
||||
enum SAOType {
|
||||
SAO_NOT_APPLIED = 0,
|
||||
SAO_BAND,
|
||||
SAO_EDGE,
|
||||
};
|
||||
|
||||
enum SAOEOClass {
|
||||
SAO_EO_HORIZ = 0,
|
||||
SAO_EO_VERT,
|
||||
SAO_EO_135D,
|
||||
SAO_EO_45D,
|
||||
};
|
||||
|
||||
typedef struct NeighbourAvailable {
|
||||
int cand_left;
|
||||
int cand_up;
|
||||
int cand_up_left;
|
||||
int cand_up_right;
|
||||
int cand_up_right_sap;
|
||||
} NeighbourAvailable;
|
||||
|
||||
enum IspType{
|
||||
ISP_NO_SPLIT,
|
||||
ISP_HOR_SPLIT,
|
||||
ISP_VER_SPLIT,
|
||||
};
|
||||
|
||||
typedef enum VVCSplitMode {
|
||||
SPLIT_NONE,
|
||||
SPLIT_TT_HOR,
|
||||
SPLIT_BT_HOR,
|
||||
SPLIT_TT_VER,
|
||||
SPLIT_BT_VER,
|
||||
SPLIT_QT,
|
||||
} VVCSplitMode;
|
||||
|
||||
typedef enum MtsIdx {
|
||||
MTS_DCT2_DCT2,
|
||||
MTS_DST7_DST7,
|
||||
MTS_DST7_DCT8,
|
||||
MTS_DCT8_DST7,
|
||||
MTS_DCT8_DCT8,
|
||||
} MtsIdx;
|
||||
|
||||
typedef struct TransformBlock {
|
||||
uint8_t has_coeffs;
|
||||
uint8_t c_idx;
|
||||
uint8_t ts; ///< transform_skip_flag
|
||||
int x0;
|
||||
int y0;
|
||||
|
||||
int tb_width;
|
||||
int tb_height;
|
||||
int log2_tb_width;
|
||||
int log2_tb_height;
|
||||
|
||||
int max_scan_x;
|
||||
int max_scan_y;
|
||||
int min_scan_x;
|
||||
int min_scan_y;
|
||||
|
||||
int qp;
|
||||
int rect_non_ts_flag;
|
||||
int bd_shift;
|
||||
int bd_offset;
|
||||
|
||||
int *coeffs;
|
||||
} TransformBlock;
|
||||
|
||||
typedef enum VVCTreeType {
|
||||
SINGLE_TREE,
|
||||
DUAL_TREE_LUMA,
|
||||
DUAL_TREE_CHROMA,
|
||||
} VVCTreeType;
|
||||
|
||||
typedef struct TransformUnit {
|
||||
int x0;
|
||||
int y0;
|
||||
int width;
|
||||
int height;
|
||||
bool avail[CHROMA + 1]; // contains luma/chroma block
|
||||
|
||||
uint8_t joint_cbcr_residual_flag; ///< tu_joint_cbcr_residual_flag
|
||||
|
||||
uint8_t coded_flag[VVC_MAX_SAMPLE_ARRAYS]; ///< tu_y_coded_flag, tu_cb_coded_flag, tu_cr_coded_flag
|
||||
uint8_t nb_tbs;
|
||||
TransformBlock tbs[VVC_MAX_SAMPLE_ARRAYS];
|
||||
|
||||
struct TransformUnit *next; ///< RefStruct reference
|
||||
} TransformUnit;
|
||||
|
||||
typedef enum PredMode {
|
||||
MODE_INTER,
|
||||
MODE_INTRA,
|
||||
MODE_SKIP,
|
||||
MODE_PLT,
|
||||
MODE_IBC,
|
||||
} PredMode;
|
||||
|
||||
typedef struct Mv {
|
||||
int x; ///< horizontal component of motion vector
|
||||
int y; ///< vertical component of motion vector
|
||||
} Mv;
|
||||
|
||||
typedef struct MvField {
|
||||
DECLARE_ALIGNED(8, Mv, mv)[2]; ///< mvL0, vvL1
|
||||
int8_t ref_idx[2]; ///< refIdxL0, refIdxL1
|
||||
uint8_t hpel_if_idx; ///< hpelIfIdx
|
||||
uint8_t bcw_idx; ///< bcwIdx
|
||||
uint8_t pred_flag;
|
||||
uint8_t ciip_flag; ///< ciip_flag
|
||||
} MvField;
|
||||
|
||||
typedef struct DMVRInfo {
|
||||
DECLARE_ALIGNED(8, Mv, mv)[2]; ///< mvL0, vvL1
|
||||
uint8_t dmvr_enabled;
|
||||
} DMVRInfo;
|
||||
|
||||
typedef enum MotionModelIdc {
|
||||
MOTION_TRANSLATION,
|
||||
MOTION_4_PARAMS_AFFINE,
|
||||
MOTION_6_PARAMS_AFFINE,
|
||||
} MotionModelIdc;
|
||||
|
||||
typedef enum PredFlag {
|
||||
PF_INTRA = 0x0,
|
||||
PF_L0 = 0x1,
|
||||
PF_L1 = 0x2,
|
||||
PF_BI = 0x3,
|
||||
PF_IBC = PF_L0 | 0x4,
|
||||
PF_PLT = 0x8,
|
||||
} PredFlag;
|
||||
|
||||
typedef enum IntraPredMode {
|
||||
INTRA_INVALID = -1,
|
||||
INTRA_PLANAR = 0,
|
||||
INTRA_DC,
|
||||
INTRA_HORZ = 18,
|
||||
INTRA_DIAG = 34,
|
||||
INTRA_VERT = 50,
|
||||
INTRA_VDIAG = 66,
|
||||
INTRA_LT_CCLM = 81,
|
||||
INTRA_L_CCLM,
|
||||
INTRA_T_CCLM
|
||||
} IntraPredMode;
|
||||
|
||||
typedef struct MotionInfo {
|
||||
MotionModelIdc motion_model_idc; ///< MotionModelIdc
|
||||
int8_t ref_idx[2]; ///< refIdxL0, refIdxL1
|
||||
uint8_t hpel_if_idx; ///< hpelIfIdx
|
||||
uint8_t bcw_idx; ///< bcwIdx
|
||||
PredFlag pred_flag;
|
||||
|
||||
Mv mv[2][MAX_CONTROL_POINTS];
|
||||
|
||||
int num_sb_x, num_sb_y;
|
||||
} MotionInfo;
|
||||
|
||||
typedef struct PredictionUnit {
|
||||
uint8_t general_merge_flag;
|
||||
uint8_t mmvd_merge_flag;
|
||||
//InterPredIdc inter_pred_idc;
|
||||
uint8_t inter_affine_flag;
|
||||
|
||||
//subblock predict
|
||||
uint8_t merge_subblock_flag;
|
||||
|
||||
uint8_t merge_gpm_flag;
|
||||
uint8_t gpm_partition_idx;
|
||||
MvField gpm_mv[2];
|
||||
|
||||
int sym_mvd_flag;
|
||||
|
||||
MotionInfo mi;
|
||||
|
||||
// for regular prediction only
|
||||
uint8_t dmvr_flag;
|
||||
uint8_t bdof_flag;
|
||||
|
||||
int16_t diff_mv_x[2][AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; ///< diffMvLX
|
||||
int16_t diff_mv_y[2][AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE]; ///< diffMvLX
|
||||
int cb_prof_flag[2];
|
||||
} PredictionUnit;
|
||||
|
||||
typedef struct Palette {
|
||||
uint8_t size;
|
||||
uint16_t entries[VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE];
|
||||
} Palette;
|
||||
|
||||
typedef struct CodingUnit {
|
||||
VVCTreeType tree_type;
|
||||
int x0;
|
||||
int y0;
|
||||
int cb_width;
|
||||
int cb_height;
|
||||
int ch_type;
|
||||
int cqt_depth;
|
||||
|
||||
uint8_t coded_flag;
|
||||
|
||||
uint8_t sbt_flag;
|
||||
uint8_t sbt_horizontal_flag;
|
||||
uint8_t sbt_pos_flag;
|
||||
|
||||
int lfnst_idx;
|
||||
MtsIdx mts_idx;
|
||||
|
||||
uint8_t act_enabled_flag;
|
||||
|
||||
uint8_t intra_luma_ref_idx; ///< IntraLumaRefLineIdx[][]
|
||||
uint8_t intra_mip_flag; ///< intra_mip_flag
|
||||
uint8_t skip_flag; ///< cu_skip_flag;
|
||||
|
||||
//inter
|
||||
uint8_t ciip_flag;
|
||||
|
||||
// Inferred parameters
|
||||
enum IspType isp_split_type; ///< IntraSubPartitionsSplitType
|
||||
|
||||
enum PredMode pred_mode; ///< PredMode
|
||||
|
||||
int num_intra_subpartitions;
|
||||
|
||||
IntraPredMode intra_pred_mode_y; ///< IntraPredModeY
|
||||
IntraPredMode intra_pred_mode_c; ///< IntraPredModeC
|
||||
int mip_chroma_direct_flag; ///< MipChromaDirectFlag
|
||||
|
||||
int bdpcm_flag[VVC_MAX_SAMPLE_ARRAYS]; ///< BdpcmFlag
|
||||
|
||||
int apply_lfnst_flag[VVC_MAX_SAMPLE_ARRAYS]; ///< ApplyLfnstFlag[]
|
||||
|
||||
struct {
|
||||
TransformUnit *head; ///< RefStruct reference
|
||||
TransformUnit *tail; ///< RefStruct reference
|
||||
} tus;
|
||||
|
||||
int8_t qp[4]; ///< QpY, Qp′Cb, Qp′Cr, Qp′CbCr
|
||||
|
||||
Palette plt[VVC_MAX_SAMPLE_ARRAYS];
|
||||
|
||||
PredictionUnit pu;
|
||||
|
||||
struct CodingUnit *next; ///< RefStruct reference
|
||||
} CodingUnit;
|
||||
|
||||
typedef struct CTU {
|
||||
int max_y[2][VVC_MAX_REF_ENTRIES];
|
||||
int max_y_idx[2];
|
||||
int has_dmvr;
|
||||
} CTU;
|
||||
|
||||
typedef struct ReconstructedArea {
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
} ReconstructedArea;
|
||||
|
||||
typedef struct VVCCabacState {
|
||||
uint16_t state[2];
|
||||
uint8_t shift[2];
|
||||
} VVCCabacState;
|
||||
|
||||
// VVC_CONTEXTS matched with SYNTAX_ELEMENT_LAST, it's checked by cabac_init_state.
|
||||
#define VVC_CONTEXTS 378
|
||||
typedef struct EntryPoint {
|
||||
int8_t qp_y; ///< QpY
|
||||
|
||||
int stat_coeff[VVC_MAX_SAMPLE_ARRAYS]; ///< StatCoeff
|
||||
|
||||
Palette pp[VVC_MAX_SAMPLE_ARRAYS]; // PalettePredictor
|
||||
|
||||
VVCCabacState cabac_state[VVC_CONTEXTS];
|
||||
CABACContext cc;
|
||||
|
||||
int ctu_start;
|
||||
int ctu_end;
|
||||
|
||||
uint8_t is_first_qg; // first quantization group
|
||||
|
||||
MvField hmvp[MAX_NUM_HMVP_CANDS]; ///< HmvpCandList
|
||||
int num_hmvp; ///< NumHmvpCand
|
||||
MvField hmvp_ibc[MAX_NUM_HMVP_CANDS]; ///< HmvpIbcCandList
|
||||
int num_hmvp_ibc; ///< NumHmvpIbcCand
|
||||
} EntryPoint;
|
||||
|
||||
typedef struct VVCLocalContext {
|
||||
uint8_t ctb_left_flag;
|
||||
uint8_t ctb_up_flag;
|
||||
uint8_t ctb_up_right_flag;
|
||||
uint8_t ctb_up_left_flag;
|
||||
int end_of_tiles_x;
|
||||
int end_of_tiles_y;
|
||||
|
||||
/* *2 for high bit depths */
|
||||
DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[EDGE_EMU_BUFFER_STRIDE * EDGE_EMU_BUFFER_STRIDE * 2];
|
||||
DECLARE_ALIGNED(32, int16_t, tmp)[MAX_PB_SIZE * MAX_PB_SIZE];
|
||||
DECLARE_ALIGNED(32, int16_t, tmp1)[MAX_PB_SIZE * MAX_PB_SIZE];
|
||||
DECLARE_ALIGNED(32, int16_t, tmp2)[MAX_PB_SIZE * MAX_PB_SIZE];
|
||||
DECLARE_ALIGNED(32, uint8_t, ciip_tmp)[MAX_PB_SIZE * MAX_PB_SIZE * 2];
|
||||
DECLARE_ALIGNED(32, uint8_t, sao_buffer)[(MAX_CTU_SIZE + 2 * SAO_PADDING_SIZE) * EDGE_EMU_BUFFER_STRIDE * 2];
|
||||
DECLARE_ALIGNED(32, uint8_t, alf_buffer_luma)[(MAX_CTU_SIZE + 2 * ALF_PADDING_SIZE) * EDGE_EMU_BUFFER_STRIDE * 2];
|
||||
DECLARE_ALIGNED(32, uint8_t, alf_buffer_chroma)[(MAX_CTU_SIZE + 2 * ALF_PADDING_SIZE) * EDGE_EMU_BUFFER_STRIDE * 2];
|
||||
DECLARE_ALIGNED(32, int32_t, alf_gradient_tmp)[ALF_GRADIENT_SIZE * ALF_GRADIENT_SIZE * ALF_NUM_DIR];
|
||||
|
||||
struct {
|
||||
int sbt_num_fourths_tb0; ///< SbtNumFourthsTb0
|
||||
|
||||
uint8_t is_cu_qp_delta_coded; ///< IsCuQpDeltaCoded
|
||||
int cu_qg_top_left_x; ///< CuQgTopLeftX
|
||||
int cu_qg_top_left_y; ///< CuQgTopLeftY
|
||||
int is_cu_chroma_qp_offset_coded; ///< IsCuChromaQpOffsetCoded
|
||||
int chroma_qp_offset[3]; ///< CuQpOffsetCb, CuQpOffsetCr, CuQpOffsetCbCr
|
||||
|
||||
int infer_tu_cbf_luma; ///< InferTuCbfLuma
|
||||
int prev_tu_cbf_y; ///< prevTuCbfY;
|
||||
|
||||
int lfnst_dc_only; ///< LfnstDcOnly
|
||||
int lfnst_zero_out_sig_coeff_flag; ///< LfnstZeroOutSigCoeffFlag
|
||||
|
||||
int mts_dc_only; ///< MtsDcOnly
|
||||
int mts_zero_out_sig_coeff_flag; ///< MtsZeroOutSigCoeffFlag;
|
||||
} parse;
|
||||
|
||||
struct {
|
||||
// lmcs cache, for recon only
|
||||
int chroma_scale;
|
||||
int x_vpdu;
|
||||
int y_vpdu;
|
||||
} lmcs;
|
||||
|
||||
CodingUnit *cu;
|
||||
ReconstructedArea ras[2][MAX_PARTS_IN_CTU];
|
||||
int num_ras[2];
|
||||
|
||||
NeighbourAvailable na;
|
||||
|
||||
#define BOUNDARY_LEFT_SLICE (1 << 0)
|
||||
#define BOUNDARY_LEFT_TILE (1 << 1)
|
||||
#define BOUNDARY_LEFT_SUBPIC (1 << 2)
|
||||
#define BOUNDARY_UPPER_SLICE (1 << 3)
|
||||
#define BOUNDARY_UPPER_TILE (1 << 4)
|
||||
#define BOUNDARY_UPPER_SUBPIC (1 << 5)
|
||||
/* properties of the boundary of the current CTB for the purposes
|
||||
* of the deblocking filter */
|
||||
int boundary_flags;
|
||||
|
||||
SliceContext *sc;
|
||||
VVCFrameContext *fc;
|
||||
EntryPoint *ep;
|
||||
int *coeffs;
|
||||
} VVCLocalContext;
|
||||
|
||||
typedef struct VVCAllowedSplit {
|
||||
int qt;
|
||||
int btv;
|
||||
int bth;
|
||||
int ttv;
|
||||
int tth;
|
||||
} VVCAllowedSplit;
|
||||
|
||||
typedef struct SAOParams {
|
||||
int offset_abs[3][4]; ///< sao_offset_abs
|
||||
int offset_sign[3][4]; ///< sao_offset_sign
|
||||
|
||||
uint8_t band_position[3]; ///< sao_band_position
|
||||
|
||||
int eo_class[3]; ///< sao_eo_class
|
||||
|
||||
int16_t offset_val[3][5]; ///< SaoOffsetVal
|
||||
|
||||
uint8_t type_idx[3]; ///< sao_type_idx
|
||||
} SAOParams;
|
||||
|
||||
typedef struct ALFParams {
|
||||
uint8_t ctb_flag[3]; ///< alf_ctb_flag[]
|
||||
uint8_t ctb_filt_set_idx_y; ///< AlfCtbFiltSetIdxY
|
||||
uint8_t alf_ctb_filter_alt_idx[2]; ///< alf_ctb_filter_alt_idx[]
|
||||
uint8_t ctb_cc_idc[2]; ///< alf_ctb_cc_cb_idc, alf_ctb_cc_cr_idc
|
||||
} ALFParams;
|
||||
|
||||
typedef struct VVCRect {
|
||||
int l; // left
|
||||
int t; // top
|
||||
int r; // right
|
||||
int b; // bottom
|
||||
} VVCRect;
|
||||
|
||||
/**
|
||||
* parse a CTU
|
||||
* @param lc local context for CTU
|
||||
* @param ctb_idx CTB(CTU) address in the current slice
|
||||
* @param rs raster order for the CTU.
|
||||
* @param rx raster order x for the CTU.
|
||||
* @param ry raster order y for the CTU.
|
||||
* @return AVERROR
|
||||
*/
|
||||
int ff_vvc_coding_tree_unit(VVCLocalContext *lc, int ctu_idx, int rs, int rx, int ry);
|
||||
|
||||
//utils
|
||||
void ff_vvc_set_neighbour_available(VVCLocalContext *lc, int x0, int y0, int w, int h);
|
||||
void ff_vvc_decode_neighbour(VVCLocalContext *lc, int x_ctb, int y_ctb, int rx, int ry, int rs);
|
||||
void ff_vvc_ctu_free_cus(CodingUnit **cus);
|
||||
int ff_vvc_get_qPy(const VVCFrameContext *fc, int xc, int yc);
|
||||
void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, int bit_depth, int persistent_rice_adaptation_enabled_flag);
|
||||
void ff_vvc_channel_range(int *start, int *end, VVCTreeType tree_type, uint8_t chroma_format_idc);
|
||||
|
||||
#endif // AVCODEC_VVC_CTU_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* VVC shared tables
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_DATA_H
|
||||
#define AVCODEC_VVC_DATA_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern const uint8_t ff_vvc_diag_scan_x[5][5][16 * 16];
|
||||
extern const uint8_t ff_vvc_diag_scan_y[5][5][16 * 16];
|
||||
|
||||
extern const uint8_t ff_vvc_scaling_pred_8[8 * 8];
|
||||
extern const uint8_t ff_vvc_scaling_pred_16[8 * 8];
|
||||
extern const int ff_vvc_scaling_list0[8 * 8];
|
||||
|
||||
extern const int8_t ff_vvc_dct8_4x4[4][4];
|
||||
extern const int8_t ff_vvc_dct8_8x8[8][8];
|
||||
extern const int8_t ff_vvc_dct8_16x16[16][16];
|
||||
extern const int8_t ff_vvc_dct8_32x32[32][32];
|
||||
extern const int8_t ff_vvc_dst7_4x4[4][4];
|
||||
extern const int8_t ff_vvc_dst7_8x8[8][8];
|
||||
extern const int8_t ff_vvc_dst7_16x16[16][16];
|
||||
extern const int8_t ff_vvc_dst7_32x32[32][32];
|
||||
extern const int8_t ff_vvc_lfnst_4x4[4][2][16][16];
|
||||
extern const int8_t ff_vvc_lfnst_8x8[4][2][16][48];
|
||||
extern const uint8_t ff_vvc_lfnst_tr_set_index[95];
|
||||
extern uint8_t ff_vvc_default_scale_m[64 * 64];
|
||||
|
||||
#define VVC_INTER_LUMA_FILTER_TYPE_AFFINE 4
|
||||
|
||||
#define VVC_INTER_LUMA_FILTER_TYPES 7
|
||||
#define VVC_INTER_CHROMA_FILTER_TYPES 3
|
||||
|
||||
#define VVC_INTER_LUMA_FACTS 16
|
||||
#define VVC_INTER_LUMA_TAPS 8
|
||||
#define VVC_INTER_CHROMA_FACTS 32
|
||||
#define VVC_INTER_CHROMA_TAPS 4
|
||||
#define VVC_INTER_LUMA_DMVR_FACTS 16
|
||||
#define VVC_INTER_LUMA_DMVR_TAPS 2
|
||||
extern const int8_t ff_vvc_inter_luma_filters[VVC_INTER_LUMA_FILTER_TYPES][VVC_INTER_LUMA_FACTS][VVC_INTER_LUMA_TAPS];
|
||||
extern const int8_t ff_vvc_inter_chroma_filters[VVC_INTER_CHROMA_FILTER_TYPES][VVC_INTER_CHROMA_FACTS][VVC_INTER_CHROMA_TAPS];
|
||||
extern const int8_t ff_vvc_inter_luma_dmvr_filters[VVC_INTER_LUMA_DMVR_FACTS][VVC_INTER_LUMA_DMVR_TAPS];
|
||||
|
||||
#define VVC_INTRA_LUMA_TYPES 2
|
||||
#define VVC_INTRA_LUMA_FACTS 32
|
||||
#define VVC_INTRA_LUMA_TAPS 4
|
||||
extern const int8_t ff_vvc_intra_luma_filter[VVC_INTRA_LUMA_TYPES][VVC_INTRA_LUMA_FACTS][VVC_INTRA_LUMA_TAPS];
|
||||
|
||||
#define VVC_GPM_NUM_PARTITION 64
|
||||
#define VVC_GPM_NUM_ANGLES 32
|
||||
#define VVC_GPM_WEIGHT_SIZE 112
|
||||
extern const uint8_t ff_vvc_gpm_angle_idx[VVC_GPM_NUM_PARTITION];
|
||||
extern const uint8_t ff_vvc_gpm_distance_idx[VVC_GPM_NUM_PARTITION];
|
||||
extern const int8_t ff_vvc_gpm_distance_lut[VVC_GPM_NUM_ANGLES];
|
||||
extern const uint8_t ff_vvc_gpm_angle_to_mirror[VVC_GPM_NUM_ANGLES];
|
||||
extern const uint8_t ff_vvc_gpm_angle_to_weights_idx[VVC_GPM_NUM_ANGLES];
|
||||
extern const uint8_t ff_vvc_gpm_weights_offset_x[VVC_GPM_NUM_PARTITION][4][4];
|
||||
extern const uint8_t ff_vvc_gpm_weights_offset_y[VVC_GPM_NUM_PARTITION][4][4];
|
||||
extern const uint8_t ff_vvc_gpm_weights[6][VVC_GPM_WEIGHT_SIZE * VVC_GPM_WEIGHT_SIZE];
|
||||
|
||||
extern const int16_t ff_vvc_alf_fix_filt_coeff[64][12];
|
||||
extern const uint8_t ff_vvc_alf_class_to_filt_map[16][25];
|
||||
extern const uint8_t ff_vvc_alf_aps_class_to_filt_map[25];
|
||||
|
||||
const uint8_t* ff_vvc_get_mip_matrix(const int size_id, const int mode_idx);
|
||||
|
||||
#endif /* AVCODEC_VVC_DATA_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* VVC video decoder
|
||||
*
|
||||
* Copyright (C) 2021 Nuo Mi
|
||||
* Copyright (C) 2022 Xu Mu
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_DEC_H
|
||||
#define AVCODEC_VVC_DEC_H
|
||||
|
||||
#include "libavcodec/videodsp.h"
|
||||
#include "libavcodec/vvc.h"
|
||||
#include "libavcodec/h274.h"
|
||||
|
||||
#include "ps.h"
|
||||
#include "dsp.h"
|
||||
#include "sei.h"
|
||||
|
||||
#define LUMA 0
|
||||
#define CHROMA 1
|
||||
#define CB 1
|
||||
#define CR 2
|
||||
#define JCBCR 3
|
||||
|
||||
#define MIN_TU_LOG2 2 ///< MinTbLog2SizeY
|
||||
#define MIN_PU_LOG2 2
|
||||
|
||||
#define L0 0
|
||||
#define L1 1
|
||||
|
||||
typedef struct VVCRefPic {
|
||||
struct VVCFrame *ref;
|
||||
int poc;
|
||||
int is_lt; // is long term reference
|
||||
|
||||
// for RPR
|
||||
int is_scaled; ///< RprConstraintsActiveFlag
|
||||
int scale[2]; ///< RefPicScale[]
|
||||
} VVCRefPic;
|
||||
|
||||
typedef struct RefPicList {
|
||||
VVCRefPic refs[VVC_MAX_REF_ENTRIES];
|
||||
int nb_refs;
|
||||
} RefPicList;
|
||||
|
||||
typedef struct RefPicListTab {
|
||||
RefPicList refPicList[2];
|
||||
} RefPicListTab;
|
||||
|
||||
typedef struct VVCWindow {
|
||||
int16_t left_offset;
|
||||
int16_t right_offset;
|
||||
int16_t top_offset;
|
||||
int16_t bottom_offset;
|
||||
} VVCWindow;
|
||||
|
||||
typedef struct VVCFrame {
|
||||
struct AVFrame *frame;
|
||||
struct AVFrame *frame_grain;
|
||||
const VVCSPS *sps; ///< RefStruct reference
|
||||
const VVCPPS *pps; ///< RefStruct reference
|
||||
struct MvField *tab_dmvr_mvf; ///< RefStruct reference
|
||||
RefPicListTab **rpl_tab; ///< RefStruct reference
|
||||
RefPicListTab *rpl; ///< RefStruct reference
|
||||
|
||||
int needs_fg; ///< 1 if grain needs to be applied by the decoder
|
||||
|
||||
int nb_rpl_elems;
|
||||
|
||||
int ctb_count;
|
||||
|
||||
int poc;
|
||||
|
||||
//for RPR
|
||||
VVCWindow scaling_win; ///< pps_scaling_win_left_offset * SubWithC, pps_scaling_win_right_offset * SubWithC,
|
||||
///< pps_scaling_win_top_offset * SubHeigtC, pps_scaling_win_bottom_offset * SubHiehgtC
|
||||
int ref_width; ///< CurrPicScalWinWidthL
|
||||
int ref_height; ///< CurrPicScalWinHeightL
|
||||
|
||||
struct VVCFrame *collocated_ref;
|
||||
|
||||
struct FrameProgress *progress; ///< RefStruct reference
|
||||
|
||||
/**
|
||||
* A sequence counter, so that old frames are output first
|
||||
* after a POC reset
|
||||
*/
|
||||
uint16_t sequence;
|
||||
/**
|
||||
* A combination of VVC_FRAME_FLAG_*
|
||||
*/
|
||||
uint8_t flags;
|
||||
|
||||
void *hwaccel_picture_private; ///< hardware accelerator private data
|
||||
} VVCFrame;
|
||||
|
||||
typedef struct SliceContext {
|
||||
int slice_idx;
|
||||
VVCSH sh;
|
||||
struct EntryPoint *eps;
|
||||
int nb_eps;
|
||||
RefPicList *rpl;
|
||||
void *ref; ///< RefStruct reference, backing slice data
|
||||
} SliceContext;
|
||||
|
||||
typedef struct VVCFrameContext {
|
||||
void *log_ctx;
|
||||
|
||||
// +1 for the current frame
|
||||
VVCFrame DPB[VVC_MAX_DPB_SIZE + 1];
|
||||
|
||||
struct AVFrame *frame;
|
||||
struct AVFrame *output_frame;
|
||||
|
||||
VVCFrameParamSets ps;
|
||||
VVCSEI sei;
|
||||
|
||||
SliceContext **slices;
|
||||
int nb_slices;
|
||||
int nb_slices_allocated;
|
||||
|
||||
VVCFrame *ref;
|
||||
|
||||
VVCDSPContext vvcdsp;
|
||||
VideoDSPContext vdsp;
|
||||
|
||||
struct VVCFrameThread *ft;
|
||||
|
||||
uint64_t decode_order;
|
||||
|
||||
struct AVRefStructPool *tab_dmvr_mvf_pool;
|
||||
struct AVRefStructPool *rpl_tab_pool;
|
||||
|
||||
struct AVRefStructPool *cu_pool;
|
||||
struct AVRefStructPool *tu_pool;
|
||||
|
||||
struct {
|
||||
int16_t *slice_idx;
|
||||
|
||||
DBParams *deblock;
|
||||
struct SAOParams *sao;
|
||||
struct ALFParams *alf;
|
||||
|
||||
int *cb_pos_x[2]; ///< CbPosX[][][]
|
||||
int *cb_pos_y[2]; ///< CbPosY[][][]
|
||||
uint8_t *cb_width[2]; ///< CbWidth[][][]
|
||||
uint8_t *cb_height[2]; ///< CbHeight[][][]
|
||||
uint8_t *cqt_depth[2]; ///< CqtDepth[][][]
|
||||
int8_t *qp[VVC_MAX_SAMPLE_ARRAYS];
|
||||
|
||||
uint8_t *skip; ///< CuSkipFlag[][]
|
||||
uint8_t *ispmf; ///< intra_sub_partitions_mode_flag
|
||||
uint8_t *msm[2]; ///< MttSplitMode[][][] in 32 pixels
|
||||
uint8_t *imf; ///< IntraMipFlag[][], intra_mip_transposed_flag[][], intra_mip_mode[][]
|
||||
uint8_t *ipm; ///< IntraPredModeY[][]
|
||||
uint8_t *cpm[2]; ///< CuPredMode[][][]
|
||||
uint8_t *msf; ///< MergeSubblockFlag[][]
|
||||
uint8_t *iaf; ///< InterAffineFlag[][]
|
||||
uint8_t *mmi; ///< MotionModelIdc[][]
|
||||
struct Mv *cp_mv[2]; ///< CpMvLX[][][][MAX_CONTROL_POINTS];
|
||||
struct MvField *mvf; ///< MvDmvrL0, MvDmvrL1
|
||||
|
||||
uint8_t *tu_coded_flag[VVC_MAX_SAMPLE_ARRAYS]; ///< tu_y_coded_flag[][], tu_cb_coded_flag[][], tu_cr_coded_flag[][]
|
||||
uint8_t *tu_joint_cbcr_residual_flag; ///< tu_joint_cbcr_residual_flag[][]
|
||||
uint8_t *tb_width[2];
|
||||
uint8_t *tb_height[2];
|
||||
uint8_t *pcmf[2];
|
||||
|
||||
uint8_t *bs[2][VVC_MAX_SAMPLE_ARRAYS]; ///< horizontal, vertical boundary filtering strength
|
||||
uint8_t *max_len_p[2]; ///< horizontal, vertical maxFilterLengthPs for luma
|
||||
uint8_t *max_len_q[2]; ///< horizontal, vertical maxFilterLengthQs for luma
|
||||
|
||||
uint8_t *sao_pixel_buffer_h[VVC_MAX_SAMPLE_ARRAYS];
|
||||
uint8_t *sao_pixel_buffer_v[VVC_MAX_SAMPLE_ARRAYS];
|
||||
uint8_t *alf_pixel_buffer_h[VVC_MAX_SAMPLE_ARRAYS][2];
|
||||
uint8_t *alf_pixel_buffer_v[VVC_MAX_SAMPLE_ARRAYS][2];
|
||||
|
||||
int *coeffs;
|
||||
struct CTU *ctus;
|
||||
struct CodingUnit **cus;
|
||||
|
||||
uint8_t *ibc_vir_buf[VVC_MAX_SAMPLE_ARRAYS]; ///< IbcVirBuf[]
|
||||
|
||||
//used in arrays_init only
|
||||
struct {
|
||||
int ctu_count;
|
||||
int ctu_size;
|
||||
int pic_size_in_min_cb;
|
||||
int pic_size_in_min_pu;
|
||||
int pic_size_in_min_tu;
|
||||
int ctu_width;
|
||||
int ctu_height;
|
||||
int width;
|
||||
int height;
|
||||
int chroma_format_idc;
|
||||
int pixel_shift;
|
||||
int ibc_buffer_width; ///< IbcBufWidth
|
||||
} sz;
|
||||
} tab;
|
||||
} VVCFrameContext;
|
||||
|
||||
typedef struct VVCContext {
|
||||
struct AVCodecContext *avctx;
|
||||
|
||||
CodedBitstreamContext *cbc;
|
||||
CodedBitstreamFragment current_frame;
|
||||
|
||||
VVCParamSets ps;
|
||||
H274FilmGrainDatabase h274db;
|
||||
|
||||
int temporal_id; ///< temporal_id_plus1 - 1
|
||||
int poc_tid0;
|
||||
|
||||
int eos; ///< current packet contains an EOS/EOB NAL
|
||||
int last_eos; ///< last packet contains an EOS/EOB NAL
|
||||
|
||||
enum VVCNALUnitType vcl_unit_type;
|
||||
int no_output_before_recovery_flag; ///< NoOutputBeforeRecoveryFlag
|
||||
int gdr_recovery_point_poc; ///< recoveryPointPocVal
|
||||
int film_grain_warning_shown;
|
||||
|
||||
/**
|
||||
* Sequence counters for decoded and output frames, so that old
|
||||
* frames are output first after a POC reset
|
||||
*/
|
||||
uint16_t seq_decode;
|
||||
uint16_t seq_output;
|
||||
|
||||
struct FFExecutor *executor;
|
||||
|
||||
VVCFrameContext *fcs;
|
||||
int nb_fcs;
|
||||
|
||||
uint64_t nb_frames; ///< processed frames
|
||||
int nb_delayed; ///< delayed frames
|
||||
|
||||
H274HashContext *hash_ctx;
|
||||
} VVCContext ;
|
||||
|
||||
#endif /* AVCODEC_VVC_DEC_H */
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* VVC DSP
|
||||
*
|
||||
* Copyright (C) 2021 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "dsp.h"
|
||||
#include "ctu.h"
|
||||
#include "itx_1d.h"
|
||||
|
||||
#define VVC_SIGN(v) (v < 0 ? -1 : !!v)
|
||||
|
||||
static int vvc_sad(const int16_t *src0, const int16_t *src1, int dx, int dy,
|
||||
const int block_w, const int block_h)
|
||||
{
|
||||
int sad = 0;
|
||||
dx -= 2;
|
||||
dy -= 2;
|
||||
src0 += (2 + dy) * MAX_PB_SIZE + 2 + dx;
|
||||
src1 += (2 - dy) * MAX_PB_SIZE + 2 - dx;
|
||||
for (int y = 0; y < block_h; y += 2) {
|
||||
for (int x = 0; x < block_w; x++) {
|
||||
sad += FFABS(src0[x] - src1[x]);
|
||||
}
|
||||
src0 += 2 * MAX_PB_SIZE;
|
||||
src1 += 2 * MAX_PB_SIZE;
|
||||
}
|
||||
return sad;
|
||||
}
|
||||
|
||||
static av_always_inline void unpack_mip_info(int *intra_mip_transposed_flag,
|
||||
int *intra_mip_mode, const uint8_t mip_info)
|
||||
{
|
||||
if (intra_mip_transposed_flag)
|
||||
*intra_mip_transposed_flag = (mip_info >> 1) & 0x1;
|
||||
if (intra_mip_mode)
|
||||
*intra_mip_mode = (mip_info >> 2) & 0xf;
|
||||
}
|
||||
|
||||
typedef struct IntraEdgeParams {
|
||||
uint8_t* top;
|
||||
uint8_t* left;
|
||||
int filter_flag;
|
||||
|
||||
uint16_t left_array[6 * MAX_TB_SIZE + 5];
|
||||
uint16_t filtered_left_array[6 * MAX_TB_SIZE + 5];
|
||||
uint16_t top_array[6 * MAX_TB_SIZE + 5];
|
||||
uint16_t filtered_top_array[6 * MAX_TB_SIZE + 5];
|
||||
} IntraEdgeParams;
|
||||
|
||||
#define PROF_BORDER_EXT 1
|
||||
#define PROF_BLOCK_SIZE (AFFINE_MIN_BLOCK_SIZE + PROF_BORDER_EXT * 2)
|
||||
|
||||
#define BDOF_BORDER_EXT 1
|
||||
#define BDOF_BLOCK_SIZE 16
|
||||
#define BDOF_MIN_BLOCK_SIZE 4
|
||||
|
||||
#define BIT_DEPTH 8
|
||||
#include "dsp_template.c"
|
||||
#undef BIT_DEPTH
|
||||
|
||||
#define BIT_DEPTH 10
|
||||
#include "dsp_template.c"
|
||||
#undef BIT_DEPTH
|
||||
|
||||
#define BIT_DEPTH 12
|
||||
#include "dsp_template.c"
|
||||
#undef BIT_DEPTH
|
||||
|
||||
void ff_vvc_dsp_init(VVCDSPContext *vvcdsp, int bit_depth)
|
||||
{
|
||||
#undef FUNC
|
||||
#define FUNC(a, depth) a ## _ ## depth
|
||||
|
||||
#define VVC_DSP(depth) \
|
||||
FUNC(ff_vvc_inter_dsp_init, depth)(&vvcdsp->inter); \
|
||||
FUNC(ff_vvc_intra_dsp_init, depth)(&vvcdsp->intra); \
|
||||
FUNC(ff_vvc_itx_dsp_init, depth)(&vvcdsp->itx); \
|
||||
FUNC(ff_vvc_lmcs_dsp_init, depth)(&vvcdsp->lmcs); \
|
||||
FUNC(ff_vvc_lf_dsp_init, depth)(&vvcdsp->lf); \
|
||||
FUNC(ff_vvc_sao_dsp_init, depth)(&vvcdsp->sao); \
|
||||
FUNC(ff_vvc_alf_dsp_init, depth)(&vvcdsp->alf); \
|
||||
|
||||
switch (bit_depth) {
|
||||
case 12:
|
||||
VVC_DSP(12);
|
||||
break;
|
||||
case 10:
|
||||
VVC_DSP(10);
|
||||
break;
|
||||
default:
|
||||
VVC_DSP(8);
|
||||
break;
|
||||
}
|
||||
|
||||
#if ARCH_AARCH64
|
||||
ff_vvc_dsp_init_aarch64(vvcdsp, bit_depth);
|
||||
#elif ARCH_RISCV
|
||||
ff_vvc_dsp_init_riscv(vvcdsp, bit_depth);
|
||||
#elif ARCH_X86
|
||||
ff_vvc_dsp_init_x86(vvcdsp, bit_depth);
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* VVC DSP
|
||||
*
|
||||
* Copyright (C) 2021 Nuo Mi
|
||||
*
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_DSP_H
|
||||
#define AVCODEC_VVC_DSP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
enum VVCTxType {
|
||||
VVC_DCT2,
|
||||
VVC_DST7,
|
||||
VVC_DCT8,
|
||||
VVC_N_TX_TYPE,
|
||||
};
|
||||
|
||||
enum VVCTxSize {
|
||||
VVC_TX_SIZE_2,
|
||||
VVC_TX_SIZE_4,
|
||||
VVC_TX_SIZE_8,
|
||||
VVC_TX_SIZE_16,
|
||||
VVC_TX_SIZE_32,
|
||||
VVC_TX_SIZE_64,
|
||||
VVC_N_TX_SIZE,
|
||||
};
|
||||
|
||||
typedef struct VVCInterDSPContext {
|
||||
void (*put[2 /* luma, chroma */][7 /* log2(width) - 1 */][2 /* int, frac */][2 /* int, frac */])(
|
||||
int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int height,
|
||||
const int8_t *hf, const int8_t *vf, int width);
|
||||
|
||||
void (*put_uni[2 /* luma, chroma */][7 /* log2(width) - 1 */][2 /* int, frac */][2 /* int, frac */])(
|
||||
uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, int height,
|
||||
const int8_t *hf, const int8_t *vf, int width);
|
||||
|
||||
void (*put_uni_w[2 /* luma, chroma */][7 /* log2(width) - 1 */][2 /* int, frac */][2 /* int, frac */])(
|
||||
uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, int height,
|
||||
int denom, int wx, int ox, const int8_t *hf, const int8_t *vf, int width);
|
||||
|
||||
void (*put_scaled[2 /* luma, chroma */][7 /* log2(width) - 1 */])(
|
||||
int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int src_height,
|
||||
int x, int y, int dx, int dy, int height, const int8_t *hf, const int8_t *vf, int width);
|
||||
|
||||
void (*put_uni_scaled[2 /* luma, chroma */][7 /* log2(width) - 1 */])(
|
||||
uint8_t *dst, const ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, int src_height,
|
||||
int x, int y, int dx, int dy, int height, const int8_t *hf, const int8_t *vf, int width);
|
||||
|
||||
void (*put_uni_w_scaled[2 /* luma, chroma */][7 /* log2(width) - 1 */])(
|
||||
uint8_t *dst, const ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride, int src_height,
|
||||
int x, int y, int dx, int dy, int height, int denom, int wx, int ox, const int8_t *hf, const int8_t *vf,
|
||||
int width);
|
||||
|
||||
void (*avg)(uint8_t *dst, ptrdiff_t dst_stride,
|
||||
const int16_t *src0, const int16_t *src1, int width, int height);
|
||||
|
||||
void (*w_avg)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const int16_t *src0, const int16_t *src1, int width, int height,
|
||||
int denom, int w0, int w1, int o0, int o1);
|
||||
|
||||
void (*put_ciip)(uint8_t *dst, ptrdiff_t dst_stride, int width, int height,
|
||||
const uint8_t *inter, ptrdiff_t inter_stride, int inter_weight);
|
||||
|
||||
void (*put_gpm)(uint8_t *dst, ptrdiff_t dst_stride, int width, int height,
|
||||
const int16_t *src0, const int16_t *src1,
|
||||
const uint8_t *weights, int step_x, int step_y);
|
||||
|
||||
void (*fetch_samples)(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int x_frac, int y_frac);
|
||||
void (*bdof_fetch_samples)(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int x_frac, int y_frac,
|
||||
int width, int height);
|
||||
|
||||
void (*apply_prof)(int16_t *dst, const int16_t *src, const int16_t *diff_mv_x, const int16_t *diff_mv_y);
|
||||
|
||||
void (*apply_prof_uni)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src,
|
||||
const int16_t *diff_mv_x, const int16_t *diff_mv_y);
|
||||
void (*apply_prof_uni_w)(uint8_t *dst, const ptrdiff_t dst_stride, const int16_t *src,
|
||||
const int16_t *diff_mv_x, const int16_t *diff_mv_y, int denom, int wx, int ox);
|
||||
|
||||
void (*apply_bdof)(uint8_t *dst, ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1, int block_w, int block_h);
|
||||
|
||||
int (*sad)(const int16_t *src0, const int16_t *src1, int dx, int dy, int block_w, int block_h);
|
||||
void (*dmvr[2][2])(int16_t *dst, const uint8_t *src, ptrdiff_t src_stride, int height,
|
||||
intptr_t mx, intptr_t my, int width);
|
||||
} VVCInterDSPContext;
|
||||
|
||||
struct VVCLocalContext;
|
||||
|
||||
typedef struct VVCIntraDSPContext {
|
||||
void (*intra_cclm_pred)(const struct VVCLocalContext *lc, int x0, int y0, int w, int h);
|
||||
void (*lmcs_scale_chroma)(struct VVCLocalContext *lc, int *coeff, int w, int h, int x0_cu, int y0_cu);
|
||||
void (*intra_pred)(const struct VVCLocalContext *lc, int x0, int y0, int w, int h, int c_idx);
|
||||
void (*pred_planar)(uint8_t *src, const uint8_t *top, const uint8_t *left, int w, int h, ptrdiff_t stride);
|
||||
void (*pred_mip)(uint8_t *src, const uint8_t *top, const uint8_t *left, int w, int h, ptrdiff_t stride,
|
||||
int mode_id, int is_transpose);
|
||||
void (*pred_dc)(uint8_t *src, const uint8_t *top, const uint8_t *left, int w, int h, ptrdiff_t stride);
|
||||
void (*pred_v)(uint8_t *src, const uint8_t *_top, int w, int h, ptrdiff_t stride);
|
||||
void (*pred_h)(uint8_t *src, const uint8_t *_left, int w, int h, ptrdiff_t stride);
|
||||
void (*pred_angular_v)(uint8_t *src, const uint8_t *_top, const uint8_t *_left,
|
||||
int w, int h, ptrdiff_t stride, int c_idx, int mode, int ref_idx, int filter_flag, int need_pdpc);
|
||||
void (*pred_angular_h)(uint8_t *src, const uint8_t *_top, const uint8_t *_left, int w, int h, ptrdiff_t stride,
|
||||
int c_idx, int mode, int ref_idx, int filter_flag, int need_pdpc);
|
||||
} VVCIntraDSPContext;
|
||||
|
||||
typedef struct VVCItxDSPContext {
|
||||
void (*add_residual)(uint8_t *dst, const int *res, int width, int height, ptrdiff_t stride);
|
||||
void (*pred_residual_joint)(int *dst, const int *src, int width, int height, int c_sign, int shift);
|
||||
|
||||
void (*itx[VVC_N_TX_TYPE][VVC_N_TX_SIZE])(int *coeffs, ptrdiff_t step, size_t nz);
|
||||
void (*transform_bdpcm)(int *coeffs, int width, int height, int vertical, int log2_transform_range);
|
||||
|
||||
void (*adaptive_color_transform)(int *y, int *u, int *v, int width, int height);
|
||||
} VVCItxDSPContext;
|
||||
|
||||
typedef struct VVCLMCSDSPContext {
|
||||
void (*filter)(uint8_t *dst, ptrdiff_t dst_stride, int width, int height, const void *lut);
|
||||
} VVCLMCSDSPContext;
|
||||
|
||||
typedef struct VVCLFDSPContext {
|
||||
int (*ladf_level[2 /* h, v */])(const uint8_t *pix, ptrdiff_t stride);
|
||||
|
||||
void (*filter_luma[2 /* h, v */])(uint8_t *pix, ptrdiff_t stride, const int32_t *beta, const int32_t *tc,
|
||||
const uint8_t *no_p, const uint8_t *no_q, const uint8_t *max_len_p, const uint8_t *max_len_q, int hor_ctu_edge);
|
||||
void (*filter_chroma[2 /* h, v */])(uint8_t *pix, ptrdiff_t stride, const int32_t *beta, const int32_t *tc,
|
||||
const uint8_t *no_p, const uint8_t *no_q, const uint8_t *max_len_p, const uint8_t *max_len_q, int shift);
|
||||
} VVCLFDSPContext;
|
||||
|
||||
struct SAOParams;
|
||||
typedef struct VVCSAODSPContext {
|
||||
void (*band_filter[9])(uint8_t *dst, const uint8_t *src, ptrdiff_t dst_stride, ptrdiff_t src_stride,
|
||||
const int16_t *sao_offset_val, int sao_left_class, int width, int height);
|
||||
/* implicit src_stride parameter has value of 2 * MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE */
|
||||
void (*edge_filter[9])(uint8_t *dst /* align 16 */, const uint8_t *src /* align 32 */, ptrdiff_t dst_stride,
|
||||
const int16_t *sao_offset_val, int sao_eo_class, int width, int height);
|
||||
void (*edge_restore[2])(uint8_t *dst, const uint8_t *src, ptrdiff_t dst_stride, ptrdiff_t src_stride,
|
||||
const struct SAOParams *sao, const int *borders, int width, int height, int c_idx,
|
||||
const uint8_t *vert_edge, const uint8_t *horiz_edge, const uint8_t *diag_edge);
|
||||
} VVCSAODSPContext;
|
||||
|
||||
typedef struct VVCALFDSPContext {
|
||||
void (*filter[2 /* luma, chroma */])(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *src, ptrdiff_t src_stride,
|
||||
int width, int height, const int16_t *filter, const int16_t *clip, int vb_pos);
|
||||
void (*filter_cc)(uint8_t *dst, ptrdiff_t dst_stride, const uint8_t *luma, ptrdiff_t luma_stride,
|
||||
int width, int height, int hs, int vs, const int16_t *filter, int vb_pos);
|
||||
|
||||
void (*classify)(int *class_idx, int *transpose_idx, const uint8_t *src, ptrdiff_t src_stride, int width, int height,
|
||||
int vb_pos, int *gradient_tmp);
|
||||
void (*recon_coeff_and_clip)(int16_t *coeff, int16_t *clip, const int *class_idx, const int *transpose_idx, int size,
|
||||
const int16_t *coeff_set, const uint8_t *clip_idx_set, const uint8_t *class_to_filt);
|
||||
} VVCALFDSPContext;
|
||||
|
||||
typedef struct VVCDSPContext {
|
||||
VVCInterDSPContext inter;
|
||||
VVCIntraDSPContext intra;
|
||||
VVCItxDSPContext itx;
|
||||
VVCLMCSDSPContext lmcs;
|
||||
VVCLFDSPContext lf;
|
||||
VVCSAODSPContext sao;
|
||||
VVCALFDSPContext alf;
|
||||
} VVCDSPContext;
|
||||
|
||||
void ff_vvc_dsp_init(VVCDSPContext *hpc, int bit_depth);
|
||||
|
||||
void ff_vvc_dsp_init_aarch64(VVCDSPContext *hpc, const int bit_depth);
|
||||
void ff_vvc_dsp_init_riscv(VVCDSPContext *hpc, const int bit_depth);
|
||||
void ff_vvc_dsp_init_x86(VVCDSPContext *hpc, const int bit_depth);
|
||||
|
||||
#endif /* AVCODEC_VVC_DSP_H */
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* VVC transform and residual DSP
|
||||
*
|
||||
* Copyright (C) 2021 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "libavutil/frame.h"
|
||||
#include "libavcodec/bit_depth_template.c"
|
||||
|
||||
#include "dec.h"
|
||||
#include "data.h"
|
||||
|
||||
#include "inter_template.c"
|
||||
#include "intra_template.c"
|
||||
#include "filter_template.c"
|
||||
|
||||
static void FUNC(add_residual)(uint8_t *_dst, const int *res,
|
||||
const int w, const int h, const ptrdiff_t _stride)
|
||||
{
|
||||
pixel *dst = (pixel *)_dst;
|
||||
|
||||
const int stride = _stride / sizeof(pixel);
|
||||
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
dst[x] = av_clip_pixel(dst[x] + *res);
|
||||
res++;
|
||||
}
|
||||
dst += stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(pred_residual_joint)(int *dst, const int *src, const int w, const int h,
|
||||
const int c_sign, const int shift)
|
||||
{
|
||||
const int size = w * h;
|
||||
for (int i = 0; i < size; i++)
|
||||
dst[i] = (src[i] * c_sign) >> shift;
|
||||
}
|
||||
|
||||
static void FUNC(transform_bdpcm)(int *coeffs, const int width, const int height,
|
||||
const int vertical, const int log2_transform_range)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
if (vertical) {
|
||||
coeffs += width;
|
||||
for (y = 0; y < height - 1; y++) {
|
||||
for (x = 0; x < width; x++)
|
||||
coeffs[x] = av_clip_intp2(coeffs[x] + coeffs[x - width], log2_transform_range);
|
||||
coeffs += width;
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 1; x < width; x++)
|
||||
coeffs[x] = av_clip_intp2(coeffs[x] + coeffs[x - 1], log2_transform_range);
|
||||
coeffs += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 8.7.4.6 Residual modification process for blocks using colour space conversion
|
||||
static void FUNC(adaptive_color_transform)(int *y, int *u, int *v, const int width, const int height)
|
||||
{
|
||||
const int size = width * height;
|
||||
const int bits = BIT_DEPTH + 1;
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
const int y0 = av_clip_intp2(y[i], bits);
|
||||
const int cg = av_clip_intp2(u[i], bits);
|
||||
const int co = av_clip_intp2(v[i], bits);
|
||||
const int t = y0 - (cg >> 1);
|
||||
|
||||
y[i] = cg + t;
|
||||
u[i] = t - (co >> 1);
|
||||
v[i] = co + u[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(ff_vvc_itx_dsp_init)(VVCItxDSPContext *const itx)
|
||||
{
|
||||
#define VVC_ITX(TYPE, type, s) \
|
||||
itx->itx[VVC_##TYPE][VVC_##TX_SIZE_##s] = ff_vvc_inv_##type##_##s; \
|
||||
|
||||
#define VVC_ITX_COMMON(TYPE, type) \
|
||||
VVC_ITX(TYPE, type, 4); \
|
||||
VVC_ITX(TYPE, type, 8); \
|
||||
VVC_ITX(TYPE, type, 16); \
|
||||
VVC_ITX(TYPE, type, 32);
|
||||
|
||||
itx->add_residual = FUNC(add_residual);
|
||||
itx->pred_residual_joint = FUNC(pred_residual_joint);
|
||||
itx->transform_bdpcm = FUNC(transform_bdpcm);
|
||||
VVC_ITX(DCT2, dct2, 2)
|
||||
VVC_ITX(DCT2, dct2, 64)
|
||||
VVC_ITX_COMMON(DCT2, dct2)
|
||||
VVC_ITX_COMMON(DCT8, dct8)
|
||||
VVC_ITX_COMMON(DST7, dst7)
|
||||
|
||||
itx->adaptive_color_transform = FUNC(adaptive_color_transform);
|
||||
|
||||
#undef VVC_ITX
|
||||
#undef VVC_ITX_COMMON
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* VVC filters
|
||||
*
|
||||
* Copyright (C) 2022 Nuo Mi
|
||||
*
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef AVCODEC_VVC_FILTER_H
|
||||
#define AVCODEC_VVC_FILTER_H
|
||||
|
||||
#include "dec.h"
|
||||
|
||||
/**
|
||||
* lmcs filter for the CTU
|
||||
* @param lc local context for CTU
|
||||
* @param x0 x position for the CTU
|
||||
* @param y0 y position for the CTU
|
||||
*/
|
||||
void ff_vvc_lmcs_filter(const VVCLocalContext *lc, const int x0, const int y0);
|
||||
|
||||
/**
|
||||
* derive boundary strength for the CTU
|
||||
* @param lc local context for CTU
|
||||
* @param rx raster x position for the CTU
|
||||
* @param ry raster y position for the CTU
|
||||
* @param rs raster position for the CTU
|
||||
*/
|
||||
void ff_vvc_deblock_bs(VVCLocalContext *lc, const int rx, const int ry, const int rs);
|
||||
|
||||
/**
|
||||
* vertical deblock filter for the CTU
|
||||
* @param lc local context for CTU
|
||||
* @param x0 x position for the CTU
|
||||
* @param y0 y position for the CTU
|
||||
* @param rs raster position for the CTU
|
||||
*/
|
||||
void ff_vvc_deblock_vertical(const VVCLocalContext *lc, int x0, int y0, int rs);
|
||||
|
||||
/**
|
||||
* horizontal deblock filter for the CTU
|
||||
* @param lc local context for CTU
|
||||
* @param x0 x position for the CTU
|
||||
* @param y0 y position for the CTU
|
||||
* @param rs raster position for the CTU
|
||||
*/
|
||||
void ff_vvc_deblock_horizontal(const VVCLocalContext *lc, int x0, int y0, int rs);
|
||||
|
||||
/**
|
||||
* sao filter for the CTU
|
||||
* @param lc local context for CTU
|
||||
* @param x0 x position for the CTU
|
||||
* @param y0 y position for the CTU
|
||||
*/
|
||||
void ff_vvc_sao_filter(VVCLocalContext *lc, const int x0, const int y0);
|
||||
|
||||
void ff_vvc_sao_copy_ctb_to_hv(VVCLocalContext* lc, int rx, int ry, int last_row);
|
||||
void ff_vvc_alf_copy_ctu_to_hv(VVCLocalContext* lc, int x0, int y0);
|
||||
|
||||
/**
|
||||
* alf filter for the CTU
|
||||
* @param lc local context for CTU
|
||||
* @param x0 x position for the CTU
|
||||
* @param y0 y position for the CTU
|
||||
*/
|
||||
void ff_vvc_alf_filter(VVCLocalContext *lc, const int x0, const int y0);
|
||||
|
||||
#endif // AVCODEC_VVC_CTU_H
|
||||
@@ -0,0 +1,862 @@
|
||||
/*
|
||||
* VVC filters DSP
|
||||
*
|
||||
* Copyright (C) 2022 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavcodec/h26x/h2656_sao_template.c"
|
||||
|
||||
static void FUNC(lmcs_filter_luma)(uint8_t *_dst, ptrdiff_t dst_stride, const int width, const int height, const void *_lut)
|
||||
{
|
||||
const pixel *lut = _lut;
|
||||
pixel *dst = (pixel*)_dst;
|
||||
dst_stride /= sizeof(pixel);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
dst[x] = lut[dst[x]];
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static av_always_inline int16_t FUNC(alf_clip)(pixel curr, pixel v0, pixel v1, int16_t clip)
|
||||
{
|
||||
return av_clip(v0 - curr, -clip, clip) + av_clip(v1 - curr, -clip, clip);
|
||||
}
|
||||
|
||||
static void FUNC(alf_filter_luma)(uint8_t *_dst, ptrdiff_t dst_stride, const uint8_t *_src, ptrdiff_t src_stride,
|
||||
const int width, const int height, const int16_t *filter, const int16_t *clip, const int vb_pos)
|
||||
{
|
||||
const pixel *src = (pixel *)_src;
|
||||
const int shift = 7;
|
||||
const int offset = 1 << ( shift - 1 );
|
||||
const int vb_above = vb_pos - 4;
|
||||
const int vb_below = vb_pos + 3;
|
||||
|
||||
dst_stride /= sizeof(pixel);
|
||||
src_stride /= sizeof(pixel);
|
||||
|
||||
for (int y = 0; y < height; y += ALF_BLOCK_SIZE) {
|
||||
for (int x = 0; x < width; x += ALF_BLOCK_SIZE) {
|
||||
const pixel *s0 = src + y * src_stride + x;
|
||||
const pixel *s1 = s0 + src_stride;
|
||||
const pixel *s2 = s0 - src_stride;
|
||||
const pixel *s3 = s1 + src_stride;
|
||||
const pixel *s4 = s2 - src_stride;
|
||||
const pixel *s5 = s3 + src_stride;
|
||||
const pixel *s6 = s4 - src_stride;
|
||||
|
||||
for (int i = 0; i < ALF_BLOCK_SIZE; i++) {
|
||||
pixel *dst = (pixel *)_dst + (y + i) * dst_stride + x;
|
||||
|
||||
const pixel *p0 = s0 + i * src_stride;
|
||||
const pixel *p1 = s1 + i * src_stride;
|
||||
const pixel *p2 = s2 + i * src_stride;
|
||||
const pixel *p3 = s3 + i * src_stride;
|
||||
const pixel *p4 = s4 + i * src_stride;
|
||||
const pixel *p5 = s5 + i * src_stride;
|
||||
const pixel *p6 = s6 + i * src_stride;
|
||||
|
||||
const int is_near_vb_above = (y + i < vb_pos) && (y + i >= vb_pos - 1);
|
||||
const int is_near_vb_below = (y + i >= vb_pos) && (y + i <= vb_pos);
|
||||
const int is_near_vb = is_near_vb_above || is_near_vb_below;
|
||||
|
||||
if ((y + i < vb_pos) && ((y + i) > vb_above)) {
|
||||
p1 = (y + i == vb_pos - 1) ? p0 : p1;
|
||||
p3 = (y + i >= vb_pos - 2) ? p1 : p3;
|
||||
p5 = (y + i >= vb_pos - 3) ? p3 : p5;
|
||||
|
||||
p2 = (y + i == vb_pos - 1) ? p0 : p2;
|
||||
p4 = (y + i >= vb_pos - 2) ? p2 : p4;
|
||||
p6 = (y + i >= vb_pos - 3) ? p4 : p6;
|
||||
} else if ((y + i >= vb_pos) && ((y + i) < vb_below)) {
|
||||
p2 = (y + i == vb_pos ) ? p0 : p2;
|
||||
p4 = (y + i <= vb_pos + 1) ? p2 : p4;
|
||||
p6 = (y + i <= vb_pos + 2) ? p4 : p6;
|
||||
|
||||
p1 = (y + i == vb_pos ) ? p0 : p1;
|
||||
p3 = (y + i <= vb_pos + 1) ? p1 : p3;
|
||||
p5 = (y + i <= vb_pos + 2) ? p3 : p5;
|
||||
}
|
||||
|
||||
for (int j = 0; j < ALF_BLOCK_SIZE; j++) {
|
||||
int sum = 0;
|
||||
const pixel curr = *p0;
|
||||
|
||||
sum += filter[0] * FUNC(alf_clip)(curr, p5[+0], p6[+0], clip[0]);
|
||||
sum += filter[1] * FUNC(alf_clip)(curr, p3[+1], p4[-1], clip[1]);
|
||||
sum += filter[2] * FUNC(alf_clip)(curr, p3[+0], p4[+0], clip[2]);
|
||||
sum += filter[3] * FUNC(alf_clip)(curr, p3[-1], p4[+1], clip[3]);
|
||||
sum += filter[4] * FUNC(alf_clip)(curr, p1[+2], p2[-2], clip[4]);
|
||||
sum += filter[5] * FUNC(alf_clip)(curr, p1[+1], p2[-1], clip[5]);
|
||||
sum += filter[6] * FUNC(alf_clip)(curr, p1[+0], p2[+0], clip[6]);
|
||||
sum += filter[7] * FUNC(alf_clip)(curr, p1[-1], p2[+1], clip[7]);
|
||||
sum += filter[8] * FUNC(alf_clip)(curr, p1[-2], p2[+2], clip[8]);
|
||||
sum += filter[9] * FUNC(alf_clip)(curr, p0[+3], p0[-3], clip[9]);
|
||||
sum += filter[10] * FUNC(alf_clip)(curr, p0[+2], p0[-2], clip[10]);
|
||||
sum += filter[11] * FUNC(alf_clip)(curr, p0[+1], p0[-1], clip[11]);
|
||||
|
||||
if (!is_near_vb)
|
||||
sum = (sum + offset) >> shift;
|
||||
else
|
||||
sum = (sum + (1 << ((shift + 3) - 1))) >> (shift + 3);
|
||||
sum += curr;
|
||||
dst[j] = CLIP(sum);
|
||||
|
||||
p0++;
|
||||
p1++;
|
||||
p2++;
|
||||
p3++;
|
||||
p4++;
|
||||
p5++;
|
||||
p6++;
|
||||
}
|
||||
}
|
||||
filter += ALF_NUM_COEFF_LUMA;
|
||||
clip += ALF_NUM_COEFF_LUMA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(alf_filter_chroma)(uint8_t* _dst, ptrdiff_t dst_stride, const uint8_t* _src, ptrdiff_t src_stride,
|
||||
const int width, const int height, const int16_t* filter, const int16_t* clip, const int vb_pos)
|
||||
{
|
||||
const pixel *src = (pixel *)_src;
|
||||
const int shift = 7;
|
||||
const int offset = 1 << ( shift - 1 );
|
||||
const int vb_above = vb_pos - 2;
|
||||
const int vb_below = vb_pos + 1;
|
||||
|
||||
dst_stride /= sizeof(pixel);
|
||||
src_stride /= sizeof(pixel);
|
||||
|
||||
for (int y = 0; y < height; y += ALF_BLOCK_SIZE) {
|
||||
for (int x = 0; x < width; x += ALF_BLOCK_SIZE) {
|
||||
const pixel *s0 = src + y * src_stride + x;
|
||||
const pixel *s1 = s0 + src_stride;
|
||||
const pixel *s2 = s0 - src_stride;
|
||||
const pixel *s3 = s1 + src_stride;
|
||||
const pixel *s4 = s2 - src_stride;
|
||||
|
||||
for (int i = 0; i < ALF_BLOCK_SIZE; i++) {
|
||||
pixel *dst = (pixel *)_dst + (y + i) * dst_stride + x;
|
||||
|
||||
const pixel *p0 = s0 + i * src_stride;
|
||||
const pixel *p1 = s1 + i * src_stride;
|
||||
const pixel *p2 = s2 + i * src_stride;
|
||||
const pixel *p3 = s3 + i * src_stride;
|
||||
const pixel *p4 = s4 + i * src_stride;
|
||||
|
||||
const int is_near_vb_above = (y + i < vb_pos) && (y + i >= vb_pos - 1);
|
||||
const int is_near_vb_below = (y + i >= vb_pos) && (y + i <= vb_pos);
|
||||
const int is_near_vb = is_near_vb_above || is_near_vb_below;
|
||||
|
||||
if ((y + i < vb_pos) && ((y + i) >= vb_above)) {
|
||||
p1 = (y + i == vb_pos - 1) ? p0 : p1;
|
||||
p3 = (y + i >= vb_pos - 2) ? p1 : p3;
|
||||
|
||||
p2 = (y + i == vb_pos - 1) ? p0 : p2;
|
||||
p4 = (y + i >= vb_pos - 2) ? p2 : p4;
|
||||
} else if ((y + i >= vb_pos) && ((y + i) <= vb_below)) {
|
||||
p2 = (y + i == vb_pos ) ? p0 : p2;
|
||||
p4 = (y + i <= vb_pos + 1) ? p2 : p4;
|
||||
|
||||
p1 = (y + i == vb_pos ) ? p0 : p1;
|
||||
p3 = (y + i <= vb_pos + 1) ? p1 : p3;
|
||||
}
|
||||
|
||||
for (int j = 0; j < ALF_BLOCK_SIZE; j++) {
|
||||
int sum = 0;
|
||||
const pixel curr = *p0;
|
||||
|
||||
sum += filter[0] * FUNC(alf_clip)(curr, p3[+0], p4[+0], clip[0]);
|
||||
sum += filter[1] * FUNC(alf_clip)(curr, p1[+1], p2[-1], clip[1]);
|
||||
sum += filter[2] * FUNC(alf_clip)(curr, p1[+0], p2[+0], clip[2]);
|
||||
sum += filter[3] * FUNC(alf_clip)(curr, p1[-1], p2[+1], clip[3]);
|
||||
sum += filter[4] * FUNC(alf_clip)(curr, p0[+2], p0[-2], clip[4]);
|
||||
sum += filter[5] * FUNC(alf_clip)(curr, p0[+1], p0[-1], clip[5]);
|
||||
|
||||
if (!is_near_vb)
|
||||
sum = (sum + offset) >> shift;
|
||||
else
|
||||
sum = (sum + (1 << ((shift + 3) - 1))) >> (shift + 3);
|
||||
sum += curr;
|
||||
dst[j] = CLIP(sum);
|
||||
|
||||
p0++;
|
||||
p1++;
|
||||
p2++;
|
||||
p3++;
|
||||
p4++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(alf_filter_cc)(uint8_t *_dst, ptrdiff_t dst_stride, const uint8_t *_luma, const ptrdiff_t luma_stride,
|
||||
const int width, const int height, const int hs, const int vs, const int16_t *filter, const int vb_pos)
|
||||
{
|
||||
const ptrdiff_t stride = luma_stride / sizeof(pixel);
|
||||
|
||||
dst_stride /= sizeof(pixel);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
int sum = 0;
|
||||
pixel *dst = (pixel *)_dst + y * dst_stride + x;
|
||||
const pixel *src = (pixel *)_luma + (y << vs) * stride + (x << hs);
|
||||
|
||||
const pixel *s0 = src - stride;
|
||||
const pixel *s1 = src;
|
||||
const pixel *s2 = src + stride;
|
||||
const pixel *s3 = src + 2 * stride;
|
||||
|
||||
const int pos = y << vs;
|
||||
if (!vs && (pos == vb_pos || pos == vb_pos + 1))
|
||||
continue;
|
||||
|
||||
if (pos == (vb_pos - 2) || pos == (vb_pos + 1))
|
||||
s3 = s2;
|
||||
else if (pos == (vb_pos - 1) || pos == vb_pos)
|
||||
s3 = s2 = s0 = s1;
|
||||
|
||||
|
||||
sum += filter[0] * (*s0 - *src);
|
||||
sum += filter[1] * (*(s1 - 1) - *src);
|
||||
sum += filter[2] * (*(s1 + 1) - *src);
|
||||
sum += filter[3] * (*(s2 - 1) - *src);
|
||||
sum += filter[4] * (*s2 - *src);
|
||||
sum += filter[5] * (*(s2 + 1) - *src);
|
||||
sum += filter[6] * (*s3 - *src);
|
||||
sum = av_clip((sum + 64) >> 7, -(1 << (BIT_DEPTH - 1)), (1 << (BIT_DEPTH - 1)) - 1);
|
||||
sum += *dst;
|
||||
*dst = av_clip_pixel(sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define ALF_DIR_VERT 0
|
||||
#define ALF_DIR_HORZ 1
|
||||
#define ALF_DIR_DIGA0 2
|
||||
#define ALF_DIR_DIGA1 3
|
||||
|
||||
static void FUNC(alf_get_idx)(int *class_idx, int *transpose_idx, const int *sum, const int ac)
|
||||
{
|
||||
static const int arg_var[] = {0, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4 };
|
||||
|
||||
int hv0, hv1, dir_hv, d0, d1, dir_d, hvd1, hvd0, sum_hv, dir1;
|
||||
|
||||
dir_hv = sum[ALF_DIR_VERT] <= sum[ALF_DIR_HORZ];
|
||||
hv1 = FFMAX(sum[ALF_DIR_VERT], sum[ALF_DIR_HORZ]);
|
||||
hv0 = FFMIN(sum[ALF_DIR_VERT], sum[ALF_DIR_HORZ]);
|
||||
|
||||
dir_d = sum[ALF_DIR_DIGA0] <= sum[ALF_DIR_DIGA1];
|
||||
d1 = FFMAX(sum[ALF_DIR_DIGA0], sum[ALF_DIR_DIGA1]);
|
||||
d0 = FFMIN(sum[ALF_DIR_DIGA0], sum[ALF_DIR_DIGA1]);
|
||||
|
||||
//promote to avoid overflow
|
||||
dir1 = (uint64_t)d1 * hv0 <= (uint64_t)hv1 * d0;
|
||||
hvd1 = dir1 ? hv1 : d1;
|
||||
hvd0 = dir1 ? hv0 : d0;
|
||||
|
||||
sum_hv = sum[ALF_DIR_HORZ] + sum[ALF_DIR_VERT];
|
||||
*class_idx = arg_var[av_clip_uintp2(sum_hv * ac >> (BIT_DEPTH - 1), 4)];
|
||||
if (hvd1 * 2 > 9 * hvd0)
|
||||
*class_idx += ((dir1 << 1) + 2) * 5;
|
||||
else if (hvd1 > 2 * hvd0)
|
||||
*class_idx += ((dir1 << 1) + 1) * 5;
|
||||
|
||||
*transpose_idx = dir_d * 2 + dir_hv;
|
||||
}
|
||||
|
||||
static void FUNC(alf_classify)(int *class_idx, int *transpose_idx,
|
||||
const uint8_t *_src, const ptrdiff_t _src_stride, const int width, const int height,
|
||||
const int vb_pos, int *gradient_tmp)
|
||||
{
|
||||
int *grad;
|
||||
|
||||
const int h = height + ALF_GRADIENT_BORDER * 2;
|
||||
const int w = width + ALF_GRADIENT_BORDER * 2;
|
||||
const int size = (ALF_BLOCK_SIZE + ALF_GRADIENT_BORDER * 2) / ALF_GRADIENT_STEP;
|
||||
const int gstride = (w / ALF_GRADIENT_STEP) * ALF_NUM_DIR;
|
||||
|
||||
const pixel *src = (const pixel *)_src;
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
src -= (ALF_GRADIENT_BORDER + 1) * src_stride + ALF_GRADIENT_BORDER;
|
||||
|
||||
grad = gradient_tmp;
|
||||
for (int y = 0; y < h; y += ALF_GRADIENT_STEP) {
|
||||
const pixel *s0 = src + y * src_stride;
|
||||
const pixel *s1 = s0 + src_stride;
|
||||
const pixel *s2 = s1 + src_stride;
|
||||
const pixel *s3 = s2 + src_stride;
|
||||
|
||||
if (y == vb_pos) //above
|
||||
s3 = s2;
|
||||
else if (y == vb_pos + ALF_GRADIENT_BORDER)
|
||||
s0 = s1;
|
||||
|
||||
for (int x = 0; x < w; x += ALF_GRADIENT_STEP) {
|
||||
//two points a time
|
||||
const pixel *a0 = s0 + x;
|
||||
const pixel *p0 = s1 + x;
|
||||
const pixel *b0 = s2 + x;
|
||||
const int val0 = (*p0) << 1;
|
||||
|
||||
const pixel *a1 = s1 + x + 1;
|
||||
const pixel *p1 = s2 + x + 1;
|
||||
const pixel *b1 = s3 + x + 1;
|
||||
const int val1 = (*p1) << 1;
|
||||
|
||||
grad[ALF_DIR_VERT] = FFABS(val0 - *a0 - *b0) + FFABS(val1 - *a1 - *b1);
|
||||
grad[ALF_DIR_HORZ] = FFABS(val0 - *(p0 - 1) - *(p0 + 1)) + FFABS(val1 - *(p1 - 1) - *(p1 + 1));
|
||||
grad[ALF_DIR_DIGA0] = FFABS(val0 - *(a0 - 1) - *(b0 + 1)) + FFABS(val1 - *(a1 - 1) - *(b1 + 1));
|
||||
grad[ALF_DIR_DIGA1] = FFABS(val0 - *(a0 + 1) - *(b0 - 1)) + FFABS(val1 - *(a1 + 1) - *(b1 - 1));
|
||||
grad += ALF_NUM_DIR;
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < height ; y += ALF_BLOCK_SIZE ) {
|
||||
int start = 0;
|
||||
int end = (ALF_BLOCK_SIZE + ALF_GRADIENT_BORDER * 2) / ALF_GRADIENT_STEP;
|
||||
int ac = 2;
|
||||
if (y + ALF_BLOCK_SIZE == vb_pos) {
|
||||
end -= ALF_GRADIENT_BORDER / ALF_GRADIENT_STEP;
|
||||
ac = 3;
|
||||
} else if (y == vb_pos) {
|
||||
start += ALF_GRADIENT_BORDER / ALF_GRADIENT_STEP;
|
||||
ac = 3;
|
||||
}
|
||||
for (int x = 0; x < width; x += ALF_BLOCK_SIZE) {
|
||||
const int xg = x / ALF_GRADIENT_STEP;
|
||||
const int yg = y / ALF_GRADIENT_STEP;
|
||||
int sum[ALF_NUM_DIR] = { 0 };
|
||||
|
||||
grad = gradient_tmp + (yg + start) * gstride + xg * ALF_NUM_DIR;
|
||||
//todo: optimize this loop
|
||||
for (int i = start; i < end; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
sum[ALF_DIR_VERT] += grad[ALF_DIR_VERT];
|
||||
sum[ALF_DIR_HORZ] += grad[ALF_DIR_HORZ];
|
||||
sum[ALF_DIR_DIGA0] += grad[ALF_DIR_DIGA0];
|
||||
sum[ALF_DIR_DIGA1] += grad[ALF_DIR_DIGA1];
|
||||
grad += ALF_NUM_DIR;
|
||||
}
|
||||
grad += gstride - size * ALF_NUM_DIR;
|
||||
}
|
||||
FUNC(alf_get_idx)(class_idx, transpose_idx, sum, ac);
|
||||
|
||||
class_idx++;
|
||||
transpose_idx++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void FUNC(alf_recon_coeff_and_clip)(int16_t *coeff, int16_t *clip,
|
||||
const int *class_idx, const int *transpose_idx, const int size,
|
||||
const int16_t *coeff_set, const uint8_t *clip_idx_set, const uint8_t *class_to_filt)
|
||||
{
|
||||
const static int index[][ALF_NUM_COEFF_LUMA] = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 },
|
||||
{ 9, 4, 10, 8, 1, 5, 11, 7, 3, 0, 2, 6 },
|
||||
{ 0, 3, 2, 1, 8, 7, 6, 5, 4, 9, 10, 11 },
|
||||
{ 9, 8, 10, 4, 3, 7, 11, 5, 1, 0, 2, 6 },
|
||||
};
|
||||
|
||||
const int16_t clip_set[] = {
|
||||
1 << BIT_DEPTH, 1 << (BIT_DEPTH - 3), 1 << (BIT_DEPTH - 5), 1 << (BIT_DEPTH - 7)
|
||||
};
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
const int16_t *src_coeff = coeff_set + class_to_filt[class_idx[i]] * ALF_NUM_COEFF_LUMA;
|
||||
const uint8_t *clip_idx = clip_idx_set + class_idx[i] * ALF_NUM_COEFF_LUMA;
|
||||
|
||||
for (int j = 0; j < ALF_NUM_COEFF_LUMA; j++) {
|
||||
const int idx = index[transpose_idx[i]][j];
|
||||
*coeff++ = src_coeff[idx];
|
||||
*clip++ = clip_set[clip_idx[idx]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#undef ALF_DIR_HORZ
|
||||
#undef ALF_DIR_VERT
|
||||
#undef ALF_DIR_DIGA0
|
||||
#undef ALF_DIR_DIGA1
|
||||
|
||||
// line zero
|
||||
#define P7 pix[-8 * xstride]
|
||||
#define P6 pix[-7 * xstride]
|
||||
#define P5 pix[-6 * xstride]
|
||||
#define P4 pix[-5 * xstride]
|
||||
#define P3 pix[-4 * xstride]
|
||||
#define P2 pix[-3 * xstride]
|
||||
#define P1 pix[-2 * xstride]
|
||||
#define P0 pix[-1 * xstride]
|
||||
#define Q0 pix[0 * xstride]
|
||||
#define Q1 pix[1 * xstride]
|
||||
#define Q2 pix[2 * xstride]
|
||||
#define Q3 pix[3 * xstride]
|
||||
#define Q4 pix[4 * xstride]
|
||||
#define Q5 pix[5 * xstride]
|
||||
#define Q6 pix[6 * xstride]
|
||||
#define Q7 pix[7 * xstride]
|
||||
#define P(x) pix[(-(x)-1) * xstride]
|
||||
#define Q(x) pix[(x) * xstride]
|
||||
|
||||
// line three. used only for deblocking decision
|
||||
#define TP7 pix[-8 * xstride + 3 * ystride]
|
||||
#define TP6 pix[-7 * xstride + 3 * ystride]
|
||||
#define TP5 pix[-6 * xstride + 3 * ystride]
|
||||
#define TP4 pix[-5 * xstride + 3 * ystride]
|
||||
#define TP3 pix[-4 * xstride + 3 * ystride]
|
||||
#define TP2 pix[-3 * xstride + 3 * ystride]
|
||||
#define TP1 pix[-2 * xstride + 3 * ystride]
|
||||
#define TP0 pix[-1 * xstride + 3 * ystride]
|
||||
#define TQ0 pix[0 * xstride + 3 * ystride]
|
||||
#define TQ1 pix[1 * xstride + 3 * ystride]
|
||||
#define TQ2 pix[2 * xstride + 3 * ystride]
|
||||
#define TQ3 pix[3 * xstride + 3 * ystride]
|
||||
#define TQ4 pix[4 * xstride + 3 * ystride]
|
||||
#define TQ5 pix[5 * xstride + 3 * ystride]
|
||||
#define TQ6 pix[6 * xstride + 3 * ystride]
|
||||
#define TQ7 pix[7 * xstride + 3 * ystride]
|
||||
#define TP(x) pix[(-(x)-1) * xstride + 3 * ystride]
|
||||
#define TQ(x) pix[(x) * xstride + 3 * ystride]
|
||||
|
||||
#define FP3 pix[-4 * xstride + 1 * ystride]
|
||||
#define FP2 pix[-3 * xstride + 1 * ystride]
|
||||
#define FP1 pix[-2 * xstride + 1 * ystride]
|
||||
#define FP0 pix[-1 * xstride + 1 * ystride]
|
||||
#define FQ0 pix[0 * xstride + 1 * ystride]
|
||||
#define FQ1 pix[1 * xstride + 1 * ystride]
|
||||
#define FQ2 pix[2 * xstride + 1 * ystride]
|
||||
#define FQ3 pix[3 * xstride + 1 * ystride]
|
||||
|
||||
#include "libavcodec/h26x/h2656_deblock_template.c"
|
||||
|
||||
static void FUNC(loop_filter_luma_large)(pixel *pix, const ptrdiff_t xstride, const ptrdiff_t ystride, const int32_t tc,
|
||||
const uint8_t no_p, const uint8_t no_q, const uint8_t max_len_p, const uint8_t max_len_q)
|
||||
{
|
||||
for (int d = 0; d < 4; d++) {
|
||||
const int p6 = P6;
|
||||
const int p5 = P5;
|
||||
const int p4 = P4;
|
||||
const int p3 = P3;
|
||||
const int p2 = P2;
|
||||
const int p1 = P1;
|
||||
const int p0 = P0;
|
||||
const int q0 = Q0;
|
||||
const int q1 = Q1;
|
||||
const int q2 = Q2;
|
||||
const int q3 = Q3;
|
||||
const int q4 = Q4;
|
||||
const int q5 = Q5;
|
||||
const int q6 = Q6;
|
||||
int m;
|
||||
if (max_len_p == 5 && max_len_q == 5)
|
||||
m = (p4 + p3 + 2 * (p2 + p1 + p0 + q0 + q1 + q2) + q3 + q4 + 8) >> 4;
|
||||
else if (max_len_p == max_len_q)
|
||||
m = (p6 + p5 + p4 + p3 + p2 + p1 + 2 * (p0 + q0) + q1 + q2 + q3 + q4 + q5 + q6 + 8) >> 4;
|
||||
else if (max_len_p + max_len_q == 12)
|
||||
m = (p5 + p4 + p3 + p2 + 2 * (p1 + p0 + q0 + q1) + q2 + q3 + q4 + q5 + 8) >> 4;
|
||||
else if (max_len_p + max_len_q == 8)
|
||||
m = (p3 + p2 + p1 + p0 + q0 + q1 + q2 + q3 + 4) >> 3;
|
||||
else if (max_len_q == 7)
|
||||
m = (2 * (p2 + p1 + p0 + q0) + p0 + p1 + q1 + q2 + q3 + q4 + q5 + q6 + 8) >> 4;
|
||||
else
|
||||
m = (p6 + p5 + p4 + p3 + p2 + p1 + 2 * (q2 + q1 + q0 + p0) + q0 + q1 + 8) >> 4;
|
||||
if (!no_p) {
|
||||
const int refp = (P(max_len_p) + P(max_len_p - 1) + 1) >> 1;
|
||||
if (max_len_p == 3) {
|
||||
P0 = p0 + av_clip(((m * 53 + refp * 11 + 32) >> 6) - p0, -(tc * 6 >> 1), (tc * 6 >> 1));
|
||||
P1 = p1 + av_clip(((m * 32 + refp * 32 + 32) >> 6) - p1, -(tc * 4 >> 1), (tc * 4 >> 1));
|
||||
P2 = p2 + av_clip(((m * 11 + refp * 53 + 32) >> 6) - p2, -(tc * 2 >> 1), (tc * 2 >> 1));
|
||||
} else if (max_len_p == 5) {
|
||||
P0 = p0 + av_clip(((m * 58 + refp * 6 + 32) >> 6) - p0, -(tc * 6 >> 1), (tc * 6 >> 1));
|
||||
P1 = p1 + av_clip(((m * 45 + refp * 19 + 32) >> 6) - p1, -(tc * 5 >> 1), (tc * 5 >> 1));
|
||||
P2 = p2 + av_clip(((m * 32 + refp * 32 + 32) >> 6) - p2, -(tc * 4 >> 1), (tc * 4 >> 1));
|
||||
P3 = p3 + av_clip(((m * 19 + refp * 45 + 32) >> 6) - p3, -(tc * 3 >> 1), (tc * 3 >> 1));
|
||||
P4 = p4 + av_clip(((m * 6 + refp * 58 + 32) >> 6) - p4, -(tc * 2 >> 1), (tc * 2 >> 1));
|
||||
} else {
|
||||
P0 = p0 + av_clip(((m * 59 + refp * 5 + 32) >> 6) - p0, -(tc * 6 >> 1), (tc * 6 >> 1));
|
||||
P1 = p1 + av_clip(((m * 50 + refp * 14 + 32) >> 6) - p1, -(tc * 5 >> 1), (tc * 5 >> 1));
|
||||
P2 = p2 + av_clip(((m * 41 + refp * 23 + 32) >> 6) - p2, -(tc * 4 >> 1), (tc * 4 >> 1));
|
||||
P3 = p3 + av_clip(((m * 32 + refp * 32 + 32) >> 6) - p3, -(tc * 3 >> 1), (tc * 3 >> 1));
|
||||
P4 = p4 + av_clip(((m * 23 + refp * 41 + 32) >> 6) - p4, -(tc * 2 >> 1), (tc * 2 >> 1));
|
||||
P5 = p5 + av_clip(((m * 14 + refp * 50 + 32) >> 6) - p5, -(tc * 1 >> 1), (tc * 1 >> 1));
|
||||
P6 = p6 + av_clip(((m * 5 + refp * 59 + 32) >> 6) - p6, -(tc * 1 >> 1), (tc * 1 >> 1));
|
||||
}
|
||||
}
|
||||
if (!no_q) {
|
||||
const int refq = (Q(max_len_q) + Q(max_len_q - 1) + 1) >> 1;
|
||||
if (max_len_q == 3) {
|
||||
Q0 = q0 + av_clip(((m * 53 + refq * 11 + 32) >> 6) - q0, -(tc * 6 >> 1), (tc * 6 >> 1));
|
||||
Q1 = q1 + av_clip(((m * 32 + refq * 32 + 32) >> 6) - q1, -(tc * 4 >> 1), (tc * 4 >> 1));
|
||||
Q2 = q2 + av_clip(((m * 11 + refq * 53 + 32) >> 6) - q2, -(tc * 2 >> 1), (tc * 2 >> 1));
|
||||
} else if (max_len_q == 5) {
|
||||
Q0 = q0 + av_clip(((m * 58 + refq * 6 + 32) >> 6) - q0, -(tc * 6 >> 1), (tc * 6 >> 1));
|
||||
Q1 = q1 + av_clip(((m * 45 + refq * 19 + 32) >> 6) - q1, -(tc * 5 >> 1), (tc * 5 >> 1));
|
||||
Q2 = q2 + av_clip(((m * 32 + refq * 32 + 32) >> 6) - q2, -(tc * 4 >> 1), (tc * 4 >> 1));
|
||||
Q3 = q3 + av_clip(((m * 19 + refq * 45 + 32) >> 6) - q3, -(tc * 3 >> 1), (tc * 3 >> 1));
|
||||
Q4 = q4 + av_clip(((m * 6 + refq * 58 + 32) >> 6) - q4, -(tc * 2 >> 1), (tc * 2 >> 1));
|
||||
} else {
|
||||
Q0 = q0 + av_clip(((m * 59 + refq * 5 + 32) >> 6) - q0, -(tc * 6 >> 1), (tc * 6 >> 1));
|
||||
Q1 = q1 + av_clip(((m * 50 + refq * 14 + 32) >> 6) - q1, -(tc * 5 >> 1), (tc * 5 >> 1));
|
||||
Q2 = q2 + av_clip(((m * 41 + refq * 23 + 32) >> 6) - q2, -(tc * 4 >> 1), (tc * 4 >> 1));
|
||||
Q3 = q3 + av_clip(((m * 32 + refq * 32 + 32) >> 6) - q3, -(tc * 3 >> 1), (tc * 3 >> 1));
|
||||
Q4 = q4 + av_clip(((m * 23 + refq * 41 + 32) >> 6) - q4, -(tc * 2 >> 1), (tc * 2 >> 1));
|
||||
Q5 = q5 + av_clip(((m * 14 + refq * 50 + 32) >> 6) - q5, -(tc * 1 >> 1), (tc * 1 >> 1));
|
||||
Q6 = q6 + av_clip(((m * 5 + refq * 59 + 32) >> 6) - q6, -(tc * 1 >> 1), (tc * 1 >> 1));
|
||||
}
|
||||
|
||||
}
|
||||
pix += ystride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(vvc_loop_filter_luma)(uint8_t* _pix, ptrdiff_t _xstride, ptrdiff_t _ystride,
|
||||
const int32_t *_beta, const int32_t *_tc, const uint8_t *_no_p, const uint8_t *_no_q,
|
||||
const uint8_t *_max_len_p, const uint8_t *_max_len_q, const int hor_ctu_edge)
|
||||
{
|
||||
const ptrdiff_t xstride = _xstride / sizeof(pixel);
|
||||
const ptrdiff_t ystride = _ystride / sizeof(pixel);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
#if BIT_DEPTH < 10
|
||||
const int tc = (_tc[i] + (1 << (9 - BIT_DEPTH))) >> (10 - BIT_DEPTH);
|
||||
#else
|
||||
const int tc = _tc[i] << (BIT_DEPTH - 10);
|
||||
#endif
|
||||
if (tc) {
|
||||
pixel* pix = (pixel*)_pix + i * 4 * ystride;
|
||||
const int dp0 = abs(P2 - 2 * P1 + P0);
|
||||
const int dq0 = abs(Q2 - 2 * Q1 + Q0);
|
||||
const int dp3 = abs(TP2 - 2 * TP1 + TP0);
|
||||
const int dq3 = abs(TQ2 - 2 * TQ1 + TQ0);
|
||||
const int d0 = dp0 + dq0;
|
||||
const int d3 = dp3 + dq3;
|
||||
const int tc25 = ((tc * 5 + 1) >> 1);
|
||||
|
||||
const int no_p = _no_p[i];
|
||||
const int no_q = _no_q[i];
|
||||
|
||||
int max_len_p = _max_len_p[i];
|
||||
int max_len_q = _max_len_q[i];
|
||||
|
||||
const int large_p = (max_len_p > 3 && !hor_ctu_edge);
|
||||
const int large_q = max_len_q > 3;
|
||||
|
||||
const int beta = _beta[i] << BIT_DEPTH - 8;
|
||||
const int beta_3 = beta >> 3;
|
||||
const int beta_2 = beta >> 2;
|
||||
|
||||
if (large_p || large_q) {
|
||||
const int dp0l = large_p ? ((dp0 + abs(P5 - 2 * P4 + P3) + 1) >> 1) : dp0;
|
||||
const int dq0l = large_q ? ((dq0 + abs(Q5 - 2 * Q4 + Q3) + 1) >> 1) : dq0;
|
||||
const int dp3l = large_p ? ((dp3 + abs(TP5 - 2 * TP4 + TP3) + 1) >> 1) : dp3;
|
||||
const int dq3l = large_q ? ((dq3 + abs(TQ5 - 2 * TQ4 + TQ3) + 1) >> 1) : dq3;
|
||||
const int d0l = dp0l + dq0l;
|
||||
const int d3l = dp3l + dq3l;
|
||||
const int beta53 = beta * 3 >> 5;
|
||||
const int beta_4 = beta >> 4;
|
||||
max_len_p = large_p ? max_len_p : 3;
|
||||
max_len_q = large_q ? max_len_q : 3;
|
||||
|
||||
if (d0l + d3l < beta) {
|
||||
const int sp0l = abs(P3 - P0) + (max_len_p == 7 ? abs(P7 - P6 - P5 + P4) : 0);
|
||||
const int sq0l = abs(Q0 - Q3) + (max_len_q == 7 ? abs(Q4 - Q5 - Q6 + Q7) : 0);
|
||||
const int sp3l = abs(TP3 - TP0) + (max_len_p == 7 ? abs(TP7 - TP6 - TP5 + TP4) : 0);
|
||||
const int sq3l = abs(TQ0 - TQ3) + (max_len_q == 7 ? abs(TQ4 - TQ5 - TQ6 + TQ7) : 0);
|
||||
const int sp0 = large_p ? ((sp0l + abs(P3 - P(max_len_p)) + 1) >> 1) : sp0l;
|
||||
const int sp3 = large_p ? ((sp3l + abs(TP3 - TP(max_len_p)) + 1) >> 1) : sp3l;
|
||||
const int sq0 = large_q ? ((sq0l + abs(Q3 - Q(max_len_q)) + 1) >> 1) : sq0l;
|
||||
const int sq3 = large_q ? ((sq3l + abs(TQ3 - TQ(max_len_q)) + 1) >> 1) : sq3l;
|
||||
if (sp0 + sq0 < beta53 && abs(P0 - Q0) < tc25 &&
|
||||
sp3 + sq3 < beta53 && abs(TP0 - TQ0) < tc25 &&
|
||||
(d0l << 1) < beta_4 && (d3l << 1) < beta_4) {
|
||||
FUNC(loop_filter_luma_large)(pix, xstride, ystride, tc, no_p, no_q, max_len_p, max_len_q);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d0 + d3 < beta) {
|
||||
if (max_len_p > 2 && max_len_q > 2 &&
|
||||
abs(P3 - P0) + abs(Q3 - Q0) < beta_3 && abs(P0 - Q0) < tc25 &&
|
||||
abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 &&
|
||||
(d0 << 1) < beta_2 && (d3 << 1) < beta_2) {
|
||||
FUNC(loop_filter_luma_strong)(pix, xstride, ystride, tc, tc << 1, tc * 3, no_p, no_q);
|
||||
} else {
|
||||
int nd_p = 1;
|
||||
int nd_q = 1;
|
||||
if (max_len_p > 1 && max_len_q > 1) {
|
||||
if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3))
|
||||
nd_p = 2;
|
||||
if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3))
|
||||
nd_q = 2;
|
||||
}
|
||||
FUNC(loop_filter_luma_weak)(pix, xstride, ystride, tc, beta, no_p, no_q, nd_p, nd_q);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(loop_filter_chroma_strong)(pixel *pix, const ptrdiff_t xstride, const ptrdiff_t ystride,
|
||||
const int size, const int32_t tc, const uint8_t no_p, const uint8_t no_q)
|
||||
{
|
||||
for (int d = 0; d < size; d++) {
|
||||
const int p3 = P3;
|
||||
const int p2 = P2;
|
||||
const int p1 = P1;
|
||||
const int p0 = P0;
|
||||
const int q0 = Q0;
|
||||
const int q1 = Q1;
|
||||
const int q2 = Q2;
|
||||
const int q3 = Q3;
|
||||
if (!no_p) {
|
||||
P0 = av_clip((p3 + p2 + p1 + 2 * p0 + q0 + q1 + q2 + 4) >> 3, p0 - tc, p0 + tc);
|
||||
P1 = av_clip((2 * p3 + p2 + 2 * p1 + p0 + q0 + q1 + 4) >> 3, p1 - tc, p1 + tc);
|
||||
P2 = av_clip((3 * p3 + 2 * p2 + p1 + p0 + q0 + 4) >> 3, p2 - tc, p2 + tc );
|
||||
}
|
||||
if (!no_q) {
|
||||
Q0 = av_clip((p2 + p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4) >> 3, q0 - tc, q0 + tc);
|
||||
Q1 = av_clip((p1 + p0 + q0 + 2 * q1 + q2 + 2 * q3 + 4) >> 3, q1 - tc, q1 + tc);
|
||||
Q2 = av_clip((p0 + q0 + q1 + 2 * q2 + 3 * q3 + 4) >> 3, q2 - tc, q2 + tc);
|
||||
}
|
||||
pix += ystride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(loop_filter_chroma_strong_one_side)(pixel *pix, const ptrdiff_t xstride, const ptrdiff_t ystride,
|
||||
const int size, const int32_t tc, const uint8_t no_p, const uint8_t no_q)
|
||||
{
|
||||
for (int d = 0; d < size; d++) {
|
||||
const int p1 = P1;
|
||||
const int p0 = P0;
|
||||
const int q0 = Q0;
|
||||
const int q1 = Q1;
|
||||
const int q2 = Q2;
|
||||
const int q3 = Q3;
|
||||
if (!no_p) {
|
||||
P0 = av_clip((3 * p1 + 2 * p0 + q0 + q1 + q2 + 4) >> 3, p0 - tc, p0 + tc);
|
||||
}
|
||||
if (!no_q) {
|
||||
Q0 = av_clip((2 * p1 + p0 + 2 * q0 + q1 + q2 + q3 + 4) >> 3, q0 - tc, q0 + tc);
|
||||
Q1 = av_clip((p1 + p0 + q0 + 2 * q1 + q2 + 2 * q3 + 4) >> 3, q1 - tc, q1 + tc);
|
||||
Q2 = av_clip((p0 + q0 + q1 + 2 * q2 + 3 * q3 + 4) >> 3, q2 - tc, q2 + tc);
|
||||
}
|
||||
pix += ystride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(vvc_loop_filter_chroma)(uint8_t *_pix, const ptrdiff_t _xstride, const ptrdiff_t _ystride,
|
||||
const int32_t *_beta, const int32_t *_tc, const uint8_t *_no_p, const uint8_t *_no_q,
|
||||
const uint8_t *_max_len_p, const uint8_t *_max_len_q, const int shift)
|
||||
{
|
||||
const ptrdiff_t xstride = _xstride / sizeof(pixel);
|
||||
const ptrdiff_t ystride = _ystride / sizeof(pixel);
|
||||
const int size = shift ? 2 : 4;
|
||||
const int end = 8 / size; // 8 samples a loop
|
||||
|
||||
for (int i = 0; i < end; i++) {
|
||||
#if BIT_DEPTH < 10
|
||||
const int tc = (_tc[i] + (1 << (9 - BIT_DEPTH))) >> (10 - BIT_DEPTH);
|
||||
#else
|
||||
const int tc = _tc[i] << (BIT_DEPTH - 10);
|
||||
#endif
|
||||
if (tc) {
|
||||
pixel *pix = (pixel *)_pix + i * size * ystride;
|
||||
const uint8_t no_p = _no_p[i];
|
||||
const uint8_t no_q = _no_q[i];
|
||||
|
||||
const int beta = _beta[i] << (BIT_DEPTH - 8);
|
||||
const int beta_3 = beta >> 3;
|
||||
const int beta_2 = beta >> 2;
|
||||
|
||||
const int tc25 = ((tc * 5 + 1) >> 1);
|
||||
|
||||
uint8_t max_len_p = _max_len_p[i];
|
||||
uint8_t max_len_q = _max_len_q[i];
|
||||
|
||||
if (!max_len_p || !max_len_q)
|
||||
continue;
|
||||
|
||||
if (max_len_q == 3){
|
||||
const int p1n = shift ? FP1 : TP1;
|
||||
const int p2n = max_len_p == 1 ? p1n : (shift ? FP2 : TP2);
|
||||
const int p0n = shift ? FP0 : TP0;
|
||||
const int q0n = shift ? FQ0 : TQ0;
|
||||
const int q1n = shift ? FQ1 : TQ1;
|
||||
const int q2n = shift ? FQ2 : TQ2;
|
||||
const int p3 = max_len_p == 1 ? P1 : P3;
|
||||
const int p2 = max_len_p == 1 ? P1 : P2;
|
||||
const int p1 = P1;
|
||||
const int p0 = P0;
|
||||
const int dp0 = abs(p2 - 2 * p1 + p0);
|
||||
const int dq0 = abs(Q2 - 2 * Q1 + Q0);
|
||||
|
||||
const int dp1 = abs(p2n - 2 * p1n + p0n);
|
||||
const int dq1 = abs(q2n - 2 * q1n + q0n);
|
||||
const int d0 = dp0 + dq0;
|
||||
const int d1 = dp1 + dq1;
|
||||
|
||||
if (d0 + d1 < beta) {
|
||||
const int p3n = max_len_p == 1 ? p1n : (shift ? FP3 : TP3);
|
||||
const int q3n = shift ? FQ3 : TQ3;
|
||||
const int dsam0 = (d0 << 1) < beta_2 && (abs(p3 - p0) + abs(Q0 - Q3) < beta_3) &&
|
||||
abs(p0 - Q0) < tc25;
|
||||
const int dsam1 = (d1 << 1) < beta_2 && (abs(p3n - p0n) + abs(q0n - q3n) < beta_3) &&
|
||||
abs(p0n - q0n) < tc25;
|
||||
if (!dsam0 || !dsam1)
|
||||
max_len_p = max_len_q = 1;
|
||||
} else {
|
||||
max_len_p = max_len_q = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_len_p == 3 && max_len_q == 3)
|
||||
FUNC(loop_filter_chroma_strong)(pix, xstride, ystride, size, tc, no_p, no_q);
|
||||
else if (max_len_q == 3)
|
||||
FUNC(loop_filter_chroma_strong_one_side)(pix, xstride, ystride, size, tc, no_p, no_q);
|
||||
else
|
||||
FUNC(loop_filter_chroma_weak)(pix, xstride, ystride, size, tc, no_p, no_q);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(vvc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
|
||||
const int32_t *beta, const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q,
|
||||
const uint8_t *max_len_p, const uint8_t *max_len_q, int shift)
|
||||
{
|
||||
FUNC(vvc_loop_filter_chroma)(pix, stride, sizeof(pixel), beta, tc,
|
||||
no_p, no_q, max_len_p, max_len_q, shift);
|
||||
}
|
||||
|
||||
static void FUNC(vvc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,
|
||||
const int32_t *beta, const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q,
|
||||
const uint8_t *max_len_p, const uint8_t *max_len_q, int shift)
|
||||
{
|
||||
FUNC(vvc_loop_filter_chroma)(pix, sizeof(pixel), stride, beta, tc,
|
||||
no_p, no_q, max_len_p, max_len_q, shift);
|
||||
}
|
||||
|
||||
static void FUNC(vvc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
|
||||
const int32_t *beta, const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q,
|
||||
const uint8_t *max_len_p, const uint8_t *max_len_q, const int hor_ctu_edge)
|
||||
{
|
||||
FUNC(vvc_loop_filter_luma)(pix, stride, sizeof(pixel), beta, tc,
|
||||
no_p, no_q, max_len_p, max_len_q, hor_ctu_edge);
|
||||
}
|
||||
|
||||
static void FUNC(vvc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,
|
||||
const int32_t *beta, const int32_t *tc, const uint8_t *no_p, const uint8_t *no_q,
|
||||
const uint8_t *max_len_p, const uint8_t *max_len_q, const int hor_ctu_edge)
|
||||
{
|
||||
FUNC(vvc_loop_filter_luma)(pix, sizeof(pixel), stride, beta, tc,
|
||||
no_p, no_q, max_len_p, max_len_q, hor_ctu_edge);
|
||||
}
|
||||
|
||||
static int FUNC(vvc_loop_ladf_level)(const uint8_t *_pix, const ptrdiff_t _xstride, const ptrdiff_t _ystride)
|
||||
{
|
||||
const pixel *pix = (pixel *)_pix;
|
||||
const ptrdiff_t xstride = _xstride / sizeof(pixel);
|
||||
const ptrdiff_t ystride = _ystride / sizeof(pixel);
|
||||
return (P0 + TP0 + Q0 + TQ0) >> 2;
|
||||
}
|
||||
|
||||
static int FUNC(vvc_h_loop_ladf_level)(const uint8_t *pix, ptrdiff_t stride)
|
||||
{
|
||||
return FUNC(vvc_loop_ladf_level)(pix, stride, sizeof(pixel));
|
||||
}
|
||||
|
||||
static int FUNC(vvc_v_loop_ladf_level)(const uint8_t *pix, ptrdiff_t stride)
|
||||
{
|
||||
return FUNC(vvc_loop_ladf_level)(pix, sizeof(pixel), stride);
|
||||
}
|
||||
|
||||
#undef P7
|
||||
#undef P6
|
||||
#undef P5
|
||||
#undef P4
|
||||
#undef P3
|
||||
#undef P2
|
||||
#undef P1
|
||||
#undef P0
|
||||
#undef Q0
|
||||
#undef Q1
|
||||
#undef Q2
|
||||
#undef Q3
|
||||
#undef Q4
|
||||
#undef Q5
|
||||
#undef Q6
|
||||
#undef Q7
|
||||
|
||||
#undef TP7
|
||||
#undef TP6
|
||||
#undef TP5
|
||||
#undef TP4
|
||||
#undef TP3
|
||||
#undef TP2
|
||||
#undef TP1
|
||||
#undef TP0
|
||||
#undef TQ0
|
||||
#undef TQ1
|
||||
#undef TQ2
|
||||
#undef TQ3
|
||||
#undef TQ4
|
||||
#undef TQ5
|
||||
#undef TQ6
|
||||
#undef TQ7
|
||||
|
||||
static void FUNC(ff_vvc_lmcs_dsp_init)(VVCLMCSDSPContext *const lmcs)
|
||||
{
|
||||
lmcs->filter = FUNC(lmcs_filter_luma);
|
||||
}
|
||||
|
||||
static void FUNC(ff_vvc_lf_dsp_init)(VVCLFDSPContext *const lf)
|
||||
{
|
||||
lf->ladf_level[0] = FUNC(vvc_h_loop_ladf_level);
|
||||
lf->ladf_level[1] = FUNC(vvc_v_loop_ladf_level);
|
||||
lf->filter_luma[0] = FUNC(vvc_h_loop_filter_luma);
|
||||
lf->filter_luma[1] = FUNC(vvc_v_loop_filter_luma);
|
||||
lf->filter_chroma[0] = FUNC(vvc_h_loop_filter_chroma);
|
||||
lf->filter_chroma[1] = FUNC(vvc_v_loop_filter_chroma);
|
||||
}
|
||||
|
||||
static void FUNC(ff_vvc_sao_dsp_init)(VVCSAODSPContext *const sao)
|
||||
{
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(sao->band_filter); i++)
|
||||
sao->band_filter[i] = FUNC(sao_band_filter);
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(sao->edge_filter); i++)
|
||||
sao->edge_filter[i] = FUNC(sao_edge_filter);
|
||||
sao->edge_restore[0] = FUNC(sao_edge_restore_0);
|
||||
sao->edge_restore[1] = FUNC(sao_edge_restore_1);
|
||||
}
|
||||
|
||||
static void FUNC(ff_vvc_alf_dsp_init)(VVCALFDSPContext *const alf)
|
||||
{
|
||||
alf->filter[LUMA] = FUNC(alf_filter_luma);
|
||||
alf->filter[CHROMA] = FUNC(alf_filter_chroma);
|
||||
alf->filter_cc = FUNC(alf_filter_cc);
|
||||
alf->classify = FUNC(alf_classify);
|
||||
alf->recon_coeff_and_clip = FUNC(alf_recon_coeff_and_clip);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* VVC inter prediction
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_INTER_H
|
||||
#define AVCODEC_VVC_INTER_H
|
||||
|
||||
#include "ctu.h"
|
||||
|
||||
/**
|
||||
* Loop entire CTU to predict all inter coding blocks
|
||||
* @param lc local context for CTU
|
||||
* @param rs raster order for the CTU
|
||||
* @return AVERROR
|
||||
*/
|
||||
int ff_vvc_predict_inter(VVCLocalContext *lc, int rs);
|
||||
|
||||
/**
|
||||
* CIIP(Combined Inter-Intra Prediction) for a coding block
|
||||
* @param lc local context for CTU
|
||||
*/
|
||||
void ff_vvc_predict_ciip(VVCLocalContext *lc);
|
||||
|
||||
#endif // AVCODEC_VVC_INTER_H
|
||||
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* VVC inter prediction DSP
|
||||
*
|
||||
* Copyright (C) 2022 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "libavcodec/h26x/h2656_inter_template.c"
|
||||
#include "libavutil/imgutils.h"
|
||||
|
||||
#define TMP_STRIDE EDGE_EMU_BUFFER_STRIDE
|
||||
static void av_always_inline FUNC(put_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const uint8_t *const _src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int _x, const int _y, const int dx, const int dy,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width, const int is_uni, const int is_chroma)
|
||||
{
|
||||
int16_t tmp_array[TMP_STRIDE * MAX_PB_SIZE];
|
||||
int16_t *tmp = tmp_array;
|
||||
pixel *dst = (pixel*)_dst;
|
||||
int16_t *dst16 = (int16_t*)_dst;
|
||||
const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
const int shift = FFMAX(2, 14 - BIT_DEPTH);
|
||||
const int offset = 1 << (shift - 1);
|
||||
const int taps = is_chroma ? VVC_INTER_CHROMA_TAPS : VVC_INTER_LUMA_TAPS;
|
||||
const int extra = is_chroma ? CHROMA_EXTRA : LUMA_EXTRA;
|
||||
const int extra_before = is_chroma ? CHROMA_EXTRA_BEFORE : LUMA_EXTRA_BEFORE;
|
||||
const int shift1 = 6 - is_chroma;
|
||||
const int shift2 = 4 + is_chroma;
|
||||
const int x0 = SCALED_INT(_x);
|
||||
const int y0 = SCALED_INT(_y);
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
const int tx = _x + dx * i;
|
||||
const int x = SCALED_INT(tx) - x0;
|
||||
const int mx = av_zero_extend(tx >> shift1, shift2);
|
||||
const int8_t *filter = hf + mx * taps;
|
||||
const pixel *src = (pixel*)_src - extra_before * src_stride;
|
||||
|
||||
for (int j = 0; j < src_height + extra; j++) {
|
||||
tmp[j] = (is_chroma ? CHROMA_FILTER(src, 1) : LUMA_FILTER(src, 1)) >> (BIT_DEPTH - 8);
|
||||
src += src_stride;
|
||||
}
|
||||
tmp += TMP_STRIDE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
const int ty = _y + dy * i;
|
||||
const int x = SCALED_INT(ty) - y0;
|
||||
const int mx = av_zero_extend(ty >> shift1, shift2);
|
||||
const int8_t *filter = vf + mx * taps;
|
||||
|
||||
tmp = tmp_array + extra_before;
|
||||
for (int j = 0; j < width; j++) {
|
||||
const int val = (is_chroma ? CHROMA_FILTER(tmp, 1) : LUMA_FILTER(tmp, 1)) >> 6;
|
||||
if (is_uni)
|
||||
dst[j] = av_clip_pixel((val + offset) >> shift);
|
||||
else
|
||||
dst16[j] = val;
|
||||
tmp += TMP_STRIDE;
|
||||
}
|
||||
if (is_uni)
|
||||
dst += dst_stride;
|
||||
else
|
||||
dst16 += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(put_luma_scaled)(int16_t *_dst,
|
||||
const uint8_t *_src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int x, const int y, const int dx, const int dy,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width)
|
||||
{
|
||||
FUNC(put_scaled)((uint8_t *)_dst, MAX_PB_SIZE * sizeof(pixel), _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 0, 0);
|
||||
}
|
||||
|
||||
static void FUNC(put_chroma_scaled)(int16_t *_dst,
|
||||
const uint8_t *_src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int x, const int y, const int dx, const int dy,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width)
|
||||
{
|
||||
FUNC(put_scaled)((uint8_t *)_dst, MAX_PB_SIZE * sizeof(pixel), _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 0, 1);
|
||||
}
|
||||
|
||||
static void FUNC(put_uni_luma_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const uint8_t *_src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int x, const int y, const int dx, const int dy,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width)
|
||||
{
|
||||
FUNC(put_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 1, 0);
|
||||
}
|
||||
|
||||
static void FUNC(put_uni_chroma_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const uint8_t *_src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int x, const int y, const int dx, const int dy,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width)
|
||||
{
|
||||
FUNC(put_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, height, hf, vf, width, 1, 1);
|
||||
}
|
||||
|
||||
static void av_always_inline FUNC(put_uni_w_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const uint8_t *const _src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int _x, const int _y, const int dx, const int dy, const int denom, const int wx, const int _ox,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width, const int is_chroma)
|
||||
{
|
||||
int16_t tmp_array[TMP_STRIDE * MAX_PB_SIZE];
|
||||
int16_t *tmp = tmp_array;
|
||||
pixel *dst = (pixel*)_dst;
|
||||
const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
const int shift = FFMAX(2, 14 - BIT_DEPTH);
|
||||
const int offset = 1 << (shift - 1);
|
||||
const int ox = _ox * (1 << (BIT_DEPTH - 8));
|
||||
const int taps = is_chroma ? VVC_INTER_CHROMA_TAPS : VVC_INTER_LUMA_TAPS;
|
||||
const int extra = is_chroma ? CHROMA_EXTRA : LUMA_EXTRA;
|
||||
const int extra_before = is_chroma ? CHROMA_EXTRA_BEFORE : LUMA_EXTRA_BEFORE;
|
||||
const int shift1 = 6 - is_chroma;
|
||||
const int shift2 = 4 + is_chroma;
|
||||
const int x0 = SCALED_INT(_x);
|
||||
const int y0 = SCALED_INT(_y);
|
||||
|
||||
for (int i = 0; i < width; i++) {
|
||||
const int tx = _x + dx * i;
|
||||
const int x = SCALED_INT(tx) - x0;
|
||||
const int mx = av_zero_extend(tx >> shift1, shift2);
|
||||
const int8_t *filter = hf + mx * taps;
|
||||
const pixel *src = (pixel*)_src - extra_before * src_stride;
|
||||
|
||||
for (int j = 0; j < src_height + extra; j++) {
|
||||
tmp[j] = (is_chroma ? CHROMA_FILTER(src, 1) : LUMA_FILTER(src, 1)) >> (BIT_DEPTH - 8);
|
||||
src += src_stride;
|
||||
}
|
||||
tmp += TMP_STRIDE;
|
||||
}
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
const int ty = _y + dy * i;
|
||||
const int x = SCALED_INT(ty) - y0;
|
||||
const int mx = av_zero_extend(ty >> shift1, shift2);
|
||||
const int8_t *filter = vf + mx * taps;
|
||||
|
||||
tmp = tmp_array + extra_before;
|
||||
for (int j = 0; j < width; j++) {
|
||||
const int val = (is_chroma ? CHROMA_FILTER(tmp, 1) : LUMA_FILTER(tmp, 1)) >> 6;
|
||||
dst[j] = av_clip_pixel(((wx * val + offset) >> shift) + ox);
|
||||
tmp += TMP_STRIDE;
|
||||
}
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(put_uni_luma_w_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const uint8_t *_src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int x, const int y, const int dx, const int dy, const int denom, const int wx, const int ox,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width)
|
||||
{
|
||||
FUNC(put_uni_w_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, denom, wx, ox, height, hf, vf, width, 0);
|
||||
}
|
||||
|
||||
static void FUNC(put_uni_chroma_w_scaled)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const uint8_t *_src, ptrdiff_t _src_stride, const int src_height,
|
||||
const int x, const int y, const int dx, const int dy, const int denom, const int wx, const int ox,
|
||||
const int height, const int8_t *hf, const int8_t *vf, const int width)
|
||||
{
|
||||
FUNC(put_uni_w_scaled)(_dst, _dst_stride, _src, _src_stride, src_height, x, y, dx, dy, denom, wx, ox, height, hf, vf, width, 1);
|
||||
}
|
||||
|
||||
#undef TMP_STRIDE
|
||||
|
||||
static void FUNC(avg)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const int16_t *src0, const int16_t *src1, const int width, const int height)
|
||||
{
|
||||
pixel *dst = (pixel*)_dst;
|
||||
const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
const int shift = FFMAX(3, 15 - BIT_DEPTH);
|
||||
const int offset = 1 << (shift - 1);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
dst[x] = av_clip_pixel((src0[x] + src1[x] + offset) >> shift);
|
||||
src0 += MAX_PB_SIZE;
|
||||
src1 += MAX_PB_SIZE;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(w_avg)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const int16_t *src0, const int16_t *src1, const int width, const int height,
|
||||
const int denom, const int w0, const int w1, const int o0, const int o1)
|
||||
{
|
||||
pixel *dst = (pixel*)_dst;
|
||||
const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
const int shift = denom + FFMAX(3, 15 - BIT_DEPTH);
|
||||
const int offset = ((o0 + o1) * (1 << (BIT_DEPTH - 8)) + 1) * (1 << (shift - 1));
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
dst[x] = av_clip_pixel((src0[x] * w0 + src1[x] * w1 + offset) >> shift);
|
||||
src0 += MAX_PB_SIZE;
|
||||
src1 += MAX_PB_SIZE;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(put_ciip)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const int width, const int height,
|
||||
const uint8_t *_inter, const ptrdiff_t _inter_stride, const int intra_weight)
|
||||
{
|
||||
pixel *dst = (pixel *)_dst;
|
||||
pixel *inter = (pixel *)_inter;
|
||||
const size_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
const size_t inter_stride = _inter_stride / sizeof(pixel);
|
||||
const int inter_weight = 4 - intra_weight;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
dst[x] = (dst[x] * intra_weight + inter[x] * inter_weight + 2) >> 2;
|
||||
dst += dst_stride;
|
||||
inter += inter_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(put_gpm)(uint8_t *_dst, ptrdiff_t dst_stride,
|
||||
const int width, const int height,
|
||||
const int16_t *src0, const int16_t *src1,
|
||||
const uint8_t *weights, const int step_x, const int step_y)
|
||||
{
|
||||
const int shift = FFMAX(5, 17 - BIT_DEPTH);
|
||||
const int offset = 1 << (shift - 1);
|
||||
pixel *dst = (pixel *)_dst;
|
||||
|
||||
dst_stride /= sizeof(pixel);
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
const uint8_t w = weights[x * step_x];
|
||||
dst[x] = av_clip_pixel((src0[x] * w + src1[x] * (8 - w) + offset) >> shift);
|
||||
}
|
||||
dst += dst_stride;
|
||||
src0 += MAX_PB_SIZE;
|
||||
src1 += MAX_PB_SIZE;
|
||||
weights += step_y;
|
||||
}
|
||||
}
|
||||
|
||||
//8.5.6.3.3 Luma integer sample fetching process, add one extra pad line
|
||||
static void FUNC(bdof_fetch_samples)(int16_t *_dst, const uint8_t *_src, const ptrdiff_t _src_stride,
|
||||
const int x_frac, const int y_frac, const int width, const int height)
|
||||
{
|
||||
const int x_off = (x_frac >> 3) - 1;
|
||||
const int y_off = (y_frac >> 3) - 1;
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
const pixel *src = (pixel*)_src + (x_off) + y_off * src_stride;
|
||||
int16_t *dst = _dst - 1 - MAX_PB_SIZE;
|
||||
const int shift = 14 - BIT_DEPTH;
|
||||
const int bdof_width = width + 2 * BDOF_BORDER_EXT;
|
||||
|
||||
// top
|
||||
for (int i = 0; i < bdof_width; i++)
|
||||
dst[i] = src[i] << shift;
|
||||
|
||||
dst += MAX_PB_SIZE;
|
||||
src += src_stride;
|
||||
|
||||
for (int i = 0; i < height; i++) {
|
||||
dst[0] = src[0] << shift;
|
||||
dst[1 + width] = src[1 + width] << shift;
|
||||
dst += MAX_PB_SIZE;
|
||||
src += src_stride;
|
||||
}
|
||||
for (int i = 0; i < bdof_width; i++)
|
||||
dst[i] = src[i] << shift;
|
||||
}
|
||||
|
||||
//8.5.6.3.3 Luma integer sample fetching process
|
||||
static void FUNC(fetch_samples)(int16_t *_dst, const uint8_t *_src, const ptrdiff_t _src_stride, const int x_frac, const int y_frac)
|
||||
{
|
||||
FUNC(bdof_fetch_samples)(_dst, _src, _src_stride, x_frac, y_frac, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE);
|
||||
}
|
||||
|
||||
static void FUNC(prof_grad_filter)(int16_t *gradient_h, int16_t *gradient_v, const ptrdiff_t gradient_stride,
|
||||
const int16_t *_src, const ptrdiff_t src_stride, const int width, const int height)
|
||||
{
|
||||
const int shift = 6;
|
||||
const int16_t *src = _src;
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
const int16_t *p = src;
|
||||
for (int x = 0; x < width; x++) {
|
||||
gradient_h[x] = (p[1] >> shift) - (p[-1] >> shift);
|
||||
gradient_v[x] = (p[src_stride] >> shift) - (p[-src_stride] >> shift);
|
||||
p++;
|
||||
}
|
||||
gradient_h += gradient_stride;
|
||||
gradient_v += gradient_stride;
|
||||
src += src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(apply_prof)(int16_t *dst, const int16_t *src, const int16_t *diff_mv_x, const int16_t *diff_mv_y)
|
||||
{
|
||||
const int limit = (1 << FFMAX(13, BIT_DEPTH + 1)); ///< dILimit
|
||||
|
||||
int16_t gradient_h[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE];
|
||||
int16_t gradient_v[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE];
|
||||
FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE);
|
||||
|
||||
for (int y = 0; y < AFFINE_MIN_BLOCK_SIZE; y++) {
|
||||
for (int x = 0; x < AFFINE_MIN_BLOCK_SIZE; x++) {
|
||||
const int o = y * AFFINE_MIN_BLOCK_SIZE + x;
|
||||
const int di = gradient_h[o] * diff_mv_x[o] + gradient_v[o] * diff_mv_y[o];
|
||||
const int val = src[x] + av_clip(di, -limit, limit - 1);
|
||||
dst[x] = val;
|
||||
|
||||
}
|
||||
src += MAX_PB_SIZE;
|
||||
dst += MAX_PB_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(apply_prof_uni)(uint8_t *_dst, const ptrdiff_t _dst_stride, const int16_t *src, const int16_t *diff_mv_x, const int16_t *diff_mv_y)
|
||||
{
|
||||
const int limit = (1 << FFMAX(13, BIT_DEPTH + 1)); ///< dILimit
|
||||
pixel *dst = (pixel*)_dst;
|
||||
const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
const int shift = 14 - BIT_DEPTH;
|
||||
#if BIT_DEPTH < 14
|
||||
const int offset = 1 << (shift - 1);
|
||||
#else
|
||||
const int offset = 0;
|
||||
#endif
|
||||
int16_t gradient_h[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE];
|
||||
int16_t gradient_v[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE];
|
||||
|
||||
FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE);
|
||||
|
||||
for (int y = 0; y < AFFINE_MIN_BLOCK_SIZE; y++) {
|
||||
for (int x = 0; x < AFFINE_MIN_BLOCK_SIZE; x++) {
|
||||
const int o = y * AFFINE_MIN_BLOCK_SIZE + x;
|
||||
const int di = gradient_h[o] * diff_mv_x[o] + gradient_v[o] * diff_mv_y[o];
|
||||
const int val = src[x] + av_clip(di, -limit, limit - 1);
|
||||
dst[x] = av_clip_pixel((val + offset) >> shift);
|
||||
|
||||
}
|
||||
src += MAX_PB_SIZE;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(apply_prof_uni_w)(uint8_t *_dst, const ptrdiff_t _dst_stride,
|
||||
const int16_t *src, const int16_t *diff_mv_x, const int16_t *diff_mv_y,
|
||||
const int denom, const int wx, const int _ox)
|
||||
{
|
||||
const int limit = (1 << FFMAX(13, BIT_DEPTH + 1)); ///< dILimit
|
||||
pixel *dst = (pixel*)_dst;
|
||||
const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
const int shift = denom + FFMAX(2, 14 - BIT_DEPTH);
|
||||
const int offset = 1 << (shift - 1);
|
||||
const int ox = _ox * (1 << (BIT_DEPTH - 8));
|
||||
int16_t gradient_h[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE];
|
||||
int16_t gradient_v[AFFINE_MIN_BLOCK_SIZE * AFFINE_MIN_BLOCK_SIZE];
|
||||
|
||||
FUNC(prof_grad_filter)(gradient_h, gradient_v, AFFINE_MIN_BLOCK_SIZE, src, MAX_PB_SIZE, AFFINE_MIN_BLOCK_SIZE, AFFINE_MIN_BLOCK_SIZE);
|
||||
|
||||
for (int y = 0; y < AFFINE_MIN_BLOCK_SIZE; y++) {
|
||||
for (int x = 0; x < AFFINE_MIN_BLOCK_SIZE; x++) {
|
||||
const int o = y * AFFINE_MIN_BLOCK_SIZE + x;
|
||||
const int di = gradient_h[o] * diff_mv_x[o] + gradient_v[o] * diff_mv_y[o];
|
||||
const int val = src[x] + av_clip(di, -limit, limit - 1);
|
||||
dst[x] = av_clip_pixel(((val * wx + offset) >> shift) + ox);
|
||||
}
|
||||
src += MAX_PB_SIZE;
|
||||
dst += dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(derive_bdof_vx_vy)(const int16_t *_src0, const int16_t *_src1,
|
||||
const int pad_left, const int pad_top, const int pad_right, const int pad_bottom,
|
||||
const int16_t **gradient_h, const int16_t **gradient_v,
|
||||
int* vx, int* vy)
|
||||
{
|
||||
const int shift2 = 4;
|
||||
const int shift3 = 1;
|
||||
const int thres = 1 << 4;
|
||||
int sgx2 = 0, sgy2 = 0, sgxgy = 0, sgxdi = 0, sgydi = 0;
|
||||
|
||||
for (int y = -1; y < BDOF_MIN_BLOCK_SIZE + 1; y++) {
|
||||
const int dy = y + (pad_top && y < 0) - (pad_bottom && y == BDOF_MIN_BLOCK_SIZE); // we pad for the first and last row
|
||||
const int16_t *src0 = _src0 + dy * MAX_PB_SIZE;
|
||||
const int16_t *src1 = _src1 + dy * MAX_PB_SIZE;
|
||||
|
||||
for (int x = -1; x < BDOF_MIN_BLOCK_SIZE + 1; x++) {
|
||||
const int dx = x + (pad_left && x < 0) - (pad_right && x == BDOF_MIN_BLOCK_SIZE); // we pad for the first and last col
|
||||
const int diff = (src0[dx] >> shift2) - (src1[dx] >> shift2);
|
||||
const int idx = BDOF_BLOCK_SIZE * dy + dx;
|
||||
const int temph = (gradient_h[0][idx] + gradient_h[1][idx]) >> shift3;
|
||||
const int tempv = (gradient_v[0][idx] + gradient_v[1][idx]) >> shift3;
|
||||
|
||||
sgx2 += FFABS(temph);
|
||||
sgy2 += FFABS(tempv);
|
||||
sgxgy += VVC_SIGN(tempv) * temph;
|
||||
sgxdi += -VVC_SIGN(temph) * diff;
|
||||
sgydi += -VVC_SIGN(tempv) * diff;
|
||||
}
|
||||
}
|
||||
*vx = sgx2 > 0 ? av_clip((sgxdi * (1 << 2)) >> av_log2(sgx2) , -thres + 1, thres - 1) : 0;
|
||||
*vy = sgy2 > 0 ? av_clip(((sgydi * (1 << 2)) - ((*vx * sgxgy) >> 1)) >> av_log2(sgy2), -thres + 1, thres - 1) : 0;
|
||||
}
|
||||
|
||||
static void FUNC(apply_bdof_min_block)(pixel* dst, const ptrdiff_t dst_stride, const int16_t *src0, const int16_t *src1,
|
||||
const int16_t **gh, const int16_t **gv, const int vx, const int vy)
|
||||
{
|
||||
const int shift4 = 15 - BIT_DEPTH;
|
||||
const int offset4 = 1 << (shift4 - 1);
|
||||
|
||||
for (int y = 0; y < BDOF_MIN_BLOCK_SIZE; y++) {
|
||||
for (int x = 0; x < BDOF_MIN_BLOCK_SIZE; x++) {
|
||||
const int idx = y * BDOF_BLOCK_SIZE + x;
|
||||
const int bdof_offset = vx * (gh[0][idx] - gh[1][idx]) + vy * (gv[0][idx] - gv[1][idx]);
|
||||
dst[x] = av_clip_pixel((src0[x] + offset4 + src1[x] + bdof_offset) >> shift4);
|
||||
}
|
||||
dst += dst_stride;
|
||||
src0 += MAX_PB_SIZE;
|
||||
src1 += MAX_PB_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void FUNC(apply_bdof)(uint8_t *_dst, const ptrdiff_t _dst_stride, const int16_t *_src0, const int16_t *_src1,
|
||||
const int block_w, const int block_h)
|
||||
{
|
||||
int16_t gradient_h[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE];
|
||||
int16_t gradient_v[2][BDOF_BLOCK_SIZE * BDOF_BLOCK_SIZE];
|
||||
int vx, vy;
|
||||
const ptrdiff_t dst_stride = _dst_stride / sizeof(pixel);
|
||||
pixel* dst = (pixel*)_dst;
|
||||
|
||||
FUNC(prof_grad_filter)(gradient_h[0], gradient_v[0], BDOF_BLOCK_SIZE,
|
||||
_src0, MAX_PB_SIZE, block_w, block_h);
|
||||
FUNC(prof_grad_filter)(gradient_h[1], gradient_v[1], BDOF_BLOCK_SIZE,
|
||||
_src1, MAX_PB_SIZE, block_w, block_h);
|
||||
|
||||
for (int y = 0; y < block_h; y += BDOF_MIN_BLOCK_SIZE) {
|
||||
for (int x = 0; x < block_w; x += BDOF_MIN_BLOCK_SIZE) {
|
||||
const int16_t* src0 = _src0 + y * MAX_PB_SIZE + x;
|
||||
const int16_t* src1 = _src1 + y * MAX_PB_SIZE + x;
|
||||
pixel *d = dst + x;
|
||||
const int idx = BDOF_BLOCK_SIZE * y + x;
|
||||
const int16_t* gh[] = { gradient_h[0] + idx, gradient_h[1] + idx };
|
||||
const int16_t* gv[] = { gradient_v[0] + idx, gradient_v[1] + idx };
|
||||
FUNC(derive_bdof_vx_vy)(src0, src1, !x, !y, x + BDOF_MIN_BLOCK_SIZE == block_w, y + BDOF_MIN_BLOCK_SIZE == block_h, gh, gv, &vx, &vy);
|
||||
FUNC(apply_bdof_min_block)(d, dst_stride, src0, src1, gh, gv, vx, vy);
|
||||
}
|
||||
dst += BDOF_MIN_BLOCK_SIZE * dst_stride;
|
||||
}
|
||||
}
|
||||
|
||||
#define DMVR_FILTER(src, stride) \
|
||||
(filter[0] * src[x] + \
|
||||
filter[1] * src[x + stride])
|
||||
|
||||
#define DMVR_FILTER2(filter, src0, src1) \
|
||||
(filter[0] * src0 + filter[1] * src1)
|
||||
|
||||
//8.5.3.2.2 Luma sample bilinear interpolation process
|
||||
static void FUNC(dmvr)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride,
|
||||
const int height, const intptr_t mx, const intptr_t my, const int width)
|
||||
{
|
||||
#if BIT_DEPTH != 10
|
||||
const pixel *src = (const pixel *)_src;
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
#if BIT_DEPTH > 10
|
||||
const int shift4 = BIT_DEPTH - 10;
|
||||
const int offset4 = 1 << (shift4 - 1);
|
||||
#define DMVR_SHIFT(s) (((s) + offset4) >> shift4)
|
||||
#else
|
||||
#define DMVR_SHIFT(s) ((s) << (10 - BIT_DEPTH))
|
||||
#endif // BIT_DEPTH > 10
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
dst[x] = DMVR_SHIFT(src[x]);
|
||||
src += src_stride;
|
||||
dst += MAX_PB_SIZE;
|
||||
}
|
||||
#undef DMVR_SHIFT
|
||||
#else
|
||||
av_image_copy_plane((uint8_t*)dst, sizeof(int16_t) * MAX_PB_SIZE, _src, _src_stride,
|
||||
width * sizeof(pixel), height);
|
||||
#endif // BIT_DEPTH != 10
|
||||
}
|
||||
|
||||
//8.5.3.2.2 Luma sample bilinear interpolation process
|
||||
static void FUNC(dmvr_h)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride,
|
||||
const int height, const intptr_t mx, const intptr_t my, const int width)
|
||||
{
|
||||
const pixel *src = (const pixel*)_src;
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
const int8_t *filter = ff_vvc_inter_luma_dmvr_filters[mx];
|
||||
const int shift1 = BIT_DEPTH - 6;
|
||||
const int offset1 = 1 << (shift1 - 1);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
dst[x] = (DMVR_FILTER(src, 1) + offset1) >> shift1;
|
||||
src += src_stride;
|
||||
dst += MAX_PB_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
//8.5.3.2.2 Luma sample bilinear interpolation process
|
||||
static void FUNC(dmvr_v)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride,
|
||||
const int height, const intptr_t mx, const intptr_t my, const int width)
|
||||
{
|
||||
const pixel *src = (pixel*)_src;
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
const int8_t *filter = ff_vvc_inter_luma_dmvr_filters[my];
|
||||
const int shift1 = BIT_DEPTH - 6;
|
||||
const int offset1 = 1 << (shift1 - 1);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++)
|
||||
dst[x] = (DMVR_FILTER(src, src_stride) + offset1) >> shift1;
|
||||
src += src_stride;
|
||||
dst += MAX_PB_SIZE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//8.5.3.2.2 Luma sample bilinear interpolation process
|
||||
static void FUNC(dmvr_hv)(int16_t *dst, const uint8_t *_src, const ptrdiff_t _src_stride,
|
||||
const int height, const intptr_t mx, const intptr_t my, const int width)
|
||||
{
|
||||
int16_t tmp_array[MAX_PB_SIZE * 2];
|
||||
int16_t *tmp0 = tmp_array;
|
||||
int16_t *tmp1 = tmp_array + MAX_PB_SIZE;
|
||||
const pixel *src = (const pixel*)_src;
|
||||
const ptrdiff_t src_stride = _src_stride / sizeof(pixel);
|
||||
const int8_t *filter_x = ff_vvc_inter_luma_dmvr_filters[mx];
|
||||
const int8_t *filter_y = ff_vvc_inter_luma_dmvr_filters[my];
|
||||
const int shift1 = BIT_DEPTH - 6;
|
||||
const int offset1 = 1 << (shift1 - 1);
|
||||
const int shift2 = 4;
|
||||
const int offset2 = 1 << (shift2 - 1);
|
||||
|
||||
src -= BILINEAR_EXTRA_BEFORE * src_stride;
|
||||
for (int x = 0; x < width; x++)
|
||||
tmp0[x] = (DMVR_FILTER2(filter_x, src[x], src[x + 1]) + offset1) >> shift1;
|
||||
src += src_stride;
|
||||
|
||||
for (int y = 1; y < height + BILINEAR_EXTRA; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
tmp1[x] = (DMVR_FILTER2(filter_x, src[x], src[x + 1]) + offset1) >> shift1;
|
||||
dst[x] = (DMVR_FILTER2(filter_y, tmp0[x], tmp1[x]) + offset2) >> shift2;
|
||||
}
|
||||
src += src_stride;
|
||||
dst += MAX_PB_SIZE;
|
||||
FFSWAP(int16_t *, tmp0, tmp1);
|
||||
}
|
||||
}
|
||||
|
||||
#define PEL_FUNC(dst, C, idx1, idx2, a) \
|
||||
do { \
|
||||
for (int w = 0; w < 7; w++) \
|
||||
inter->dst[C][w][idx1][idx2] = FUNC(a); \
|
||||
} while (0) \
|
||||
|
||||
#define DIR_FUNCS(d, C, c) \
|
||||
PEL_FUNC(put_##d, C, 0, 0, put_##d##_pixels); \
|
||||
PEL_FUNC(put_##d, C, 0, 1, put_##d##_##c##_h); \
|
||||
PEL_FUNC(put_##d, C, 1, 0, put_##d##_##c##_v); \
|
||||
PEL_FUNC(put_##d, C, 1, 1, put_##d##_##c##_hv); \
|
||||
PEL_FUNC(put_##d##_w, C, 0, 0, put_##d##_w_pixels); \
|
||||
PEL_FUNC(put_##d##_w, C, 0, 1, put_##d##_##c##_w_h); \
|
||||
PEL_FUNC(put_##d##_w, C, 1, 0, put_##d##_##c##_w_v); \
|
||||
PEL_FUNC(put_##d##_w, C, 1, 1, put_##d##_##c##_w_hv);
|
||||
|
||||
#define FUNCS(C, c) \
|
||||
PEL_FUNC(put, C, 0, 0, put_pixels); \
|
||||
PEL_FUNC(put, C, 0, 1, put_##c##_h); \
|
||||
PEL_FUNC(put, C, 1, 0, put_##c##_v); \
|
||||
PEL_FUNC(put, C, 1, 1, put_##c##_hv); \
|
||||
DIR_FUNCS(uni, C, c); \
|
||||
|
||||
static void FUNC(ff_vvc_inter_dsp_init)(VVCInterDSPContext *const inter)
|
||||
{
|
||||
FUNCS(LUMA, luma);
|
||||
FUNCS(CHROMA, chroma);
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(inter->put_scaled[LUMA]); i++) {
|
||||
inter->put_scaled[LUMA][i] = FUNC(put_luma_scaled);
|
||||
inter->put_scaled[CHROMA][i] = FUNC(put_chroma_scaled);
|
||||
inter->put_uni_scaled[LUMA][i] = FUNC(put_uni_luma_scaled);
|
||||
inter->put_uni_scaled[CHROMA][i] = FUNC(put_uni_chroma_scaled);
|
||||
inter->put_uni_w_scaled[LUMA][i] = FUNC(put_uni_luma_w_scaled);
|
||||
inter->put_uni_w_scaled[CHROMA][i] = FUNC(put_uni_chroma_w_scaled);
|
||||
}
|
||||
|
||||
inter->avg = FUNC(avg);
|
||||
inter->w_avg = FUNC(w_avg);
|
||||
|
||||
inter->dmvr[0][0] = FUNC(dmvr);
|
||||
inter->dmvr[0][1] = FUNC(dmvr_h);
|
||||
inter->dmvr[1][0] = FUNC(dmvr_v);
|
||||
inter->dmvr[1][1] = FUNC(dmvr_hv);
|
||||
|
||||
inter->put_ciip = FUNC(put_ciip);
|
||||
inter->put_gpm = FUNC(put_gpm);
|
||||
|
||||
inter->fetch_samples = FUNC(fetch_samples);
|
||||
inter->bdof_fetch_samples = FUNC(bdof_fetch_samples);
|
||||
inter->apply_prof = FUNC(apply_prof);
|
||||
inter->apply_prof_uni = FUNC(apply_prof_uni);
|
||||
inter->apply_prof_uni_w = FUNC(apply_prof_uni_w);
|
||||
inter->apply_bdof = FUNC(apply_bdof);
|
||||
inter->sad = vvc_sad;
|
||||
}
|
||||
|
||||
#undef FUNCS
|
||||
#undef PEL_FUNC
|
||||
#undef DMVR_FUNCS
|
||||
@@ -0,0 +1,740 @@
|
||||
/*
|
||||
* VVC intra prediction
|
||||
*
|
||||
* Copyright (C) 2021 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "libavutil/frame.h"
|
||||
#include "libavutil/imgutils.h"
|
||||
|
||||
#include "data.h"
|
||||
#include "inter.h"
|
||||
#include "intra.h"
|
||||
#include "itx_1d.h"
|
||||
|
||||
#define POS(c_idx, x, y) \
|
||||
&fc->frame->data[c_idx][((y) >> fc->ps.sps->vshift[c_idx]) * fc->frame->linesize[c_idx] + \
|
||||
(((x) >> fc->ps.sps->hshift[c_idx]) << fc->ps.sps->pixel_shift)]
|
||||
|
||||
static int is_cclm(enum IntraPredMode mode)
|
||||
{
|
||||
return mode == INTRA_LT_CCLM || mode == INTRA_L_CCLM || mode == INTRA_T_CCLM;
|
||||
}
|
||||
|
||||
static int derive_ilfnst_pred_mode_intra(const VVCLocalContext *lc, const TransformBlock *tb)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
const int x_tb = tb->x0 >> fc->ps.sps->min_cb_log2_size_y;
|
||||
const int y_tb = tb->y0 >> fc->ps.sps->min_cb_log2_size_y;
|
||||
const int x_c = (tb->x0 + (tb->tb_width << sps->hshift[1] >> 1) ) >> fc->ps.sps->min_cb_log2_size_y;
|
||||
const int y_c = (tb->y0 + (tb->tb_height << sps->vshift[1] >> 1)) >> fc->ps.sps->min_cb_log2_size_y;
|
||||
const int min_cb_width = fc->ps.pps->min_cb_width;
|
||||
const int intra_mip_flag = SAMPLE_CTB(fc->tab.imf, x_tb, y_tb);
|
||||
int pred_mode_intra = tb->c_idx == 0 ? cu->intra_pred_mode_y : cu->intra_pred_mode_c;
|
||||
if (intra_mip_flag && !tb->c_idx) {
|
||||
pred_mode_intra = INTRA_PLANAR;
|
||||
} else if (is_cclm(pred_mode_intra)) {
|
||||
int intra_mip_flag_c = SAMPLE_CTB(fc->tab.imf, x_c, y_c);
|
||||
int cu_pred_mode = SAMPLE_CTB(fc->tab.cpm[0], x_c, y_c);
|
||||
if (intra_mip_flag_c) {
|
||||
pred_mode_intra = INTRA_PLANAR;
|
||||
} else if (cu_pred_mode == MODE_IBC || cu_pred_mode == MODE_PLT) {
|
||||
pred_mode_intra = INTRA_DC;
|
||||
} else {
|
||||
pred_mode_intra = SAMPLE_CTB(fc->tab.ipm, x_c, y_c);
|
||||
}
|
||||
}
|
||||
pred_mode_intra = ff_vvc_wide_angle_mode_mapping(cu, tb->tb_width, tb->tb_height, tb->c_idx, pred_mode_intra);
|
||||
|
||||
return pred_mode_intra;
|
||||
}
|
||||
|
||||
//8.7.4 Transformation process for scaled transform coefficients
|
||||
static void ilfnst_transform(const VVCLocalContext *lc, TransformBlock *tb)
|
||||
{
|
||||
const VVCSPS *sps = lc->fc->ps.sps;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
const int w = tb->tb_width;
|
||||
const int h = tb->tb_height;
|
||||
const int n_lfnst_out_size = (w >= 8 && h >= 8) ? 48 : 16; ///< nLfnstOutSize
|
||||
const int log2_lfnst_size = (w >= 8 && h >= 8) ? 3 : 2; ///< log2LfnstSize
|
||||
const int n_lfnst_size = 1 << log2_lfnst_size; ///< nLfnstSize
|
||||
const int non_zero_size = ((w == 8 && h == 8) || (w == 4 && h == 4)) ? 8 : 16; ///< nonZeroSize
|
||||
const int pred_mode_intra = derive_ilfnst_pred_mode_intra(lc, tb);
|
||||
const int transpose = pred_mode_intra > 34;
|
||||
int u[16], v[48];
|
||||
|
||||
for (int x = 0; x < non_zero_size; x++) {
|
||||
int xc = ff_vvc_diag_scan_x[2][2][x];
|
||||
int yc = ff_vvc_diag_scan_y[2][2][x];
|
||||
u[x] = tb->coeffs[w * yc + xc];
|
||||
}
|
||||
ff_vvc_inv_lfnst_1d(v, u, non_zero_size, n_lfnst_out_size, pred_mode_intra,
|
||||
cu->lfnst_idx, sps->log2_transform_range);
|
||||
if (transpose) {
|
||||
int *dst = tb->coeffs;
|
||||
const int *src = v;
|
||||
if (n_lfnst_size == 4) {
|
||||
for (int y = 0; y < 4; y++) {
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[4];
|
||||
dst[2] = src[8];
|
||||
dst[3] = src[12];
|
||||
src++;
|
||||
dst += w;
|
||||
}
|
||||
} else {
|
||||
for (int y = 0; y < 8; y++) {
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[8];
|
||||
dst[2] = src[16];
|
||||
dst[3] = src[24];
|
||||
if (y < 4) {
|
||||
dst[4] = src[32];
|
||||
dst[5] = src[36];
|
||||
dst[6] = src[40];
|
||||
dst[7] = src[44];
|
||||
}
|
||||
src++;
|
||||
dst += w;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
int *dst = tb->coeffs;
|
||||
const int *src = v;
|
||||
for (int y = 0; y < n_lfnst_size; y++) {
|
||||
int size = (y < 4) ? n_lfnst_size : 4;
|
||||
memcpy(dst, src, size * sizeof(int));
|
||||
src += size;
|
||||
dst += w;
|
||||
}
|
||||
}
|
||||
tb->max_scan_x = n_lfnst_size - 1;
|
||||
tb->max_scan_y = n_lfnst_size - 1;
|
||||
}
|
||||
|
||||
//part of 8.7.4 Transformation process for scaled transform coefficients
|
||||
static void derive_transform_type(const VVCFrameContext *fc, const VVCLocalContext *lc, const TransformBlock *tb, enum VVCTxType *trh, enum VVCTxType *trv)
|
||||
{
|
||||
const CodingUnit *cu = lc->cu;
|
||||
static const enum VVCTxType mts_to_trh[] = { VVC_DCT2, VVC_DST7, VVC_DCT8, VVC_DST7, VVC_DCT8 };
|
||||
static const enum VVCTxType mts_to_trv[] = { VVC_DCT2, VVC_DST7, VVC_DST7, VVC_DCT8, VVC_DCT8 };
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
int implicit_mts_enabled = 0;
|
||||
if (tb->c_idx || (cu->isp_split_type != ISP_NO_SPLIT && cu->lfnst_idx)) {
|
||||
*trh = *trv = VVC_DCT2;
|
||||
return;
|
||||
}
|
||||
|
||||
if (sps->r->sps_mts_enabled_flag) {
|
||||
if (cu->isp_split_type != ISP_NO_SPLIT ||
|
||||
(cu->sbt_flag && FFMAX(tb->tb_width, tb->tb_height) <= 32) ||
|
||||
(!sps->r->sps_explicit_mts_intra_enabled_flag && cu->pred_mode == MODE_INTRA &&
|
||||
!cu->lfnst_idx && !cu->intra_mip_flag)) {
|
||||
implicit_mts_enabled = 1;
|
||||
}
|
||||
}
|
||||
if (implicit_mts_enabled) {
|
||||
const int w = tb->tb_width;
|
||||
const int h = tb->tb_height;
|
||||
if (cu->sbt_flag) {
|
||||
*trh = (cu->sbt_horizontal_flag || cu->sbt_pos_flag) ? VVC_DST7 : VVC_DCT8;
|
||||
*trv = (!cu->sbt_horizontal_flag || cu->sbt_pos_flag) ? VVC_DST7 : VVC_DCT8;
|
||||
} else {
|
||||
*trh = (w >= 4 && w <= 16) ? VVC_DST7 : VVC_DCT2;
|
||||
*trv = (h >= 4 && h <= 16) ? VVC_DST7 : VVC_DCT2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
*trh = mts_to_trh[cu->mts_idx];
|
||||
*trv = mts_to_trv[cu->mts_idx];
|
||||
}
|
||||
|
||||
static int add_reconstructed_area(VVCLocalContext *lc, const int ch_type, const int x0, const int y0, const int w, const int h)
|
||||
{
|
||||
const VVCSPS *sps = lc->fc->ps.sps;
|
||||
const int hs = sps->hshift[ch_type];
|
||||
const int vs = sps->vshift[ch_type];
|
||||
ReconstructedArea *a;
|
||||
|
||||
if (lc->num_ras[ch_type] >= FF_ARRAY_ELEMS(lc->ras[ch_type]))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
a = &lc->ras[ch_type][lc->num_ras[ch_type]];
|
||||
a->x = x0 >> hs;
|
||||
a->y = y0 >> vs;
|
||||
a->w = w >> hs;
|
||||
a->h = h >> vs;
|
||||
lc->num_ras[ch_type]++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void add_tu_area(const TransformUnit *tu, int *x0, int *y0, int *w, int *h)
|
||||
{
|
||||
*x0 = tu->x0;
|
||||
*y0 = tu->y0;
|
||||
*w = tu->width;
|
||||
*h = tu->height;
|
||||
}
|
||||
|
||||
#define MIN_ISP_PRED_WIDTH 4
|
||||
static int get_luma_predict_unit(const CodingUnit *cu, const TransformUnit *tu, const int idx, int *x0, int *y0, int *w, int *h)
|
||||
{
|
||||
int has_luma = 1;
|
||||
add_tu_area(tu, x0, y0, w, h);
|
||||
if (cu->isp_split_type == ISP_VER_SPLIT && tu->width < MIN_ISP_PRED_WIDTH) {
|
||||
*w = MIN_ISP_PRED_WIDTH;
|
||||
has_luma = !(idx % (MIN_ISP_PRED_WIDTH / tu->width));
|
||||
}
|
||||
return has_luma;
|
||||
}
|
||||
|
||||
static int get_chroma_predict_unit(const CodingUnit *cu, const TransformUnit *tu, const int idx, int *x0, int *y0, int *w, int *h)
|
||||
{
|
||||
if (cu->isp_split_type == ISP_NO_SPLIT) {
|
||||
add_tu_area(tu, x0, y0, w, h);
|
||||
return 1;
|
||||
}
|
||||
if (idx == cu->num_intra_subpartitions - 1) {
|
||||
*x0 = cu->x0;
|
||||
*y0 = cu->y0;
|
||||
*w = cu->cb_width;
|
||||
*h = cu->cb_height;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//8.4.5.1 General decoding process for intra blocks
|
||||
static void predict_intra(VVCLocalContext *lc, const TransformUnit *tu, const int idx, const int target_ch_type)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
const VVCTreeType tree_type = cu->tree_type;
|
||||
int x0, y0, w, h;
|
||||
if (cu->pred_mode != MODE_INTRA) {
|
||||
add_reconstructed_area(lc, target_ch_type, tu->x0, tu->y0, tu->width, tu->height);
|
||||
return;
|
||||
}
|
||||
if (!target_ch_type && tree_type != DUAL_TREE_CHROMA) {
|
||||
if (get_luma_predict_unit(cu, tu, idx, &x0, &y0, &w, &h)) {
|
||||
ff_vvc_set_neighbour_available(lc, x0, y0, w, h);
|
||||
fc->vvcdsp.intra.intra_pred(lc, x0, y0, w, h, 0);
|
||||
add_reconstructed_area(lc, 0, x0, y0, w, h);
|
||||
}
|
||||
}
|
||||
if (target_ch_type && tree_type != DUAL_TREE_LUMA) {
|
||||
if (get_chroma_predict_unit(cu, tu, idx, &x0, &y0, &w, &h)){
|
||||
ff_vvc_set_neighbour_available(lc, x0, y0, w, h);
|
||||
if (is_cclm(cu->intra_pred_mode_c)) {
|
||||
fc->vvcdsp.intra.intra_cclm_pred(lc, x0, y0, w, h);
|
||||
} else {
|
||||
fc->vvcdsp.intra.intra_pred(lc, x0, y0, w, h, 1);
|
||||
fc->vvcdsp.intra.intra_pred(lc, x0, y0, w, h, 2);
|
||||
}
|
||||
add_reconstructed_area(lc, 1, x0, y0, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void scale_clip(int *coeff, const int nzw, const int w, const int h,
|
||||
const int shift, const int log2_transform_range)
|
||||
{
|
||||
const int add = 1 << (shift - 1);
|
||||
for (int y = 0; y < h; y++) {
|
||||
int *p = coeff + y * w;
|
||||
for (int x = 0; x < nzw; x++) {
|
||||
*p = av_clip_intp2((*p + add) >> shift, log2_transform_range);
|
||||
p++;
|
||||
}
|
||||
memset(p, 0, sizeof(*p) * (w - nzw));
|
||||
}
|
||||
}
|
||||
|
||||
static void scale(int *out, const int *in, const int w, const int h, const int shift)
|
||||
{
|
||||
const int add = 1 << (shift - 1);
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int x = 0; x < w; x++) {
|
||||
int *o = out + y * w + x;
|
||||
const int *i = in + y * w + x;
|
||||
*o = (*i + add) >> shift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// part of 8.7.3 Scaling process for transform coefficients
|
||||
static void derive_qp(const VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb)
|
||||
{
|
||||
const VVCSPS *sps = lc->fc->ps.sps;
|
||||
const H266RawSliceHeader *rsh = lc->sc->sh.r;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
const bool is_jcbcr = tb->c_idx && tu->joint_cbcr_residual_flag && tu->coded_flag[CB] && tu->coded_flag[CR];
|
||||
const int idx = is_jcbcr ? JCBCR : tb->c_idx;
|
||||
const int qp = cu->qp[idx] + (idx ? 0 : sps->qp_bd_offset);
|
||||
const int act_offset[] = { -5, 1, 3, 1 };
|
||||
const int qp_act_offset = cu->act_enabled_flag ? act_offset[idx] : 0;
|
||||
|
||||
if (tb->ts) {
|
||||
const int qp_prime_ts_min = 4 + 6 * sps->r->sps_min_qp_prime_ts;
|
||||
|
||||
tb->qp = av_clip(qp + qp_act_offset, qp_prime_ts_min, 63 + sps->qp_bd_offset);
|
||||
tb->rect_non_ts_flag = 0;
|
||||
tb->bd_shift = 10;
|
||||
} else {
|
||||
const int log_sum = tb->log2_tb_width + tb->log2_tb_height;
|
||||
const int rect_non_ts_flag = log_sum & 1;
|
||||
|
||||
tb->qp = av_clip(qp + qp_act_offset, 0, 63 + sps->qp_bd_offset);
|
||||
tb->rect_non_ts_flag = rect_non_ts_flag;
|
||||
tb->bd_shift = sps->bit_depth + rect_non_ts_flag + (log_sum / 2)
|
||||
+ 10 - sps->log2_transform_range + rsh->sh_dep_quant_used_flag;
|
||||
}
|
||||
tb->bd_offset = (1 << tb->bd_shift) >> 1;
|
||||
}
|
||||
|
||||
static const uint8_t rem6[63 + 8 * 6 + 1] = {
|
||||
0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
|
||||
0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
|
||||
0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
|
||||
0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
|
||||
0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3,
|
||||
};
|
||||
|
||||
static const uint8_t div6[63 + 8 * 6 + 1] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
|
||||
4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7,
|
||||
8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11,
|
||||
12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15,
|
||||
16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18,
|
||||
};
|
||||
|
||||
const static int level_scale[2][6] = {
|
||||
{ 40, 45, 51, 57, 64, 72 },
|
||||
{ 57, 64, 72, 80, 90, 102 }
|
||||
};
|
||||
|
||||
//8.7.3 Scaling process for transform coefficients
|
||||
static av_always_inline int derive_scale(const TransformBlock *tb, const int sh_dep_quant_used_flag)
|
||||
{
|
||||
const int addin = sh_dep_quant_used_flag && !tb->ts;
|
||||
const int qp = tb->qp + addin;
|
||||
|
||||
return level_scale[tb->rect_non_ts_flag][rem6[qp]] << div6[qp];
|
||||
}
|
||||
|
||||
//8.7.3 Scaling process for transform coefficients
|
||||
static const uint8_t* derive_scale_m(const VVCLocalContext *lc, const TransformBlock *tb, uint8_t *scale_m)
|
||||
{
|
||||
//Table 38 – Specification of the scaling matrix identifier variable id according to predMode, cIdx, nTbW, and nTbH
|
||||
const int ids[2][3][6] = {
|
||||
{
|
||||
{ 0, 2, 8, 14, 20, 26 },
|
||||
{ 0, 3, 9, 15, 21, 21 },
|
||||
{ 0, 4, 10, 16, 22, 22 }
|
||||
},
|
||||
{
|
||||
{ 0, 5, 11, 17, 23, 27 },
|
||||
{ 0, 6, 12, 18, 24, 24 },
|
||||
{ 1, 7, 13, 19, 25, 25 },
|
||||
}
|
||||
};
|
||||
const VVCFrameParamSets *ps = &lc->fc->ps;
|
||||
const VVCSPS *sps = ps->sps;
|
||||
const H266RawSliceHeader *rsh = lc->sc->sh.r;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
const VVCScalingList *sl = ps->sl;
|
||||
const int id = ids[cu->pred_mode != MODE_INTRA][tb->c_idx][FFMAX(tb->log2_tb_height, tb->log2_tb_width) - 1];
|
||||
const int log2_matrix_size = (id < 2) ? 1 : (id < 8) ? 2 : 3;
|
||||
uint8_t *p = scale_m;
|
||||
|
||||
if (!rsh->sh_explicit_scaling_list_used_flag || tb->ts ||
|
||||
(sps->r->sps_scaling_matrix_for_lfnst_disabled_flag && cu->apply_lfnst_flag[tb->c_idx]) ||
|
||||
(sps->r->sps_scaling_matrix_for_alternative_colour_space_disabled_flag &&
|
||||
sps->r->sps_scaling_matrix_designated_colour_space_flag == cu->act_enabled_flag))
|
||||
return ff_vvc_default_scale_m;
|
||||
|
||||
if (!sl) {
|
||||
av_log(lc->fc->log_ctx, AV_LOG_WARNING, "bug: no scaling list aps, id = %d", ps->ph.r->ph_scaling_list_aps_id);
|
||||
return ff_vvc_default_scale_m;
|
||||
}
|
||||
|
||||
for (int y = tb->min_scan_y; y <= tb->max_scan_y; y++) {
|
||||
const int off = y << log2_matrix_size >> tb->log2_tb_height << log2_matrix_size;
|
||||
const uint8_t *m = &sl->scaling_matrix_rec[id][off];
|
||||
|
||||
for (int x = tb->min_scan_x; x <= tb->max_scan_x; x++)
|
||||
*p++ = m[x << log2_matrix_size >> tb->log2_tb_width];
|
||||
}
|
||||
if (id >= SL_START_16x16 && !tb->min_scan_x && !tb->min_scan_y)
|
||||
*scale_m = sl->scaling_matrix_dc_rec[id - SL_START_16x16];
|
||||
|
||||
return scale_m;
|
||||
}
|
||||
|
||||
//8.7.3 Scaling process for transform coefficients
|
||||
static av_always_inline int scale_coeff(const TransformBlock *tb, int coeff,
|
||||
const int scale, const int scale_m, const int log2_transform_range)
|
||||
{
|
||||
coeff = ((int64_t) coeff * scale * scale_m + tb->bd_offset) >> tb->bd_shift;
|
||||
coeff = av_clip_intp2(coeff, log2_transform_range);
|
||||
return coeff;
|
||||
}
|
||||
|
||||
static void dequant(const VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb)
|
||||
{
|
||||
uint8_t tmp[MAX_TB_SIZE * MAX_TB_SIZE];
|
||||
const H266RawSliceHeader *rsh = lc->sc->sh.r;
|
||||
const VVCSPS *sps = lc->fc->ps.sps;
|
||||
const uint8_t *scale_m = derive_scale_m(lc, tb, tmp);
|
||||
int scale;
|
||||
|
||||
derive_qp(lc, tu, tb);
|
||||
scale = derive_scale(tb, rsh->sh_dep_quant_used_flag);
|
||||
|
||||
for (int y = tb->min_scan_y; y <= tb->max_scan_y; y++) {
|
||||
for (int x = tb->min_scan_x; x <= tb->max_scan_x; x++) {
|
||||
int *coeff = tb->coeffs + y * tb->tb_width + x;
|
||||
|
||||
if (*coeff)
|
||||
*coeff = scale_coeff(tb, *coeff, scale, *scale_m, sps->log2_transform_range);
|
||||
scale_m++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//transmatrix[0][0]
|
||||
#define DCT_A 64
|
||||
static void itx_2d(const VVCFrameContext *fc, TransformBlock *tb, const enum VVCTxType trh, const enum VVCTxType trv)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const int w = tb->tb_width;
|
||||
const int h = tb->tb_height;
|
||||
const size_t nzw = tb->max_scan_x + 1;
|
||||
const size_t nzh = tb->max_scan_y + 1;
|
||||
const int shift[] = { 7, 5 + sps->log2_transform_range - sps->bit_depth };
|
||||
|
||||
if (w == h && nzw == 1 && nzh == 1 && trh == VVC_DCT2 && trv == VVC_DCT2) {
|
||||
const int add[] = { 1 << (shift[0] - 1), 1 << (shift[1] - 1) };
|
||||
const int t = (tb->coeffs[0] * DCT_A + add[0]) >> shift[0];
|
||||
const int dc = (t * DCT_A + add[1]) >> shift[1];
|
||||
|
||||
for (int i = 0; i < w * h; i++)
|
||||
tb->coeffs[i] = dc;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (int x = 0; x < nzw; x++)
|
||||
fc->vvcdsp.itx.itx[trv][tb->log2_tb_height - 1](tb->coeffs + x, w, nzh);
|
||||
scale_clip(tb->coeffs, nzw, w, h, shift[0], sps->log2_transform_range);
|
||||
|
||||
for (int y = 0; y < h; y++)
|
||||
fc->vvcdsp.itx.itx[trh][tb->log2_tb_width - 1](tb->coeffs + y * w, 1, nzw);
|
||||
scale(tb->coeffs, tb->coeffs, w, h, shift[1]);
|
||||
}
|
||||
|
||||
static void itx_1d(const VVCFrameContext *fc, TransformBlock *tb, const enum VVCTxType trh, const enum VVCTxType trv)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const int w = tb->tb_width;
|
||||
const int h = tb->tb_height;
|
||||
const size_t nzw = tb->max_scan_x + 1;
|
||||
const size_t nzh = tb->max_scan_y + 1;
|
||||
|
||||
if ((w > 1 && nzw == 1 && trh == VVC_DCT2) || (h > 1 && nzh == 1 && trv == VVC_DCT2)) {
|
||||
const int shift = 6 + sps->log2_transform_range - sps->bit_depth;
|
||||
const int add = 1 << (shift - 1);
|
||||
const int dc = (tb->coeffs[0] * DCT_A + add) >> shift;
|
||||
|
||||
for (int i = 0; i < w * h; i++)
|
||||
tb->coeffs[i] = dc;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (w > 1)
|
||||
fc->vvcdsp.itx.itx[trh][tb->log2_tb_width - 1](tb->coeffs, 1, nzw);
|
||||
else
|
||||
fc->vvcdsp.itx.itx[trv][tb->log2_tb_height - 1](tb->coeffs, 1, nzh);
|
||||
scale(tb->coeffs, tb->coeffs, w, h, 6 + sps->log2_transform_range - sps->bit_depth);
|
||||
}
|
||||
|
||||
static void transform_bdpcm(TransformBlock *tb, const VVCLocalContext *lc, const CodingUnit *cu)
|
||||
{
|
||||
const VVCSPS *sps = lc->fc->ps.sps;
|
||||
const IntraPredMode mode = tb->c_idx ? cu->intra_pred_mode_c : cu->intra_pred_mode_y;
|
||||
const int vertical = mode == INTRA_VERT;
|
||||
lc->fc->vvcdsp.itx.transform_bdpcm(tb->coeffs, tb->tb_width, tb->tb_height,
|
||||
vertical, sps->log2_transform_range);
|
||||
if (vertical)
|
||||
tb->max_scan_y = tb->tb_height - 1;
|
||||
else
|
||||
tb->max_scan_x = tb->tb_width - 1;
|
||||
}
|
||||
|
||||
static void lmcs_scale_chroma(VVCLocalContext *lc, TransformUnit *tu, TransformBlock *tb, const int target_ch_type)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const VVCSH *sh = &lc->sc->sh;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
const int c_idx = tb->c_idx;
|
||||
const int ch_type = c_idx > 0;
|
||||
const int w = tb->tb_width;
|
||||
const int h = tb->tb_height;
|
||||
const int chroma_scale = ch_type && sh->r->sh_lmcs_used_flag && fc->ps.ph.r->ph_chroma_residual_scale_flag && (w * h > 4);
|
||||
const int has_jcbcr = tu->joint_cbcr_residual_flag && c_idx;
|
||||
|
||||
for (int j = 0; j < 1 + has_jcbcr; j++) {
|
||||
const bool is_jcbcr = j > 0;
|
||||
const int jcbcr_idx = CB + tu->coded_flag[CB];
|
||||
TransformBlock *jcbcr = &tu->tbs[jcbcr_idx - tu->tbs[0].c_idx];
|
||||
int *coeffs = is_jcbcr ? jcbcr->coeffs : tb->coeffs;
|
||||
|
||||
if (!j && has_jcbcr) {
|
||||
const int c_sign = 1 - 2 * fc->ps.ph.r->ph_joint_cbcr_sign_flag;
|
||||
const int shift = tu->coded_flag[CB] ^ tu->coded_flag[CR];
|
||||
fc->vvcdsp.itx.pred_residual_joint(jcbcr->coeffs, tb->coeffs, w, h, c_sign, shift);
|
||||
}
|
||||
if (chroma_scale)
|
||||
fc->vvcdsp.intra.lmcs_scale_chroma(lc, coeffs, w, h, cu->x0, cu->y0);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_residual(const VVCLocalContext *lc, TransformUnit *tu, const int target_ch_type)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
|
||||
for (int i = 0; i < tu->nb_tbs; i++) {
|
||||
TransformBlock *tb = tu->tbs + i;
|
||||
const int c_idx = tb->c_idx;
|
||||
const int ch_type = c_idx > 0;
|
||||
const ptrdiff_t stride = fc->frame->linesize[c_idx];
|
||||
const bool has_residual = tb->has_coeffs || cu->act_enabled_flag ||
|
||||
(c_idx && tu->joint_cbcr_residual_flag);
|
||||
uint8_t *dst = POS(c_idx, tb->x0, tb->y0);
|
||||
|
||||
if (ch_type == target_ch_type && has_residual)
|
||||
fc->vvcdsp.itx.add_residual(dst, tb->coeffs, tb->tb_width, tb->tb_height, stride);
|
||||
}
|
||||
}
|
||||
|
||||
static void itransform(VVCLocalContext *lc, TransformUnit *tu, const int target_ch_type)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
TransformBlock *tbs = tu->tbs;
|
||||
const bool is_act_luma = cu->act_enabled_flag && target_ch_type == LUMA;
|
||||
|
||||
for (int i = 0; i < tu->nb_tbs; i++) {
|
||||
TransformBlock *tb = tbs + i;
|
||||
const int c_idx = tb->c_idx;
|
||||
const int ch_type = c_idx > 0;
|
||||
const bool do_itx = is_act_luma || !cu->act_enabled_flag && ch_type == target_ch_type;
|
||||
|
||||
if (tb->has_coeffs && do_itx) {
|
||||
if (cu->bdpcm_flag[tb->c_idx])
|
||||
transform_bdpcm(tb, lc, cu);
|
||||
dequant(lc, tu, tb);
|
||||
if (!tb->ts) {
|
||||
enum VVCTxType trh, trv;
|
||||
|
||||
if (cu->apply_lfnst_flag[c_idx])
|
||||
ilfnst_transform(lc, tb);
|
||||
derive_transform_type(fc, lc, tb, &trh, &trv);
|
||||
if (tb->tb_width > 1 && tb->tb_height > 1)
|
||||
itx_2d(fc, tb, trh, trv);
|
||||
else
|
||||
itx_1d(fc, tb, trh, trv);
|
||||
}
|
||||
lmcs_scale_chroma(lc, tu, tb, target_ch_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_act_luma) {
|
||||
fc->vvcdsp.itx.adaptive_color_transform(
|
||||
tbs[LUMA].coeffs, tbs[CB].coeffs, tbs[CR].coeffs,
|
||||
tbs[LUMA].tb_width, tbs[LUMA].tb_height);
|
||||
}
|
||||
|
||||
add_residual(lc, tu, target_ch_type);
|
||||
}
|
||||
|
||||
static int reconstruct(VVCLocalContext *lc)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
CodingUnit *cu = lc->cu;
|
||||
const int start = cu->tree_type == DUAL_TREE_CHROMA;
|
||||
const int end = fc->ps.sps->r->sps_chroma_format_idc && (cu->tree_type != DUAL_TREE_LUMA);
|
||||
|
||||
for (int ch_type = start; ch_type <= end; ch_type++) {
|
||||
TransformUnit *tu = cu->tus.head;
|
||||
for (int i = 0; tu; i++) {
|
||||
predict_intra(lc, tu, i, ch_type);
|
||||
itransform(lc, tu, ch_type);
|
||||
tu = tu->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define IBC_POS(c_idx, x, y) \
|
||||
(fc->tab.ibc_vir_buf[c_idx] + \
|
||||
(x << ps) + (y + ((cu->y0 & ~(sps->ctb_size_y - 1)) >> vs)) * ibc_stride)
|
||||
#define IBC_X(x) ((x) & ((fc->tab.sz.ibc_buffer_width >> hs) - 1))
|
||||
#define IBC_Y(y) ((y) & ((1 << sps->ctb_log2_size_y >> vs) - 1))
|
||||
|
||||
static void intra_block_copy(const VVCLocalContext *lc, const int c_idx)
|
||||
{
|
||||
const CodingUnit *cu = lc->cu;
|
||||
const PredictionUnit *pu = &cu->pu;
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const Mv *bv = &pu->mi.mv[L0][0];
|
||||
const int hs = sps->hshift[c_idx];
|
||||
const int vs = sps->vshift[c_idx];
|
||||
const int ps = sps->pixel_shift;
|
||||
const int ref_x = IBC_X((cu->x0 >> hs) + (bv->x >> (4 + hs)));
|
||||
const int ref_y = IBC_Y((cu->y0 >> vs) + (bv->y >> (4 + vs)));
|
||||
const int w = cu->cb_width >> hs;
|
||||
const int h = cu->cb_height >> vs;
|
||||
const int ibc_buf_width = fc->tab.sz.ibc_buffer_width >> hs; ///< IbcBufWidthY and IbcBufWidthC
|
||||
const int rw = FFMIN(w, ibc_buf_width - ref_x);
|
||||
const int ibc_stride = ibc_buf_width << ps;
|
||||
const int dst_stride = fc->frame->linesize[c_idx];
|
||||
const uint8_t *ibc_buf = IBC_POS(c_idx, ref_x, ref_y);
|
||||
uint8_t *dst = POS(c_idx, cu->x0, cu->y0);
|
||||
|
||||
av_image_copy_plane(dst, dst_stride, ibc_buf, ibc_stride, rw << ps, h);
|
||||
|
||||
if (w > rw) {
|
||||
//wrap around, left part
|
||||
ibc_buf = IBC_POS(c_idx, 0, ref_y);
|
||||
dst += rw << ps;
|
||||
av_image_copy_plane(dst, dst_stride, ibc_buf, ibc_stride, (w - rw) << ps, h);
|
||||
}
|
||||
}
|
||||
|
||||
static void vvc_predict_ibc(const VVCLocalContext *lc)
|
||||
{
|
||||
const H266RawSPS *rsps = lc->fc->ps.sps->r;
|
||||
|
||||
intra_block_copy(lc, LUMA);
|
||||
if (lc->cu->tree_type == SINGLE_TREE && rsps->sps_chroma_format_idc) {
|
||||
intra_block_copy(lc, CB);
|
||||
intra_block_copy(lc, CR);
|
||||
}
|
||||
}
|
||||
|
||||
static void ibc_fill_vir_buf(const VVCLocalContext *lc, const CodingUnit *cu)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
int start, end;
|
||||
|
||||
ff_vvc_channel_range(&start, &end, cu->tree_type, sps->r->sps_chroma_format_idc);
|
||||
|
||||
for (int c_idx = start; c_idx < end; c_idx++) {
|
||||
const int hs = sps->hshift[c_idx];
|
||||
const int vs = sps->vshift[c_idx];
|
||||
const int ps = sps->pixel_shift;
|
||||
const int x = IBC_X(cu->x0 >> hs);
|
||||
const int y = IBC_Y(cu->y0 >> vs);
|
||||
const int src_stride = fc->frame->linesize[c_idx];
|
||||
const int ibc_stride = fc->tab.sz.ibc_buffer_width >> hs << ps;
|
||||
const uint8_t *src = POS(c_idx, cu->x0, cu->y0);
|
||||
uint8_t *ibc_buf = IBC_POS(c_idx, x, y);
|
||||
|
||||
av_image_copy_plane(ibc_buf, ibc_stride, src, src_stride, cu->cb_width >> hs << ps , cu->cb_height >> vs);
|
||||
}
|
||||
}
|
||||
|
||||
int ff_vvc_palette_derive_scale(VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb)
|
||||
{
|
||||
const VVCSPS *sps = lc->fc->ps.sps;
|
||||
const int qp_prime_ts_min = 4 + 6 * sps->r->sps_min_qp_prime_ts;
|
||||
int qp;
|
||||
|
||||
derive_qp(lc, tu, tb);
|
||||
qp = FFMAX(qp_prime_ts_min, tb->qp);
|
||||
return level_scale[0][rem6[qp]] << div6[qp];
|
||||
}
|
||||
|
||||
// 8.4.5.3 Decoding process for palette mode
|
||||
static void vvc_predict_palette(VVCLocalContext *lc)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const CodingUnit *cu = lc->cu;
|
||||
TransformUnit *tu = cu->tus.head;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const int ps = sps->pixel_shift;
|
||||
|
||||
for (int i = 0; i < tu->nb_tbs; i++) {
|
||||
TransformBlock *tb = &tu->tbs[i];
|
||||
const int c_idx = tb->c_idx;
|
||||
const int w = tb->tb_width;
|
||||
const int h = tb->tb_height;
|
||||
const ptrdiff_t stride = fc->frame->linesize[c_idx];
|
||||
uint8_t *dst = POS(c_idx, cu->x0, cu->y0);
|
||||
|
||||
av_image_copy_plane(dst, stride, (uint8_t*)tb->coeffs, w << ps, w << ps, h);
|
||||
}
|
||||
}
|
||||
|
||||
int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const int x_ctb = rx << sps->ctb_log2_size_y;
|
||||
const int y_ctb = ry << sps->ctb_log2_size_y;
|
||||
CodingUnit *cu = fc->tab.cus[rs];
|
||||
int ret = 0;
|
||||
|
||||
lc->num_ras[0] = lc->num_ras[1] = 0;
|
||||
lc->lmcs.x_vpdu = -1;
|
||||
lc->lmcs.y_vpdu = -1;
|
||||
ff_vvc_decode_neighbour(lc, x_ctb, y_ctb, rx, ry, rs);
|
||||
while (cu) {
|
||||
lc->cu = cu;
|
||||
|
||||
if (cu->ciip_flag)
|
||||
ff_vvc_predict_ciip(lc);
|
||||
else if (cu->pred_mode == MODE_IBC)
|
||||
vvc_predict_ibc(lc);
|
||||
else if (cu->pred_mode == MODE_PLT)
|
||||
vvc_predict_palette(lc);
|
||||
if (cu->coded_flag) {
|
||||
ret = reconstruct(lc);
|
||||
} else {
|
||||
if (cu->tree_type != DUAL_TREE_CHROMA)
|
||||
add_reconstructed_area(lc, LUMA, cu->x0, cu->y0, cu->cb_width, cu->cb_height);
|
||||
if (sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA)
|
||||
add_reconstructed_area(lc, CHROMA, cu->x0, cu->y0, cu->cb_width, cu->cb_height);
|
||||
}
|
||||
if (sps->r->sps_ibc_enabled_flag)
|
||||
ibc_fill_vir_buf(lc, cu);
|
||||
cu = cu->next;
|
||||
}
|
||||
ff_vvc_ctu_free_cus(fc->tab.cus + rs);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* VVC intra prediction
|
||||
*
|
||||
* Copyright (C) 2021 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#ifndef AVCODEC_VVC_INTRA_H
|
||||
#define AVCODEC_VVC_INTRA_H
|
||||
|
||||
#include "ctu.h"
|
||||
|
||||
/**
|
||||
* reconstruct a CTU
|
||||
* @param lc local context for CTU
|
||||
* @param rs raster order for the CTU.
|
||||
* @param rx raster order x for the CTU.
|
||||
* @param ry raster order y for the CTU.
|
||||
* @return AVERROR
|
||||
*/
|
||||
int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry);
|
||||
|
||||
//utils for vvc_intra_template
|
||||
int ff_vvc_get_top_available(const VVCLocalContext *lc, int x0, int y0, int target_size, int c_idx);
|
||||
int ff_vvc_get_left_available(const VVCLocalContext *lc, int x0, int y0, int target_size, int c_idx);
|
||||
int ff_vvc_get_mip_size_id(int w, int h);
|
||||
int ff_vvc_need_pdpc(int w, int h, uint8_t bdpcm_flag, int mode, int ref_idx);
|
||||
int ff_vvc_nscale_derive(int w, int h, int mode);
|
||||
int ff_vvc_ref_filter_flag_derive(int mode);
|
||||
int ff_vvc_intra_pred_angle_derive(int pred_mode);
|
||||
int ff_vvc_intra_inv_angle_derive(int pred_mode);
|
||||
int ff_vvc_wide_angle_mode_mapping(const CodingUnit *cu,
|
||||
int tb_width, int tb_height, int c_idx, int pred_mode_intra);
|
||||
int ff_vvc_palette_derive_scale(VVCLocalContext *lc, const TransformUnit *tu, TransformBlock *tb);
|
||||
|
||||
#endif // AVCODEC_VVC_INTRA_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* VVC intra prediction utils
|
||||
*
|
||||
* Copyright (C) 2021 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "libavutil/avassert.h"
|
||||
#include "libavutil/macros.h"
|
||||
#include "libavutil/common.h"
|
||||
#include "ctu.h"
|
||||
#include "intra.h"
|
||||
#include "ps.h"
|
||||
#include "dec.h"
|
||||
|
||||
int ff_vvc_get_mip_size_id(const int w, const int h)
|
||||
{
|
||||
if (w == 4 && h == 4)
|
||||
return 0;
|
||||
if ((w == 4 || h == 4) || (w == 8 && h == 8))
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
int ff_vvc_nscale_derive(const int w, const int h, const int mode)
|
||||
{
|
||||
int side_size, nscale;
|
||||
av_assert0(mode < INTRA_LT_CCLM && !(mode > INTRA_HORZ && mode < INTRA_VERT));
|
||||
if (mode == INTRA_PLANAR || mode == INTRA_DC ||
|
||||
mode == INTRA_HORZ || mode == INTRA_VERT) {
|
||||
nscale = (av_log2(w) + av_log2(h) - 2) >> 2;
|
||||
} else {
|
||||
const int intra_pred_angle = ff_vvc_intra_pred_angle_derive(mode);
|
||||
const int inv_angle = ff_vvc_intra_inv_angle_derive(intra_pred_angle);
|
||||
if (mode >= INTRA_VERT)
|
||||
side_size = h;
|
||||
if (mode <= INTRA_HORZ)
|
||||
side_size = w;
|
||||
nscale = FFMIN(2, av_log2(side_size) - av_log2(3 * inv_angle - 2) + 8);
|
||||
}
|
||||
return nscale;
|
||||
}
|
||||
|
||||
int ff_vvc_need_pdpc(const int w, const int h, const uint8_t bdpcm_flag, const int mode, const int ref_idx)
|
||||
{
|
||||
av_assert0(mode < INTRA_LT_CCLM);
|
||||
if ((w >= 4 && h >= 4) && !ref_idx && !bdpcm_flag) {
|
||||
int nscale;
|
||||
if (mode == INTRA_PLANAR || mode == INTRA_DC ||
|
||||
mode == INTRA_HORZ || mode == INTRA_VERT)
|
||||
return 1;
|
||||
if (mode > INTRA_HORZ && mode < INTRA_VERT)
|
||||
return 0;
|
||||
nscale = ff_vvc_nscale_derive(w, h, mode);
|
||||
return nscale >= 0;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const ReconstructedArea* get_reconstructed_area(const VVCLocalContext *lc, const int x, const int y, const int c_idx)
|
||||
{
|
||||
const int ch_type = c_idx > 0;
|
||||
for (int i = lc->num_ras[ch_type] - 1; i >= 0; i--) {
|
||||
const ReconstructedArea* a = &lc->ras[ch_type][i];
|
||||
const int r = (a->x + a->w);
|
||||
const int b = (a->y + a->h);
|
||||
if (a->x <= x && x < r && a->y <= y && y < b)
|
||||
return a;
|
||||
|
||||
//it's too far away, no need check it;
|
||||
if (x >= r && y >= b)
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ff_vvc_get_top_available(const VVCLocalContext *lc, const int x, const int y, int target_size, const int c_idx)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const int hs = sps->hshift[c_idx];
|
||||
const int vs = sps->vshift[c_idx];
|
||||
const int log2_ctb_size_v = sps->ctb_log2_size_y - vs;
|
||||
const int end_of_ctb_x = ((lc->cu->x0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y;
|
||||
const int y0b = av_zero_extend(y, log2_ctb_size_v);
|
||||
const int max_x = FFMIN(fc->ps.pps->width, end_of_ctb_x) >> hs;
|
||||
const ReconstructedArea *a;
|
||||
int px = x;
|
||||
|
||||
if (!y0b) {
|
||||
if (!lc->ctb_up_flag)
|
||||
return 0;
|
||||
target_size = FFMIN(target_size, (lc->end_of_tiles_x >> hs) - x);
|
||||
if (sps->r->sps_entropy_coding_sync_enabled_flag)
|
||||
target_size = FFMIN(target_size, (end_of_ctb_x >> hs) - x);
|
||||
return target_size;
|
||||
}
|
||||
|
||||
target_size = FFMAX(0, FFMIN(target_size, max_x - x));
|
||||
while (target_size > 0 && (a = get_reconstructed_area(lc, px, y - 1, c_idx))) {
|
||||
const int sz = FFMIN(target_size, a->x + a->w - px);
|
||||
px += sz;
|
||||
target_size -= sz;
|
||||
}
|
||||
return px - x;
|
||||
}
|
||||
|
||||
int ff_vvc_get_left_available(const VVCLocalContext *lc, const int x, const int y, int target_size, const int c_idx)
|
||||
{
|
||||
const VVCFrameContext *fc = lc->fc;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const int hs = sps->hshift[c_idx];
|
||||
const int vs = sps->vshift[c_idx];
|
||||
const int log2_ctb_size_h = sps->ctb_log2_size_y - hs;
|
||||
const int x0b = av_zero_extend(x, log2_ctb_size_h);
|
||||
const int end_of_ctb_y = ((lc->cu->y0 >> sps->ctb_log2_size_y) + 1) << sps->ctb_log2_size_y;
|
||||
const int max_y = FFMIN(fc->ps.pps->height, end_of_ctb_y) >> vs;
|
||||
const ReconstructedArea *a;
|
||||
int py = y;
|
||||
|
||||
if (!x0b && !lc->ctb_left_flag)
|
||||
return 0;
|
||||
|
||||
target_size = FFMAX(0, FFMIN(target_size, max_y - y));
|
||||
if (!x0b)
|
||||
return target_size;
|
||||
|
||||
while (target_size > 0 && (a = get_reconstructed_area(lc, x - 1, py, c_idx))) {
|
||||
const int sz = FFMIN(target_size, a->y + a->h - py);
|
||||
py += sz;
|
||||
target_size -= sz;
|
||||
}
|
||||
return py - y;
|
||||
}
|
||||
|
||||
static int less(const void *a, const void *b)
|
||||
{
|
||||
return *(const int*)a - *(const int*)b;
|
||||
}
|
||||
|
||||
int ff_vvc_ref_filter_flag_derive(const int mode)
|
||||
{
|
||||
static const int modes[] = { -14, -12, -10, -6, INTRA_PLANAR, 2, 34, 66, 72, 76, 78, 80};
|
||||
return bsearch(&mode, modes, FF_ARRAY_ELEMS(modes), sizeof(int), less) != NULL;
|
||||
}
|
||||
|
||||
int ff_vvc_intra_pred_angle_derive(const int pred_mode)
|
||||
{
|
||||
static const int angles[] = {
|
||||
0, 1, 2, 3, 4, 6, 8, 10, 12, 14, 16, 18, 20, 23, 26, 29,
|
||||
32, 35, 39, 45, 51, 57, 64, 73, 86, 102, 128, 171, 256, 341, 512
|
||||
};
|
||||
int sign = 1, idx, intra_pred_angle;
|
||||
if (pred_mode > INTRA_DIAG) {
|
||||
idx = pred_mode - INTRA_VERT;
|
||||
} else if (pred_mode > 0) {
|
||||
idx = INTRA_HORZ - pred_mode;
|
||||
} else {
|
||||
idx = INTRA_HORZ - 2 - pred_mode;
|
||||
}
|
||||
if (idx < 0) {
|
||||
idx = -idx;
|
||||
sign = -1;
|
||||
}
|
||||
intra_pred_angle = sign * angles[idx];
|
||||
return intra_pred_angle;
|
||||
}
|
||||
|
||||
int ff_vvc_intra_inv_angle_derive(const int intra_pred_angle)
|
||||
{
|
||||
av_assert2(intra_pred_angle != 0);
|
||||
if (intra_pred_angle > 0)
|
||||
return ROUNDED_DIV(32*512, intra_pred_angle);
|
||||
else
|
||||
return -ROUNDED_DIV(32*512, -intra_pred_angle);
|
||||
}
|
||||
|
||||
//8.4.5.2.7 Wide angle intra prediction mode mapping process
|
||||
int ff_vvc_wide_angle_mode_mapping(const CodingUnit *cu,
|
||||
const int tb_width, const int tb_height, const int c_idx, int pred_mode_intra)
|
||||
{
|
||||
int nw, nh, wh_ratio, min, max;
|
||||
|
||||
if (cu->isp_split_type == ISP_NO_SPLIT || c_idx) {
|
||||
nw = tb_width;
|
||||
nh = tb_height;
|
||||
} else {
|
||||
nw = cu->cb_width;
|
||||
nh = cu->cb_height;
|
||||
}
|
||||
wh_ratio = FFABS(ff_log2(nw) - ff_log2(nh));
|
||||
max = (wh_ratio > 1) ? (8 + 2 * wh_ratio) : 8;
|
||||
min = (wh_ratio > 1) ? (60 - 2 * wh_ratio) : 60;
|
||||
|
||||
if (nw > nh && pred_mode_intra >=2 && pred_mode_intra < max)
|
||||
pred_mode_intra += 65;
|
||||
else if (nh > nw && pred_mode_intra <= 66 && pred_mode_intra > min)
|
||||
pred_mode_intra -= 67;
|
||||
return pred_mode_intra;
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
/*
|
||||
* VVC 1D transform
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/* The copyright in this software is being made available under the BSD
|
||||
* License, included below. This software may be subject to other third party
|
||||
* and contributor rights, including patent rights, and no such rights are
|
||||
* granted under this license.
|
||||
*
|
||||
* Copyright (c) 2010-2021, ITU/ISO/IEC
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
|
||||
* be used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* optimizaed with partial butterfly, see Hung C-Y, Landman P (1997)
|
||||
Compact inverse discrete cosine transform circuit for MPEG video decoding.
|
||||
*/
|
||||
|
||||
#include "data.h"
|
||||
#include "itx_1d.h"
|
||||
#include "libavutil/avutil.h"
|
||||
|
||||
#define G2(m) ((nz > 2) ? (m) : 0)
|
||||
#define G4(m) ((nz > 4) ? (m) : 0)
|
||||
#define G8(m) ((nz > 8) ? (m) : 0)
|
||||
#define G16(m) ((nz > 16) ? (m) : 0)
|
||||
|
||||
/*
|
||||
transmatrix[2][2] = {
|
||||
{ a, a },
|
||||
{ a, -a },
|
||||
}
|
||||
*/
|
||||
void ff_vvc_inv_dct2_2(int *coeffs, const ptrdiff_t stride, const size_t nz)
|
||||
{
|
||||
const int a = 64;
|
||||
const int x0 = coeffs[0 * stride], x1 = coeffs[1 * stride];
|
||||
|
||||
coeffs[0 * stride] = a * (x0 + x1);
|
||||
coeffs[1 * stride] = a * (x0 - x1);
|
||||
}
|
||||
|
||||
/*
|
||||
transmatrix[4][4] = {
|
||||
{ a, a, a, a},
|
||||
{ b, c, -c, -b},
|
||||
{ a, -a, -a, a},
|
||||
{ c, -b, b, -c},
|
||||
}
|
||||
*/
|
||||
void ff_vvc_inv_dct2_4(int *coeffs, const ptrdiff_t stride, const size_t nz)
|
||||
{
|
||||
const int a = 64, b = 83, c = 36;
|
||||
const int x0 = coeffs[0 * stride], x1 = coeffs[1 * stride];
|
||||
const int x2 = coeffs[2 * stride], x3 = coeffs[3 * stride];
|
||||
const int E[2] = {
|
||||
a * (x0 + G2(+x2)),
|
||||
a * (x0 + G2(-x2)),
|
||||
};
|
||||
const int O[2] = {
|
||||
b * x1 + G2(+c * x3),
|
||||
c * x1 + G2(-b * x3),
|
||||
};
|
||||
|
||||
coeffs[0 * stride] = E[0] + O[0];
|
||||
coeffs[1 * stride] = E[1] + O[1];
|
||||
coeffs[2 * stride] = E[1] - O[1];
|
||||
coeffs[3 * stride] = E[0] - O[0];
|
||||
}
|
||||
|
||||
/*
|
||||
transmatrix[8][8] = {
|
||||
{ a, a, a, a, a, a, a, a},
|
||||
{ d, e, f, g, -g, -f, -e, -d},
|
||||
{ b, c, -c, -b, -b, -c, c, b},
|
||||
{ e, -g, -d, -f, f, d, g, -e},
|
||||
{ a, -a, -a, a, a, -a, -a, a},
|
||||
{ f, -d, g, e, -e, -g, d, -f},
|
||||
{ c, -b, b, -c, -c, b, -b, c},
|
||||
{ g, -f, e, -d, d, -e, f, -g},
|
||||
}
|
||||
*/
|
||||
void ff_vvc_inv_dct2_8(int *coeffs, const ptrdiff_t stride, const size_t nz)
|
||||
{
|
||||
const int a = 64, b = 83, c = 36, d = 89, e = 75, f = 50, g = 18;
|
||||
const int x0 = coeffs[0 * stride], x1 = coeffs[1 * stride];
|
||||
const int x2 = coeffs[2 * stride], x3 = coeffs[3 * stride];
|
||||
const int x4 = coeffs[4 * stride], x5 = coeffs[5 * stride];
|
||||
const int x6 = coeffs[6 * stride], x7 = coeffs[7 * stride];
|
||||
const int EE[2] = {
|
||||
a * (x0 + G4(+x4)),
|
||||
a * (x0 + G4(-x4)),
|
||||
};
|
||||
const int EO[2] = {
|
||||
G2(b * x2) + G4(+c * x6),
|
||||
G2(c * x2) + G4(-b * x6),
|
||||
};
|
||||
const int E[4] = {
|
||||
EE[0] + EO[0], EE[1] + EO[1],
|
||||
EE[1] - EO[1], EE[0] - EO[0],
|
||||
};
|
||||
const int O[4] = {
|
||||
d * x1 + G2(+e * x3) + G4(+f * x5 + g * x7),
|
||||
e * x1 + G2(-g * x3) + G4(-d * x5 - f * x7),
|
||||
f * x1 + G2(-d * x3) + G4(+g * x5 + e * x7),
|
||||
g * x1 + G2(-f * x3) + G4(+e * x5 - d * x7),
|
||||
};
|
||||
|
||||
coeffs[0 * stride] = E[0] + O[0];
|
||||
coeffs[1 * stride] = E[1] + O[1];
|
||||
coeffs[2 * stride] = E[2] + O[2];
|
||||
coeffs[3 * stride] = E[3] + O[3];
|
||||
coeffs[4 * stride] = E[3] - O[3];
|
||||
coeffs[5 * stride] = E[2] - O[2];
|
||||
coeffs[6 * stride] = E[1] - O[1];
|
||||
coeffs[7 * stride] = E[0] - O[0];
|
||||
}
|
||||
|
||||
/*
|
||||
transmatrix[16][16] = {
|
||||
{ a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a},
|
||||
{ h, i, j, k, l, m, n, o, -o, -n, -m, -l, -k, -j, -i, -h},
|
||||
{ d, e, f, g, -g, -f, -e, -d, -d, -e, -f, -g, g, f, e, d},
|
||||
{ i, l, o, -m, -j, -h, -k, -n, n, k, h, j, m, -o, -l, -i},
|
||||
{ b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b},
|
||||
{ j, o, -k, -i, -n, l, h, m, -m, -h, -l, n, i, k, -o, -j},
|
||||
{ e, -g, -d, -f, f, d, g, -e, -e, g, d, f, -f, -d, -g, e},
|
||||
{ k, -m, -i, o, h, n, -j, -l, l, j, -n, -h, -o, i, m, -k},
|
||||
{ a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a},
|
||||
{ l, -j, -n, h, -o, -i, m, k, -k, -m, i, o, -h, n, j, -l},
|
||||
{ f, -d, g, e, -e, -g, d, -f, -f, d, -g, -e, e, g, -d, f},
|
||||
{ m, -h, l, n, -i, k, o, -j, j, -o, -k, i, -n, -l, h, -m},
|
||||
{ c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c},
|
||||
{ n, -k, h, -j, m, o, -l, i, -i, l, -o, -m, j, -h, k, -n},
|
||||
{ g, -f, e, -d, d, -e, f, -g, -g, f, -e, d, -d, e, -f, g},
|
||||
{ o, -n, m, -l, k, -j, i, -h, h, -i, j, -k, l, -m, n, -o},
|
||||
}
|
||||
*/
|
||||
void ff_vvc_inv_dct2_16(int *coeffs, const ptrdiff_t stride, const size_t nz)
|
||||
{
|
||||
const int a = 64, b = 83, c = 36, d = 89, e = 75, f = 50, g = 18, h = 90;
|
||||
const int i = 87, j = 80, k = 70, l = 57, m = 43, n = 25, o = 9;
|
||||
const int x0 = coeffs[0 * stride], x1 = coeffs[1 * stride];
|
||||
const int x2 = coeffs[2 * stride], x3 = coeffs[3 * stride];
|
||||
const int x4 = coeffs[4 * stride], x5 = coeffs[5 * stride];
|
||||
const int x6 = coeffs[6 * stride], x7 = coeffs[7 * stride];
|
||||
const int x8 = coeffs[8 * stride], x9 = coeffs[9 * stride];
|
||||
const int x10 = coeffs[10 * stride], x11 = coeffs[11 * stride];
|
||||
const int x12 = coeffs[12 * stride], x13 = coeffs[13 * stride];
|
||||
const int x14 = coeffs[14 * stride], x15 = coeffs[15 * stride];
|
||||
const int EEE[2] = {
|
||||
a * (x0 + G8(+x8)),
|
||||
a * (x0 + G8(-x8)),
|
||||
};
|
||||
const int EEO[2] = {
|
||||
G4(b * x4) + G8(+c * x12),
|
||||
G4(c * x4) + G8(-b * x12),
|
||||
};
|
||||
const int EE[4] = {
|
||||
EEE[0] + EEO[0], EEE[1] + EEO[1],
|
||||
EEE[1] - EEO[1], EEE[0] - EEO[0],
|
||||
};
|
||||
const int EO[4] = {
|
||||
G2(d * x2) + G4(+e * x6) + G8(+f * x10 + g * x14),
|
||||
G2(e * x2) + G4(-g * x6) + G8(-d * x10 - f * x14),
|
||||
G2(f * x2) + G4(-d * x6) + G8(+g * x10 + e * x14),
|
||||
G2(g * x2) + G4(-f * x6) + G8(+e * x10 - d * x14),
|
||||
};
|
||||
const int E[8] = {
|
||||
EE[0] + EO[0], EE[1] + EO[1], EE[2] + EO[2], EE[3] + EO[3],
|
||||
EE[3] - EO[3], EE[2] - EO[2], EE[1] - EO[1], EE[0] - EO[0],
|
||||
};
|
||||
const int O[8] = {
|
||||
h * x1 + G2(+i * x3) + G4(+j * x5 + k * x7) + G8(+l * x9 + m * x11 + n * x13 + o * x15),
|
||||
i * x1 + G2(+l * x3) + G4(+o * x5 - m * x7) + G8(-j * x9 - h * x11 - k * x13 - n * x15),
|
||||
j * x1 + G2(+o * x3) + G4(-k * x5 - i * x7) + G8(-n * x9 + l * x11 + h * x13 + m * x15),
|
||||
k * x1 + G2(-m * x3) + G4(-i * x5 + o * x7) + G8(+h * x9 + n * x11 - j * x13 - l * x15),
|
||||
l * x1 + G2(-j * x3) + G4(-n * x5 + h * x7) + G8(-o * x9 - i * x11 + m * x13 + k * x15),
|
||||
m * x1 + G2(-h * x3) + G4(+l * x5 + n * x7) + G8(-i * x9 + k * x11 + o * x13 - j * x15),
|
||||
n * x1 + G2(-k * x3) + G4(+h * x5 - j * x7) + G8(+m * x9 + o * x11 - l * x13 + i * x15),
|
||||
o * x1 + G2(-n * x3) + G4(+m * x5 - l * x7) + G8(+k * x9 - j * x11 + i * x13 - h * x15),
|
||||
};
|
||||
|
||||
coeffs[0 * stride] = E[0] + O[0];
|
||||
coeffs[1 * stride] = E[1] + O[1];
|
||||
coeffs[2 * stride] = E[2] + O[2];
|
||||
coeffs[3 * stride] = E[3] + O[3];
|
||||
coeffs[4 * stride] = E[4] + O[4];
|
||||
coeffs[5 * stride] = E[5] + O[5];
|
||||
coeffs[6 * stride] = E[6] + O[6];
|
||||
coeffs[7 * stride] = E[7] + O[7];
|
||||
coeffs[8 * stride] = E[7] - O[7];
|
||||
coeffs[9 * stride] = E[6] - O[6];
|
||||
coeffs[10 * stride] = E[5] - O[5];
|
||||
coeffs[11 * stride] = E[4] - O[4];
|
||||
coeffs[12 * stride] = E[3] - O[3];
|
||||
coeffs[13 * stride] = E[2] - O[2];
|
||||
coeffs[14 * stride] = E[1] - O[1];
|
||||
coeffs[15 * stride] = E[0] - O[0];
|
||||
}
|
||||
|
||||
/*
|
||||
transMatrix[32][32] = {
|
||||
{ a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a},
|
||||
{ p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, -E, -D, -C, -B, -A, -z, -y, -x, -w, -v, -u, -t, -s, -r, -q, -p},
|
||||
{ h, i, j, k, l, m, n, o, -o, -n, -m, -l, -k, -j, -i, -h, -h, -i, -j, -k, -l, -m, -n, -o, o, n, m, l, k, j, i, h},
|
||||
{ q, t, w, z, C, -E, -B, -y, -v, -s, -p, -r, -u, -x, -A, -D, D, A, x, u, r, p, s, v, y, B, E, -C, -z, -w, -t, -q},
|
||||
{ d, e, f, g, -g, -f, -e, -d, -d, -e, -f, -g, g, f, e, d, d, e, f, g, -g, -f, -e, -d, -d, -e, -f, -g, g, f, e, d},
|
||||
{ r, w, B, -D, -y, -t, -p, -u, -z, -E, A, v, q, s, x, C, -C, -x, -s, -q, -v, -A, E, z, u, p, t, y, D, -B, -w, -r},
|
||||
{ i, l, o, -m, -j, -h, -k, -n, n, k, h, j, m, -o, -l, -i, -i, -l, -o, m, j, h, k, n, -n, -k, -h, -j, -m, o, l, i},
|
||||
{ s, z, -D, -w, -p, -v, -C, A, t, r, y, -E, -x, -q, -u, -B, B, u, q, x, E, -y, -r, -t, -A, C, v, p, w, D, -z, -s},
|
||||
{ b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b, b, c, -c, -b, -b, -c, c, b},
|
||||
{ t, C, -y, -p, -x, D, u, s, B, -z, -q, -w, E, v, r, A, -A, -r, -v, -E, w, q, z, -B, -s, -u, -D, x, p, y, -C, -t},
|
||||
{ j, o, -k, -i, -n, l, h, m, -m, -h, -l, n, i, k, -o, -j, -j, -o, k, i, n, -l, -h, -m, m, h, l, -n, -i, -k, o, j},
|
||||
{ u, -E, -t, -v, D, s, w, -C, -r, -x, B, q, y, -A, -p, -z, z, p, A, -y, -q, -B, x, r, C, -w, -s, -D, v, t, E, -u},
|
||||
{ e, -g, -d, -f, f, d, g, -e, -e, g, d, f, -f, -d, -g, e, e, -g, -d, -f, f, d, g, -e, -e, g, d, f, -f, -d, -g, e},
|
||||
{ v, -B, -p, -C, u, w, -A, -q, -D, t, x, -z, -r, -E, s, y, -y, -s, E, r, z, -x, -t, D, q, A, -w, -u, C, p, B, -v},
|
||||
{ k, -m, -i, o, h, n, -j, -l, l, j, -n, -h, -o, i, m, -k, -k, m, i, -o, -h, -n, j, l, -l, -j, n, h, o, -i, -m, k},
|
||||
{ w, -y, -u, A, s, -C, -q, E, p, D, -r, -B, t, z, -v, -x, x, v, -z, -t, B, r, -D, -p, -E, q, C, -s, -A, u, y, -w},
|
||||
{ a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a, a, -a, -a, a},
|
||||
{ x, -v, -z, t, B, -r, -D, p, -E, -q, C, s, -A, -u, y, w, -w, -y, u, A, -s, -C, q, E, -p, D, r, -B, -t, z, v, -x},
|
||||
{ l, -j, -n, h, -o, -i, m, k, -k, -m, i, o, -h, n, j, -l, -l, j, n, -h, o, i, -m, -k, k, m, -i, -o, h, -n, -j, l},
|
||||
{ y, -s, -E, r, -z, -x, t, D, -q, A, w, -u, -C, p, -B, -v, v, B, -p, C, u, -w, -A, q, -D, -t, x, z, -r, E, s, -y},
|
||||
{ f, -d, g, e, -e, -g, d, -f, -f, d, -g, -e, e, g, -d, f, f, -d, g, e, -e, -g, d, -f, -f, d, -g, -e, e, g, -d, f},
|
||||
{ z, -p, A, y, -q, B, x, -r, C, w, -s, D, v, -t, E, u, -u, -E, t, -v, -D, s, -w, -C, r, -x, -B, q, -y, -A, p, -z},
|
||||
{ m, -h, l, n, -i, k, o, -j, j, -o, -k, i, -n, -l, h, -m, -m, h, -l, -n, i, -k, -o, j, -j, o, k, -i, n, l, -h, m},
|
||||
{ A, -r, v, -E, -w, q, -z, -B, s, -u, D, x, -p, y, C, -t, t, -C, -y, p, -x, -D, u, -s, B, z, -q, w, E, -v, r, -A},
|
||||
{ c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c, c, -b, b, -c, -c, b, -b, c},
|
||||
{ B, -u, q, -x, E, y, -r, t, -A, -C, v, -p, w, -D, -z, s, -s, z, D, -w, p, -v, C, A, -t, r, -y, -E, x, -q, u, -B},
|
||||
{ n, -k, h, -j, m, o, -l, i, -i, l, -o, -m, j, -h, k, -n, -n, k, -h, j, -m, -o, l, -i, i, -l, o, m, -j, h, -k, n},
|
||||
{ C, -x, s, -q, v, -A, -E, z, -u, p, -t, y, -D, -B, w, -r, r, -w, B, D, -y, t, -p, u, -z, E, A, -v, q, -s, x, -C},
|
||||
{ g, -f, e, -d, d, -e, f, -g, -g, f, -e, d, -d, e, -f, g, g, -f, e, -d, d, -e, f, -g, -g, f, -e, d, -d, e, -f, g},
|
||||
{ D, -A, x, -u, r, -p, s, -v, y, -B, E, C, -z, w, -t, q, -q, t, -w, z, -C, -E, B, -y, v, -s, p, -r, u, -x, A, -D},
|
||||
{ o, -n, m, -l, k, -j, i, -h, h, -i, j, -k, l, -m, n, -o, -o, n, -m, l, -k, j, -i, h, -h, i, -j, k, -l, m, -n, o},
|
||||
{ E, -D, C, -B, A, -z, y, -x, w, -v, u, -t, s, -r, q, -p, p, -q, r, -s, t, -u, v, -w, x, -y, z, -A, B, -C, D, -E},
|
||||
}
|
||||
*/
|
||||
void ff_vvc_inv_dct2_32(int *coeffs, const ptrdiff_t stride, const size_t nz)
|
||||
{
|
||||
const int a = 64, b = 83, c = 36, d = 89, e = 75, f = 50, g = 18, h = 90;
|
||||
const int i = 87, j = 80, k = 70, l = 57, m = 43, n = 25, o = 9, p = 90;
|
||||
const int q = 90, r = 88, s = 85, t = 82, u = 78, v = 73, w = 67, x = 61;
|
||||
const int y = 54, z = 46, A = 38, B = 31, C = 22, D = 13, E_= 4;
|
||||
const int x0 = coeffs[0 * stride], x1 = coeffs[1 * stride];
|
||||
const int x2 = coeffs[2 * stride], x3 = coeffs[3 * stride];
|
||||
const int x4 = coeffs[4 * stride], x5 = coeffs[5 * stride];
|
||||
const int x6 = coeffs[6 * stride], x7 = coeffs[7 * stride];
|
||||
const int x8 = coeffs[8 * stride], x9 = coeffs[9 * stride];
|
||||
const int x10 = coeffs[10 * stride], x11 = coeffs[11 * stride];
|
||||
const int x12 = coeffs[12 * stride], x13 = coeffs[13 * stride];
|
||||
const int x14 = coeffs[14 * stride], x15 = coeffs[15 * stride];
|
||||
const int x16 = coeffs[16 * stride], x17 = coeffs[17 * stride];
|
||||
const int x18 = coeffs[18 * stride], x19 = coeffs[19 * stride];
|
||||
const int x20 = coeffs[20 * stride], x21 = coeffs[21 * stride];
|
||||
const int x22 = coeffs[22 * stride], x23 = coeffs[23 * stride];
|
||||
const int x24 = coeffs[24 * stride], x25 = coeffs[25 * stride];
|
||||
const int x26 = coeffs[26 * stride], x27 = coeffs[27 * stride];
|
||||
const int x28 = coeffs[28 * stride], x29 = coeffs[29 * stride];
|
||||
const int x30 = coeffs[30 * stride], x31 = coeffs[31 * stride];
|
||||
const int EEEE[2] = {
|
||||
a * (x0 + G16(+x16)),
|
||||
a * (x0 + G16(-x16)),
|
||||
};
|
||||
const int EEEO[2] = {
|
||||
G8(b * x8) + G16(+c * x24),
|
||||
G8(c * x8) + G16(-b * x24),
|
||||
};
|
||||
const int EEE[4] = {
|
||||
EEEE[0] + EEEO[0], EEEE[1] + EEEO[1],
|
||||
EEEE[1] - EEEO[1], EEEE[0] - EEEO[0],
|
||||
};
|
||||
const int EEO[4] = {
|
||||
G4(d * x4) + G8(+e * x12) + G16(+f * x20 + g * x28),
|
||||
G4(e * x4) + G8(-g * x12) + G16(-d * x20 - f * x28),
|
||||
G4(f * x4) + G8(-d * x12) + G16(+g * x20 + e * x28),
|
||||
G4(g * x4) + G8(-f * x12) + G16(+e * x20 - d * x28),
|
||||
};
|
||||
const int EE[8] = {
|
||||
EEE[0] + EEO[0], EEE[1] + EEO[1], EEE[2] + EEO[2], EEE[3] + EEO[3],
|
||||
EEE[3] - EEO[3], EEE[2] - EEO[2], EEE[1] - EEO[1], EEE[0] - EEO[0],
|
||||
};
|
||||
const int EO[8] = {
|
||||
G2(h * x2) + G4(+i * x6) + G8(+ j * x10 + k * x14) + G16(+l * x18 + m * x22 + n * x26 + o * x30),
|
||||
G2(i * x2) + G4(+l * x6) + G8(+ o * x10 - m * x14) + G16(-j * x18 - h * x22 - k * x26 - n * x30),
|
||||
G2(j * x2) + G4(+o * x6) + G8(- k * x10 - i * x14) + G16(-n * x18 + l * x22 + h * x26 + m * x30),
|
||||
G2(k * x2) + G4(-m * x6) + G8(- i * x10 + o * x14) + G16(+h * x18 + n * x22 - j * x26 - l * x30),
|
||||
G2(l * x2) + G4(-j * x6) + G8(- n * x10 + h * x14) + G16(-o * x18 - i * x22 + m * x26 + k * x30),
|
||||
G2(m * x2) + G4(-h * x6) + G8(+ l * x10 + n * x14) + G16(-i * x18 + k * x22 + o * x26 - j * x30),
|
||||
G2(n * x2) + G4(-k * x6) + G8(+ h * x10 - j * x14) + G16(+m * x18 + o * x22 - l * x26 + i * x30),
|
||||
G2(o * x2) + G4(-n * x6) + G8(+ m * x10 - l * x14) + G16(+k * x18 - j * x22 + i * x26 - h * x30),
|
||||
};
|
||||
const int E[16] = {
|
||||
EE[0] + EO[0], EE[1] + EO[1], EE[2] + EO[2], EE[3] + EO[3], EE[4] + EO[4], EE[5] + EO[5], EE[6] + EO[6], EE[7] + EO[7],
|
||||
EE[7] - EO[7], EE[6] - EO[6], EE[5] - EO[5], EE[4] - EO[4], EE[3] - EO[3], EE[2] - EO[2], EE[1] - EO[1], EE[0] - EO[0],
|
||||
};
|
||||
const int O[16] = {
|
||||
p * x1 + G2(+q * x3) + G4(+r * x5 + s * x7) + G8(+t * x9 + u * x11 + v * x13 + w * x15) + G16(+x * x17 + y * x19 + z * x21 + A * x23 + B * x25 + C * x27 + D * x29 + E_* x31),
|
||||
q * x1 + G2(+t * x3) + G4(+w * x5 + z * x7) + G8(+C * x9 - E_* x11 - B * x13 - y * x15) + G16(-v * x17 - s * x19 - p * x21 - r * x23 - u * x25 - x * x27 - A * x29 - D * x31),
|
||||
r * x1 + G2(+w * x3) + G4(+B * x5 - D * x7) + G8(-y * x9 - t * x11 - p * x13 - u * x15) + G16(-z * x17 - E_* x19 + A * x21 + v * x23 + q * x25 + s * x27 + x * x29 + C * x31),
|
||||
s * x1 + G2(+z * x3) + G4(-D * x5 - w * x7) + G8(-p * x9 - v * x11 - C * x13 + A * x15) + G16(+t * x17 + r * x19 + y * x21 - E_* x23 - x * x25 - q * x27 - u * x29 - B * x31),
|
||||
t * x1 + G2(+C * x3) + G4(-y * x5 - p * x7) + G8(-x * x9 + D * x11 + u * x13 + s * x15) + G16(+B * x17 - z * x19 - q * x21 - w * x23 + E_* x25 + v * x27 + r * x29 + A * x31),
|
||||
u * x1 + G2(-E_* x3) + G4(-t * x5 - v * x7) + G8(+D * x9 + s * x11 + w * x13 - C * x15) + G16(-r * x17 - x * x19 + B * x21 + q * x23 + y * x25 - A * x27 - p * x29 - z * x31),
|
||||
v * x1 + G2(-B * x3) + G4(-p * x5 - C * x7) + G8(+u * x9 + w * x11 - A * x13 - q * x15) + G16(-D * x17 + t * x19 + x * x21 - z * x23 - r * x25 - E_* x27 + s * x29 + y * x31),
|
||||
w * x1 + G2(-y * x3) + G4(-u * x5 + A * x7) + G8(+s * x9 - C * x11 - q * x13 + E_* x15) + G16(+p * x17 + D * x19 - r * x21 - B * x23 + t * x25 + z * x27 - v * x29 - x * x31),
|
||||
x * x1 + G2(-v * x3) + G4(-z * x5 + t * x7) + G8(+B * x9 - r * x11 - D * x13 + p * x15) + G16(-E_* x17 - q * x19 + C * x21 + s * x23 - A * x25 - u * x27 + y * x29 + w * x31),
|
||||
y * x1 + G2(-s * x3) + G4(-E_* x5 + r * x7) + G8(-z * x9 - x * x11 + t * x13 + D * x15) + G16(-q * x17 + A * x19 + w * x21 - u * x23 - C * x25 + p * x27 - B * x29 - v * x31),
|
||||
z * x1 + G2(-p * x3) + G4(+A * x5 + y * x7) + G8(-q * x9 + B * x11 + x * x13 - r * x15) + G16(+C * x17 + w * x19 - s * x21 + D * x23 + v * x25 - t * x27 + E_* x29 + u * x31),
|
||||
A * x1 + G2(-r * x3) + G4(+v * x5 - E_* x7) + G8(-w * x9 + q * x11 - z * x13 - B * x15) + G16(+s * x17 - u * x19 + D * x21 + x * x23 - p * x25 + y * x27 + C * x29 - t * x31),
|
||||
B * x1 + G2(-u * x3) + G4(+q * x5 - x * x7) + G8(+E_* x9 + y * x11 - r * x13 + t * x15) + G16(-A * x17 - C * x19 + v * x21 - p * x23 + w * x25 - D * x27 - z * x29 + s * x31),
|
||||
C * x1 + G2(-x * x3) + G4(+s * x5 - q * x7) + G8(+v * x9 - A * x11 - E_* x13 + z * x15) + G16(-u * x17 + p * x19 - t * x21 + y * x23 - D * x25 - B * x27 + w * x29 - r * x31),
|
||||
D * x1 + G2(-A * x3) + G4(+x * x5 - u * x7) + G8(+r * x9 - p * x11 + s * x13 - v * x15) + G16(+y * x17 - B * x19 + E_* x21 + C * x23 - z * x25 + w * x27 - t * x29 + q * x31),
|
||||
E_* x1 + G2(-D * x3) + G4(+C * x5 - B * x7) + G8(+A * x9 - z * x11 + y * x13 - x * x15) + G16(+w * x17 - v * x19 + u * x21 - t * x23 + s * x25 - r * x27 + q * x29 - p * x31),
|
||||
};
|
||||
|
||||
coeffs[0 * stride] = E[0] + O[0];
|
||||
coeffs[1 * stride] = E[1] + O[1];
|
||||
coeffs[2 * stride] = E[2] + O[2];
|
||||
coeffs[3 * stride] = E[3] + O[3];
|
||||
coeffs[4 * stride] = E[4] + O[4];
|
||||
coeffs[5 * stride] = E[5] + O[5];
|
||||
coeffs[6 * stride] = E[6] + O[6];
|
||||
coeffs[7 * stride] = E[7] + O[7];
|
||||
coeffs[8 * stride] = E[8] + O[8];
|
||||
coeffs[9 * stride] = E[9] + O[9];
|
||||
coeffs[10 * stride] = E[10] + O[10];
|
||||
coeffs[11 * stride] = E[11] + O[11];
|
||||
coeffs[12 * stride] = E[12] + O[12];
|
||||
coeffs[13 * stride] = E[13] + O[13];
|
||||
coeffs[14 * stride] = E[14] + O[14];
|
||||
coeffs[15 * stride] = E[15] + O[15];
|
||||
coeffs[16 * stride] = E[15] - O[15];
|
||||
coeffs[17 * stride] = E[14] - O[14];
|
||||
coeffs[18 * stride] = E[13] - O[13];
|
||||
coeffs[19 * stride] = E[12] - O[12];
|
||||
coeffs[20 * stride] = E[11] - O[11];
|
||||
coeffs[21 * stride] = E[10] - O[10];
|
||||
coeffs[22 * stride] = E[9] - O[9];
|
||||
coeffs[23 * stride] = E[8] - O[8];
|
||||
coeffs[24 * stride] = E[7] - O[7];
|
||||
coeffs[25 * stride] = E[6] - O[6];
|
||||
coeffs[26 * stride] = E[5] - O[5];
|
||||
coeffs[27 * stride] = E[4] - O[4];
|
||||
coeffs[28 * stride] = E[3] - O[3];
|
||||
coeffs[29 * stride] = E[2] - O[2];
|
||||
coeffs[30 * stride] = E[1] - O[1];
|
||||
coeffs[31 * stride] = E[0] - O[0];
|
||||
}
|
||||
|
||||
/*
|
||||
transMatrix[64][64] = {
|
||||
{ aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa, aa },
|
||||
{ bf, bg, bh, bi, bj, bk, bl, bm, bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, by, bz, ca, cb, cc, cd, ce, cf, cg, ch, ci, cj, ck, -ck, -cj, -ci, -ch, -cg, -cf, -ce, -cd, -cc, -cb, -ca, -bz, -by, -bx, -bw, -bv, -bu, -bt, -bs, -br, -bq, -bp, -bo, -bn, -bm, -bl, -bk, -bj, -bi, -bh, -bg, -bf },
|
||||
{ ap, aq, ar, as, at, au, av, aw, ax, ay, az, ba, bb, bc, bd, be, -be, -bd, -bc, -bb, -ba, -az, -ay, -ax, -aw, -av, -au, -at, -as, -ar, -aq, -ap, -ap, -aq, -ar, -as, -at, -au, -av, -aw, -ax, -ay, -az, -ba, -bb, -bc, -bd, -be, be, bd, bc, bb, ba, az, ay, ax, aw, av, au, at, as, ar, aq, ap },
|
||||
{ bg, bj, bm, bp, bs, bv, by, cb, ce, ch, ck, -ci, -cf, -cc, -bz, -bw, -bt, -bq, -bn, -bk, -bh, -bf, -bi, -bl, -bo, -br, -bu, -bx, -ca, -cd, -cg, -cj, cj, cg, cd, ca, bx, bu, br, bo, bl, bi, bf, bh, bk, bn, bq, bt, bw, bz, cc, cf, ci, -ck, -ch, -ce, -cb, -by, -bv, -bs, -bp, -bm, -bj, -bg },
|
||||
{ ah, ai, aj, ak, al, am, an, ao, -ao, -an, -am, -al, -ak, -aj, -ai, -ah, -ah, -ai, -aj, -ak, -al, -am, -an, -ao, ao, an, am, al, ak, aj, ai, ah, ah, ai, aj, ak, al, am, an, ao, -ao, -an, -am, -al, -ak, -aj, -ai, -ah, -ah, -ai, -aj, -ak, -al, -am, -an, -ao, ao, an, am, al, ak, aj, ai, ah },
|
||||
{ bh, bm, br, bw, cb, cg, -ck, -cf, -ca, -bv, -bq, -bl, -bg, -bi, -bn, -bs, -bx, -cc, -ch, cj, ce, bz, bu, bp, bk, bf, bj, bo, bt, by, cd, ci, -ci, -cd, -by, -bt, -bo, -bj, -bf, -bk, -bp, -bu, -bz, -ce, -cj, ch, cc, bx, bs, bn, bi, bg, bl, bq, bv, ca, cf, ck, -cg, -cb, -bw, -br, -bm, -bh },
|
||||
{ aq, at, aw, az, bc, -be, -bb, -ay, -av, -as, -ap, -ar, -au, -ax, -ba, -bd, bd, ba, ax, au, ar, ap, as, av, ay, bb, be, -bc, -az, -aw, -at, -aq, -aq, -at, -aw, -az, -bc, be, bb, ay, av, as, ap, ar, au, ax, ba, bd, -bd, -ba, -ax, -au, -ar, -ap, -as, -av, -ay, -bb, -be, bc, az, aw, at, aq },
|
||||
{ bi, bp, bw, cd, ck, -ce, -bx, -bq, -bj, -bh, -bo, -bv, -cc, -cj, cf, by, br, bk, bg, bn, bu, cb, ci, -cg, -bz, -bs, -bl, -bf, -bm, -bt, -ca, -ch, ch, ca, bt, bm, bf, bl, bs, bz, cg, -ci, -cb, -bu, -bn, -bg, -bk, -br, -by, -cf, cj, cc, bv, bo, bh, bj, bq, bx, ce, -ck, -cd, -bw, -bp, -bi },
|
||||
{ ad, ae, af, ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag, ag, af, ae, ad, ad, ae, af, ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag, ag, af, ae, ad, ad, ae, af, ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag, ag, af, ae, ad, ad, ae, af, ag, -ag, -af, -ae, -ad, -ad, -ae, -af, -ag, ag, af, ae, ad },
|
||||
{ bj, bs, cb, ck, -cc, -bt, -bk, -bi, -br, -ca, -cj, cd, bu, bl, bh, bq, bz, ci, -ce, -bv, -bm, -bg, -bp, -by, -ch, cf, bw, bn, bf, bo, bx, cg, -cg, -bx, -bo, -bf, -bn, -bw, -cf, ch, by, bp, bg, bm, bv, ce, -ci, -bz, -bq, -bh, -bl, -bu, -cd, cj, ca, br, bi, bk, bt, cc, -ck, -cb, -bs, -bj },
|
||||
{ ar, aw, bb, -bd, -ay, -at, -ap, -au, -az, -be, ba, av, aq, as, ax, bc, -bc, -ax, -as, -aq, -av, -ba, be, az, au, ap, at, ay, bd, -bb, -aw, -ar, -ar, -aw, -bb, bd, ay, at, ap, au, az, be, -ba, -av, -aq, -as, -ax, -bc, bc, ax, as, aq, av, ba, -be, -az, -au, -ap, -at, -ay, -bd, bb, aw, ar },
|
||||
{ bk, bv, cg, -ce, -bt, -bi, -bm, -bx, -ci, cc, br, bg, bo, bz, ck, -ca, -bp, -bf, -bq, -cb, cj, by, bn, bh, bs, cd, -ch, -bw, -bl, -bj, -bu, -cf, cf, bu, bj, bl, bw, ch, -cd, -bs, -bh, -bn, -by, -cj, cb, bq, bf, bp, ca, -ck, -bz, -bo, -bg, -br, -cc, ci, bx, bm, bi, bt, ce, -cg, -bv, -bk },
|
||||
{ ai, al, ao, -am, -aj, -ah, -ak, -an, an, ak, ah, aj, am, -ao, -al, -ai, -ai, -al, -ao, am, aj, ah, ak, an, -an, -ak, -ah, -aj, -am, ao, al, ai, ai, al, ao, -am, -aj, -ah, -ak, -an, an, ak, ah, aj, am, -ao, -al, -ai, -ai, -al, -ao, am, aj, ah, ak, an, -an, -ak, -ah, -aj, -am, ao, al, ai },
|
||||
{ bl, by, -ck, -bx, -bk, -bm, -bz, cj, bw, bj, bn, ca, -ci, -bv, -bi, -bo, -cb, ch, bu, bh, bp, cc, -cg, -bt, -bg, -bq, -cd, cf, bs, bf, br, ce, -ce, -br, -bf, -bs, -cf, cd, bq, bg, bt, cg, -cc, -bp, -bh, -bu, -ch, cb, bo, bi, bv, ci, -ca, -bn, -bj, -bw, -cj, bz, bm, bk, bx, ck, -by, -bl },
|
||||
{ as, az, -bd, -aw, -ap, -av, -bc, ba, at, ar, ay, -be, -ax, -aq, -au, -bb, bb, au, aq, ax, be, -ay, -ar, -at, -ba, bc, av, ap, aw, bd, -az, -as, -as, -az, bd, aw, ap, av, bc, -ba, -at, -ar, -ay, be, ax, aq, au, bb, -bb, -au, -aq, -ax, -be, ay, ar, at, ba, -bc, -av, -ap, -aw, -bd, az, as },
|
||||
{ bm, cb, -cf, -bq, -bi, -bx, cj, bu, bf, bt, ci, -by, -bj, -bp, -ce, cc, bn, bl, ca, -cg, -br, -bh, -bw, ck, bv, bg, bs, ch, -bz, -bk, -bo, -cd, cd, bo, bk, bz, -ch, -bs, -bg, -bv, -ck, bw, bh, br, cg, -ca, -bl, -bn, -cc, ce, bp, bj, by, -ci, -bt, -bf, -bu, -cj, bx, bi, bq, cf, -cb, -bm },
|
||||
{ ab, ac, -ac, -ab, -ab, -ac, ac, ab, ab, ac, -ac, -ab, -ab, -ac, ac, ab, ab, ac, -ac, -ab, -ab, -ac, ac, ab, ab, ac, -ac, -ab, -ab, -ac, ac, ab, ab, ac, -ac, -ab, -ab, -ac, ac, ab, ab, ac, -ac, -ab, -ab, -ac, ac, ab, ab, ac, -ac, -ab, -ab, -ac, ac, ab, ab, ac, -ac, -ab, -ab, -ac, ac, ab },
|
||||
{ bn, ce, -ca, -bj, -br, -ci, bw, bf, bv, -cj, -bs, -bi, -bz, cf, bo, bm, cd, -cb, -bk, -bq, -ch, bx, bg, bu, -ck, -bt, -bh, -by, cg, bp, bl, cc, -cc, -bl, -bp, -cg, by, bh, bt, ck, -bu, -bg, -bx, ch, bq, bk, cb, -cd, -bm, -bo, -cf, bz, bi, bs, cj, -bv, -bf, -bw, ci, br, bj, ca, -ce, -bn },
|
||||
{ at, bc, -ay, -ap, -ax, bd, au, as, bb, -az, -aq, -aw, be, av, ar, ba, -ba, -ar, -av, -be, aw, aq, az, -bb, -as, -au, -bd, ax, ap, ay, -bc, -at, -at, -bc, ay, ap, ax, -bd, -au, -as, -bb, az, aq, aw, -be, -av, -ar, -ba, ba, ar, av, be, -aw, -aq, -az, bb, as, au, bd, -ax, -ap, -ay, bc, at },
|
||||
{ bo, ch, -bv, -bh, -ca, cc, bj, bt, -cj, -bq, -bm, -cf, bx, bf, by, -ce, -bl, -br, -ck, bs, bk, cd, -bz, -bg, -bw, cg, bn, bp, ci, -bu, -bi, -cb, cb, bi, bu, -ci, -bp, -bn, -cg, bw, bg, bz, -cd, -bk, -bs, ck, br, bl, ce, -by, -bf, -bx, cf, bm, bq, cj, -bt, -bj, -cc, ca, bh, bv, -ch, -bo },
|
||||
{ aj, ao, -ak, -ai, -an, al, ah, am, -am, -ah, -al, an, ai, ak, -ao, -aj, -aj, -ao, ak, ai, an, -al, -ah, -am, am, ah, al, -an, -ai, -ak, ao, aj, aj, ao, -ak, -ai, -an, al, ah, am, -am, -ah, -al, an, ai, ak, -ao, -aj, -aj, -ao, ak, ai, an, -al, -ah, -am, am, ah, al, -an, -ai, -ak, ao, aj },
|
||||
{ bp, ck, -bq, -bo, -cj, br, bn, ci, -bs, -bm, -ch, bt, bl, cg, -bu, -bk, -cf, bv, bj, ce, -bw, -bi, -cd, bx, bh, cc, -by, -bg, -cb, bz, bf, ca, -ca, -bf, -bz, cb, bg, by, -cc, -bh, -bx, cd, bi, bw, -ce, -bj, -bv, cf, bk, bu, -cg, -bl, -bt, ch, bm, bs, -ci, -bn, -br, cj, bo, bq, -ck, -bp },
|
||||
{ au, -be, -at, -av, bd, as, aw, -bc, -ar, -ax, bb, aq, ay, -ba, -ap, -az, az, ap, ba, -ay, -aq, -bb, ax, ar, bc, -aw, -as, -bd, av, at, be, -au, -au, be, at, av, -bd, -as, -aw, bc, ar, ax, -bb, -aq, -ay, ba, ap, az, -az, -ap, -ba, ay, aq, bb, -ax, -ar, -bc, aw, as, bd, -av, -at, -be, au },
|
||||
{ bq, -ci, -bl, -bv, cd, bg, ca, -by, -bi, -cf, bt, bn, ck, -bo, -bs, cg, bj, bx, -cb, -bf, -cc, bw, bk, ch, -br, -bp, cj, bm, bu, -ce, -bh, -bz, bz, bh, ce, -bu, -bm, -cj, bp, br, -ch, -bk, -bw, cc, bf, cb, -bx, -bj, -cg, bs, bo, -ck, -bn, -bt, cf, bi, by, -ca, -bg, -cd, bv, bl, ci, -bq },
|
||||
{ ae, -ag, -ad, -af, af, ad, ag, -ae, -ae, ag, ad, af, -af, -ad, -ag, ae, ae, -ag, -ad, -af, af, ad, ag, -ae, -ae, ag, ad, af, -af, -ad, -ag, ae, ae, -ag, -ad, -af, af, ad, ag, -ae, -ae, ag, ad, af, -af, -ad, -ag, ae, ae, -ag, -ad, -af, af, ad, ag, -ae, -ae, ag, ad, af, -af, -ad, -ag, ae },
|
||||
{ br, -cf, -bg, -cc, bu, bo, -ci, -bj, -bz, bx, bl, ck, -bm, -bw, ca, bi, ch, -bp, -bt, cd, bf, ce, -bs, -bq, cg, bh, cb, -bv, -bn, cj, bk, by, -by, -bk, -cj, bn, bv, -cb, -bh, -cg, bq, bs, -ce, -bf, -cd, bt, bp, -ch, -bi, -ca, bw, bm, -ck, -bl, -bx, bz, bj, ci, -bo, -bu, cc, bg, cf, -br },
|
||||
{ av, -bb, -ap, -bc, au, aw, -ba, -aq, -bd, at, ax, -az, -ar, -be, as, ay, -ay, -as, be, ar, az, -ax, -at, bd, aq, ba, -aw, -au, bc, ap, bb, -av, -av, bb, ap, bc, -au, -aw, ba, aq, bd, -at, -ax, az, ar, be, -as, -ay, ay, as, -be, -ar, -az, ax, at, -bd, -aq, -ba, aw, au, -bc, -ap, -bb, av },
|
||||
{ bs, -cc, -bi, -cj, bl, bz, -bv, -bp, cf, bf, cg, -bo, -bw, by, bm, -ci, -bh, -cd, br, bt, -cb, -bj, -ck, bk, ca, -bu, -bq, ce, bg, ch, -bn, -bx, bx, bn, -ch, -bg, -ce, bq, bu, -ca, -bk, ck, bj, cb, -bt, -br, cd, bh, ci, -bm, -by, bw, bo, -cg, -bf, -cf, bp, bv, -bz, -bl, cj, bi, cc, -bs },
|
||||
{ ak, -am, -ai, ao, ah, an, -aj, -al, al, aj, -an, -ah, -ao, ai, am, -ak, -ak, am, ai, -ao, -ah, -an, aj, al, -al, -aj, an, ah, ao, -ai, -am, ak, ak, -am, -ai, ao, ah, an, -aj, -al, al, aj, -an, -ah, -ao, ai, am, -ak, -ak, am, ai, -ao, -ah, -an, aj, al, -al, -aj, an, ah, ao, -ai, -am, ak },
|
||||
{ bt, -bz, -bn, cf, bh, ck, -bi, -ce, bo, by, -bu, -bs, ca, bm, -cg, -bg, -cj, bj, cd, -bp, -bx, bv, br, -cb, -bl, ch, bf, ci, -bk, -cc, bq, bw, -bw, -bq, cc, bk, -ci, -bf, -ch, bl, cb, -br, -bv, bx, bp, -cd, -bj, cj, bg, cg, -bm, -ca, bs, bu, -by, -bo, ce, bi, -ck, -bh, -cf, bn, bz, -bt },
|
||||
{ aw, -ay, -au, ba, as, -bc, -aq, be, ap, bd, -ar, -bb, at, az, -av, -ax, ax, av, -az, -at, bb, ar, -bd, -ap, -be, aq, bc, -as, -ba, au, ay, -aw, -aw, ay, au, -ba, -as, bc, aq, -be, -ap, -bd, ar, bb, -at, -az, av, ax, -ax, -av, az, at, -bb, -ar, bd, ap, be, -aq, -bc, as, ba, -au, -ay, aw },
|
||||
{ bu, -bw, -bs, by, bq, -ca, -bo, cc, bm, -ce, -bk, cg, bi, -ci, -bg, ck, bf, cj, -bh, -ch, bj, cf, -bl, -cd, bn, cb, -bp, -bz, br, bx, -bt, -bv, bv, bt, -bx, -br, bz, bp, -cb, -bn, cd, bl, -cf, -bj, ch, bh, -cj, -bf, -ck, bg, ci, -bi, -cg, bk, ce, -bm, -cc, bo, ca, -bq, -by, bs, bw, -bu },
|
||||
{ aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa, aa, -aa, -aa, aa },
|
||||
{ bv, -bt, -bx, br, bz, -bp, -cb, bn, cd, -bl, -cf, bj, ch, -bh, -cj, bf, -ck, -bg, ci, bi, -cg, -bk, ce, bm, -cc, -bo, ca, bq, -by, -bs, bw, bu, -bu, -bw, bs, by, -bq, -ca, bo, cc, -bm, -ce, bk, cg, -bi, -ci, bg, ck, -bf, cj, bh, -ch, -bj, cf, bl, -cd, -bn, cb, bp, -bz, -br, bx, bt, -bv },
|
||||
{ ax, -av, -az, at, bb, -ar, -bd, ap, -be, -aq, bc, as, -ba, -au, ay, aw, -aw, -ay, au, ba, -as, -bc, aq, be, -ap, bd, ar, -bb, -at, az, av, -ax, -ax, av, az, -at, -bb, ar, bd, -ap, be, aq, -bc, -as, ba, au, -ay, -aw, aw, ay, -au, -ba, as, bc, -aq, -be, ap, -bd, -ar, bb, at, -az, -av, ax },
|
||||
{ bw, -bq, -cc, bk, ci, -bf, ch, bl, -cb, -br, bv, bx, -bp, -cd, bj, cj, -bg, cg, bm, -ca, -bs, bu, by, -bo, -ce, bi, ck, -bh, cf, bn, -bz, -bt, bt, bz, -bn, -cf, bh, -ck, -bi, ce, bo, -by, -bu, bs, ca, -bm, -cg, bg, -cj, -bj, cd, bp, -bx, -bv, br, cb, -bl, -ch, bf, -ci, -bk, cc, bq, -bw },
|
||||
{ al, -aj, -an, ah, -ao, -ai, am, ak, -ak, -am, ai, ao, -ah, an, aj, -al, -al, aj, an, -ah, ao, ai, -am, -ak, ak, am, -ai, -ao, ah, -an, -aj, al, al, -aj, -an, ah, -ao, -ai, am, ak, -ak, -am, ai, ao, -ah, an, aj, -al, -al, aj, an, -ah, ao, ai, -am, -ak, ak, am, -ai, -ao, ah, -an, -aj, al },
|
||||
{ bx, -bn, -ch, bg, -ce, -bq, bu, ca, -bk, -ck, bj, -cb, -bt, br, cd, -bh, ci, bm, -by, -bw, bo, cg, -bf, cf, bp, -bv, -bz, bl, cj, -bi, cc, bs, -bs, -cc, bi, -cj, -bl, bz, bv, -bp, -cf, bf, -cg, -bo, bw, by, -bm, -ci, bh, -cd, -br, bt, cb, -bj, ck, bk, -ca, -bu, bq, ce, -bg, ch, bn, -bx },
|
||||
{ ay, -as, -be, ar, -az, -ax, at, bd, -aq, ba, aw, -au, -bc, ap, -bb, -av, av, bb, -ap, bc, au, -aw, -ba, aq, -bd, -at, ax, az, -ar, be, as, -ay, -ay, as, be, -ar, az, ax, -at, -bd, aq, -ba, -aw, au, bc, -ap, bb, av, -av, -bb, ap, -bc, -au, aw, ba, -aq, bd, at, -ax, -az, ar, -be, -as, ay },
|
||||
{ by, -bk, cj, bn, -bv, -cb, bh, -cg, -bq, bs, ce, -bf, cd, bt, -bp, -ch, bi, -ca, -bw, bm, ck, -bl, bx, bz, -bj, ci, bo, -bu, -cc, bg, -cf, -br, br, cf, -bg, cc, bu, -bo, -ci, bj, -bz, -bx, bl, -ck, -bm, bw, ca, -bi, ch, bp, -bt, -cd, bf, -ce, -bs, bq, cg, -bh, cb, bv, -bn, -cj, bk, -by },
|
||||
{ af, -ad, ag, ae, -ae, -ag, ad, -af, -af, ad, -ag, -ae, ae, ag, -ad, af, af, -ad, ag, ae, -ae, -ag, ad, -af, -af, ad, -ag, -ae, ae, ag, -ad, af, af, -ad, ag, ae, -ae, -ag, ad, -af, -af, ad, -ag, -ae, ae, ag, -ad, af, af, -ad, ag, ae, -ae, -ag, ad, -af, -af, ad, -ag, -ae, ae, ag, -ad, af },
|
||||
{ bz, -bh, ce, bu, -bm, cj, bp, -br, -ch, bk, -bw, -cc, bf, -cb, -bx, bj, -cg, -bs, bo, ck, -bn, bt, cf, -bi, by, ca, -bg, cd, bv, -bl, ci, bq, -bq, -ci, bl, -bv, -cd, bg, -ca, -by, bi, -cf, -bt, bn, -ck, -bo, bs, cg, -bj, bx, cb, -bf, cc, bw, -bk, ch, br, -bp, -cj, bm, -bu, -ce, bh, -bz },
|
||||
{ az, -ap, ba, ay, -aq, bb, ax, -ar, bc, aw, -as, bd, av, -at, be, au, -au, -be, at, -av, -bd, as, -aw, -bc, ar, -ax, -bb, aq, -ay, -ba, ap, -az, -az, ap, -ba, -ay, aq, -bb, -ax, ar, -bc, -aw, as, -bd, -av, at, -be, -au, au, be, -at, av, bd, -as, aw, bc, -ar, ax, bb, -aq, ay, ba, -ap, az },
|
||||
{ ca, -bf, bz, cb, -bg, by, cc, -bh, bx, cd, -bi, bw, ce, -bj, bv, cf, -bk, bu, cg, -bl, bt, ch, -bm, bs, ci, -bn, br, cj, -bo, bq, ck, -bp, bp, -ck, -bq, bo, -cj, -br, bn, -ci, -bs, bm, -ch, -bt, bl, -cg, -bu, bk, -cf, -bv, bj, -ce, -bw, bi, -cd, -bx, bh, -cc, -by, bg, -cb, -bz, bf, -ca },
|
||||
{ am, -ah, al, an, -ai, ak, ao, -aj, aj, -ao, -ak, ai, -an, -al, ah, -am, -am, ah, -al, -an, ai, -ak, -ao, aj, -aj, ao, ak, -ai, an, al, -ah, am, am, -ah, al, an, -ai, ak, ao, -aj, aj, -ao, -ak, ai, -an, -al, ah, -am, -am, ah, -al, -an, ai, -ak, -ao, aj, -aj, ao, ak, -ai, an, al, -ah, am },
|
||||
{ cb, -bi, bu, ci, -bp, bn, -cg, -bw, bg, -bz, -cd, bk, -bs, -ck, br, -bl, ce, by, -bf, bx, cf, -bm, bq, -cj, -bt, bj, -cc, -ca, bh, -bv, -ch, bo, -bo, ch, bv, -bh, ca, cc, -bj, bt, cj, -bq, bm, -cf, -bx, bf, -by, -ce, bl, -br, ck, bs, -bk, cd, bz, -bg, bw, cg, -bn, bp, -ci, -bu, bi, -cb },
|
||||
{ ba, -ar, av, -be, -aw, aq, -az, -bb, as, -au, bd, ax, -ap, ay, bc, -at, at, -bc, -ay, ap, -ax, -bd, au, -as, bb, az, -aq, aw, be, -av, ar, -ba, -ba, ar, -av, be, aw, -aq, az, bb, -as, au, -bd, -ax, ap, -ay, -bc, at, -at, bc, ay, -ap, ax, bd, -au, as, -bb, -az, aq, -aw, -be, av, -ar, ba },
|
||||
{ cc, -bl, bp, -cg, -by, bh, -bt, ck, bu, -bg, bx, ch, -bq, bk, -cb, -cd, bm, -bo, cf, bz, -bi, bs, -cj, -bv, bf, -bw, -ci, br, -bj, ca, ce, -bn, bn, -ce, -ca, bj, -br, ci, bw, -bf, bv, cj, -bs, bi, -bz, -cf, bo, -bm, cd, cb, -bk, bq, -ch, -bx, bg, -bu, -ck, bt, -bh, by, cg, -bp, bl, -cc },
|
||||
{ ac, -ab, ab, -ac, -ac, ab, -ab, ac, ac, -ab, ab, -ac, -ac, ab, -ab, ac, ac, -ab, ab, -ac, -ac, ab, -ab, ac, ac, -ab, ab, -ac, -ac, ab, -ab, ac, ac, -ab, ab, -ac, -ac, ab, -ab, ac, ac, -ab, ab, -ac, -ac, ab, -ab, ac, ac, -ab, ab, -ac, -ac, ab, -ab, ac, ac, -ab, ab, -ac, -ac, ab, -ab, ac },
|
||||
{ cd, -bo, bk, -bz, -ch, bs, -bg, bv, -ck, -bw, bh, -br, cg, ca, -bl, bn, -cc, -ce, bp, -bj, by, ci, -bt, bf, -bu, cj, bx, -bi, bq, -cf, -cb, bm, -bm, cb, cf, -bq, bi, -bx, -cj, bu, -bf, bt, -ci, -by, bj, -bp, ce, cc, -bn, bl, -ca, -cg, br, -bh, bw, ck, -bv, bg, -bs, ch, bz, -bk, bo, -cd },
|
||||
{ bb, -au, aq, -ax, be, ay, -ar, at, -ba, -bc, av, -ap, aw, -bd, -az, as, -as, az, bd, -aw, ap, -av, bc, ba, -at, ar, -ay, -be, ax, -aq, au, -bb, -bb, au, -aq, ax, -be, -ay, ar, -at, ba, bc, -av, ap, -aw, bd, az, -as, as, -az, -bd, aw, -ap, av, -bc, -ba, at, -ar, ay, be, -ax, aq, -au, bb },
|
||||
{ ce, -br, bf, -bs, cf, cd, -bq, bg, -bt, cg, cc, -bp, bh, -bu, ch, cb, -bo, bi, -bv, ci, ca, -bn, bj, -bw, cj, bz, -bm, bk, -bx, ck, by, -bl, bl, -by, -ck, bx, -bk, bm, -bz, -cj, bw, -bj, bn, -ca, -ci, bv, -bi, bo, -cb, -ch, bu, -bh, bp, -cc, -cg, bt, -bg, bq, -cd, -cf, bs, -bf, br, -ce },
|
||||
{ an, -ak, ah, -aj, am, ao, -al, ai, -ai, al, -ao, -am, aj, -ah, ak, -an, -an, ak, -ah, aj, -am, -ao, al, -ai, ai, -al, ao, am, -aj, ah, -ak, an, an, -ak, ah, -aj, am, ao, -al, ai, -ai, al, -ao, -am, aj, -ah, ak, -an, -an, ak, -ah, aj, -am, -ao, al, -ai, ai, -al, ao, am, -aj, ah, -ak, an },
|
||||
{ cf, -bu, bj, -bl, bw, -ch, -cd, bs, -bh, bn, -by, cj, cb, -bq, bf, -bp, ca, ck, -bz, bo, -bg, br, -cc, -ci, bx, -bm, bi, -bt, ce, cg, -bv, bk, -bk, bv, -cg, -ce, bt, -bi, bm, -bx, ci, cc, -br, bg, -bo, bz, -ck, -ca, bp, -bf, bq, -cb, -cj, by, -bn, bh, -bs, cd, ch, -bw, bl, -bj, bu, -cf },
|
||||
{ bc, -ax, as, -aq, av, -ba, -be, az, -au, ap, -at, ay, -bd, -bb, aw, -ar, ar, -aw, bb, bd, -ay, at, -ap, au, -az, be, ba, -av, aq, -as, ax, -bc, -bc, ax, -as, aq, -av, ba, be, -az, au, -ap, at, -ay, bd, bb, -aw, ar, -ar, aw, -bb, -bd, ay, -at, ap, -au, az, -be, -ba, av, -aq, as, -ax, bc },
|
||||
{ cg, -bx, bo, -bf, bn, -bw, cf, ch, -by, bp, -bg, bm, -bv, ce, ci, -bz, bq, -bh, bl, -bu, cd, cj, -ca, br, -bi, bk, -bt, cc, ck, -cb, bs, -bj, bj, -bs, cb, -ck, -cc, bt, -bk, bi, -br, ca, -cj, -cd, bu, -bl, bh, -bq, bz, -ci, -ce, bv, -bm, bg, -bp, by, -ch, -cf, bw, -bn, bf, -bo, bx, -cg },
|
||||
{ ag, -af, ae, -ad, ad, -ae, af, -ag, -ag, af, -ae, ad, -ad, ae, -af, ag, ag, -af, ae, -ad, ad, -ae, af, -ag, -ag, af, -ae, ad, -ad, ae, -af, ag, ag, -af, ae, -ad, ad, -ae, af, -ag, -ag, af, -ae, ad, -ad, ae, -af, ag, ag, -af, ae, -ad, ad, -ae, af, -ag, -ag, af, -ae, ad, -ad, ae, -af, ag },
|
||||
{ ch, -ca, bt, -bm, bf, -bl, bs, -bz, cg, ci, -cb, bu, -bn, bg, -bk, br, -by, cf, cj, -cc, bv, -bo, bh, -bj, bq, -bx, ce, ck, -cd, bw, -bp, bi, -bi, bp, -bw, cd, -ck, -ce, bx, -bq, bj, -bh, bo, -bv, cc, -cj, -cf, by, -br, bk, -bg, bn, -bu, cb, -ci, -cg, bz, -bs, bl, -bf, bm, -bt, ca, -ch },
|
||||
{ bd, -ba, ax, -au, ar, -ap, as, -av, ay, -bb, be, bc, -az, aw, -at, aq, -aq, at, -aw, az, -bc, -be, bb, -ay, av, -as, ap, -ar, au, -ax, ba, -bd, -bd, ba, -ax, au, -ar, ap, -as, av, -ay, bb, -be, -bc, az, -aw, at, -aq, aq, -at, aw, -az, bc, be, -bb, ay, -av, as, -ap, ar, -au, ax, -ba, bd },
|
||||
{ ci, -cd, by, -bt, bo, -bj, bf, -bk, bp, -bu, bz, -ce, cj, ch, -cc, bx, -bs, bn, -bi, bg, -bl, bq, -bv, ca, -cf, ck, cg, -cb, bw, -br, bm, -bh, bh, -bm, br, -bw, cb, -cg, -ck, cf, -ca, bv, -bq, bl, -bg, bi, -bn, bs, -bx, cc, -ch, -cj, ce, -bz, bu, -bp, bk, -bf, bj, -bo, bt, -by, cd, -ci },
|
||||
{ ao, -an, am, -al, ak, -aj, ai, -ah, ah, -ai, aj, -ak, al, -am, an, -ao, -ao, an, -am, al, -ak, aj, -ai, ah, -ah, ai, -aj, ak, -al, am, -an, ao, ao, -an, am, -al, ak, -aj, ai, -ah, ah, -ai, aj, -ak, al, -am, an, -ao, -ao, an, -am, al, -ak, aj, -ai, ah, -ah, ai, -aj, ak, -al, am, -an, ao },
|
||||
{ cj, -cg, cd, -ca, bx, -bu, br, -bo, bl, -bi, bf, -bh, bk, -bn, bq, -bt, bw, -bz, cc, -cf, ci, ck, -ch, ce, -cb, by, -bv, bs, -bp, bm, -bj, bg, -bg, bj, -bm, bp, -bs, bv, -by, cb, -ce, ch, -ck, -ci, cf, -cc, bz, -bw, bt, -bq, bn, -bk, bh, -bf, bi, -bl, bo, -br, bu, -bx, ca, -cd, cg, -cj },
|
||||
{ be, -bd, bc, -bb, ba, -az, ay, -ax, aw, -av, au, -at, as, -ar, aq, -ap, ap, -aq, ar, -as, at, -au, av, -aw, ax, -ay, az, -ba, bb, -bc, bd, -be, -be, bd, -bc, bb, -ba, az, -ay, ax, -aw, av, -au, at, -as, ar, -aq, ap, -ap, aq, -ar, as, -at, au, -av, aw, -ax, ay, -az, ba, -bb, bc, -bd, be },
|
||||
{ ck, -cj, ci, -ch, cg, -cf, ce, -cd, cc, -cb, ca, -bz, by, -bx, bw, -bv, bu, -bt, bs, -br, bq, -bp, bo, -bn, bm, -bl, bk, -bj, bi, -bh, bg, -bf, bf, -bg, bh, -bi, bj, -bk, bl, -bm, bn, -bo, bp, -bq, br, -bs, bt, -bu, bv, -bw, bx, -by, bz, -ca, cb, -cc, cd, -ce, cf, -cg, ch, -ci, cj, -ck },
|
||||
}
|
||||
*/
|
||||
|
||||
void ff_vvc_inv_dct2_64(int *coeffs, const ptrdiff_t stride, const size_t nz)
|
||||
{
|
||||
const int aa = 64, ab = 83, ac = 36, ad = 89, ae = 75, af = 50, ag = 18, ah = 90;
|
||||
const int ai = 87, aj = 80, ak = 70, al = 57, am = 43, an = 25, ao = 9, ap = 90;
|
||||
const int aq = 90, ar = 88, as = 85, at = 82, au = 78, av = 73, aw = 67, ax = 61;
|
||||
const int ay = 54, az = 46, ba = 38, bb = 31, bc = 22, bd = 13, be = 4, bf = 91;
|
||||
const int bg = 90, bh = 90, bi = 90, bj = 88, bk = 87, bl = 86, bm = 84, bn = 83;
|
||||
const int bo = 81, bp = 79, bq = 77, br = 73, bs = 71, bt = 69, bu = 65, bv = 62;
|
||||
const int bw = 59, bx = 56, by = 52, bz = 48, ca = 44, cb = 41, cc = 37, cd = 33;
|
||||
const int ce = 28, cf = 24, cg = 20, ch = 15, ci = 11, cj = 7, ck = 2;
|
||||
const int x0 = coeffs[0 * stride], x1 = coeffs[1 * stride];
|
||||
const int x2 = coeffs[2 * stride], x3 = coeffs[3 * stride];
|
||||
const int x4 = coeffs[4 * stride], x5 = coeffs[5 * stride];
|
||||
const int x6 = coeffs[6 * stride], x7 = coeffs[7 * stride];
|
||||
const int x8 = coeffs[8 * stride], x9 = coeffs[9 * stride];
|
||||
const int x10 = coeffs[10 * stride], x11 = coeffs[11 * stride];
|
||||
const int x12 = coeffs[12 * stride], x13 = coeffs[13 * stride];
|
||||
const int x14 = coeffs[14 * stride], x15 = coeffs[15 * stride];
|
||||
const int x16 = coeffs[16 * stride], x17 = coeffs[17 * stride];
|
||||
const int x18 = coeffs[18 * stride], x19 = coeffs[19 * stride];
|
||||
const int x20 = coeffs[20 * stride], x21 = coeffs[21 * stride];
|
||||
const int x22 = coeffs[22 * stride], x23 = coeffs[23 * stride];
|
||||
const int x24 = coeffs[24 * stride], x25 = coeffs[25 * stride];
|
||||
const int x26 = coeffs[26 * stride], x27 = coeffs[27 * stride];
|
||||
const int x28 = coeffs[28 * stride], x29 = coeffs[29 * stride];
|
||||
const int x30 = coeffs[30 * stride], x31 = coeffs[31 * stride];
|
||||
//according to vvc specification, x31 to x63 are zeros
|
||||
const int EEEEE[2] = {
|
||||
aa * x0,
|
||||
aa * x0,
|
||||
};
|
||||
const int EEEEO[2] = {
|
||||
G16(ab * x16),
|
||||
G16(ac * x16),
|
||||
};
|
||||
const int EEEE[4] = {
|
||||
EEEEE[0] + EEEEO[0], EEEEE[1] + EEEEO[1],
|
||||
EEEEE[1] - EEEEO[1], EEEEE[0] - EEEEO[0],
|
||||
};
|
||||
const int EEEO[4] = {
|
||||
G8(ad * x8) + G16(+ae * x24),
|
||||
G8(ae * x8) + G16(-ag * x24),
|
||||
G8(af * x8) + G16(-ad * x24),
|
||||
G8(ag * x8) + G16(-af * x24),
|
||||
};
|
||||
const int EEE[8] = {
|
||||
EEEE[0] + EEEO[0], EEEE[1] + EEEO[1], EEEE[2] + EEEO[2], EEEE[3] + EEEO[3],
|
||||
EEEE[3] - EEEO[3], EEEE[2] - EEEO[2], EEEE[1] - EEEO[1], EEEE[0] - EEEO[0],
|
||||
};
|
||||
const int EEO[8] = {
|
||||
G4(ah * x4) + G8(+ai * x12) + G16(+aj * x20 + ak * x28),
|
||||
G4(ai * x4) + G8(+al * x12) + G16(+ao * x20 - am * x28),
|
||||
G4(aj * x4) + G8(+ao * x12) + G16(-ak * x20 - ai * x28),
|
||||
G4(ak * x4) + G8(-am * x12) + G16(-ai * x20 + ao * x28),
|
||||
G4(al * x4) + G8(-aj * x12) + G16(-an * x20 + ah * x28),
|
||||
G4(am * x4) + G8(-ah * x12) + G16(+al * x20 + an * x28),
|
||||
G4(an * x4) + G8(-ak * x12) + G16(+ah * x20 - aj * x28),
|
||||
G4(ao * x4) + G8(-an * x12) + G16(+am * x20 - al * x28),
|
||||
};
|
||||
const int EE[16] = {
|
||||
EEE[0] + EEO[0], EEE[1] + EEO[1], EEE[2] + EEO[2], EEE[3] + EEO[3], EEE[4] + EEO[4], EEE[5] + EEO[5], EEE[6] + EEO[6], EEE[7] + EEO[7],
|
||||
EEE[7] - EEO[7], EEE[6] - EEO[6], EEE[5] - EEO[5], EEE[4] - EEO[4], EEE[3] - EEO[3], EEE[2] - EEO[2], EEE[1] - EEO[1], EEE[0] - EEO[0],
|
||||
};
|
||||
const int EO[16] = {
|
||||
G2(ap * x2) + G4(+aq * x6) + G8(+ar * x10 + as * x14) + G16(+at * x18 + au * x22 + av * x26 + aw * x30),
|
||||
G2(aq * x2) + G4(+at * x6) + G8(+aw * x10 + az * x14) + G16(+bc * x18 - be * x22 - bb * x26 - ay * x30),
|
||||
G2(ar * x2) + G4(+aw * x6) + G8(+bb * x10 - bd * x14) + G16(-ay * x18 - at * x22 - ap * x26 - au * x30),
|
||||
G2(as * x2) + G4(+az * x6) + G8(-bd * x10 - aw * x14) + G16(-ap * x18 - av * x22 - bc * x26 + ba * x30),
|
||||
G2(at * x2) + G4(+bc * x6) + G8(-ay * x10 - ap * x14) + G16(-ax * x18 + bd * x22 + au * x26 + as * x30),
|
||||
G2(au * x2) + G4(-be * x6) + G8(-at * x10 - av * x14) + G16(+bd * x18 + as * x22 + aw * x26 - bc * x30),
|
||||
G2(av * x2) + G4(-bb * x6) + G8(-ap * x10 - bc * x14) + G16(+au * x18 + aw * x22 - ba * x26 - aq * x30),
|
||||
G2(aw * x2) + G4(-ay * x6) + G8(-au * x10 + ba * x14) + G16(+as * x18 - bc * x22 - aq * x26 + be * x30),
|
||||
G2(ax * x2) + G4(-av * x6) + G8(-az * x10 + at * x14) + G16(+bb * x18 - ar * x22 - bd * x26 + ap * x30),
|
||||
G2(ay * x2) + G4(-as * x6) + G8(-be * x10 + ar * x14) + G16(-az * x18 - ax * x22 + at * x26 + bd * x30),
|
||||
G2(az * x2) + G4(-ap * x6) + G8(+ba * x10 + ay * x14) + G16(-aq * x18 + bb * x22 + ax * x26 - ar * x30),
|
||||
G2(ba * x2) + G4(-ar * x6) + G8(+av * x10 - be * x14) + G16(-aw * x18 + aq * x22 - az * x26 - bb * x30),
|
||||
G2(bb * x2) + G4(-au * x6) + G8(+aq * x10 - ax * x14) + G16(+be * x18 + ay * x22 - ar * x26 + at * x30),
|
||||
G2(bc * x2) + G4(-ax * x6) + G8(+as * x10 - aq * x14) + G16(+av * x18 - ba * x22 - be * x26 + az * x30),
|
||||
G2(bd * x2) + G4(-ba * x6) + G8(+ax * x10 - au * x14) + G16(+ar * x18 - ap * x22 + as * x26 - av * x30),
|
||||
G2(be * x2) + G4(-bd * x6) + G8(+bc * x10 - bb * x14) + G16(+ba * x18 - az * x22 + ay * x26 - ax * x30),
|
||||
};
|
||||
const int E[32] = {
|
||||
EE[0] + EO[0], EE[1] + EO[1], EE[2] + EO[2], EE[3] + EO[3], EE[4] + EO[4], EE[5] + EO[5], EE[6] + EO[6], EE[7] + EO[7], EE[8] + EO[8], EE[9] + EO[9], EE[10] + EO[10], EE[11] + EO[11], EE[12] + EO[12], EE[13] + EO[13], EE[14] + EO[14], EE[15] + EO[15],
|
||||
EE[15] - EO[15], EE[14] - EO[14], EE[13] - EO[13], EE[12] - EO[12], EE[11] - EO[11], EE[10] - EO[10], EE[9] - EO[9], EE[8] - EO[8], EE[7] - EO[7], EE[6] - EO[6], EE[5] - EO[5], EE[4] - EO[4], EE[3] - EO[3], EE[2] - EO[2], EE[1] - EO[1], EE[0] - EO[0],
|
||||
};
|
||||
const int O[32] = {
|
||||
bf * x1 + G2(+bg * x3) + G4(+bh * x5 + bi * x7) + G8(+bj * x9 + bk * x11 + bl * x13 + bm * x15) + G16(+bn * x17 + bo * x19 + bp * x21 + bq * x23 + br * x25 + bs * x27 + bt * x29 + bu * x31),
|
||||
bg * x1 + G2(+bj * x3) + G4(+bm * x5 + bp * x7) + G8(+bs * x9 + bv * x11 + by * x13 + cb * x15) + G16(+ce * x17 + ch * x19 + ck * x21 - ci * x23 + -cf * x25 - cc * x27 - bz * x29 - bw * x31),
|
||||
bh * x1 + G2(+bm * x3) + G4(+br * x5 + bw * x7) + G8(+cb * x9 + cg * x11 - ck * x13 - cf * x15) + G16(-ca * x17 - bv * x19 - bq * x21 - bl * x23 + -bg * x25 - bi * x27 - bn * x29 - bs * x31),
|
||||
bi * x1 + G2(+bp * x3) + G4(+bw * x5 + cd * x7) + G8(+ck * x9 - ce * x11 - bx * x13 - bq * x15) + G16(-bj * x17 - bh * x19 - bo * x21 - bv * x23 + -cc * x25 - cj * x27 + cf * x29 + by * x31),
|
||||
bj * x1 + G2(+bs * x3) + G4(+cb * x5 + ck * x7) + G8(-cc * x9 - bt * x11 - bk * x13 - bi * x15) + G16(-br * x17 - ca * x19 - cj * x21 + cd * x23 + bu * x25 + bl * x27 + bh * x29 + bq * x31),
|
||||
bk * x1 + G2(+bv * x3) + G4(+cg * x5 - ce * x7) + G8(-bt * x9 - bi * x11 - bm * x13 - bx * x15) + G16(-ci * x17 + cc * x19 + br * x21 + bg * x23 + bo * x25 + bz * x27 + ck * x29 - ca * x31),
|
||||
bl * x1 + G2(+by * x3) + G4(-ck * x5 - bx * x7) + G8(-bk * x9 - bm * x11 - bz * x13 + cj * x15) + G16(+bw * x17 + bj * x19 + bn * x21 + ca * x23 + -ci * x25 - bv * x27 - bi * x29 - bo * x31),
|
||||
bm * x1 + G2(+cb * x3) + G4(-cf * x5 - bq * x7) + G8(-bi * x9 - bx * x11 + cj * x13 + bu * x15) + G16(+bf * x17 + bt * x19 + ci * x21 - by * x23 + -bj * x25 - bp * x27 - ce * x29 + cc * x31),
|
||||
bn * x1 + G2(+ce * x3) + G4(-ca * x5 - bj * x7) + G8(-br * x9 - ci * x11 + bw * x13 + bf * x15) + G16(+bv * x17 - cj * x19 - bs * x21 - bi * x23 + -bz * x25 + cf * x27 + bo * x29 + bm * x31),
|
||||
bo * x1 + G2(+ch * x3) + G4(-bv * x5 - bh * x7) + G8(-ca * x9 + cc * x11 + bj * x13 + bt * x15) + G16(-cj * x17 - bq * x19 - bm * x21 - cf * x23 + bx * x25 + bf * x27 + by * x29 - ce * x31),
|
||||
bp * x1 + G2(+ck * x3) + G4(-bq * x5 - bo * x7) + G8(-cj * x9 + br * x11 + bn * x13 + ci * x15) + G16(-bs * x17 - bm * x19 - ch * x21 + bt * x23 + bl * x25 + cg * x27 - bu * x29 - bk * x31),
|
||||
bq * x1 + G2(-ci * x3) + G4(-bl * x5 - bv * x7) + G8(+cd * x9 + bg * x11 + ca * x13 - by * x15) + G16(-bi * x17 - cf * x19 + bt * x21 + bn * x23 + ck * x25 - bo * x27 - bs * x29 + cg * x31),
|
||||
br * x1 + G2(-cf * x3) + G4(-bg * x5 - cc * x7) + G8(+bu * x9 + bo * x11 - ci * x13 - bj * x15) + G16(-bz * x17 + bx * x19 + bl * x21 + ck * x23 + -bm * x25 - bw * x27 + ca * x29 + bi * x31),
|
||||
bs * x1 + G2(-cc * x3) + G4(-bi * x5 - cj * x7) + G8(+bl * x9 + bz * x11 - bv * x13 - bp * x15) + G16(+cf * x17 + bf * x19 + cg * x21 - bo * x23 + -bw * x25 + by * x27 + bm * x29 - ci * x31),
|
||||
bt * x1 + G2(-bz * x3) + G4(-bn * x5 + cf * x7) + G8(+bh * x9 + ck * x11 - bi * x13 - ce * x15) + G16(+bo * x17 + by * x19 - bu * x21 - bs * x23 + ca * x25 + bm * x27 - cg * x29 - bg * x31),
|
||||
bu * x1 + G2(-bw * x3) + G4(-bs * x5 + by * x7) + G8(+bq * x9 - ca * x11 - bo * x13 + cc * x15) + G16(+bm * x17 - ce * x19 - bk * x21 + cg * x23 + bi * x25 - ci * x27 - bg * x29 + ck * x31),
|
||||
bv * x1 + G2(-bt * x3) + G4(-bx * x5 + br * x7) + G8(+bz * x9 - bp * x11 - cb * x13 + bn * x15) + G16(+cd * x17 - bl * x19 - cf * x21 + bj * x23 + ch * x25 - bh * x27 - cj * x29 + bf * x31),
|
||||
bw * x1 + G2(-bq * x3) + G4(-cc * x5 + bk * x7) + G8(+ci * x9 - bf * x11 + ch * x13 + bl * x15) + G16(-cb * x17 - br * x19 + bv * x21 + bx * x23 + -bp * x25 - cd * x27 + bj * x29 + cj * x31),
|
||||
bx * x1 + G2(-bn * x3) + G4(-ch * x5 + bg * x7) + G8(-ce * x9 - bq * x11 + bu * x13 + ca * x15) + G16(-bk * x17 - ck * x19 + bj * x21 - cb * x23 + -bt * x25 + br * x27 + cd * x29 - bh * x31),
|
||||
by * x1 + G2(-bk * x3) + G4(+cj * x5 + bn * x7) + G8(-bv * x9 - cb * x11 + bh * x13 - cg * x15) + G16(-bq * x17 + bs * x19 + ce * x21 - bf * x23 + cd * x25 + bt * x27 - bp * x29 - ch * x31),
|
||||
bz * x1 + G2(-bh * x3) + G4(+ce * x5 + bu * x7) + G8(-bm * x9 + cj * x11 + bp * x13 - br * x15) + G16(-ch * x17 + bk * x19 - bw * x21 - cc * x23 + bf * x25 - cb * x27 - bx * x29 + bj * x31),
|
||||
ca * x1 + G2(-bf * x3) + G4(+bz * x5 + cb * x7) + G8(-bg * x9 + by * x11 + cc * x13 - bh * x15) + G16(+bx * x17 + cd * x19 - bi * x21 + bw * x23 + ce * x25 - bj * x27 + bv * x29 + cf * x31),
|
||||
cb * x1 + G2(-bi * x3) + G4(+bu * x5 + ci * x7) + G8(-bp * x9 + bn * x11 - cg * x13 - bw * x15) + G16(+bg * x17 - bz * x19 - cd * x21 + bk * x23 + -bs * x25 - ck * x27 + br * x29 - bl * x31),
|
||||
cc * x1 + G2(-bl * x3) + G4(+bp * x5 - cg * x7) + G8(-by * x9 + bh * x11 - bt * x13 + ck * x15) + G16(+bu * x17 - bg * x19 + bx * x21 + ch * x23 + -bq * x25 + bk * x27 - cb * x29 - cd * x31),
|
||||
cd * x1 + G2(-bo * x3) + G4(+bk * x5 - bz * x7) + G8(-ch * x9 + bs * x11 - bg * x13 + bv * x15) + G16(-ck * x17 - bw * x19 + bh * x21 - br * x23 + cg * x25 + ca * x27 - bl * x29 + bn * x31),
|
||||
ce * x1 + G2(-br * x3) + G4(+bf * x5 - bs * x7) + G8(+cf * x9 + cd * x11 - bq * x13 + bg * x15) + G16(-bt * x17 + cg * x19 + cc * x21 - bp * x23 + bh * x25 - bu * x27 + ch * x29 + cb * x31),
|
||||
cf * x1 + G2(-bu * x3) + G4(+bj * x5 - bl * x7) + G8(+bw * x9 - ch * x11 - cd * x13 + bs * x15) + G16(-bh * x17 + bn * x19 - by * x21 + cj * x23 + cb * x25 - bq * x27 + bf * x29 - bp * x31),
|
||||
cg * x1 + G2(-bx * x3) + G4(+bo * x5 - bf * x7) + G8(+bn * x9 - bw * x11 + cf * x13 + ch * x15) + G16(-by * x17 + bp * x19 - bg * x21 + bm * x23 + -bv * x25 + ce * x27 + ci * x29 - bz * x31),
|
||||
ch * x1 + G2(-ca * x3) + G4(+bt * x5 - bm * x7) + G8(+bf * x9 - bl * x11 + bs * x13 - bz * x15) + G16(+cg * x17 + ci * x19 - cb * x21 + bu * x23 + -bn * x25 + bg * x27 - bk * x29 + br * x31),
|
||||
ci * x1 + G2(-cd * x3) + G4(+by * x5 - bt * x7) + G8(+bo * x9 - bj * x11 + bf * x13 - bk * x15) + G16(+bp * x17 - bu * x19 + bz * x21 - ce * x23 + cj * x25 + ch * x27 - cc * x29 + bx * x31),
|
||||
cj * x1 + G2(-cg * x3) + G4(+cd * x5 - ca * x7) + G8(+bx * x9 - bu * x11 + br * x13 - bo * x15) + G16(+bl * x17 - bi * x19 + bf * x21 - bh * x23 + bk * x25 - bn * x27 + bq * x29 - bt * x31),
|
||||
ck * x1 + G2(-cj * x3) + G4(+ci * x5 - ch * x7) + G8(+cg * x9 - cf * x11 + ce * x13 - cd * x15) + G16(+cc * x17 - cb * x19 + ca * x21 - bz * x23 + by * x25 - bx * x27 + bw * x29 - bv * x31),
|
||||
};
|
||||
coeffs[0 * stride] = E[0 ] + O[0 ];
|
||||
coeffs[1 * stride] = E[1 ] + O[1 ];
|
||||
coeffs[2 * stride] = E[2 ] + O[2 ];
|
||||
coeffs[3 * stride] = E[3 ] + O[3 ];
|
||||
coeffs[4 * stride] = E[4 ] + O[4 ];
|
||||
coeffs[5 * stride] = E[5 ] + O[5 ];
|
||||
coeffs[6 * stride] = E[6 ] + O[6 ];
|
||||
coeffs[7 * stride] = E[7 ] + O[7 ];
|
||||
coeffs[8 * stride] = E[8 ] + O[8 ];
|
||||
coeffs[9 * stride] = E[9 ] + O[9 ];
|
||||
coeffs[10 * stride] = E[10] + O[10];
|
||||
coeffs[11 * stride] = E[11] + O[11];
|
||||
coeffs[12 * stride] = E[12] + O[12];
|
||||
coeffs[13 * stride] = E[13] + O[13];
|
||||
coeffs[14 * stride] = E[14] + O[14];
|
||||
coeffs[15 * stride] = E[15] + O[15];
|
||||
coeffs[16 * stride] = E[16] + O[16];
|
||||
coeffs[17 * stride] = E[17] + O[17];
|
||||
coeffs[18 * stride] = E[18] + O[18];
|
||||
coeffs[19 * stride] = E[19] + O[19];
|
||||
coeffs[20 * stride] = E[20] + O[20];
|
||||
coeffs[21 * stride] = E[21] + O[21];
|
||||
coeffs[22 * stride] = E[22] + O[22];
|
||||
coeffs[23 * stride] = E[23] + O[23];
|
||||
coeffs[24 * stride] = E[24] + O[24];
|
||||
coeffs[25 * stride] = E[25] + O[25];
|
||||
coeffs[26 * stride] = E[26] + O[26];
|
||||
coeffs[27 * stride] = E[27] + O[27];
|
||||
coeffs[28 * stride] = E[28] + O[28];
|
||||
coeffs[29 * stride] = E[29] + O[29];
|
||||
coeffs[30 * stride] = E[30] + O[30];
|
||||
coeffs[31 * stride] = E[31] + O[31];
|
||||
coeffs[32 * stride] = E[31] - O[31];
|
||||
coeffs[33 * stride] = E[30] - O[30];
|
||||
coeffs[34 * stride] = E[29] - O[29];
|
||||
coeffs[35 * stride] = E[28] - O[28];
|
||||
coeffs[36 * stride] = E[27] - O[27];
|
||||
coeffs[37 * stride] = E[26] - O[26];
|
||||
coeffs[38 * stride] = E[25] - O[25];
|
||||
coeffs[39 * stride] = E[24] - O[24];
|
||||
coeffs[40 * stride] = E[23] - O[23];
|
||||
coeffs[41 * stride] = E[22] - O[22];
|
||||
coeffs[42 * stride] = E[21] - O[21];
|
||||
coeffs[43 * stride] = E[20] - O[20];
|
||||
coeffs[44 * stride] = E[19] - O[19];
|
||||
coeffs[45 * stride] = E[18] - O[18];
|
||||
coeffs[46 * stride] = E[17] - O[17];
|
||||
coeffs[47 * stride] = E[16] - O[16];
|
||||
coeffs[48 * stride] = E[15] - O[15];
|
||||
coeffs[49 * stride] = E[14] - O[14];
|
||||
coeffs[50 * stride] = E[13] - O[13];
|
||||
coeffs[51 * stride] = E[12] - O[12];
|
||||
coeffs[52 * stride] = E[11] - O[11];
|
||||
coeffs[53 * stride] = E[10] - O[10];
|
||||
coeffs[54 * stride] = E[9] - O[9];
|
||||
coeffs[55 * stride] = E[8] - O[8];
|
||||
coeffs[56 * stride] = E[7] - O[7];
|
||||
coeffs[57 * stride] = E[6] - O[6];
|
||||
coeffs[58 * stride] = E[5] - O[5];
|
||||
coeffs[59 * stride] = E[4] - O[4];
|
||||
coeffs[60 * stride] = E[3] - O[3];
|
||||
coeffs[61 * stride] = E[2] - O[2];
|
||||
coeffs[62 * stride] = E[1] - O[1];
|
||||
coeffs[63 * stride] = E[0] - O[0];
|
||||
}
|
||||
|
||||
static void matrix_mul(int *coeffs, const ptrdiff_t stride, const int8_t* matrix, const int size, const size_t nz)
|
||||
{
|
||||
//for dst7 and dct8, coeffs > 16 are zero out
|
||||
int tmp[16];
|
||||
|
||||
for (int i = 0; i < nz; i++)
|
||||
tmp[i] = coeffs[i * stride];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
int o = 0;
|
||||
|
||||
for (int j = 0; j < nz; j++)
|
||||
o += tmp[j] * matrix[j * size];
|
||||
*coeffs = o;
|
||||
coeffs += stride;
|
||||
matrix++;
|
||||
}
|
||||
}
|
||||
|
||||
static void inv_dct8(int *coeffs, const ptrdiff_t stride, const int8_t *matrix, const int size, const size_t nz)
|
||||
{
|
||||
matrix_mul(coeffs, stride, matrix, size, nz);
|
||||
}
|
||||
|
||||
#define DEFINE_INV_DCT8_1D(S) \
|
||||
void ff_vvc_inv_dct8_ ## S(int *coeffs, const ptrdiff_t stride, const size_t nz) \
|
||||
{ \
|
||||
inv_dct8(coeffs, stride, &ff_vvc_dct8_##S##x##S[0][0], S, nz); \
|
||||
}
|
||||
|
||||
DEFINE_INV_DCT8_1D( 4)
|
||||
DEFINE_INV_DCT8_1D( 8)
|
||||
DEFINE_INV_DCT8_1D(16)
|
||||
DEFINE_INV_DCT8_1D(32)
|
||||
|
||||
static void inv_dst7(int *coeffs, const ptrdiff_t stride, const int8_t *matrix, const int size, const size_t nz)
|
||||
{
|
||||
matrix_mul(coeffs, stride, matrix, size, nz);
|
||||
}
|
||||
|
||||
#define DEFINE_INV_DST7_1D(S) \
|
||||
void ff_vvc_inv_dst7_ ## S(int *coeffs, const ptrdiff_t stride, const size_t nz) \
|
||||
{ \
|
||||
inv_dst7(coeffs, stride, &ff_vvc_dst7_##S##x##S[0][0], S, nz); \
|
||||
}
|
||||
|
||||
DEFINE_INV_DST7_1D( 4)
|
||||
DEFINE_INV_DST7_1D( 8)
|
||||
DEFINE_INV_DST7_1D(16)
|
||||
DEFINE_INV_DST7_1D(32)
|
||||
|
||||
void ff_vvc_inv_lfnst_1d(int *v, const int *u, int no_zero_size, int n_tr_s,
|
||||
int pred_mode_intra, int lfnst_idx, int log2_transform_range)
|
||||
{
|
||||
int lfnst_tr_set_idx = pred_mode_intra < 0 ? 1 : ff_vvc_lfnst_tr_set_index[pred_mode_intra];
|
||||
const int8_t *tr_mat = n_tr_s > 16 ? ff_vvc_lfnst_8x8[lfnst_tr_set_idx][lfnst_idx-1][0] : ff_vvc_lfnst_4x4[lfnst_tr_set_idx][lfnst_idx - 1][0];
|
||||
|
||||
for (int j = 0; j < n_tr_s; j++, tr_mat++) {
|
||||
int t = 0;
|
||||
|
||||
for (int i = 0; i < no_zero_size; i++)
|
||||
t += u[i] * tr_mat[i * n_tr_s];
|
||||
v[j] = av_clip_intp2((t + 64) >> 7 , log2_transform_range);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* VVC 1D transform
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_ITX_1D_H
|
||||
#define AVCODEC_VVC_ITX_1D_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define vvc_itx_1d_fn(name) \
|
||||
void (name)(int *coeffs, ptrdiff_t stride, size_t nz)
|
||||
typedef vvc_itx_1d_fn(*vvc_itx_1d_fn);
|
||||
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct2_2);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct2_4);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct2_8);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct2_16);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct2_32);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct2_64);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dst7_4);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dst7_8);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dst7_16);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dst7_32);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct8_4);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct8_8);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct8_16);
|
||||
vvc_itx_1d_fn(ff_vvc_inv_dct8_32);
|
||||
|
||||
|
||||
void ff_vvc_inv_lfnst_1d(int *v, const int *u, int no_zero_size, int n_tr_s,
|
||||
int pred_mode_intra, int lfnst_idx, int log2_transform_range);
|
||||
|
||||
#endif // AVCODEC_VVC_ITX_1D_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* VVC motion vector decoder
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_MVS_H
|
||||
#define AVCODEC_VVC_MVS_H
|
||||
|
||||
#include "ctu.h"
|
||||
|
||||
void ff_vvc_round_mv(Mv *mv, int lshift, int rshift);
|
||||
void ff_vvc_clip_mv(Mv *mv);
|
||||
void ff_vvc_mv_scale(Mv *dst, const Mv *src, int td, int tb);
|
||||
void ff_vvc_luma_mv_merge_mode(VVCLocalContext *lc, int merge_idx, int ciip_flag, MvField *mv);
|
||||
void ff_vvc_luma_mv_merge_gpm(VVCLocalContext *lc, const int merge_gpm_idx[2], MvField *mv);
|
||||
int ff_vvc_luma_mv_merge_ibc(VVCLocalContext *lc, int merge_idx, Mv *mv);
|
||||
void ff_vvc_mvp(VVCLocalContext *lc, const int *mvp_lx_flag, const int amvr_shift, MotionInfo *mi);
|
||||
int ff_vvc_mvp_ibc(VVCLocalContext *lc, int mvp_l0_flag, int amvr_shift, Mv *mv);
|
||||
void ff_vvc_sb_mv_merge_mode(VVCLocalContext *lc, int merge_subblock_idx, PredictionUnit *pu);
|
||||
void ff_vvc_affine_mvp(VVCLocalContext *lc, const int *mvp_lx_flag, const int amvr_shift, MotionInfo* mi);
|
||||
void ff_vvc_store_sb_mvs(const VVCLocalContext *lc, PredictionUnit *pu);
|
||||
void ff_vvc_store_mv(const VVCLocalContext *lc, const MotionInfo *mi);
|
||||
void ff_vvc_store_mvf(const VVCLocalContext *lc, const MvField *mvf);
|
||||
void ff_vvc_store_gpm_mvf(const VVCLocalContext *lc, const PredictionUnit* pu);
|
||||
void ff_vvc_update_hmvp(VVCLocalContext *lc, const MotionInfo *mi);
|
||||
int ff_vvc_no_backward_pred_flag(const VVCLocalContext *lc);
|
||||
MvField* ff_vvc_get_mvf(const VVCFrameContext *fc, const int x0, const int y0);
|
||||
void ff_vvc_set_mvf(const VVCLocalContext *lc, const int x0, const int y0, const int w, const int h, const MvField *mvf);
|
||||
void ff_vvc_set_intra_mvf(const VVCLocalContext *lc, bool dmvr, PredFlag pf, bool ciip_flag);
|
||||
|
||||
#endif //AVCODEC_VVC_MVS_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* VVC parameter set parser
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_PS_H
|
||||
#define AVCODEC_VVC_PS_H
|
||||
|
||||
#include "libavcodec/cbs_h266.h"
|
||||
#include "libavcodec/vvc.h"
|
||||
|
||||
#define IS_IDR(s) ((s)->vcl_unit_type == VVC_IDR_W_RADL || (s)->vcl_unit_type == VVC_IDR_N_LP)
|
||||
#define IS_CRA(s) ((s)->vcl_unit_type == VVC_CRA_NUT)
|
||||
#define IS_IRAP(s) (IS_IDR(s) || IS_CRA(s))
|
||||
#define IS_GDR(s) ((s)->vcl_unit_type == VVC_GDR_NUT)
|
||||
#define IS_CVSS(s) (IS_IRAP(s)|| IS_GDR(s))
|
||||
#define IS_CLVSS(s) (IS_CVSS(s) && s->no_output_before_recovery_flag)
|
||||
#define IS_RASL(s) ((s)->vcl_unit_type == VVC_RASL_NUT)
|
||||
#define IS_RADL(s) ((s)->vcl_unit_type == VVC_RADL_NUT)
|
||||
|
||||
#define IS_I(rsh) ((rsh)->sh_slice_type == VVC_SLICE_TYPE_I)
|
||||
#define IS_P(rsh) ((rsh)->sh_slice_type == VVC_SLICE_TYPE_P)
|
||||
#define IS_B(rsh) ((rsh)->sh_slice_type == VVC_SLICE_TYPE_B)
|
||||
|
||||
#define INV_POC INT_MIN
|
||||
#define GDR_IS_RECOVERED(s) (s->gdr_recovery_point_poc == INV_POC)
|
||||
#define GDR_SET_RECOVERED(s) (s->gdr_recovery_point_poc = INV_POC)
|
||||
|
||||
#define LMCS_MAX_BIT_DEPTH 12
|
||||
#define LMCS_MAX_LUT_SIZE (1 << LMCS_MAX_BIT_DEPTH)
|
||||
#define LMCS_MAX_BIN_SIZE 16
|
||||
#define LADF_MAX_INTERVAL 5
|
||||
|
||||
enum {
|
||||
CHROMA_FORMAT_MONO,
|
||||
CHROMA_FORMAT_420,
|
||||
CHROMA_FORMAT_422,
|
||||
CHROMA_FORMAT_444,
|
||||
};
|
||||
|
||||
typedef struct VVCSPS {
|
||||
const H266RawSPS *r; ///< RefStruct reference
|
||||
|
||||
//derived values
|
||||
uint8_t hshift[VVC_MAX_SAMPLE_ARRAYS];
|
||||
uint8_t vshift[VVC_MAX_SAMPLE_ARRAYS];
|
||||
uint32_t max_pic_order_cnt_lsb; ///< MaxPicOrderCntLsb
|
||||
|
||||
uint8_t pixel_shift;
|
||||
enum AVPixelFormat pix_fmt;
|
||||
|
||||
uint8_t bit_depth; ///< BitDepth
|
||||
uint8_t qp_bd_offset; ///< QpBdOffset
|
||||
uint8_t ctb_log2_size_y; ///< CtbLog2SizeY
|
||||
uint16_t ctb_size_y; ///< CtbSizeY
|
||||
uint8_t min_cb_log2_size_y; ///< MinCbLog2SizeY
|
||||
uint8_t min_cb_size_y; ///< MinCbSizeY
|
||||
uint8_t max_tb_size_y; ///< MaxTbSizeY
|
||||
uint8_t max_ts_size; ///< MaxTsSize
|
||||
uint8_t max_num_merge_cand; ///< MaxNumMergeCand
|
||||
uint8_t max_num_ibc_merge_cand; ///< MaxNumIbcMergeCand
|
||||
uint8_t max_num_gpm_merge_cand; ///< MaxNumGpmMergeCand
|
||||
uint8_t num_ladf_intervals; ///< sps_num_ladf_intervals_minus2 + 2;
|
||||
uint32_t ladf_interval_lower_bound[LADF_MAX_INTERVAL]; ///< SpsLadfIntervalLowerBound[]
|
||||
uint8_t log2_parallel_merge_level; ///< sps_log2_parallel_merge_level_minus2 + 2;
|
||||
uint8_t log2_transform_range; ///< Log2TransformRange
|
||||
int8_t chroma_qp_table[3][VVC_MAX_POINTS_IN_QP_TABLE]; ///< ChromaQpTable
|
||||
} VVCSPS;
|
||||
|
||||
typedef struct DBParams {
|
||||
int8_t beta_offset[VVC_MAX_SAMPLE_ARRAYS];
|
||||
int8_t tc_offset[VVC_MAX_SAMPLE_ARRAYS];
|
||||
} DBParams;
|
||||
|
||||
typedef struct VVCPPS {
|
||||
const H266RawPPS *r; ///< RefStruct reference
|
||||
|
||||
//derived value;
|
||||
int8_t chroma_qp_offset[3]; ///< pps_cb_qp_offset, pps_cr_qp_offset, pps_joint_cbcr_qp_offset_value
|
||||
int8_t chroma_qp_offset_list[6][3]; ///< pps_cb_qp_offset_list, pps_cr_qp_offset_list, pps_joint_cbcr_qp_offset_list
|
||||
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
|
||||
uint16_t slice_start_offset[VVC_MAX_SLICES];
|
||||
uint16_t num_ctus_in_slice [VVC_MAX_SLICES];
|
||||
|
||||
uint16_t min_cb_width;
|
||||
uint16_t min_cb_height;
|
||||
|
||||
uint16_t ctb_width;
|
||||
uint16_t ctb_height;
|
||||
uint32_t ctb_count;
|
||||
|
||||
uint16_t min_pu_width;
|
||||
uint16_t min_pu_height;
|
||||
uint16_t min_tu_width;
|
||||
uint16_t min_tu_height;
|
||||
|
||||
uint32_t *ctb_addr_in_slice; ///< CtbAddrInCurrSlice for entire picture
|
||||
uint16_t *col_bd; ///< TileColBdVal
|
||||
uint16_t *row_bd; ///< TileRowBdVal
|
||||
uint16_t *ctb_to_col_bd; ///< CtbToTileColBd
|
||||
uint16_t *ctb_to_row_bd; ///< CtbToTileRowBd
|
||||
|
||||
uint16_t width32; ///< width in 32 pixels
|
||||
uint16_t height32; ///< height in 32 pixels
|
||||
uint16_t width64; ///< width in 64 pixels
|
||||
uint16_t height64; ///< height in 64 pixels
|
||||
|
||||
uint16_t ref_wraparound_offset; ///< PpsRefWraparoundOffset
|
||||
|
||||
uint16_t subpic_x[VVC_MAX_SLICES]; ///< SubpicLeftBoundaryPos
|
||||
uint16_t subpic_y[VVC_MAX_SLICES]; ///< SubpicTopBoundaryPos
|
||||
uint16_t subpic_width[VVC_MAX_SLICES];
|
||||
uint16_t subpic_height[VVC_MAX_SLICES];
|
||||
} VVCPPS;
|
||||
|
||||
#define MAX_WEIGHTS 15
|
||||
typedef struct PredWeightTable {
|
||||
uint8_t log2_denom[2]; ///< luma_log2_weight_denom, ChromaLog2WeightDenom
|
||||
|
||||
uint8_t nb_weights[2]; ///< num_l0_weights, num_l1_weights
|
||||
uint8_t weight_flag[2][2][MAX_WEIGHTS]; ///< luma_weight_l0_flag, chroma_weight_l0_flag,
|
||||
///< luma_weight_l1_flag, chroma_weight_l1_flag,
|
||||
int16_t weight[2][VVC_MAX_SAMPLE_ARRAYS][MAX_WEIGHTS]; ///< LumaWeightL0, LumaWeightL1, ChromaWeightL0, ChromaWeightL1
|
||||
int16_t offset[2][VVC_MAX_SAMPLE_ARRAYS][MAX_WEIGHTS]; ///< luma_offset_l0, luma_offset_l1, ChromaOffsetL0, ChromaOffsetL1
|
||||
} PredWeightTable;
|
||||
|
||||
typedef struct VVCPH {
|
||||
const H266RawPictureHeader *r;
|
||||
void *rref; ///< RefStruct reference, backing ph above
|
||||
|
||||
//derived values
|
||||
uint32_t max_num_subblock_merge_cand; ///< MaxNumSubblockMergeCand
|
||||
int32_t poc; ///< PicOrderCntVal
|
||||
|
||||
uint8_t num_ver_vbs; ///< NumVerVirtualBoundaries
|
||||
uint16_t vb_pos_x[VVC_MAX_VBS]; ///< VirtualBoundaryPosX
|
||||
uint8_t num_hor_vbs; ///< NumHorVirtualBoundaries
|
||||
uint16_t vb_pos_y[VVC_MAX_VBS]; ///< VirtualBoundaryPosY
|
||||
|
||||
PredWeightTable pwt;
|
||||
} VVCPH;
|
||||
|
||||
#define ALF_NUM_FILTERS_LUMA 25
|
||||
#define ALF_NUM_FILTERS_CHROMA 8
|
||||
#define ALF_NUM_FILTERS_CC 4
|
||||
|
||||
#define ALF_NUM_COEFF_LUMA 12
|
||||
#define ALF_NUM_COEFF_CHROMA 6
|
||||
#define ALF_NUM_COEFF_CC 7
|
||||
|
||||
typedef struct VVCALF {
|
||||
const H266RawAPS *r;
|
||||
int16_t luma_coeff [ALF_NUM_FILTERS_LUMA][ALF_NUM_COEFF_LUMA];
|
||||
uint8_t luma_clip_idx [ALF_NUM_FILTERS_LUMA][ALF_NUM_COEFF_LUMA];
|
||||
|
||||
uint8_t num_chroma_filters;
|
||||
int16_t chroma_coeff [ALF_NUM_FILTERS_CHROMA][ALF_NUM_COEFF_CHROMA];
|
||||
uint8_t chroma_clip_idx[ALF_NUM_FILTERS_CHROMA][ALF_NUM_COEFF_CHROMA];
|
||||
|
||||
uint8_t num_cc_filters[2]; ///< alf_cc_cb_filters_signalled_minus1 + 1, alf_cc_cr_filters_signalled_minus1 + 1
|
||||
int16_t cc_coeff[2][ALF_NUM_FILTERS_CC][ALF_NUM_COEFF_CC];
|
||||
} VVCALF;
|
||||
|
||||
enum {
|
||||
SL_START_2x2 = 0,
|
||||
SL_START_4x4 = 2,
|
||||
SL_START_8x8 = 8,
|
||||
SL_START_16x16 = 14,
|
||||
SL_START_32x32 = 20,
|
||||
SL_START_64x64 = 26,
|
||||
SL_MAX_ID = 28,
|
||||
};
|
||||
|
||||
#define SL_MAX_MATRIX_SIZE 8
|
||||
|
||||
typedef struct VVCScalingList {
|
||||
uint8_t scaling_matrix_rec[SL_MAX_ID][SL_MAX_MATRIX_SIZE * SL_MAX_MATRIX_SIZE]; ///< ScalingMatrixRec
|
||||
uint8_t scaling_matrix_dc_rec[SL_MAX_ID - SL_START_16x16]; ///< ScalingMatrixDcRec[refId − 14]
|
||||
} VVCScalingList;
|
||||
|
||||
typedef struct VVCLMCS {
|
||||
uint8_t min_bin_idx;
|
||||
uint8_t max_bin_idx;
|
||||
|
||||
union {
|
||||
uint8_t u8[LMCS_MAX_LUT_SIZE];
|
||||
uint16_t u16[LMCS_MAX_LUT_SIZE]; ///< for high bit-depth
|
||||
} fwd_lut, inv_lut;
|
||||
|
||||
uint16_t pivot[LMCS_MAX_BIN_SIZE + 1];
|
||||
uint16_t chroma_scale_coeff[LMCS_MAX_BIN_SIZE];
|
||||
} VVCLMCS;
|
||||
|
||||
#define VVC_MAX_ALF_COUNT 8
|
||||
#define VVC_MAX_LMCS_COUNT 4
|
||||
#define VVC_MAX_SL_COUNT 8
|
||||
|
||||
typedef struct VVCParamSets {
|
||||
const VVCSPS *sps_list[VVC_MAX_SPS_COUNT]; ///< RefStruct reference
|
||||
const VVCPPS *pps_list[VVC_MAX_PPS_COUNT]; ///< RefStruct reference
|
||||
const VVCALF *alf_list[VVC_MAX_ALF_COUNT]; ///< RefStruct reference
|
||||
const H266RawAPS *lmcs_list[VVC_MAX_LMCS_COUNT]; ///< RefStruct reference
|
||||
const VVCScalingList *scaling_list[VVC_MAX_SL_COUNT]; ///< RefStruct reference
|
||||
|
||||
// Bit field of SPS IDs used in the current CVS
|
||||
uint16_t sps_id_used;
|
||||
} VVCParamSets;
|
||||
|
||||
typedef struct VVCFrameParamSets {
|
||||
const VVCSPS *sps; ///< RefStruct reference
|
||||
const VVCPPS *pps; ///< RefStruct reference
|
||||
VVCPH ph;
|
||||
const VVCALF *alf_list[VVC_MAX_ALF_COUNT]; ///< RefStruct reference
|
||||
VVCLMCS lmcs;
|
||||
const VVCScalingList *sl; ///< RefStruct reference
|
||||
} VVCFrameParamSets;
|
||||
|
||||
typedef struct VVCSH {
|
||||
const H266RawSliceHeader *r; ///< RefStruct reference
|
||||
|
||||
// derived values
|
||||
// ctu address
|
||||
uint32_t num_ctus_in_curr_slice; ///< NumCtusInCurrSlice
|
||||
const uint32_t* ctb_addr_in_curr_slice; ///< CtbAddrInCurrSlice
|
||||
|
||||
// inter
|
||||
PredWeightTable pwt;
|
||||
int8_t ref_idx_sym[2]; ///< RefIdxSymL0, RefIdxSymL1
|
||||
|
||||
// qp_y
|
||||
int8_t slice_qp_y; ///< SliceQpY
|
||||
|
||||
// deblock_offsets
|
||||
DBParams deblock;
|
||||
|
||||
// partition constrains
|
||||
uint8_t min_qt_size[2]; ///< MinQtSizeY, MinQtSizeC
|
||||
uint8_t max_bt_size[2]; ///< MaxBtSizeY, MaxBtSizeC
|
||||
uint8_t max_tt_size[2]; ///< MaxTtSizeY, MaxTtSizeC
|
||||
uint8_t max_mtt_depth[2]; ///< MaxMttDepthY, MaxMttDepthC
|
||||
uint8_t cu_qp_delta_subdiv; ///< CuQpDeltaSubdiv
|
||||
uint8_t cu_chroma_qp_offset_subdiv; ///< CuChromaQpOffsetSubdiv
|
||||
|
||||
// entries
|
||||
uint32_t entry_point_start_ctu[VVC_MAX_ENTRY_POINTS]; ///< entry point start in ctu_addr
|
||||
} VVCSH;
|
||||
|
||||
struct VVCContext;
|
||||
|
||||
int ff_vvc_decode_frame_ps(VVCFrameParamSets *fps, struct VVCContext *s);
|
||||
int ff_vvc_decode_aps(VVCParamSets *ps, const CodedBitstreamUnit *unit);
|
||||
int ff_vvc_decode_sh(VVCSH *sh, const VVCFrameParamSets *ps, const CodedBitstreamUnit *unit);
|
||||
void ff_vvc_frame_ps_free(VVCFrameParamSets *fps);
|
||||
void ff_vvc_ps_uninit(VVCParamSets *ps);
|
||||
|
||||
#endif /* AVCODEC_VVC_PS_H */
|
||||
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
* VVC reference management
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/thread.h"
|
||||
#include "libavutil/refstruct.h"
|
||||
#include "libavcodec/thread.h"
|
||||
#include "libavcodec/decode.h"
|
||||
|
||||
#include "refs.h"
|
||||
|
||||
|
||||
typedef struct FrameProgress {
|
||||
atomic_int progress[VVC_PROGRESS_LAST];
|
||||
VVCProgressListener *listener[VVC_PROGRESS_LAST];
|
||||
AVMutex lock;
|
||||
AVCond cond;
|
||||
uint8_t has_lock;
|
||||
uint8_t has_cond;
|
||||
} FrameProgress;
|
||||
|
||||
void ff_vvc_unref_frame(VVCFrameContext *fc, VVCFrame *frame, int flags)
|
||||
{
|
||||
/* frame->frame can be NULL if context init failed */
|
||||
if (!frame->frame || !frame->frame->buf[0])
|
||||
return;
|
||||
|
||||
frame->flags &= ~flags;
|
||||
if (!(frame->flags & ~VVC_FRAME_FLAG_CORRUPT))
|
||||
frame->flags = 0;
|
||||
if (!frame->flags) {
|
||||
av_frame_unref(frame->frame);
|
||||
|
||||
if (frame->needs_fg) {
|
||||
av_frame_unref(frame->frame_grain);
|
||||
frame->needs_fg = 0;
|
||||
}
|
||||
|
||||
av_refstruct_unref(&frame->sps);
|
||||
av_refstruct_unref(&frame->pps);
|
||||
av_refstruct_unref(&frame->progress);
|
||||
|
||||
av_refstruct_unref(&frame->tab_dmvr_mvf);
|
||||
|
||||
av_refstruct_unref(&frame->rpl);
|
||||
frame->nb_rpl_elems = 0;
|
||||
av_refstruct_unref(&frame->rpl_tab);
|
||||
|
||||
frame->collocated_ref = NULL;
|
||||
av_refstruct_unref(&frame->hwaccel_picture_private);
|
||||
}
|
||||
}
|
||||
|
||||
const RefPicList *ff_vvc_get_ref_list(const VVCFrameContext *fc, const VVCFrame *ref, int x0, int y0)
|
||||
{
|
||||
const int x_cb = x0 >> fc->ps.sps->ctb_log2_size_y;
|
||||
const int y_cb = y0 >> fc->ps.sps->ctb_log2_size_y;
|
||||
const int pic_width_cb = fc->ps.pps->ctb_width;
|
||||
const int ctb_addr_rs = y_cb * pic_width_cb + x_cb;
|
||||
|
||||
return (const RefPicList *)ref->rpl_tab[ctb_addr_rs];
|
||||
}
|
||||
|
||||
void ff_vvc_clear_refs(VVCFrameContext *fc)
|
||||
{
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++)
|
||||
ff_vvc_unref_frame(fc, &fc->DPB[i],
|
||||
VVC_FRAME_FLAG_SHORT_REF | VVC_FRAME_FLAG_LONG_REF);
|
||||
}
|
||||
|
||||
void ff_vvc_flush_dpb(VVCFrameContext *fc)
|
||||
{
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++)
|
||||
ff_vvc_unref_frame(fc, &fc->DPB[i], ~0);
|
||||
}
|
||||
|
||||
static void free_progress(AVRefStructOpaque unused, void *obj)
|
||||
{
|
||||
FrameProgress *p = (FrameProgress *)obj;
|
||||
|
||||
if (p->has_cond)
|
||||
ff_cond_destroy(&p->cond);
|
||||
if (p->has_lock)
|
||||
ff_mutex_destroy(&p->lock);
|
||||
}
|
||||
|
||||
static FrameProgress *alloc_progress(void)
|
||||
{
|
||||
FrameProgress *p = av_refstruct_alloc_ext(sizeof(*p), 0, NULL, free_progress);
|
||||
|
||||
if (p) {
|
||||
p->has_lock = !ff_mutex_init(&p->lock, NULL);
|
||||
p->has_cond = !ff_cond_init(&p->cond, NULL);
|
||||
if (!p->has_lock || !p->has_cond)
|
||||
av_refstruct_unref(&p);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static VVCFrame *alloc_frame(VVCContext *s, VVCFrameContext *fc)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const VVCPPS *pps = fc->ps.pps;
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
int ret;
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
VVCWindow *win = &frame->scaling_win;
|
||||
if (frame->frame->buf[0])
|
||||
continue;
|
||||
|
||||
frame->sps = av_refstruct_ref_c(fc->ps.sps);
|
||||
frame->pps = av_refstruct_ref_c(fc->ps.pps);
|
||||
|
||||
ret = ff_thread_get_buffer(s->avctx, frame->frame, AV_GET_BUFFER_FLAG_REF);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
frame->rpl = av_refstruct_allocz(s->current_frame.nb_units * sizeof(RefPicListTab));
|
||||
if (!frame->rpl)
|
||||
goto fail;
|
||||
frame->nb_rpl_elems = s->current_frame.nb_units;
|
||||
|
||||
frame->tab_dmvr_mvf = av_refstruct_pool_get(fc->tab_dmvr_mvf_pool);
|
||||
if (!frame->tab_dmvr_mvf)
|
||||
goto fail;
|
||||
|
||||
frame->rpl_tab = av_refstruct_pool_get(fc->rpl_tab_pool);
|
||||
if (!frame->rpl_tab)
|
||||
goto fail;
|
||||
frame->ctb_count = pps->ctb_width * pps->ctb_height;
|
||||
for (int j = 0; j < frame->ctb_count; j++)
|
||||
frame->rpl_tab[j] = frame->rpl;
|
||||
|
||||
win->left_offset = pps->r->pps_scaling_win_left_offset * (1 << sps->hshift[CHROMA]);
|
||||
win->right_offset = pps->r->pps_scaling_win_right_offset * (1 << sps->hshift[CHROMA]);
|
||||
win->top_offset = pps->r->pps_scaling_win_top_offset * (1 << sps->vshift[CHROMA]);
|
||||
win->bottom_offset = pps->r->pps_scaling_win_bottom_offset * (1 << sps->vshift[CHROMA]);
|
||||
frame->ref_width = pps->r->pps_pic_width_in_luma_samples - win->left_offset - win->right_offset;
|
||||
frame->ref_height = pps->r->pps_pic_height_in_luma_samples - win->bottom_offset - win->top_offset;
|
||||
|
||||
if (fc->sei.frame_field_info.present) {
|
||||
if (fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD)
|
||||
frame->frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRST;
|
||||
if (fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_TOP_FIELD ||
|
||||
fc->sei.frame_field_info.picture_struct == AV_PICTURE_STRUCTURE_BOTTOM_FIELD)
|
||||
frame->frame->flags |= AV_FRAME_FLAG_INTERLACED;
|
||||
}
|
||||
|
||||
frame->progress = alloc_progress();
|
||||
if (!frame->progress)
|
||||
goto fail;
|
||||
|
||||
ret = ff_hwaccel_frame_priv_alloc(s->avctx, &frame->hwaccel_picture_private);
|
||||
if (ret < 0)
|
||||
goto fail;
|
||||
|
||||
return frame;
|
||||
fail:
|
||||
ff_vvc_unref_frame(fc, frame, ~0);
|
||||
return NULL;
|
||||
}
|
||||
av_log(s->avctx, AV_LOG_ERROR, "Error allocating frame, DPB full.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void set_pict_type(AVFrame *frame, const VVCContext *s, const VVCFrameContext *fc)
|
||||
{
|
||||
bool has_b = false, has_inter = false;
|
||||
|
||||
if (IS_IRAP(s)) {
|
||||
frame->pict_type = AV_PICTURE_TYPE_I;
|
||||
frame->flags |= AV_FRAME_FLAG_KEY;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fc->ps.ph.r->ph_inter_slice_allowed_flag) {
|
||||
// At this point, fc->slices is not fully initialized; we need to inspect the CBS directly.
|
||||
const CodedBitstreamFragment *current = &s->current_frame;
|
||||
for (int i = 0; i < current->nb_units && !has_b; i++) {
|
||||
const CodedBitstreamUnit *unit = current->units + i;
|
||||
if (unit->content_ref && unit->type <= VVC_RSV_IRAP_11) {
|
||||
const H266RawSliceHeader *rsh = unit->content_ref;
|
||||
has_inter |= !IS_I(rsh);
|
||||
has_b |= IS_B(rsh);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!has_inter)
|
||||
frame->pict_type = AV_PICTURE_TYPE_I;
|
||||
else if (has_b)
|
||||
frame->pict_type = AV_PICTURE_TYPE_B;
|
||||
else
|
||||
frame->pict_type = AV_PICTURE_TYPE_P;
|
||||
}
|
||||
|
||||
int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, AVFrame **frame)
|
||||
{
|
||||
const VVCPH *ph= &fc->ps.ph;
|
||||
const int poc = ph->poc;
|
||||
VVCFrame *ref;
|
||||
|
||||
/* check that this POC doesn't already exist */
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
|
||||
if (frame->frame->buf[0] && frame->sequence == s->seq_decode &&
|
||||
frame->poc == poc) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "Duplicate POC in a sequence: %d.\n", poc);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
}
|
||||
|
||||
ref = alloc_frame(s, fc);
|
||||
if (!ref)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
set_pict_type(ref->frame, s, fc);
|
||||
*frame = ref->frame;
|
||||
fc->ref = ref;
|
||||
|
||||
if (s->no_output_before_recovery_flag && (IS_RASL(s) || !GDR_IS_RECOVERED(s)))
|
||||
ref->flags = VVC_FRAME_FLAG_SHORT_REF;
|
||||
else if (ph->r->ph_pic_output_flag)
|
||||
ref->flags = VVC_FRAME_FLAG_OUTPUT | VVC_FRAME_FLAG_SHORT_REF;
|
||||
|
||||
if (!ph->r->ph_non_ref_pic_flag)
|
||||
ref->flags |= VVC_FRAME_FLAG_SHORT_REF;
|
||||
|
||||
ref->poc = poc;
|
||||
ref->sequence = s->seq_decode;
|
||||
ref->frame->crop_left = fc->ps.pps->r->pps_conf_win_left_offset << fc->ps.sps->hshift[CHROMA];
|
||||
ref->frame->crop_right = fc->ps.pps->r->pps_conf_win_right_offset << fc->ps.sps->hshift[CHROMA];
|
||||
ref->frame->crop_top = fc->ps.pps->r->pps_conf_win_top_offset << fc->ps.sps->vshift[CHROMA];
|
||||
ref->frame->crop_bottom = fc->ps.pps->r->pps_conf_win_bottom_offset << fc->ps.sps->vshift[CHROMA];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_vvc_output_frame(VVCContext *s, VVCFrameContext *fc, AVFrame *out, const int no_output_of_prior_pics_flag, int flush)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
do {
|
||||
int nb_output = 0;
|
||||
int min_poc = INT_MAX;
|
||||
int min_idx, ret;
|
||||
|
||||
if (no_output_of_prior_pics_flag) {
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
if (!(frame->flags & VVC_FRAME_FLAG_BUMPING) && frame->poc != fc->ps.ph.poc &&
|
||||
frame->sequence == s->seq_output) {
|
||||
ff_vvc_unref_frame(fc, frame, VVC_FRAME_FLAG_OUTPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
if ((frame->flags & VVC_FRAME_FLAG_OUTPUT) &&
|
||||
frame->sequence == s->seq_output) {
|
||||
nb_output++;
|
||||
if (frame->poc < min_poc || nb_output == 1) {
|
||||
min_poc = frame->poc;
|
||||
min_idx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* wait for more frames before output */
|
||||
if (!flush && s->seq_output == s->seq_decode && sps &&
|
||||
nb_output <= sps->r->sps_dpb_params.dpb_max_num_reorder_pics[sps->r->sps_max_sublayers_minus1])
|
||||
return 0;
|
||||
|
||||
if (nb_output) {
|
||||
VVCFrame *frame = &fc->DPB[min_idx];
|
||||
|
||||
if (frame->flags & VVC_FRAME_FLAG_CORRUPT)
|
||||
frame->frame->flags |= AV_FRAME_FLAG_CORRUPT;
|
||||
|
||||
ret = av_frame_ref(out, frame->needs_fg ? frame->frame_grain : frame->frame);
|
||||
|
||||
if (!ret && !(s->avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))
|
||||
av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
|
||||
|
||||
if (frame->flags & VVC_FRAME_FLAG_BUMPING)
|
||||
ff_vvc_unref_frame(fc, frame, VVC_FRAME_FLAG_OUTPUT | VVC_FRAME_FLAG_BUMPING);
|
||||
else
|
||||
ff_vvc_unref_frame(fc, frame, VVC_FRAME_FLAG_OUTPUT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
av_log(s->avctx, AV_LOG_DEBUG,
|
||||
"Output frame with POC %d.\n", frame->poc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (s->seq_output != s->seq_decode)
|
||||
s->seq_output = (s->seq_output + 1) & 0xff;
|
||||
else
|
||||
break;
|
||||
} while (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ff_vvc_bump_frame(VVCContext *s, VVCFrameContext *fc)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const int poc = fc->ps.ph.poc;
|
||||
int dpb = 0;
|
||||
int min_poc = INT_MAX;
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
if ((frame->flags) &&
|
||||
frame->sequence == s->seq_output &&
|
||||
frame->poc != poc) {
|
||||
dpb++;
|
||||
}
|
||||
}
|
||||
|
||||
if (sps && dpb >= sps->r->sps_dpb_params.dpb_max_dec_pic_buffering_minus1[sps->r->sps_max_sublayers_minus1] + 1) {
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
if ((frame->flags) &&
|
||||
frame->sequence == s->seq_output &&
|
||||
frame->poc != poc) {
|
||||
if (frame->flags == VVC_FRAME_FLAG_OUTPUT && frame->poc < min_poc) {
|
||||
min_poc = frame->poc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
if (frame->flags & VVC_FRAME_FLAG_OUTPUT &&
|
||||
frame->sequence == s->seq_output &&
|
||||
frame->poc <= min_poc) {
|
||||
frame->flags |= VVC_FRAME_FLAG_BUMPING;
|
||||
}
|
||||
}
|
||||
|
||||
dpb--;
|
||||
}
|
||||
}
|
||||
|
||||
static VVCFrame *find_ref_idx(VVCContext *s, VVCFrameContext *fc, int poc, uint8_t use_msb)
|
||||
{
|
||||
const unsigned mask = use_msb ? ~0 : fc->ps.sps->max_pic_order_cnt_lsb - 1;
|
||||
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *ref = &fc->DPB[i];
|
||||
if (ref->frame->buf[0] && ref->sequence == s->seq_decode) {
|
||||
if ((ref->poc & mask) == poc)
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void mark_ref(VVCFrame *frame, int flag)
|
||||
{
|
||||
frame->flags &= ~(VVC_FRAME_FLAG_LONG_REF | VVC_FRAME_FLAG_SHORT_REF);
|
||||
frame->flags |= flag;
|
||||
}
|
||||
|
||||
static VVCFrame *generate_missing_ref(VVCContext *s, VVCFrameContext *fc, int poc)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const VVCPPS *pps = fc->ps.pps;
|
||||
VVCFrame *frame;
|
||||
|
||||
frame = alloc_frame(s, fc);
|
||||
if (!frame)
|
||||
return NULL;
|
||||
|
||||
if (!s->avctx->hwaccel) {
|
||||
if (!sps->pixel_shift) {
|
||||
for (int i = 0; frame->frame->buf[i]; i++)
|
||||
memset(frame->frame->buf[i]->data, 1 << (sps->bit_depth - 1),
|
||||
frame->frame->buf[i]->size);
|
||||
} else {
|
||||
for (int i = 0; frame->frame->data[i]; i++)
|
||||
for (int y = 0; y < (pps->height >> sps->vshift[i]); y++) {
|
||||
uint8_t *dst = frame->frame->data[i] + y * frame->frame->linesize[i];
|
||||
AV_WN16(dst, 1 << (sps->bit_depth - 1));
|
||||
av_memcpy_backptr(dst + 2, 2, 2*(pps->width >> sps->hshift[i]) - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frame->poc = poc;
|
||||
frame->sequence = s->seq_decode;
|
||||
frame->flags = VVC_FRAME_FLAG_CORRUPT;
|
||||
|
||||
ff_vvc_report_frame_finished(frame);
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
#define CHECK_MAX(d) (frame->ref_##d * frame->sps->r->sps_pic_##d##_max_in_luma_samples >= ref->ref_##d * (frame->pps->r->pps_pic_##d##_in_luma_samples - max))
|
||||
#define CHECK_SAMPLES(d) (frame->pps->r->pps_pic_##d##_in_luma_samples == ref->pps->r->pps_pic_##d##_in_luma_samples)
|
||||
static int check_candidate_ref(const VVCFrame *frame, const VVCRefPic *refp)
|
||||
{
|
||||
const VVCFrame *ref = refp->ref;
|
||||
|
||||
if (refp->is_scaled) {
|
||||
const int max = FFMAX(8, frame->sps->min_cb_size_y);
|
||||
return frame->ref_width * 2 >= ref->ref_width &&
|
||||
frame->ref_height * 2 >= ref->ref_height &&
|
||||
frame->ref_width <= ref->ref_width * 8 &&
|
||||
frame->ref_height <= ref->ref_height * 8 &&
|
||||
CHECK_MAX(width) && CHECK_MAX(height);
|
||||
}
|
||||
return CHECK_SAMPLES(width) && CHECK_SAMPLES(height);
|
||||
}
|
||||
|
||||
#define RPR_SCALE(f) (((ref->f << 14) + (fc->ref->f >> 1)) / fc->ref->f)
|
||||
/* add a reference with the given poc to the list and mark it as used in DPB */
|
||||
static int add_candidate_ref(VVCContext *s, VVCFrameContext *fc, RefPicList *list,
|
||||
int poc, int ref_flag, uint8_t use_msb)
|
||||
{
|
||||
VVCFrame *ref = find_ref_idx(s, fc, poc, use_msb);
|
||||
VVCRefPic *refp = &list->refs[list->nb_refs];
|
||||
|
||||
if (ref == fc->ref || list->nb_refs >= VVC_MAX_REF_ENTRIES)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if (!IS_CVSS(s)) {
|
||||
const bool ref_corrupt = !ref || (ref->flags & VVC_FRAME_FLAG_CORRUPT);
|
||||
const bool recovering = s->no_output_before_recovery_flag && !GDR_IS_RECOVERED(s);
|
||||
|
||||
if (ref_corrupt && !recovering) {
|
||||
if (!(s->avctx->flags & AV_CODEC_FLAG_OUTPUT_CORRUPT) &&
|
||||
!(s->avctx->flags2 & AV_CODEC_FLAG2_SHOW_ALL))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
fc->ref->flags |= VVC_FRAME_FLAG_CORRUPT;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ref) {
|
||||
ref = generate_missing_ref(s, fc, poc);
|
||||
if (!ref)
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
refp->poc = poc;
|
||||
refp->ref = ref;
|
||||
refp->is_lt = ref_flag & VVC_FRAME_FLAG_LONG_REF;
|
||||
refp->is_scaled = ref->sps->r->sps_num_subpics_minus1 != fc->ref->sps->r->sps_num_subpics_minus1||
|
||||
memcmp(&ref->scaling_win, &fc->ref->scaling_win, sizeof(ref->scaling_win)) ||
|
||||
ref->pps->r->pps_pic_width_in_luma_samples != fc->ref->pps->r->pps_pic_width_in_luma_samples ||
|
||||
ref->pps->r->pps_pic_height_in_luma_samples != fc->ref->pps->r->pps_pic_height_in_luma_samples;
|
||||
|
||||
if (!check_candidate_ref(fc->ref, refp))
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
if (refp->is_scaled) {
|
||||
refp->scale[0] = RPR_SCALE(ref_width);
|
||||
refp->scale[1] = RPR_SCALE(ref_height);
|
||||
}
|
||||
list->nb_refs++;
|
||||
|
||||
mark_ref(ref, ref_flag);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_slice_rpl(const VVCFrameContext *fc, SliceContext *sc)
|
||||
{
|
||||
VVCFrame *frame = fc->ref;
|
||||
const VVCSH *sh = &sc->sh;
|
||||
|
||||
if (sc->slice_idx >= frame->nb_rpl_elems)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
for (int i = 0; i < sh->num_ctus_in_curr_slice; i++) {
|
||||
const int rs = sh->ctb_addr_in_curr_slice[i];
|
||||
frame->rpl_tab[rs] = frame->rpl + sc->slice_idx;
|
||||
}
|
||||
|
||||
sc->rpl = frame->rpl_tab[sh->ctb_addr_in_curr_slice[0]]->refPicList;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delta_poc_st(const H266RefPicListStruct *rpls,
|
||||
const int lx, const int i, const VVCSPS *sps)
|
||||
{
|
||||
int abs_delta_poc_st = rpls->abs_delta_poc_st[i];
|
||||
if (!((sps->r->sps_weighted_pred_flag ||
|
||||
sps->r->sps_weighted_bipred_flag) && i != 0))
|
||||
abs_delta_poc_st++;
|
||||
return (1 - 2 * rpls->strp_entry_sign_flag[i]) * abs_delta_poc_st;
|
||||
}
|
||||
|
||||
static int poc_lt(int *prev_delta_poc_msb, const int poc, const H266RefPicLists *ref_lists,
|
||||
const int lx, const int j, const int max_poc_lsb)
|
||||
{
|
||||
const H266RefPicListStruct *rpls = ref_lists->rpl_ref_list + lx;
|
||||
int lt_poc = rpls->ltrp_in_header_flag ? ref_lists->poc_lsb_lt[lx][j] : rpls->rpls_poc_lsb_lt[j];
|
||||
|
||||
if (ref_lists->delta_poc_msb_cycle_present_flag[lx][j]) {
|
||||
const uint32_t delta = ref_lists->delta_poc_msb_cycle_lt[lx][j] + *prev_delta_poc_msb;
|
||||
lt_poc += poc - delta * max_poc_lsb - (poc & (max_poc_lsb - 1));
|
||||
*prev_delta_poc_msb = delta;
|
||||
}
|
||||
return lt_poc;
|
||||
}
|
||||
|
||||
int ff_vvc_slice_rpl(VVCContext *s, VVCFrameContext *fc, SliceContext *sc)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const H266RawPPS *pps = fc->ps.pps->r;
|
||||
const VVCPH *ph = &fc->ps.ph;
|
||||
const H266RawSliceHeader *rsh = sc->sh.r;
|
||||
const int max_poc_lsb = sps->max_pic_order_cnt_lsb;
|
||||
const H266RefPicLists *ref_lists =
|
||||
pps->pps_rpl_info_in_ph_flag ? &ph->r->ph_ref_pic_lists : &rsh->sh_ref_pic_lists;
|
||||
int ret = 0;
|
||||
|
||||
ret = init_slice_rpl(fc, sc);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (int lx = L0; lx <= L1; lx++) {
|
||||
const H266RefPicListStruct *rpls = ref_lists->rpl_ref_list + lx;
|
||||
RefPicList *rpl = sc->rpl + lx;
|
||||
int poc_base = ph->poc;
|
||||
int prev_delta_poc_msb = 0;
|
||||
|
||||
rpl->nb_refs = 0;
|
||||
for (int i = 0, j = 0; i < rpls->num_ref_entries; i++) {
|
||||
int poc;
|
||||
if (!rpls->inter_layer_ref_pic_flag[i]) {
|
||||
int use_msb = 1;
|
||||
int ref_flag;
|
||||
if (rpls->st_ref_pic_flag[i]) {
|
||||
poc = poc_base + delta_poc_st(rpls, lx, i, sps);
|
||||
poc_base = poc;
|
||||
ref_flag = VVC_FRAME_FLAG_SHORT_REF;
|
||||
} else {
|
||||
use_msb = ref_lists->delta_poc_msb_cycle_present_flag[lx][j];
|
||||
poc = poc_lt(&prev_delta_poc_msb, ph->poc, ref_lists, lx, j, max_poc_lsb);
|
||||
ref_flag = VVC_FRAME_FLAG_LONG_REF;
|
||||
j++;
|
||||
}
|
||||
ret = add_candidate_ref(s, fc, rpl, poc, ref_flag, use_msb);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
// OPI_B_3.bit and VPS_A_3.bit should cover this
|
||||
avpriv_report_missing_feature(fc->log_ctx, "Inter layer ref");
|
||||
ret = AVERROR_PATCHWELCOME;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
if (ph->r->ph_temporal_mvp_enabled_flag &&
|
||||
(!rsh->sh_collocated_from_l0_flag) == lx &&
|
||||
rsh->sh_collocated_ref_idx < rpl->nb_refs) {
|
||||
const VVCRefPic *refp = rpl->refs + rsh->sh_collocated_ref_idx;
|
||||
if (refp->is_scaled || refp->ref->sps->ctb_log2_size_y != sps->ctb_log2_size_y)
|
||||
return AVERROR_INVALIDDATA;
|
||||
fc->ref->collocated_ref = refp->ref;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_vvc_frame_rpl(VVCContext *s, VVCFrameContext *fc, SliceContext *sc)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* clear the reference flags on all frames except the current one */
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++) {
|
||||
VVCFrame *frame = &fc->DPB[i];
|
||||
|
||||
if (frame == fc->ref)
|
||||
continue;
|
||||
|
||||
mark_ref(frame, 0);
|
||||
}
|
||||
|
||||
if ((ret = ff_vvc_slice_rpl(s, fc, sc)) < 0)
|
||||
goto fail;
|
||||
|
||||
fail:
|
||||
/* release any frames that are now unused */
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(fc->DPB); i++)
|
||||
ff_vvc_unref_frame(fc, &fc->DPB[i], 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ff_vvc_report_frame_finished(VVCFrame *frame)
|
||||
{
|
||||
ff_vvc_report_progress(frame, VVC_PROGRESS_MV, INT_MAX);
|
||||
ff_vvc_report_progress(frame, VVC_PROGRESS_PIXEL, INT_MAX);
|
||||
}
|
||||
|
||||
static int is_progress_done(const FrameProgress *p, const VVCProgressListener *l)
|
||||
{
|
||||
return p->progress[l->vp] > l->y;
|
||||
}
|
||||
|
||||
static void add_listener(VVCProgressListener **prev, VVCProgressListener *l)
|
||||
{
|
||||
l->next = *prev;
|
||||
*prev = l;
|
||||
}
|
||||
|
||||
static VVCProgressListener* remove_listener(VVCProgressListener **prev, VVCProgressListener *l)
|
||||
{
|
||||
*prev = l->next;
|
||||
l->next = NULL;
|
||||
return l;
|
||||
}
|
||||
|
||||
static VVCProgressListener* get_done_listener(FrameProgress *p, const VVCProgress vp)
|
||||
{
|
||||
VVCProgressListener *list = NULL;
|
||||
VVCProgressListener **prev = &p->listener[vp];
|
||||
|
||||
while (*prev) {
|
||||
if (is_progress_done(p, *prev)) {
|
||||
VVCProgressListener *l = remove_listener(prev, *prev);
|
||||
add_listener(&list, l);
|
||||
} else {
|
||||
prev = &(*prev)->next;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void ff_vvc_report_progress(VVCFrame *frame, const VVCProgress vp, const int y)
|
||||
{
|
||||
FrameProgress *p = frame->progress;
|
||||
VVCProgressListener *l = NULL;
|
||||
|
||||
ff_mutex_lock(&p->lock);
|
||||
if (p->progress[vp] < y) {
|
||||
// Due to the nature of thread scheduling, later progress may reach this point before earlier progress.
|
||||
// Therefore, we only update the progress when p->progress[vp] < y.
|
||||
p->progress[vp] = y;
|
||||
l = get_done_listener(p, vp);
|
||||
ff_cond_signal(&p->cond);
|
||||
}
|
||||
ff_mutex_unlock(&p->lock);
|
||||
|
||||
while (l) {
|
||||
l->progress_done(l);
|
||||
l = l->next;
|
||||
}
|
||||
}
|
||||
|
||||
void ff_vvc_add_progress_listener(VVCFrame *frame, VVCProgressListener *l)
|
||||
{
|
||||
FrameProgress *p = frame->progress;
|
||||
|
||||
ff_mutex_lock(&p->lock);
|
||||
|
||||
if (is_progress_done(p, l)) {
|
||||
ff_mutex_unlock(&p->lock);
|
||||
l->progress_done(l);
|
||||
} else {
|
||||
add_listener(p->listener + l->vp, l);
|
||||
ff_mutex_unlock(&p->lock);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* VVC reference management
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_REFS_H
|
||||
#define AVCODEC_VVC_REFS_H
|
||||
|
||||
#include "dec.h"
|
||||
|
||||
#define VVC_FRAME_FLAG_OUTPUT (1 << 0)
|
||||
#define VVC_FRAME_FLAG_SHORT_REF (1 << 1)
|
||||
#define VVC_FRAME_FLAG_LONG_REF (1 << 2)
|
||||
#define VVC_FRAME_FLAG_BUMPING (1 << 3)
|
||||
#define VVC_FRAME_FLAG_CORRUPT (1 << 4)
|
||||
|
||||
int ff_vvc_output_frame(VVCContext *s, VVCFrameContext *fc, struct AVFrame *out, int no_output_of_prior_pics_flag, int flush);
|
||||
void ff_vvc_bump_frame(VVCContext *s, VVCFrameContext *fc);
|
||||
int ff_vvc_set_new_ref(VVCContext *s, VVCFrameContext *fc, struct AVFrame **frame);
|
||||
const RefPicList *ff_vvc_get_ref_list(const VVCFrameContext *fc, const VVCFrame *ref, int x0, int y0);
|
||||
int ff_vvc_frame_rpl(VVCContext *s, VVCFrameContext *fc, SliceContext *sc);
|
||||
int ff_vvc_slice_rpl(VVCContext *s, VVCFrameContext *fc, SliceContext *sc);
|
||||
void ff_vvc_unref_frame(VVCFrameContext *fc, VVCFrame *frame, int flags);
|
||||
void ff_vvc_clear_refs(VVCFrameContext *fc);
|
||||
void ff_vvc_flush_dpb(VVCFrameContext *fc);
|
||||
|
||||
typedef enum VVCProgress {
|
||||
VVC_PROGRESS_MV,
|
||||
VVC_PROGRESS_PIXEL,
|
||||
VVC_PROGRESS_LAST,
|
||||
} VVCProgress;
|
||||
|
||||
typedef struct VVCProgressListener VVCProgressListener;
|
||||
typedef void (*progress_done_fn)(VVCProgressListener *l);
|
||||
|
||||
struct VVCProgressListener {
|
||||
VVCProgress vp;
|
||||
int y;
|
||||
progress_done_fn progress_done;
|
||||
VVCProgressListener *next; //used by ff_vvc_add_progress_listener only
|
||||
};
|
||||
|
||||
void ff_vvc_report_frame_finished(VVCFrame *frame);
|
||||
void ff_vvc_report_progress(VVCFrame *frame, VVCProgress vp, int y);
|
||||
void ff_vvc_add_progress_listener(VVCFrame *frame, VVCProgressListener *l);
|
||||
|
||||
#endif // AVCODEC_VVC_REFS_H
|
||||
@@ -0,0 +1,254 @@
|
||||
/*
|
||||
* VVC Supplementary Enhancement Information messages
|
||||
*
|
||||
* copyright (c) 2024 Wu Jianhua <toqsxw@outlook.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "sei.h"
|
||||
#include "dec.h"
|
||||
#include "libavutil/refstruct.h"
|
||||
|
||||
static int decode_film_grain_characteristics(H2645SEIFilmGrainCharacteristics *h, const SEIRawFilmGrainCharacteristics *s, const VVCFrameContext *fc)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
|
||||
h->present = !s->fg_characteristics_cancel_flag;
|
||||
if (h->present) {
|
||||
h->model_id = s->fg_model_id;
|
||||
h->separate_colour_description_present_flag = s->fg_separate_colour_description_present_flag;
|
||||
if (h->separate_colour_description_present_flag) {
|
||||
h->bit_depth_luma = s->fg_bit_depth_luma_minus8 + 8;
|
||||
h->bit_depth_chroma = s->fg_bit_depth_chroma_minus8 + 8;
|
||||
h->full_range = s->fg_full_range_flag;
|
||||
h->color_primaries = s->fg_colour_primaries;
|
||||
h->transfer_characteristics = s->fg_transfer_characteristics;
|
||||
h->matrix_coeffs = s->fg_matrix_coeffs;
|
||||
} else {
|
||||
if (!sps) {
|
||||
av_log(fc->log_ctx, AV_LOG_ERROR,
|
||||
"No active SPS for film_grain_characteristics.\n");
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
h->bit_depth_luma = sps->bit_depth;
|
||||
h->bit_depth_chroma = sps->bit_depth;
|
||||
h->full_range = sps->r->vui.vui_full_range_flag;
|
||||
h->color_primaries = sps->r->vui.vui_colour_primaries;
|
||||
h->transfer_characteristics = sps->r->vui.vui_transfer_characteristics;
|
||||
h->matrix_coeffs = sps->r->vui.vui_matrix_coeffs ;
|
||||
}
|
||||
|
||||
h->blending_mode_id = s->fg_blending_mode_id;
|
||||
h->log2_scale_factor = s->fg_log2_scale_factor;
|
||||
|
||||
for (int c = 0; c < 3; c++) {
|
||||
h->comp_model_present_flag[c] = s->fg_comp_model_present_flag[c];
|
||||
if (h->comp_model_present_flag[c]) {
|
||||
h->num_intensity_intervals[c] = s->fg_num_intensity_intervals_minus1[c] + 1;
|
||||
h->num_model_values[c] = s->fg_num_model_values_minus1[c] + 1;
|
||||
|
||||
if (h->num_model_values[c] > 6)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
for (int i = 0; i < h->num_intensity_intervals[c]; i++) {
|
||||
h->intensity_interval_lower_bound[c][i] = s->fg_intensity_interval_lower_bound[c][i];
|
||||
h->intensity_interval_upper_bound[c][i] = s->fg_intensity_interval_upper_bound[c][i];
|
||||
for (int j = 0; j < h->num_model_values[c]; j++)
|
||||
h->comp_model_value[c][i][j] = s->fg_comp_model_value[c][i][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h->persistence_flag = s->fg_characteristics_persistence_flag;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_decoded_picture_hash(H274SEIPictureHash *h, const SEIRawDecodedPictureHash *s)
|
||||
{
|
||||
h->present = 1;
|
||||
h->hash_type = s->dph_sei_hash_type;
|
||||
if (h->hash_type == 0)
|
||||
memcpy(h->md5, s->dph_sei_picture_md5, sizeof(h->md5));
|
||||
else if (h->hash_type == 1)
|
||||
memcpy(h->crc, s->dph_sei_picture_crc, sizeof(h->crc));
|
||||
else if (h->hash_type == 2)
|
||||
memcpy(h->checksum, s->dph_sei_picture_checksum, sizeof(h->checksum));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_display_orientation(H2645SEIDisplayOrientation *h, const SEIRawDisplayOrientation *s)
|
||||
{
|
||||
int degrees[] = { 0, 0x8000, 0x4000, 0xC000 };
|
||||
|
||||
h->present = !s->display_orientation_cancel_flag;
|
||||
if (h->present) {
|
||||
if (s->display_orientation_transform_type > 7)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
h->vflip = 0;
|
||||
if (s->display_orientation_transform_type == 1 ||
|
||||
s->display_orientation_transform_type == 3 ||
|
||||
s->display_orientation_transform_type == 4 ||
|
||||
s->display_orientation_transform_type == 6) {
|
||||
h->hflip = 1;
|
||||
} else {
|
||||
h->hflip = 0;
|
||||
}
|
||||
h->anticlockwise_rotation = degrees[s->display_orientation_transform_type >> 1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_content_light_level_info(H2645SEIContentLight *h, const SEIRawContentLightLevelInfo *s)
|
||||
{
|
||||
h->present = 1;
|
||||
h->max_content_light_level = s->max_content_light_level;
|
||||
h->max_pic_average_light_level = s->max_pic_average_light_level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_frame_field_info(H274SEIFrameFieldInfo *h, const SEIRawFrameFieldInformation *s)
|
||||
{
|
||||
if (s->ffi_source_scan_type > 3)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
h->present = 1;
|
||||
if (s->ffi_field_pic_flag) {
|
||||
if (s->ffi_bottom_field_flag)
|
||||
h->picture_struct = AV_PICTURE_STRUCTURE_BOTTOM_FIELD;
|
||||
else
|
||||
h->picture_struct = AV_PICTURE_STRUCTURE_TOP_FIELD;
|
||||
} else {
|
||||
h->display_elemental_periods = s->ffi_display_elemental_periods_minus1 + 1;
|
||||
}
|
||||
|
||||
h->source_scan_type = s->ffi_source_scan_type;
|
||||
h->duplicate_flag = s->ffi_duplicate_flag;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_ambient_viewing_environment(H2645SEIAmbientViewingEnvironment *h, const SEIRawAmbientViewingEnvironment *s)
|
||||
{
|
||||
h->present = 1;
|
||||
h->ambient_illuminance = s->ambient_illuminance;
|
||||
h->ambient_light_x = s->ambient_light_x;
|
||||
h->ambient_light_y = s->ambient_light_y;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int decode_mastering_display_colour_volume(H2645SEIMasteringDisplay *h, const SEIRawMasteringDisplayColourVolume *s)
|
||||
{
|
||||
h->present = 1;
|
||||
|
||||
for (int c = 0; c < 3; c++) {
|
||||
h->display_primaries[c][0] = s->display_primaries_x[c];
|
||||
h->display_primaries[c][1] = s->display_primaries_y[c];
|
||||
}
|
||||
|
||||
h->white_point[0] = s->white_point_x;
|
||||
h->white_point[1] = s->white_point_y;
|
||||
|
||||
h->max_luminance = s->max_display_mastering_luminance;
|
||||
h->min_luminance = s->min_display_mastering_luminance;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_vvc_sei_decode(VVCSEI *s, const H266RawSEI *sei, const struct VVCFrameContext *fc)
|
||||
{
|
||||
H2645SEI *c = &s->common;
|
||||
|
||||
if (!sei)
|
||||
return AVERROR_INVALIDDATA;
|
||||
|
||||
for (int i = 0; i < sei->message_list.nb_messages; i++) {
|
||||
int ret = 0;
|
||||
SEIRawMessage *message = &sei->message_list.messages[i];
|
||||
void *payload = message->payload;
|
||||
|
||||
switch (message->payload_type) {
|
||||
case SEI_TYPE_FILM_GRAIN_CHARACTERISTICS:
|
||||
av_refstruct_unref(&c->film_grain_characteristics);
|
||||
c->film_grain_characteristics = av_refstruct_allocz(sizeof(*c->film_grain_characteristics));
|
||||
if (!c->film_grain_characteristics)
|
||||
return AVERROR(ENOMEM);
|
||||
ret = decode_film_grain_characteristics(c->film_grain_characteristics, payload, fc);
|
||||
break;
|
||||
|
||||
case SEI_TYPE_DECODED_PICTURE_HASH:
|
||||
ret = decode_decoded_picture_hash(&s->picture_hash, payload);
|
||||
break;
|
||||
|
||||
case SEI_TYPE_DISPLAY_ORIENTATION:
|
||||
ret = decode_display_orientation(&s->common.display_orientation, payload);
|
||||
break;
|
||||
|
||||
case SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO:
|
||||
ret = decode_content_light_level_info(&s->common.content_light, payload);
|
||||
break;
|
||||
|
||||
case SEI_TYPE_FRAME_FIELD_INFO:
|
||||
ret = decode_frame_field_info(&s->frame_field_info, payload);
|
||||
break;
|
||||
|
||||
case SEI_TYPE_AMBIENT_VIEWING_ENVIRONMENT:
|
||||
ret = decode_ambient_viewing_environment(&s->common.ambient_viewing_environment, payload);
|
||||
break;
|
||||
|
||||
case SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME:
|
||||
ret = decode_mastering_display_colour_volume(&s->common.mastering_display, payload);
|
||||
break;
|
||||
|
||||
default:
|
||||
av_log(fc->log_ctx, AV_LOG_DEBUG, "Skipped %s SEI %d\n",
|
||||
sei->nal_unit_header.nal_unit_type == VVC_PREFIX_SEI_NUT ?
|
||||
"PREFIX" : "SUFFIX", message->payload_type);
|
||||
return FF_H2645_SEI_MESSAGE_UNHANDLED;
|
||||
}
|
||||
|
||||
if (ret == AVERROR(ENOMEM))
|
||||
return ret;
|
||||
if (ret < 0)
|
||||
av_log(fc->log_ctx, AV_LOG_WARNING, "Failure to parse %s SEI %d: %s\n",
|
||||
sei->nal_unit_header.nal_unit_type == VVC_PREFIX_SEI_NUT ?
|
||||
"PREFIX" : "SUFFIX", message->payload_type, av_err2str(ret));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_vvc_sei_replace(VVCSEI *dst, const VVCSEI *src)
|
||||
{
|
||||
dst->picture_hash.present = 0; // drop hash
|
||||
dst->frame_field_info.present = 0; // drop field info
|
||||
return ff_h2645_sei_ctx_replace(&dst->common, &src->common);
|
||||
}
|
||||
|
||||
void ff_vvc_sei_reset(VVCSEI *s)
|
||||
{
|
||||
ff_h2645_sei_reset(&s->common);
|
||||
s->picture_hash.present = 0;
|
||||
s->frame_field_info.present = 0;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* VVC Supplementary Enhancement Information messages
|
||||
*
|
||||
* copyright (c) 2024 Wu Jianhua <toqsxw@outlook.com>
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_SEI_H
|
||||
#define AVCODEC_VVC_SEI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "libavcodec/get_bits.h"
|
||||
#include "libavcodec/cbs.h"
|
||||
#include "libavcodec/cbs_h266.h"
|
||||
#include "libavcodec/h2645_sei.h"
|
||||
#include "libavcodec/sei.h"
|
||||
#include "libavcodec/vvc.h"
|
||||
#include "libavcodec/h274.h"
|
||||
|
||||
typedef struct VVCSEI {
|
||||
H2645SEI common;
|
||||
H274SEIPictureHash picture_hash;
|
||||
H274SEIFrameFieldInfo frame_field_info;
|
||||
} VVCSEI;
|
||||
|
||||
struct VVCFrameContext;
|
||||
|
||||
int ff_vvc_sei_decode(VVCSEI *s, const H266RawSEI *sei, const struct VVCFrameContext *fc);
|
||||
int ff_vvc_sei_replace(VVCSEI *dst, const VVCSEI *src);
|
||||
void ff_vvc_sei_reset(VVCSEI *s);
|
||||
|
||||
#endif /* AVCODEC_VVC_SEI_H */
|
||||
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
* VVC thread logic
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <stdatomic.h>
|
||||
|
||||
#include "libavcodec/executor.h"
|
||||
#include "libavutil/mem.h"
|
||||
#include "libavutil/thread.h"
|
||||
|
||||
#include "thread.h"
|
||||
#include "ctu.h"
|
||||
#include "filter.h"
|
||||
#include "inter.h"
|
||||
#include "intra.h"
|
||||
#include "refs.h"
|
||||
|
||||
typedef struct ProgressListener {
|
||||
VVCProgressListener l;
|
||||
struct VVCTask *task;
|
||||
VVCContext *s;
|
||||
} ProgressListener;
|
||||
|
||||
typedef enum VVCTaskStage {
|
||||
VVC_TASK_STAGE_INIT, // for CTU(0, 0) only
|
||||
VVC_TASK_STAGE_PARSE,
|
||||
VVC_TASK_STAGE_DEBLOCK_BS,
|
||||
VVC_TASK_STAGE_INTER,
|
||||
VVC_TASK_STAGE_RECON,
|
||||
VVC_TASK_STAGE_LMCS,
|
||||
VVC_TASK_STAGE_DEBLOCK_V,
|
||||
VVC_TASK_STAGE_DEBLOCK_H,
|
||||
VVC_TASK_STAGE_SAO,
|
||||
VVC_TASK_STAGE_ALF,
|
||||
VVC_TASK_STAGE_LAST
|
||||
} VVCTaskStage;
|
||||
|
||||
typedef struct VVCTask {
|
||||
union {
|
||||
struct VVCTask *next; //for executor debug only
|
||||
FFTask task;
|
||||
} u;
|
||||
|
||||
VVCTaskStage stage;
|
||||
|
||||
// ctu x, y, and raster scan order
|
||||
int rx, ry, rs;
|
||||
VVCFrameContext *fc;
|
||||
|
||||
ProgressListener col_listener;
|
||||
ProgressListener listener[2][VVC_MAX_REF_ENTRIES];
|
||||
|
||||
// for parse task only
|
||||
SliceContext *sc;
|
||||
EntryPoint *ep;
|
||||
int ctu_idx; //ctu idx in the current slice
|
||||
|
||||
// tasks with target scores met are ready for scheduling
|
||||
atomic_uchar score[VVC_TASK_STAGE_LAST];
|
||||
atomic_uchar target_inter_score;
|
||||
} VVCTask;
|
||||
|
||||
typedef struct VVCRowThread {
|
||||
atomic_int col_progress[VVC_PROGRESS_LAST];
|
||||
} VVCRowThread;
|
||||
|
||||
typedef struct VVCFrameThread {
|
||||
// error return for tasks
|
||||
atomic_int ret;
|
||||
|
||||
VVCRowThread *rows;
|
||||
VVCTask *tasks;
|
||||
|
||||
int ctu_size;
|
||||
int ctu_width;
|
||||
int ctu_height;
|
||||
int ctu_count;
|
||||
|
||||
//protected by lock
|
||||
atomic_int nb_scheduled_tasks;
|
||||
atomic_int nb_scheduled_listeners;
|
||||
|
||||
int row_progress[VVC_PROGRESS_LAST];
|
||||
|
||||
AVMutex lock;
|
||||
AVCond cond;
|
||||
} VVCFrameThread;
|
||||
|
||||
#define PRIORITY_LOWEST 2
|
||||
static void add_task(VVCContext *s, VVCTask *t)
|
||||
{
|
||||
VVCFrameThread *ft = t->fc->ft;
|
||||
FFTask *task = &t->u.task;
|
||||
const int priorities[] = {
|
||||
0, // VVC_TASK_STAGE_INIT,
|
||||
0, // VVC_TASK_STAGE_PARSE,
|
||||
1, // VVC_TASK_STAGE_DEBLOCK_BS
|
||||
// For an 8K clip, a CTU line completed in the reference frame may trigger 64 and more inter tasks.
|
||||
// We assign these tasks the lowest priority to avoid being overwhelmed with inter tasks.
|
||||
PRIORITY_LOWEST, // VVC_TASK_STAGE_INTER
|
||||
1, // VVC_TASK_STAGE_RECON,
|
||||
1, // VVC_TASK_STAGE_LMCS,
|
||||
1, // VVC_TASK_STAGE_DEBLOCK_V,
|
||||
1, // VVC_TASK_STAGE_DEBLOCK_H,
|
||||
1, // VVC_TASK_STAGE_SAO,
|
||||
1, // VVC_TASK_STAGE_ALF,
|
||||
};
|
||||
|
||||
atomic_fetch_add(&ft->nb_scheduled_tasks, 1);
|
||||
task->priority = priorities[t->stage];
|
||||
ff_executor_execute(s->executor, task);
|
||||
}
|
||||
|
||||
static void task_init(VVCTask *t, VVCTaskStage stage, VVCFrameContext *fc, const int rx, const int ry)
|
||||
{
|
||||
memset(t, 0, sizeof(*t));
|
||||
t->stage = stage;
|
||||
t->fc = fc;
|
||||
t->rx = rx;
|
||||
t->ry = ry;
|
||||
t->rs = ry * fc->ft->ctu_width + rx;
|
||||
for (int i = 0; i < FF_ARRAY_ELEMS(t->score); i++)
|
||||
atomic_store(t->score + i, 0);
|
||||
atomic_store(&t->target_inter_score, 0);
|
||||
}
|
||||
|
||||
static int task_init_parse(VVCTask *t, SliceContext *sc, EntryPoint *ep, const int ctu_idx)
|
||||
{
|
||||
if (t->sc) {
|
||||
// the task already inited, error bitstream
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
t->sc = sc;
|
||||
t->ep = ep;
|
||||
t->ctu_idx = ctu_idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint8_t task_add_score(VVCTask *t, const VVCTaskStage stage)
|
||||
{
|
||||
return atomic_fetch_add(&t->score[stage], 1) + 1;
|
||||
}
|
||||
|
||||
static uint8_t task_get_score(VVCTask *t, const VVCTaskStage stage)
|
||||
{
|
||||
return atomic_load(&t->score[stage]);
|
||||
}
|
||||
|
||||
//first row in tile or slice
|
||||
static int is_first_row(const VVCFrameContext *fc, const int rx, const int ry)
|
||||
{
|
||||
const VVCFrameThread *ft = fc->ft;
|
||||
const VVCPPS *pps = fc->ps.pps;
|
||||
|
||||
if (ry != pps->ctb_to_row_bd[ry]) {
|
||||
const int rs = ry * ft->ctu_width + rx;
|
||||
return fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - ft->ctu_width];
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int task_has_target_score(VVCTask *t, const VVCTaskStage stage, const uint8_t score)
|
||||
{
|
||||
// l:left, r:right, t: top, b: bottom
|
||||
static const uint8_t target_score[] =
|
||||
{
|
||||
2, //VVC_TASK_STAGE_DEBLOCK_BS,need l + t parse
|
||||
0, //VVC_TASK_STAGE_INTER, not used
|
||||
2, //VVC_TASK_STAGE_RECON, need l + rt recon
|
||||
3, //VVC_TASK_STAGE_LMCS, need r + b + rb recon
|
||||
1, //VVC_TASK_STAGE_DEBLOCK_V, need l deblock v
|
||||
2, //VVC_TASK_STAGE_DEBLOCK_H, need r deblock v + t deblock h
|
||||
5, //VVC_TASK_STAGE_SAO, need l + r + lb + b + rb deblock h
|
||||
8, //VVC_TASK_STAGE_ALF, need sao around the ctu
|
||||
};
|
||||
uint8_t target = 0;
|
||||
VVCFrameContext *fc = t->fc;
|
||||
|
||||
if (stage == VVC_TASK_STAGE_INIT)
|
||||
return 1;
|
||||
|
||||
if (stage == VVC_TASK_STAGE_PARSE) {
|
||||
const H266RawSPS *rsps = fc->ps.sps->r;
|
||||
const int wpp = rsps->sps_entropy_coding_sync_enabled_flag && !is_first_row(fc, t->rx, t->ry);
|
||||
const int no_prev_stage = t->rs > 0;
|
||||
target = 2 + wpp - no_prev_stage; //left parse + colocation + wpp - no_prev_stage
|
||||
} else if (stage == VVC_TASK_STAGE_INTER) {
|
||||
target = atomic_load(&t->target_inter_score);
|
||||
} else {
|
||||
target = target_score[stage - VVC_TASK_STAGE_DEBLOCK_BS];
|
||||
}
|
||||
|
||||
//+1 for previous stage
|
||||
av_assert0(score <= target + 1);
|
||||
return score == target + 1;
|
||||
}
|
||||
|
||||
static void frame_thread_add_score(VVCContext *s, VVCFrameThread *ft,
|
||||
const int rx, const int ry, const VVCTaskStage stage)
|
||||
{
|
||||
VVCTask *t = ft->tasks + ft->ctu_width * ry + rx;
|
||||
uint8_t score;
|
||||
|
||||
if (rx < 0 || rx >= ft->ctu_width || ry < 0 || ry >= ft->ctu_height)
|
||||
return;
|
||||
|
||||
score = task_add_score(t, stage);
|
||||
if (task_has_target_score(t, stage, score)) {
|
||||
av_assert0(s);
|
||||
av_assert0(stage == t->stage);
|
||||
add_task(s, t);
|
||||
}
|
||||
}
|
||||
|
||||
static void sheduled_done(VVCFrameThread *ft, atomic_int *scheduled)
|
||||
{
|
||||
if (atomic_fetch_sub(scheduled, 1) == 1) {
|
||||
ff_mutex_lock(&ft->lock);
|
||||
ff_cond_signal(&ft->cond);
|
||||
ff_mutex_unlock(&ft->lock);
|
||||
}
|
||||
}
|
||||
|
||||
static void progress_done(VVCProgressListener *_l, const int type)
|
||||
{
|
||||
const ProgressListener *l = (ProgressListener *)_l;
|
||||
const VVCTask *t = l->task;
|
||||
VVCFrameThread *ft = t->fc->ft;
|
||||
|
||||
frame_thread_add_score(l->s, ft, t->rx, t->ry, type);
|
||||
sheduled_done(ft, &ft->nb_scheduled_listeners);
|
||||
}
|
||||
|
||||
static void pixel_done(VVCProgressListener *l)
|
||||
{
|
||||
progress_done(l, VVC_TASK_STAGE_INTER);
|
||||
}
|
||||
|
||||
static void mv_done(VVCProgressListener *l)
|
||||
{
|
||||
progress_done(l, VVC_TASK_STAGE_PARSE);
|
||||
}
|
||||
|
||||
static void listener_init(ProgressListener *l, VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
|
||||
{
|
||||
const int is_inter = vp == VVC_PROGRESS_PIXEL;
|
||||
|
||||
l->task = t;
|
||||
l->s = s;
|
||||
l->l.vp = vp;
|
||||
l->l.y = y;
|
||||
l->l.progress_done = is_inter ? pixel_done : mv_done;
|
||||
if (is_inter)
|
||||
atomic_fetch_add(&t->target_inter_score, 1);
|
||||
}
|
||||
|
||||
static void add_progress_listener(VVCFrame *ref, ProgressListener *l,
|
||||
VVCTask *t, VVCContext *s, const VVCProgress vp, const int y)
|
||||
{
|
||||
VVCFrameThread *ft = t->fc->ft;
|
||||
|
||||
atomic_fetch_add(&ft->nb_scheduled_listeners, 1);
|
||||
listener_init(l, t, s, vp, y);
|
||||
ff_vvc_add_progress_listener(ref, (VVCProgressListener*)l);
|
||||
}
|
||||
|
||||
static void ep_init_wpp(EntryPoint *next, const EntryPoint *ep, const VVCSPS *sps)
|
||||
{
|
||||
memcpy(next->cabac_state, ep->cabac_state, sizeof(next->cabac_state));
|
||||
memcpy(next->pp, ep->pp, sizeof(next->pp));
|
||||
ff_vvc_ep_init_stat_coeff(next, sps->bit_depth, sps->r->sps_persistent_rice_adaptation_enabled_flag);
|
||||
}
|
||||
|
||||
static void schedule_next_parse(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, const VVCTask *t)
|
||||
{
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
EntryPoint *ep = t->ep;
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
|
||||
if (sps->r->sps_entropy_coding_sync_enabled_flag) {
|
||||
if (t->rx == fc->ps.pps->ctb_to_col_bd[t->rx]) {
|
||||
EntryPoint *next = ep + 1;
|
||||
if (next < sc->eps + sc->nb_eps && !is_first_row(fc, t->rx, t->ry + 1))
|
||||
ep_init_wpp(next, ep, sps);
|
||||
}
|
||||
if (t->ry + 1 < ft->ctu_height && !is_first_row(fc, t->rx, t->ry + 1))
|
||||
frame_thread_add_score(s, ft, t->rx, t->ry + 1, VVC_TASK_STAGE_PARSE);
|
||||
}
|
||||
|
||||
if (t->ctu_idx + 1 < t->ep->ctu_end) {
|
||||
const int next_rs = sc->sh.ctb_addr_in_curr_slice[t->ctu_idx + 1];
|
||||
const int next_rx = next_rs % ft->ctu_width;
|
||||
const int next_ry = next_rs / ft->ctu_width;
|
||||
frame_thread_add_score(s, ft, next_rx, next_ry, VVC_TASK_STAGE_PARSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void schedule_inter(VVCContext *s, VVCFrameContext *fc, const SliceContext *sc, VVCTask *t, const int rs)
|
||||
{
|
||||
const VVCSH *sh = &sc->sh;
|
||||
|
||||
if (!IS_I(sh->r)) {
|
||||
CTU *ctu = fc->tab.ctus + rs;
|
||||
for (int lx = 0; lx < 2; lx++) {
|
||||
for (int i = 0; i < sh->r->num_ref_idx_active[lx]; i++) {
|
||||
int y = ctu->max_y[lx][i];
|
||||
VVCRefPic *refp = sc->rpl[lx].refs + i;
|
||||
VVCFrame *ref = refp->ref;
|
||||
if (ref && y >= 0) {
|
||||
if (refp->is_scaled)
|
||||
y = y * refp->scale[1] >> 14;
|
||||
add_progress_listener(ref, &t->listener[lx][i], t, s, VVC_PROGRESS_PIXEL, y + LUMA_EXTRA_AFTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_task_done(VVCContext *s, VVCFrameContext *fc, const int rx, const int ry)
|
||||
{
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int rs = ry * ft->ctu_width + rx;
|
||||
const int slice_idx = fc->tab.slice_idx[rs];
|
||||
VVCTask *t = ft->tasks + rs;
|
||||
const SliceContext *sc = fc->slices[slice_idx];
|
||||
|
||||
schedule_next_parse(s, fc, sc, t);
|
||||
schedule_inter(s, fc, sc, t, rs);
|
||||
}
|
||||
|
||||
static void task_stage_done(const VVCTask *t, VVCContext *s)
|
||||
{
|
||||
VVCFrameContext *fc = t->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const VVCTaskStage stage = t->stage;
|
||||
|
||||
#define ADD(dx, dy, stage) frame_thread_add_score(s, ft, t->rx + (dx), t->ry + (dy), stage)
|
||||
|
||||
//this is a reserve map of ready_score, ordered by zigzag
|
||||
if (stage == VVC_TASK_STAGE_PARSE) {
|
||||
ADD( 0, 1, VVC_TASK_STAGE_DEBLOCK_BS);
|
||||
ADD( 1, 0, VVC_TASK_STAGE_DEBLOCK_BS);
|
||||
if (t->rx < 0 || t->rx >= ft->ctu_width || t->ry < 0 || t->ry >= ft->ctu_height)
|
||||
return;
|
||||
parse_task_done(s, fc, t->rx, t->ry);
|
||||
} else if (stage == VVC_TASK_STAGE_RECON) {
|
||||
ADD(-1, 1, VVC_TASK_STAGE_RECON);
|
||||
ADD( 1, 0, VVC_TASK_STAGE_RECON);
|
||||
ADD(-1, -1, VVC_TASK_STAGE_LMCS);
|
||||
ADD( 0, -1, VVC_TASK_STAGE_LMCS);
|
||||
ADD(-1, 0, VVC_TASK_STAGE_LMCS);
|
||||
} else if (stage == VVC_TASK_STAGE_DEBLOCK_V) {
|
||||
ADD( 1, 0, VVC_TASK_STAGE_DEBLOCK_V);
|
||||
ADD(-1, 0, VVC_TASK_STAGE_DEBLOCK_H);
|
||||
} else if (stage == VVC_TASK_STAGE_DEBLOCK_H) {
|
||||
ADD( 0, 1, VVC_TASK_STAGE_DEBLOCK_H);
|
||||
ADD(-1, -1, VVC_TASK_STAGE_SAO);
|
||||
ADD( 0, -1, VVC_TASK_STAGE_SAO);
|
||||
ADD(-1, 0, VVC_TASK_STAGE_SAO);
|
||||
ADD( 1, -1, VVC_TASK_STAGE_SAO);
|
||||
ADD( 1, 0, VVC_TASK_STAGE_SAO);
|
||||
} else if (stage == VVC_TASK_STAGE_SAO) {
|
||||
ADD(-1, -1, VVC_TASK_STAGE_ALF);
|
||||
ADD( 0, -1, VVC_TASK_STAGE_ALF);
|
||||
ADD(-1, 0, VVC_TASK_STAGE_ALF);
|
||||
ADD( 1, -1, VVC_TASK_STAGE_ALF);
|
||||
ADD(-1, 1, VVC_TASK_STAGE_ALF);
|
||||
ADD( 1, 0, VVC_TASK_STAGE_ALF);
|
||||
ADD( 0, 1, VVC_TASK_STAGE_ALF);
|
||||
ADD( 1, 1, VVC_TASK_STAGE_ALF);
|
||||
}
|
||||
}
|
||||
|
||||
static int task_is_stage_ready(VVCTask *t, int add)
|
||||
{
|
||||
const VVCTaskStage stage = t->stage;
|
||||
uint8_t score;
|
||||
if (stage > VVC_TASK_STAGE_ALF)
|
||||
return 0;
|
||||
score = task_get_score(t, stage) + add;
|
||||
return task_has_target_score(t, stage, score);
|
||||
}
|
||||
|
||||
static void check_colocation(VVCContext *s, VVCTask *t)
|
||||
{
|
||||
const VVCFrameContext *fc = t->fc;
|
||||
|
||||
if (fc->ps.ph.r->ph_temporal_mvp_enabled_flag || fc->ps.sps->r->sps_sbtmvp_enabled_flag) {
|
||||
VVCFrame *col = fc->ref->collocated_ref;
|
||||
const int first_col = t->rx == fc->ps.pps->ctb_to_col_bd[t->rx];
|
||||
if (col && first_col) {
|
||||
//we depend on bottom and right boundary, do not - 1 for y
|
||||
const int y = (t->ry << fc->ps.sps->ctb_log2_size_y);
|
||||
add_progress_listener(col, &t->col_listener, t, s, VVC_PROGRESS_MV, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
frame_thread_add_score(s, fc->ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
|
||||
}
|
||||
|
||||
static void submit_entry_point(VVCContext *s, VVCFrameThread *ft, SliceContext *sc, EntryPoint *ep)
|
||||
{
|
||||
const int rs = sc->sh.ctb_addr_in_curr_slice[ep->ctu_start];
|
||||
VVCTask *t = ft->tasks + rs;
|
||||
|
||||
frame_thread_add_score(s, ft, t->rx, t->ry, VVC_TASK_STAGE_PARSE);
|
||||
}
|
||||
|
||||
static int run_init(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int ret = ff_vvc_per_frame_init(fc);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
for (int i = 0; i < fc->nb_slices; i++) {
|
||||
SliceContext *sc = fc->slices[i];
|
||||
for (int j = 0; j < sc->nb_eps; j++) {
|
||||
EntryPoint *ep = sc->eps + j;
|
||||
for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
|
||||
const int rs = sc->sh.ctb_addr_in_curr_slice[k];
|
||||
VVCTask *t = ft->tasks + rs;
|
||||
check_colocation(s, t);
|
||||
}
|
||||
submit_entry_point(s, ft, sc, ep);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void report_frame_progress(VVCFrameContext *fc,
|
||||
const int ry, const VVCProgress idx)
|
||||
{
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int ctu_size = ft->ctu_size;
|
||||
int old;
|
||||
|
||||
if (atomic_fetch_add(&ft->rows[ry].col_progress[idx], 1) == ft->ctu_width - 1) {
|
||||
int y;
|
||||
ff_mutex_lock(&ft->lock);
|
||||
y = old = ft->row_progress[idx];
|
||||
while (y < ft->ctu_height && atomic_load(&ft->rows[y].col_progress[idx]) == ft->ctu_width)
|
||||
y++;
|
||||
if (old != y)
|
||||
ft->row_progress[idx] = y;
|
||||
// ff_vvc_report_progress will acquire other frames' locks, which could lead to a deadlock
|
||||
// We need to unlock ft->lock first
|
||||
ff_mutex_unlock(&ft->lock);
|
||||
|
||||
if (old != y) {
|
||||
const int progress = y == ft->ctu_height ? INT_MAX : y * ctu_size;
|
||||
ff_vvc_report_progress(fc->ref, idx, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int run_parse(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
int ret;
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
const int rs = t->rs;
|
||||
const CTU *ctu = fc->tab.ctus + rs;
|
||||
|
||||
lc->ep = t->ep;
|
||||
|
||||
ret = ff_vvc_coding_tree_unit(lc, t->ctu_idx, rs, t->rx, t->ry);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!ctu->has_dmvr)
|
||||
report_frame_progress(lc->fc, t->ry, VVC_PROGRESS_MV);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_deblock_bs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag)
|
||||
ff_vvc_deblock_bs(lc, t->rx, t->ry, t->rs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_inter(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
const CTU *ctu = fc->tab.ctus + t->rs;
|
||||
int ret;
|
||||
|
||||
ret = ff_vvc_predict_inter(lc, t->rs);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ctu->has_dmvr)
|
||||
report_frame_progress(fc, t->ry, VVC_PROGRESS_MV);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_recon(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
return ff_vvc_reconstruct(lc, t->rs, t->rx, t->ry);
|
||||
}
|
||||
|
||||
static int run_lmcs(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int ctu_size = ft->ctu_size;
|
||||
const int x0 = t->rx * ctu_size;
|
||||
const int y0 = t->ry * ctu_size;
|
||||
|
||||
ff_vvc_lmcs_filter(lc, x0, y0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_deblock_v(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int ctb_size = ft->ctu_size;
|
||||
const int x0 = t->rx * ctb_size;
|
||||
const int y0 = t->ry * ctb_size;
|
||||
|
||||
if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) {
|
||||
ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
|
||||
ff_vvc_deblock_vertical(lc, x0, y0, t->rs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_deblock_h(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int ctb_size = ft->ctu_size;
|
||||
const int x0 = t->rx * ctb_size;
|
||||
const int y0 = t->ry * ctb_size;
|
||||
|
||||
if (!lc->sc->sh.r->sh_deblocking_filter_disabled_flag) {
|
||||
ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
|
||||
ff_vvc_deblock_horizontal(lc, x0, y0, t->rs);
|
||||
}
|
||||
if (fc->ps.sps->r->sps_sao_enabled_flag)
|
||||
ff_vvc_sao_copy_ctb_to_hv(lc, t->rx, t->ry, t->ry == ft->ctu_height - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_sao(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int ctb_size = ft->ctu_size;
|
||||
const int x0 = t->rx * ctb_size;
|
||||
const int y0 = t->ry * ctb_size;
|
||||
|
||||
if (fc->ps.sps->r->sps_sao_enabled_flag) {
|
||||
ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
|
||||
ff_vvc_sao_filter(lc, x0, y0);
|
||||
}
|
||||
|
||||
if (fc->ps.sps->r->sps_alf_enabled_flag)
|
||||
ff_vvc_alf_copy_ctu_to_hv(lc, x0, y0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_alf(VVCContext *s, VVCLocalContext *lc, VVCTask *t)
|
||||
{
|
||||
VVCFrameContext *fc = lc->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const int ctu_size = ft->ctu_size;
|
||||
const int x0 = t->rx * ctu_size;
|
||||
const int y0 = t->ry * ctu_size;
|
||||
|
||||
if (fc->ps.sps->r->sps_alf_enabled_flag) {
|
||||
ff_vvc_decode_neighbour(lc, x0, y0, t->rx, t->ry, t->rs);
|
||||
ff_vvc_alf_filter(lc, x0, y0);
|
||||
}
|
||||
report_frame_progress(fc, t->ry, VVC_PROGRESS_PIXEL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const static char* task_name[] = {
|
||||
"INIT",
|
||||
"P",
|
||||
"B",
|
||||
"I",
|
||||
"R",
|
||||
"L",
|
||||
"V",
|
||||
"H",
|
||||
"S",
|
||||
"A"
|
||||
};
|
||||
|
||||
typedef int (*run_func)(VVCContext *s, VVCLocalContext *lc, VVCTask *t);
|
||||
|
||||
static void task_run_stage(VVCTask *t, VVCContext *s, VVCLocalContext *lc)
|
||||
{
|
||||
int ret;
|
||||
VVCFrameContext *fc = t->fc;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
const VVCTaskStage stage = t->stage;
|
||||
static const run_func run[] = {
|
||||
run_init,
|
||||
run_parse,
|
||||
run_deblock_bs,
|
||||
run_inter,
|
||||
run_recon,
|
||||
run_lmcs,
|
||||
run_deblock_v,
|
||||
run_deblock_h,
|
||||
run_sao,
|
||||
run_alf,
|
||||
};
|
||||
|
||||
ff_dlog(s->avctx, "frame %5d, %s(%3d, %3d)\r\n", (int)t->fc->decode_order, task_name[stage], t->rx, t->ry);
|
||||
|
||||
lc->sc = t->sc;
|
||||
|
||||
if (!atomic_load(&ft->ret)) {
|
||||
if ((ret = run[stage](s, lc, t)) < 0) {
|
||||
#ifdef COMPAT_ATOMICS_WIN32_STDATOMIC_H
|
||||
intptr_t zero = 0;
|
||||
#else
|
||||
int zero = 0;
|
||||
#endif
|
||||
atomic_compare_exchange_strong(&ft->ret, &zero, ret);
|
||||
av_log(s->avctx, AV_LOG_ERROR,
|
||||
"frame %5d, %s(%3d, %3d) failed with %d\r\n",
|
||||
(int)fc->decode_order, task_name[stage], t->rx, t->ry, ret);
|
||||
}
|
||||
if (!ret)
|
||||
task_stage_done(t, s);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int task_run(FFTask *_t, void *local_context, void *user_data)
|
||||
{
|
||||
VVCTask *t = (VVCTask*)_t;
|
||||
VVCContext *s = (VVCContext *)user_data;
|
||||
VVCLocalContext *lc = local_context;
|
||||
VVCFrameThread *ft = t->fc->ft;
|
||||
|
||||
lc->fc = t->fc;
|
||||
|
||||
do {
|
||||
task_run_stage(t, s, lc);
|
||||
t->stage++;
|
||||
} while (task_is_stage_ready(t, 1));
|
||||
|
||||
if (t->stage != VVC_TASK_STAGE_LAST)
|
||||
frame_thread_add_score(s, ft, t->rx, t->ry, t->stage);
|
||||
|
||||
sheduled_done(ft, &ft->nb_scheduled_tasks);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FFExecutor* ff_vvc_executor_alloc(VVCContext *s, const int thread_count)
|
||||
{
|
||||
FFTaskCallbacks callbacks = {
|
||||
s,
|
||||
sizeof(VVCLocalContext),
|
||||
PRIORITY_LOWEST + 1,
|
||||
task_run,
|
||||
};
|
||||
return ff_executor_alloc(&callbacks, thread_count);
|
||||
}
|
||||
|
||||
void ff_vvc_executor_free(FFExecutor **e)
|
||||
{
|
||||
ff_executor_free(e);
|
||||
}
|
||||
|
||||
void ff_vvc_frame_thread_free(VVCFrameContext *fc)
|
||||
{
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
|
||||
if (!ft)
|
||||
return;
|
||||
|
||||
ff_mutex_destroy(&ft->lock);
|
||||
ff_cond_destroy(&ft->cond);
|
||||
av_freep(&ft->rows);
|
||||
av_freep(&ft->tasks);
|
||||
av_freep(&ft);
|
||||
}
|
||||
|
||||
static void frame_thread_init_score(VVCFrameContext *fc)
|
||||
{
|
||||
const VVCFrameThread *ft = fc->ft;
|
||||
VVCTask task;
|
||||
|
||||
task_init(&task, VVC_TASK_STAGE_PARSE, fc, 0, 0);
|
||||
|
||||
for (int i = VVC_TASK_STAGE_PARSE; i < VVC_TASK_STAGE_LAST; i++) {
|
||||
task.stage = i;
|
||||
|
||||
for (task.rx = -1; task.rx <= ft->ctu_width; task.rx++) {
|
||||
task.ry = -1; //top
|
||||
task_stage_done(&task, NULL);
|
||||
task.ry = ft->ctu_height; //bottom
|
||||
task_stage_done(&task, NULL);
|
||||
}
|
||||
|
||||
for (task.ry = 0; task.ry < ft->ctu_height; task.ry++) {
|
||||
task.rx = -1; //left
|
||||
task_stage_done(&task, NULL);
|
||||
task.rx = ft->ctu_width; //right
|
||||
task_stage_done(&task, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ff_vvc_frame_thread_init(VVCFrameContext *fc)
|
||||
{
|
||||
const VVCSPS *sps = fc->ps.sps;
|
||||
const VVCPPS *pps = fc->ps.pps;
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
int ret;
|
||||
|
||||
if (!ft || ft->ctu_width != pps->ctb_width ||
|
||||
ft->ctu_height != pps->ctb_height ||
|
||||
ft->ctu_size != sps->ctb_size_y) {
|
||||
|
||||
ff_vvc_frame_thread_free(fc);
|
||||
ft = av_calloc(1, sizeof(*fc->ft));
|
||||
if (!ft)
|
||||
return AVERROR(ENOMEM);
|
||||
|
||||
ft->ctu_width = fc->ps.pps->ctb_width;
|
||||
ft->ctu_height = fc->ps.pps->ctb_height;
|
||||
ft->ctu_count = fc->ps.pps->ctb_count;
|
||||
ft->ctu_size = fc->ps.sps->ctb_size_y;
|
||||
|
||||
ft->rows = av_calloc(ft->ctu_height, sizeof(*ft->rows));
|
||||
if (!ft->rows)
|
||||
goto fail;
|
||||
|
||||
ft->tasks = av_malloc(ft->ctu_count * sizeof(*ft->tasks));
|
||||
if (!ft->tasks)
|
||||
goto fail;
|
||||
|
||||
if ((ret = ff_cond_init(&ft->cond, NULL)))
|
||||
goto fail;
|
||||
|
||||
if ((ret = ff_mutex_init(&ft->lock, NULL))) {
|
||||
ff_cond_destroy(&ft->cond);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
fc->ft = ft;
|
||||
ft->ret = 0;
|
||||
for (int y = 0; y < ft->ctu_height; y++) {
|
||||
VVCRowThread *row = ft->rows + y;
|
||||
memset(row->col_progress, 0, sizeof(row->col_progress));
|
||||
}
|
||||
|
||||
for (int rs = 0; rs < ft->ctu_count; rs++) {
|
||||
VVCTask *t = ft->tasks + rs;
|
||||
task_init(t, rs ? VVC_TASK_STAGE_PARSE : VVC_TASK_STAGE_INIT, fc, rs % ft->ctu_width, rs / ft->ctu_width);
|
||||
}
|
||||
|
||||
memset(&ft->row_progress[0], 0, sizeof(ft->row_progress));
|
||||
|
||||
frame_thread_init_score(fc);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (ft) {
|
||||
av_freep(&ft->rows);
|
||||
av_freep(&ft->tasks);
|
||||
av_freep(&ft);
|
||||
}
|
||||
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc)
|
||||
{
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
|
||||
for (int i = 0; i < fc->nb_slices; i++) {
|
||||
SliceContext *sc = fc->slices[i];
|
||||
for (int j = 0; j < sc->nb_eps; j++) {
|
||||
EntryPoint *ep = sc->eps + j;
|
||||
for (int k = ep->ctu_start; k < ep->ctu_end; k++) {
|
||||
const int rs = sc->sh.ctb_addr_in_curr_slice[k];
|
||||
VVCTask *t = ft->tasks + rs;
|
||||
const int ret = task_init_parse(t, sc, ep, k);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int rs = 0; rs < ft->ctu_count; rs++) {
|
||||
const VVCTask *t = ft->tasks + rs;
|
||||
if (!t->sc) {
|
||||
av_log(s->avctx, AV_LOG_ERROR, "frame %5d, CTU(%d, %d) not belong to any slice\r\n", (int)fc->decode_order, t->rx, t->ry);
|
||||
return AVERROR_INVALIDDATA;
|
||||
}
|
||||
}
|
||||
frame_thread_add_score(s, ft, 0, 0, VVC_TASK_STAGE_INIT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc)
|
||||
{
|
||||
VVCFrameThread *ft = fc->ft;
|
||||
|
||||
ff_mutex_lock(&ft->lock);
|
||||
|
||||
while (atomic_load(&ft->nb_scheduled_tasks) || atomic_load(&ft->nb_scheduled_listeners))
|
||||
ff_cond_wait(&ft->cond, &ft->lock);
|
||||
|
||||
ff_mutex_unlock(&ft->lock);
|
||||
ff_vvc_report_frame_finished(fc->ref);
|
||||
|
||||
ff_dlog(s->avctx, "frame %5d done\r\n", (int)fc->decode_order);
|
||||
return ft->ret;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* VVC thread logic
|
||||
*
|
||||
* Copyright (C) 2023 Nuo Mi
|
||||
*
|
||||
* This file is part of FFmpeg.
|
||||
*
|
||||
* FFmpeg is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* FFmpeg is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with FFmpeg; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef AVCODEC_VVC_THREAD_H
|
||||
#define AVCODEC_VVC_THREAD_H
|
||||
|
||||
#include "dec.h"
|
||||
|
||||
struct FFExecutor* ff_vvc_executor_alloc(VVCContext *s, int thread_count);
|
||||
void ff_vvc_executor_free(struct FFExecutor **e);
|
||||
|
||||
int ff_vvc_frame_thread_init(VVCFrameContext *fc);
|
||||
void ff_vvc_frame_thread_free(VVCFrameContext *fc);
|
||||
int ff_vvc_frame_submit(VVCContext *s, VVCFrameContext *fc);
|
||||
int ff_vvc_frame_wait(VVCContext *s, VVCFrameContext *fc);
|
||||
int ff_vvc_per_frame_init(VVCFrameContext *fc);
|
||||
|
||||
#endif // AVCODEC_VVC_THREAD_H
|
||||
Reference in New Issue
Block a user