From: Wu Jianhua <toq...@outlook.com> Signed-off-by: Wu Jianhua <toq...@outlook.com> --- libavcodec/vvc/ctu.c | 339 ++++++++++++++++++++++++++++++++++++---- libavcodec/vvc/ctu.h | 11 ++ libavcodec/vvc/dec.c | 3 + libavcodec/vvc/mvs.c | 3 +- libavcodec/vvc/thread.c | 1 + 5 files changed, 327 insertions(+), 30 deletions(-)
diff --git a/libavcodec/vvc/ctu.c b/libavcodec/vvc/ctu.c index c5df898f7b..979a27c6ad 100644 --- a/libavcodec/vvc/ctu.c +++ b/libavcodec/vvc/ctu.c @@ -25,6 +25,7 @@ #include "cabac.h" #include "ctu.h" #include "inter.h" +#include "intra.h" #include "mvs.h" #define PROF_TEMP_SIZE (PROF_BLOCK_SIZE) * sizeof(int16_t) @@ -1046,13 +1047,15 @@ static PredMode pred_mode_decode(VVCLocalContext *lc, const H266RawSliceHeader *rsh = lc->sc->sh.r; const int ch_type = tree_type == DUAL_TREE_CHROMA ? 1 : 0; const int is_4x4 = cu->cb_width == 4 && cu->cb_height == 4; + const int is_128 = cu->cb_width == 128 || cu->cb_height == 128; + const int hs = sps->hshift[CHROMA]; + const int vs = sps->vshift[CHROMA]; int pred_mode_flag; int pred_mode_ibc_flag; PredMode pred_mode; cu->skip_flag = 0; if (!IS_I(rsh) || sps->r->sps_ibc_enabled_flag) { - const int is_128 = cu->cb_width == 128 || cu->cb_height == 128; if (tree_type != DUAL_TREE_CHROMA && ((!is_4x4 && mode_type != MODE_TYPE_INTRA) || (sps->r->sps_ibc_enabled_flag && !is_128))) { @@ -1087,6 +1090,14 @@ static PredMode pred_mode_decode(VVCLocalContext *lc, pred_mode = MODE_INTRA; } + if (pred_mode == MODE_INTRA && sps->r->sps_palette_enabled_flag && !is_128 && !cu->skip_flag && + mode_type != MODE_TYPE_INTER && ((cu->cb_width * cu->cb_height) > + (tree_type != DUAL_TREE_CHROMA ? 16 : (16 << hs << vs))) && + (mode_type != MODE_TYPE_INTRA || tree_type != DUAL_TREE_CHROMA)) { + if (ff_vvc_pred_mode_plt_flag(lc)) + pred_mode = MODE_PLT; + } + set_cb_tab(lc, fc->tab.cpm[cu->ch_type], pred_mode); if (tree_type == SINGLE_TREE) set_cb_tab(lc, fc->tab.cpm[CHROMA], pred_mode); @@ -1755,8 +1766,8 @@ static void fill_dmvr_info(const VVCLocalContext *lc) const VVCFrameContext *fc = lc->fc; const CodingUnit *cu = lc->cu; - if (cu->pred_mode == MODE_IBC) { - ff_vvc_set_intra_mvf(lc, true, PF_IBC, false); + if (cu->pred_mode == MODE_IBC || cu->pred_mode == MODE_PLT) { + ff_vvc_set_intra_mvf(lc, true, cu->pred_mode == MODE_IBC ? PF_IBC : PF_PLT, false); } else { const VVCPPS *pps = fc->ps.pps; const int w = cu->cb_width >> MIN_PU_LOG2; @@ -1805,9 +1816,291 @@ static int inter_data(VVCLocalContext *lc) return ret; } +static TransformUnit* palette_add_tu(VVCLocalContext *lc, const int start, const int end, const VVCTreeType tree_type) +{ + CodingUnit *cu = lc->cu; + const VVCSPS *sps = lc->fc->ps.sps; + TransformUnit *tu = add_tu(lc->fc, cu, cu->x0, cu->y0, cu->cb_width, cu->cb_height); + + if (!tu) + return NULL; + + for (int c = start; c < end; c++) { + const int w = tu->width >> sps->hshift[c]; + const int h = tu->height >> sps->vshift[c]; + TransformBlock *tb = add_tb(tu, lc, tu->x0, tu->y0, w, h, c); + if (c != CR) + set_tb_size(lc->fc, tb); + } + + for (int i = 0; i < FF_ARRAY_ELEMS(cu->plt); i++) + cu->plt[i].size = 0; + + return tu; +} + +static void palette_predicted(VVCLocalContext *lc, const bool local_dual_tree, int start, int end, + bool *predictor_reused, const int predictor_size, const int max_entries) +{ + CodingUnit *cu = lc->cu; + int nb_predicted = 0; + + if (local_dual_tree) { + start = LUMA; + end = VVC_MAX_SAMPLE_ARRAYS; + } + + for (int i = 0; i < predictor_size && nb_predicted < max_entries; i++) { + const int run = ff_vvc_palette_predictor_run(lc); + if (run == 1) + break; + + if (run > 1) + i += run - 1; + predictor_reused[i] = true; + for (int c = start; c < end; c++) + cu->plt[c].entries[nb_predicted] = lc->ep->pp[c].entries[i]; + nb_predicted++; + } + + for (int c = start; c < end; c++) + cu->plt[c].size = nb_predicted; +} + +static void palette_signaled(VVCLocalContext *lc, const bool local_dual_tree, + const int start, const int end, const int max_entries) +{ + const VVCSPS *sps = lc->fc->ps.sps; + CodingUnit *cu = lc->cu; + const int nb_predicted = cu->plt[start].size; + const int nb_signaled = nb_predicted < max_entries ? ff_vvc_num_signalled_palette_entries(lc) : 0; + const int size = nb_predicted + nb_signaled; + const bool dual_tree_luma = local_dual_tree && cu->tree_type == DUAL_TREE_LUMA; + + for (int c = start; c < end; c++) { + Palette *plt = cu->plt + c; + for (int i = nb_predicted; i < size; i++) { + plt->entries[i] = ff_vvc_new_palette_entries(lc, sps->bit_depth); + if (dual_tree_luma) { + plt[CB].entries[i] = 1 << (sps->bit_depth - 1); + plt[CR].entries[i] = 1 << (sps->bit_depth - 1); + } + } + plt->size = size; + } +} + +static void palette_update_predictor(VVCLocalContext *lc, const bool local_dual_tree, int start, int end, + bool *predictor_reused, const int predictor_size) +{ + CodingUnit *cu = lc->cu; + const int max_predictor = VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE >> (cu->tree_type != SINGLE_TREE && !local_dual_tree); + + if (local_dual_tree) { + start = LUMA; + end = VVC_MAX_SAMPLE_ARRAYS; + } + + for (int c = start; c < end; c++) { + Palette *pp = lc->ep->pp + c; + Palette *plt = cu->plt + c; + int i = cu->plt[start].size;; + + // copy unused predictors to the end of plt + for (int j = 0; j < predictor_size && i < max_predictor; j++) { + if (!predictor_reused[j]) { + plt->entries[i] = pp->entries[j]; + i++; + } + } + + memcpy(pp->entries, plt->entries, i * sizeof(pp->entries[0])); + pp->size = i; + } +} + +static void palette_qp(VVCLocalContext *lc, VVCTreeType tree_type, const bool escape_present) +{ + const VVCFrameContext *fc = lc->fc; + const VVCPPS *pps = fc->ps.pps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const CodingUnit *cu = lc->cu; + + if (tree_type != DUAL_TREE_CHROMA) { + const bool has_qp_delta = escape_present && + pps->r->pps_cu_qp_delta_enabled_flag && !lc->parse.is_cu_qp_delta_coded; + set_qp_y(lc, cu->x0, cu->y0, has_qp_delta); + } + + if (tree_type != DUAL_TREE_LUMA) { + if (rsh->sh_cu_chroma_qp_offset_enabled_flag && !lc->parse.is_cu_chroma_qp_offset_coded) + chroma_qp_offset_decode(lc, 0, 1); + set_qp_c(lc); + } +} + +#define PALETTE_SET_PIXEL(xc, yc, pix) \ + do { \ + const int off = ((xc) >> hs) + ((yc) >> vs) * tb->tb_width; \ + if (sps->bit_depth == 8) \ + u8[off] = pix; \ + else \ + u16[off] = pix; \ + } while (0) + +#define PALETTE_INDEX(x, y) index[(y) * cu->cb_width + (x)] + +// 6.5.3 Horizontal and vertical traverse scan order array initialization process +// The hTravScan and vTravScan tables require approximately 576 KB of memory. +// To save space, we use a macro to achieve the same functionality. +#define TRAV_COL(p, wlog, mask) ((p & mask) ^ (-((p >> wlog) & 1) & mask)) +#define TRAV_ROW(p, hlog) (p >> hlog) +#define TRAV(trans, p, wlog, hlog, mask) (trans ? TRAV_ROW((p), hlog) : TRAV_COL((p), wlog, mask)) +#define TRAV_X(pos) TRAV(transpose, pos, wlog2, hlog2, wmask) +#define TRAV_Y(pos) TRAV(!transpose, pos, hlog2, wlog2, hmask) + +static int palette_subblock_data(VVCLocalContext *lc, + const int max_index, const int subset_id, const bool transpose, + uint8_t *run_type, uint8_t *index, int *prev_run_pos, bool *adjust) +{ + const CodingUnit *cu = lc->cu; + TransformUnit *tu = cu->tus.head; + const VVCSPS *sps = lc->fc->ps.sps; + const int min_pos = subset_id << 4; + const int max_pos = FFMIN(min_pos + 16, cu->cb_width * cu->cb_height); + const int wmask = cu->cb_width - 1; + const int hmask = cu->cb_height - 1; + const int wlog2 = av_log2(cu->cb_width); + const int hlog2 = av_log2(cu->cb_height); + const uint8_t esc = cu->plt[tu->tbs[0].c_idx].size; + uint8_t run_copy[16] = { 0 }; + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + + if (i > 0 && max_index > 0) + run_copy[i - min_pos] = ff_vvc_run_copy_flag(lc, run_type[i - 1], *prev_run_pos, i); + + run_type[i] = 0; + if (max_index > 0 && !run_copy[i - min_pos]) { + if (((!transpose && yc > 0) || (transpose && xc > 0)) + && i > 0 && !run_type[i - 1]) { + run_type[i] = ff_vvc_copy_above_palette_indices_flag(lc); + } + *prev_run_pos = i; + } else if (i > 0) { + run_type[i] = run_type[i - 1]; + } + } + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + const int prev_xc = i > 0 ? TRAV_X(i - 1) : 0; + const int prev_yc = i > 0 ? TRAV_Y(i - 1) : 0; + + int idx = 0; + if (max_index > 0 && !run_copy[i - min_pos] && !run_type[i]) { + if (max_index - *adjust > 0) + idx = ff_vvc_palette_idx_idc(lc, max_index, *adjust); + if (i > 0) { + const int ref_idx = !run_type[i - 1] ? + PALETTE_INDEX(prev_xc, prev_yc) : PALETTE_INDEX(xc - transpose, yc - !transpose); + idx += (idx >= ref_idx); + } + *adjust = true; + } else { + idx = PALETTE_INDEX(prev_xc, prev_yc); + } + + if (!run_type[i]) + PALETTE_INDEX(xc, yc) = idx; + else + PALETTE_INDEX(xc, yc) = PALETTE_INDEX(xc - transpose, yc - !transpose); + } + + for (int c = 0; c < tu->nb_tbs; c++) { + TransformBlock *tb = &tu->tbs[c]; + const Palette *plt = cu->plt + tb->c_idx; + const int scale = ff_vvc_palette_derive_scale(lc, tu, tb); + const int hs = sps->hshift[c]; + const int vs = sps->vshift[c]; + uint8_t *u8 = (uint8_t *)tb->coeffs; + uint16_t *u16 = (uint16_t *)tb->coeffs; + + for (int i = min_pos; i < max_pos; i++) { + const int xc = TRAV_X(i); + const int yc = TRAV_Y(i); + if (!(xc & hs) && !(yc & vs)) { + const int v = PALETTE_INDEX(xc, yc); + if (v == esc) { + const int coeff = ff_vvc_palette_escape_val(lc); + const int pixel = av_clip_intp2(RSHIFT(coeff * scale, 6), sps->bit_depth); + PALETTE_SET_PIXEL(xc, yc, pixel); + } else { + PALETTE_SET_PIXEL(xc, yc, plt->entries[v]); + } + } + } + } + + return 0; +} + +static int hls_palette_coding(VVCLocalContext *lc, const VVCTreeType tree_type) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + CodingUnit *cu = lc->cu; + Palette *pp = lc->ep->pp; + const int max_entries = tree_type == SINGLE_TREE ? 31 : 15; + const bool local_dual_tree = tree_type != SINGLE_TREE && + (!IS_I(rsh) || (IS_I(rsh) && !sps->r->sps_qtbtt_dual_tree_intra_flag)); + bool escape_present = false; + bool transpose = false; + bool adjust = false; + int max_index = 0; + int prev_run_pos = 0; + + int predictor_size, start, end; + bool reused[VVC_MAX_NUM_PALETTE_PREDICTOR_SIZE]; + uint8_t run_type[MAX_PALETTE_CU_SIZE * MAX_PALETTE_CU_SIZE]; + uint8_t index[MAX_PALETTE_CU_SIZE * MAX_PALETTE_CU_SIZE]; + + ff_vvc_channel_range(&start, &end, tree_type, sps->r->sps_chroma_format_idc); + + if (!palette_add_tu(lc, start, end, tree_type)) + return AVERROR(ENOMEM); + + predictor_size = pp[start].size; + memset(reused, 0, sizeof(reused[0]) * predictor_size); + palette_predicted(lc, local_dual_tree, start, end, reused, predictor_size, max_entries); + palette_signaled(lc, local_dual_tree, start, end, max_entries); + palette_update_predictor(lc, local_dual_tree, start, end, reused, predictor_size); + + if (cu->plt[start].size > 0) + escape_present = ff_vvc_palette_escape_val_present_flag(lc); + + max_index = cu->plt[start].size - 1 + escape_present; + if (max_index > 0) { + adjust = false; + transpose = ff_vvc_palette_transpose_flag(lc); + } + + palette_qp(lc, tree_type, escape_present); + + index[0] = 0; + for (int i = 0; i <= (cu->cb_width * cu->cb_height - 1) >> 4; i++) + palette_subblock_data(lc, max_index, i, transpose, + run_type, index, &prev_run_pos, &adjust); + + return 0; +} + static int intra_data(VVCLocalContext *lc) { - const VVCFrameContext *fc = lc->fc; const VVCSPS *sps = lc->fc->ps.sps; const CodingUnit *cu = lc->cu; const VVCTreeType tree_type = cu->tree_type; @@ -1816,8 +2109,9 @@ static int intra_data(VVCLocalContext *lc) if (tree_type == SINGLE_TREE || tree_type == DUAL_TREE_LUMA) { if (pred_mode_plt_flag) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; + if ((ret = hls_palette_coding(lc, tree_type)) < 0) + return ret; + ff_vvc_set_intra_mvf(lc, false, PF_PLT, false); } else { intra_luma_pred_modes(lc); ff_vvc_set_intra_mvf(lc, false, PF_INTRA, cu->ciip_flag); @@ -1825,8 +2119,8 @@ static int intra_data(VVCLocalContext *lc) } if ((tree_type == SINGLE_TREE || tree_type == DUAL_TREE_CHROMA) && sps->r->sps_chroma_format_idc) { if (pred_mode_plt_flag && tree_type == DUAL_TREE_CHROMA) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; + if ((ret = hls_palette_coding(lc, tree_type)) < 0) + return ret; } else if (!pred_mode_plt_flag) { if (!cu->act_enabled_flag) intra_chroma_pred_modes(lc); @@ -1839,14 +2133,11 @@ static int intra_data(VVCLocalContext *lc) static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, int cb_height, int cqt_depth, const VVCTreeType tree_type, VVCModeType mode_type) { - const VVCFrameContext *fc = lc->fc; - const VVCSPS *sps = fc->ps.sps; - const H266RawSliceHeader *rsh = lc->sc->sh.r; - const int hs = sps->hshift[CHROMA]; - const int vs = sps->vshift[CHROMA]; - const int is_128 = cb_width > 64 || cb_height > 64; - int pred_mode_plt_flag = 0; - int ret = 0; + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const H266RawSliceHeader *rsh = lc->sc->sh.r; + const int is_128 = cb_width > 64 || cb_height > 64; + int ret = 0; CodingUnit *cu = add_cu(lc, x0, y0, cb_width, cb_height, cqt_depth, tree_type); @@ -1859,16 +2150,6 @@ static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, in mode_type = MODE_TYPE_INTRA; cu->pred_mode = pred_mode_decode(lc, tree_type, mode_type); - if (cu->pred_mode == MODE_INTRA && sps->r->sps_palette_enabled_flag && !is_128 && !cu->skip_flag && - mode_type != MODE_TYPE_INTER && ((cb_width * cb_height) > - (tree_type != DUAL_TREE_CHROMA ? 16 : (16 << hs << vs))) && - (mode_type != MODE_TYPE_INTRA || tree_type != DUAL_TREE_CHROMA)) { - pred_mode_plt_flag = ff_vvc_pred_mode_plt_flag(lc); - if (pred_mode_plt_flag) { - avpriv_report_missing_feature(fc->log_ctx, "Palette"); - return AVERROR_PATCHWELCOME; - } - } if (cu->pred_mode == MODE_INTRA && sps->r->sps_act_enabled_flag && tree_type == SINGLE_TREE) { avpriv_report_missing_feature(fc->log_ctx, "Adaptive Color Transform"); return AVERROR_PATCHWELCOME; @@ -1881,10 +2162,10 @@ static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, in if (ret < 0) return ret; - if (cu->pred_mode != MODE_INTRA && !pred_mode_plt_flag && !lc->cu->pu.general_merge_flag) + if (cu->pred_mode != MODE_INTRA && cu->pred_mode != MODE_PLT && !lc->cu->pu.general_merge_flag) cu->coded_flag = ff_vvc_cu_coded_flag(lc); else - cu->coded_flag = !(cu->skip_flag || pred_mode_plt_flag); + cu->coded_flag = !(cu->skip_flag || cu->pred_mode == MODE_PLT); if (cu->coded_flag) { sbt_info(lc, sps); @@ -1902,7 +2183,7 @@ static int hls_coding_unit(VVCLocalContext *lc, int x0, int y0, int cb_width, in cu->lfnst_idx = lfnst_idx_decode(lc); cu->mts_idx = mts_idx_decode(lc); set_qp_c(lc); - } else { + } else if (cu->pred_mode != MODE_PLT) { ret = skipped_transform_tree_unit(lc); if (ret < 0) return ret; diff --git a/libavcodec/vvc/ctu.h b/libavcodec/vvc/ctu.h index dab6f453f1..e37bacf9dd 100644 --- a/libavcodec/vvc/ctu.h +++ b/libavcodec/vvc/ctu.h @@ -36,6 +36,7 @@ #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)) @@ -224,6 +225,7 @@ typedef enum PredFlag { PF_L1 = 0x2, PF_BI = 0x3, PF_IBC = PF_L0 | 0x4, + PF_PLT = 0x8, } PredFlag; typedef enum IntraPredMode { @@ -277,6 +279,11 @@ typedef struct PredictionUnit { 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; @@ -326,6 +333,8 @@ typedef struct CodingUnit { int8_t qp[4]; ///< QpY, Qp′Cb, Qp′Cr, Qp′CbCr + Palette plt[VVC_MAX_SAMPLE_ARRAYS]; + PredictionUnit pu; struct CodingUnit *next; ///< RefStruct reference @@ -356,6 +365,8 @@ typedef struct EntryPoint { int stat_coeff[VVC_MAX_SAMPLE_ARRAYS]; ///< StatCoeff + Palette pp[VVC_MAX_SAMPLE_ARRAYS]; // PalettePredictor + VVCCabacState cabac_state[VVC_CONTEXTS]; CABACContext cc; diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c index 09b0053703..3db2c9955c 100644 --- a/libavcodec/vvc/dec.c +++ b/libavcodec/vvc/dec.c @@ -551,6 +551,9 @@ static int ep_init(EntryPoint *ep, const int ctu_addr, const int ctu_end, GetBit ep->ctu_start = ctu_addr; ep->ctu_end = ctu_end; + for (int c_idx = LUMA; c_idx <= CR; c_idx++) + ep->pp[c_idx].size = 0; + return 0; } diff --git a/libavcodec/vvc/mvs.c b/libavcodec/vvc/mvs.c index 8946b00b5b..2cf67def7b 100644 --- a/libavcodec/vvc/mvs.c +++ b/libavcodec/vvc/mvs.c @@ -145,7 +145,8 @@ static int derive_temporal_colocated_mvs(const VVCLocalContext *lc, MvField temp RefPicList* refPicList = sc->rpl; if (temp_col.pred_flag == PF_INTRA || - temp_col.pred_flag == PF_IBC) + temp_col.pred_flag == PF_IBC || + temp_col.pred_flag == PF_PLT) return 0; if (sb_flag){ diff --git a/libavcodec/vvc/thread.c b/libavcodec/vvc/thread.c index e1d64bd3d2..2138341b0f 100644 --- a/libavcodec/vvc/thread.c +++ b/libavcodec/vvc/thread.c @@ -286,6 +286,7 @@ static void add_progress_listener(VVCFrame *ref, ProgressListener *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); } -- 2.44.0.windows.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".