mirror of https://github.com/FFmpeg/FFmpeg.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2564 lines
96 KiB
2564 lines
96 KiB
/* |
|
* 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 |
|
*/ |
|
|
|
#include "libavcodec/refstruct.h" |
|
|
|
#include "cabac.h" |
|
#include "ctu.h" |
|
#include "inter.h" |
|
#include "mvs.h" |
|
|
|
#define PROF_TEMP_SIZE (PROF_BLOCK_SIZE) * sizeof(int16_t) |
|
|
|
#define TAB_MSM(fc, depth, x, y) fc->tab.msm[(depth)][((y) >> 5) * fc->ps.pps->width32 + ((x) >> 5)] |
|
#define TAB_ISPMF(fc, x, y) fc->tab.ispmf[((y) >> 6) * fc->ps.pps->width64 + ((x) >> 6)] |
|
|
|
typedef enum VVCModeType { |
|
MODE_TYPE_ALL, |
|
MODE_TYPE_INTER, |
|
MODE_TYPE_INTRA, |
|
} VVCModeType; |
|
|
|
static void set_tb_pos(const VVCFrameContext *fc, const TransformBlock *tb) |
|
{ |
|
const int x_tb = tb->x0 >> MIN_TU_LOG2; |
|
const int y_tb = tb->y0 >> MIN_TU_LOG2; |
|
const int hs = fc->ps.sps->hshift[tb->c_idx]; |
|
const int vs = fc->ps.sps->vshift[tb->c_idx]; |
|
const int is_chroma = tb->c_idx != 0; |
|
const int width = FFMAX(1, tb->tb_width >> (MIN_TU_LOG2 - hs)); |
|
const int end = y_tb + FFMAX(1, tb->tb_height >> (MIN_TU_LOG2 - vs)); |
|
|
|
for (int y = y_tb; y < end; y++) { |
|
const int off = y * fc->ps.pps->min_tu_width + x_tb; |
|
for (int i = 0; i < width; i++) { |
|
fc->tab.tb_pos_x0[is_chroma][off + i] = tb->x0; |
|
fc->tab.tb_pos_y0[is_chroma][off + i] = tb->y0; |
|
} |
|
memset(fc->tab.tb_width [is_chroma] + off, tb->tb_width, width); |
|
memset(fc->tab.tb_height[is_chroma] + off, tb->tb_height, width); |
|
} |
|
} |
|
|
|
static void set_tb_tab(uint8_t *tab, uint8_t v, const VVCFrameContext *fc, |
|
const TransformBlock *tb) |
|
{ |
|
const int width = tb->tb_width << fc->ps.sps->hshift[tb->c_idx]; |
|
const int height = tb->tb_height << fc->ps.sps->vshift[tb->c_idx]; |
|
|
|
for (int h = 0; h < height; h += MIN_TU_SIZE) { |
|
const int y = (tb->y0 + h) >> MIN_TU_LOG2; |
|
const int off = y * fc->ps.pps->min_tu_width + (tb->x0 >> MIN_TU_LOG2); |
|
const int w = FFMAX(1, width >> MIN_TU_LOG2); |
|
memset(tab + off, v, w); |
|
} |
|
} |
|
|
|
// 8.7.1 Derivation process for quantization parameters |
|
static int get_qp_y_pred(const VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const CodingUnit *cu = lc->cu; |
|
const int ctb_log2_size = sps->ctb_log2_size_y; |
|
const int ctb_size_mask = (1 << ctb_log2_size) - 1; |
|
const int xQg = lc->parse.cu_qg_top_left_x; |
|
const int yQg = lc->parse.cu_qg_top_left_y; |
|
const int min_cb_width = fc->ps.pps->min_cb_width; |
|
const int x_cb = cu->x0 >> sps->min_cb_log2_size_y; |
|
const int y_cb = cu->y0 >> sps->min_cb_log2_size_y; |
|
const int rx = cu->x0 >> ctb_log2_size; |
|
const int ry = cu->y0 >> ctb_log2_size; |
|
const int in_same_ctb_a = ((xQg - 1) >> ctb_log2_size) == rx && (yQg >> ctb_log2_size) == ry; |
|
const int in_same_ctb_b = (xQg >> ctb_log2_size) == rx && ((yQg - 1) >> ctb_log2_size) == ry; |
|
int qPy_pred, qPy_a, qPy_b; |
|
|
|
if (lc->na.cand_up) { |
|
const int first_qg_in_ctu = !(xQg & ctb_size_mask) && !(yQg & ctb_size_mask); |
|
const int qPy_up = fc->tab.qp[LUMA][x_cb + (y_cb - 1) * min_cb_width]; |
|
if (first_qg_in_ctu && pps->ctb_to_col_bd[xQg >> ctb_log2_size] == xQg >> ctb_log2_size) |
|
return qPy_up; |
|
} |
|
|
|
// qPy_pred |
|
qPy_pred = lc->ep->is_first_qg ? lc->sc->sh.slice_qp_y : lc->ep->qp_y; |
|
|
|
// qPy_b |
|
if (!lc->na.cand_up || !in_same_ctb_b) |
|
qPy_b = qPy_pred; |
|
else |
|
qPy_b = fc->tab.qp[LUMA][x_cb + (y_cb - 1) * min_cb_width]; |
|
|
|
// qPy_a |
|
if (!lc->na.cand_left || !in_same_ctb_a) |
|
qPy_a = qPy_pred; |
|
else |
|
qPy_a = fc->tab.qp[LUMA][(x_cb - 1) + y_cb * min_cb_width]; |
|
|
|
av_assert2(qPy_a >= -fc->ps.sps->qp_bd_offset && qPy_a < 63); |
|
av_assert2(qPy_b >= -fc->ps.sps->qp_bd_offset && qPy_b < 63); |
|
|
|
return (qPy_a + qPy_b + 1) >> 1; |
|
} |
|
|
|
static void set_cb_tab(const VVCLocalContext *lc, uint8_t *tab, const uint8_t v) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const CodingUnit *cu = lc->cu; |
|
const int log2_min_cb_size = fc->ps.sps->min_cb_log2_size_y; |
|
const int x_cb = cu->x0 >> log2_min_cb_size; |
|
const int y_cb = cu->y0 >> log2_min_cb_size; |
|
const int cb_width = cu->cb_width; |
|
const int cb_height = cu->cb_height; |
|
int x = y_cb * pps->min_cb_width + x_cb; |
|
|
|
for (int y = 0; y < (cb_height >> log2_min_cb_size); y++) { |
|
const int width = cb_width >> log2_min_cb_size; |
|
|
|
memset(&tab[x], v, width); |
|
x += pps->min_cb_width; |
|
} |
|
} |
|
|
|
static int set_qp_y(VVCLocalContext *lc, const int x0, const int y0, const int has_qp_delta) |
|
{ |
|
const VVCSPS *sps = lc->fc->ps.sps; |
|
EntryPoint *ep = lc->ep; |
|
CodingUnit *cu = lc->cu; |
|
int cu_qp_delta = 0; |
|
|
|
if (!lc->fc->ps.pps->r->pps_cu_qp_delta_enabled_flag) { |
|
ep->qp_y = lc->sc->sh.slice_qp_y; |
|
} else if (ep->is_first_qg || (lc->parse.cu_qg_top_left_x == x0 && lc->parse.cu_qg_top_left_y == y0)) { |
|
ep->qp_y = get_qp_y_pred(lc); |
|
ep->is_first_qg = 0; |
|
} |
|
|
|
if (has_qp_delta) { |
|
const int cu_qp_delta_abs = ff_vvc_cu_qp_delta_abs(lc); |
|
|
|
if (cu_qp_delta_abs) |
|
cu_qp_delta = ff_vvc_cu_qp_delta_sign_flag(lc) ? -cu_qp_delta_abs : cu_qp_delta_abs; |
|
if (cu_qp_delta > (31 + sps->qp_bd_offset / 2) || cu_qp_delta < -(32 + sps->qp_bd_offset / 2)) |
|
return AVERROR_INVALIDDATA; |
|
lc->parse.is_cu_qp_delta_coded = 1; |
|
|
|
if (cu_qp_delta) { |
|
int off = sps->qp_bd_offset; |
|
ep->qp_y = FFUMOD(ep->qp_y + cu_qp_delta + 64 + 2 * off, 64 + off) - off; |
|
} |
|
} |
|
|
|
set_cb_tab(lc, lc->fc->tab.qp[LUMA], ep->qp_y); |
|
cu->qp[LUMA] = ep->qp_y; |
|
|
|
return 0; |
|
} |
|
|
|
static void set_qp_c_tab(const VVCLocalContext *lc, const TransformUnit *tu, const TransformBlock *tb) |
|
{ |
|
const int is_jcbcr = tu->joint_cbcr_residual_flag && tu->coded_flag[CB] && tu->coded_flag[CR]; |
|
const int idx = is_jcbcr ? JCBCR : tb->c_idx; |
|
|
|
set_tb_tab(lc->fc->tab.qp[tb->c_idx], lc->cu->qp[idx], lc->fc, tb); |
|
} |
|
|
|
static void set_qp_c(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const H266RawSliceHeader *rsh = lc->sc->sh.r; |
|
CodingUnit *cu = lc->cu; |
|
const int x_center = cu->x0 + cu->cb_width / 2; |
|
const int y_center = cu->y0 + cu->cb_height / 2; |
|
const int single_tree = cu->tree_type == SINGLE_TREE; |
|
const int qp_luma = (single_tree ? lc->ep->qp_y : ff_vvc_get_qPy(fc, x_center, y_center)) + sps->qp_bd_offset; |
|
const int qp_chroma = av_clip(qp_luma, 0, MAX_QP + sps->qp_bd_offset); |
|
const int sh_chroma_qp_offset[] = { |
|
rsh->sh_cb_qp_offset, |
|
rsh->sh_cr_qp_offset, |
|
rsh->sh_joint_cbcr_qp_offset, |
|
}; |
|
int qp; |
|
|
|
for (int i = CB - 1; i < CR + sps->r->sps_joint_cbcr_enabled_flag; i++) { |
|
qp = sps->chroma_qp_table[i][qp_chroma]; |
|
qp = qp + pps->chroma_qp_offset[i] + sh_chroma_qp_offset[i] + lc->parse.chroma_qp_offset[i]; |
|
qp = av_clip(qp, -sps->qp_bd_offset, MAX_QP) + sps->qp_bd_offset; |
|
cu->qp[i + 1] = qp; |
|
} |
|
} |
|
|
|
static TransformUnit* alloc_tu(VVCFrameContext *fc, CodingUnit *cu) |
|
{ |
|
TransformUnit *tu = ff_refstruct_pool_get(fc->tu_pool); |
|
if (!tu) |
|
return NULL; |
|
|
|
tu->next = NULL; |
|
|
|
if (cu->tus.tail) |
|
cu->tus.tail->next = tu; |
|
else |
|
cu->tus.head = tu; |
|
cu->tus.tail = tu; |
|
|
|
return tu; |
|
} |
|
|
|
static TransformUnit* add_tu(VVCFrameContext *fc, CodingUnit *cu, const int x0, const int y0, const int tu_width, const int tu_height) |
|
{ |
|
TransformUnit *tu = alloc_tu(fc, cu); |
|
|
|
if (!tu) |
|
return NULL; |
|
|
|
tu->x0 = x0; |
|
tu->y0 = y0; |
|
tu->width = tu_width; |
|
tu->height = tu_height; |
|
tu->joint_cbcr_residual_flag = 0; |
|
memset(tu->coded_flag, 0, sizeof(tu->coded_flag)); |
|
tu->nb_tbs = 0; |
|
|
|
return tu; |
|
} |
|
|
|
static TransformBlock* add_tb(TransformUnit *tu, VVCLocalContext *lc, |
|
const int x0, const int y0, const int tb_width, const int tb_height, const int c_idx) |
|
{ |
|
TransformBlock *tb; |
|
|
|
tb = &tu->tbs[tu->nb_tbs++]; |
|
tb->has_coeffs = 0; |
|
tb->x0 = x0; |
|
tb->y0 = y0; |
|
tb->tb_width = tb_width; |
|
tb->tb_height = tb_height; |
|
tb->log2_tb_width = av_log2(tb_width); |
|
tb->log2_tb_height = av_log2(tb_height); |
|
|
|
tb->max_scan_x = tb->max_scan_y = 0; |
|
tb->min_scan_x = tb->min_scan_y = 0; |
|
|
|
tb->c_idx = c_idx; |
|
tb->ts = 0; |
|
tb->coeffs = lc->coeffs; |
|
lc->coeffs += tb_width * tb_height; |
|
return tb; |
|
} |
|
|
|
static uint8_t tu_y_coded_flag_decode(VVCLocalContext *lc, const int is_sbt_not_coded, |
|
const int sub_tu_index, const int is_isp, const int is_chroma_coded) |
|
{ |
|
uint8_t tu_y_coded_flag = 0; |
|
const VVCSPS *sps = lc->fc->ps.sps; |
|
CodingUnit *cu = lc->cu; |
|
|
|
if (!is_sbt_not_coded) { |
|
int has_y_coded_flag = sub_tu_index < cu->num_intra_subpartitions - 1 || !lc->parse.infer_tu_cbf_luma; |
|
if (!is_isp) { |
|
const int is_large = cu->cb_width > sps->max_tb_size_y || cu->cb_height > sps->max_tb_size_y; |
|
has_y_coded_flag = (cu->pred_mode == MODE_INTRA && !cu->act_enabled_flag) || is_chroma_coded || is_large; |
|
} |
|
tu_y_coded_flag = has_y_coded_flag ? ff_vvc_tu_y_coded_flag(lc) : 1; |
|
} |
|
if (is_isp) |
|
lc->parse.infer_tu_cbf_luma = lc->parse.infer_tu_cbf_luma && !tu_y_coded_flag; |
|
return tu_y_coded_flag; |
|
} |
|
|
|
static void chroma_qp_offset_decode(VVCLocalContext *lc, const int is_128, const int is_chroma_coded) |
|
{ |
|
const VVCPPS *pps = lc->fc->ps.pps; |
|
const H266RawSliceHeader *rsh = lc->sc->sh.r; |
|
|
|
if ((is_128 || is_chroma_coded) && |
|
rsh->sh_cu_chroma_qp_offset_enabled_flag && !lc->parse.is_cu_chroma_qp_offset_coded) { |
|
const int cu_chroma_qp_offset_flag = ff_vvc_cu_chroma_qp_offset_flag(lc); |
|
if (cu_chroma_qp_offset_flag) { |
|
int cu_chroma_qp_offset_idx = 0; |
|
if (pps->r->pps_chroma_qp_offset_list_len_minus1 > 0) |
|
cu_chroma_qp_offset_idx = ff_vvc_cu_chroma_qp_offset_idx(lc); |
|
for (int i = CB - 1; i < JCBCR; i++) |
|
lc->parse.chroma_qp_offset[i] = pps->chroma_qp_offset_list[cu_chroma_qp_offset_idx][i]; |
|
} else { |
|
memset(lc->parse.chroma_qp_offset, 0, sizeof(lc->parse.chroma_qp_offset)); |
|
} |
|
lc->parse.is_cu_chroma_qp_offset_coded = 1; |
|
} |
|
} |
|
|
|
static int hls_transform_unit(VVCLocalContext *lc, int x0, int y0,int tu_width, int tu_height, int sub_tu_index, int ch_type) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
CodingUnit *cu = lc->cu; |
|
TransformUnit *tu = add_tu(fc, cu, x0, y0, tu_width, tu_height); |
|
const int min_cb_width = pps->min_cb_width; |
|
const VVCTreeType tree_type = cu->tree_type; |
|
const int is_128 = cu->cb_width > 64 || cu->cb_height > 64; |
|
const int is_isp = cu->isp_split_type != ISP_NO_SPLIT; |
|
const int is_isp_last_tu = is_isp && (sub_tu_index == cu->num_intra_subpartitions - 1); |
|
const int is_sbt_not_coded = cu->sbt_flag && |
|
((sub_tu_index == 0 && cu->sbt_pos_flag) || (sub_tu_index == 1 && !cu->sbt_pos_flag)); |
|
const int chroma_available = tree_type != DUAL_TREE_LUMA && sps->r->sps_chroma_format_idc && |
|
(!is_isp || is_isp_last_tu); |
|
int ret, xc, yc, wc, hc, is_chroma_coded; |
|
|
|
if (!tu) |
|
return AVERROR_INVALIDDATA; |
|
|
|
if (tree_type == SINGLE_TREE && is_isp_last_tu) { |
|
const int x_cu = x0 >> fc->ps.sps->min_cb_log2_size_y; |
|
const int y_cu = y0 >> fc->ps.sps->min_cb_log2_size_y; |
|
xc = SAMPLE_CTB(fc->tab.cb_pos_x[ch_type], x_cu, y_cu); |
|
yc = SAMPLE_CTB(fc->tab.cb_pos_y[ch_type], x_cu, y_cu); |
|
wc = SAMPLE_CTB(fc->tab.cb_width[ch_type], x_cu, y_cu); |
|
hc = SAMPLE_CTB(fc->tab.cb_height[ch_type], x_cu, y_cu); |
|
} else { |
|
xc = x0, yc = y0, wc = tu_width, hc = tu_height; |
|
} |
|
|
|
if (chroma_available && !is_sbt_not_coded) { |
|
tu->coded_flag[CB] = ff_vvc_tu_cb_coded_flag(lc); |
|
tu->coded_flag[CR] = ff_vvc_tu_cr_coded_flag(lc, tu->coded_flag[CB]); |
|
} |
|
|
|
is_chroma_coded = chroma_available && (tu->coded_flag[CB] || tu->coded_flag[CR]); |
|
|
|
if (tree_type != DUAL_TREE_CHROMA) { |
|
int has_qp_delta; |
|
tu->coded_flag[LUMA] = tu_y_coded_flag_decode(lc, is_sbt_not_coded, sub_tu_index, is_isp, is_chroma_coded); |
|
has_qp_delta = (is_128 || tu->coded_flag[LUMA] || is_chroma_coded) && |
|
pps->r->pps_cu_qp_delta_enabled_flag && !lc->parse.is_cu_qp_delta_coded; |
|
ret = set_qp_y(lc, x0, y0, has_qp_delta); |
|
if (ret < 0) |
|
return ret; |
|
add_tb(tu, lc, x0, y0, tu_width, tu_height, LUMA); |
|
} |
|
if (tree_type != DUAL_TREE_LUMA) { |
|
chroma_qp_offset_decode(lc, is_128, is_chroma_coded); |
|
if (chroma_available) { |
|
const int hs = sps->hshift[CHROMA]; |
|
const int vs = sps->vshift[CHROMA]; |
|
add_tb(tu, lc, xc, yc, wc >> hs, hc >> vs, CB); |
|
add_tb(tu, lc, xc, yc, wc >> hs, hc >> vs, CR); |
|
} |
|
} |
|
if (sps->r->sps_joint_cbcr_enabled_flag && ((cu->pred_mode == MODE_INTRA && |
|
(tu->coded_flag[CB] || tu->coded_flag[CR])) || |
|
(tu->coded_flag[CB] && tu->coded_flag[CR])) && |
|
chroma_available) { |
|
tu->joint_cbcr_residual_flag = ff_vvc_tu_joint_cbcr_residual_flag(lc, tu->coded_flag[1], tu->coded_flag[2]); |
|
} |
|
|
|
for (int i = 0; i < tu->nb_tbs; i++) { |
|
TransformBlock *tb = &tu->tbs[i]; |
|
const int is_chroma = tb->c_idx != LUMA; |
|
tb->has_coeffs = tu->coded_flag[tb->c_idx]; |
|
if (tb->has_coeffs && is_chroma) |
|
tb->has_coeffs = tb->c_idx == CB ? 1 : !(tu->coded_flag[CB] && tu->joint_cbcr_residual_flag); |
|
if (tb->has_coeffs) { |
|
tb->ts = cu->bdpcm_flag[tb->c_idx]; |
|
if (sps->r->sps_transform_skip_enabled_flag && !cu->bdpcm_flag[tb->c_idx] && |
|
tb->tb_width <= sps->max_ts_size && tb->tb_height <= sps->max_ts_size && |
|
!cu->sbt_flag && (is_chroma || !is_isp)) { |
|
tb->ts = ff_vvc_transform_skip_flag(lc, is_chroma); |
|
} |
|
ret = ff_vvc_residual_coding(lc, tb); |
|
if (ret < 0) |
|
return ret; |
|
set_tb_tab(fc->tab.tu_coded_flag[tb->c_idx], tu->coded_flag[tb->c_idx], fc, tb); |
|
} |
|
if (tb->c_idx != CR) |
|
set_tb_pos(fc, tb); |
|
if (tb->c_idx == CB) |
|
set_tb_tab(fc->tab.tu_joint_cbcr_residual_flag, tu->joint_cbcr_residual_flag, fc, tb); |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int hls_transform_tree(VVCLocalContext *lc, int x0, int y0,int tu_width, int tu_height, int ch_type) |
|
{ |
|
const CodingUnit *cu = lc->cu; |
|
const VVCSPS *sps = lc->fc->ps.sps; |
|
int ret; |
|
|
|
lc->parse.infer_tu_cbf_luma = 1; |
|
if (cu->isp_split_type == ISP_NO_SPLIT && !cu->sbt_flag) { |
|
if (tu_width > sps->max_tb_size_y || tu_height > sps->max_tb_size_y) { |
|
const int ver_split_first = tu_width > sps->max_tb_size_y && tu_width > tu_height; |
|
const int trafo_width = ver_split_first ? (tu_width / 2) : tu_width; |
|
const int trafo_height = !ver_split_first ? (tu_height / 2) : tu_height; |
|
|
|
#define TRANSFORM_TREE(x, y) do { \ |
|
ret = hls_transform_tree(lc, x, y, trafo_width, trafo_height, ch_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0) |
|
|
|
TRANSFORM_TREE(x0, y0); |
|
if (ver_split_first) |
|
TRANSFORM_TREE(x0 + trafo_width, y0); |
|
else |
|
TRANSFORM_TREE(x0, y0 + trafo_height); |
|
|
|
} else { |
|
ret = hls_transform_unit(lc, x0, y0, tu_width, tu_height, 0, ch_type); |
|
if (ret < 0) |
|
return ret; |
|
|
|
} |
|
} else if (cu->sbt_flag) { |
|
if (!cu->sbt_horizontal_flag) { |
|
#define TRANSFORM_UNIT(x, width, idx) do { \ |
|
ret = hls_transform_unit(lc, x, y0, width, tu_height, idx, ch_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0) |
|
|
|
const int trafo_width = tu_width * lc->parse.sbt_num_fourths_tb0 / 4; |
|
TRANSFORM_UNIT(x0, trafo_width, 0); |
|
TRANSFORM_UNIT(x0 + trafo_width, tu_width - trafo_width, 1); |
|
|
|
#undef TRANSFORM_UNIT |
|
} else { |
|
#define TRANSFORM_UNIT(y, height, idx) do { \ |
|
ret = hls_transform_unit(lc, x0, y, tu_width, height, idx, ch_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0) |
|
|
|
const int trafo_height = tu_height * lc->parse.sbt_num_fourths_tb0 / 4; |
|
TRANSFORM_UNIT(y0, trafo_height, 0); |
|
TRANSFORM_UNIT(y0 + trafo_height, tu_height - trafo_height, 1); |
|
|
|
#undef TRANSFORM_UNIT |
|
} |
|
} else if (cu->isp_split_type == ISP_HOR_SPLIT) { |
|
const int trafo_height = tu_height / cu->num_intra_subpartitions; |
|
for (int i = 0; i < cu->num_intra_subpartitions; i++) { |
|
ret = hls_transform_unit(lc, x0, y0 + trafo_height * i, tu_width, trafo_height, i, 0); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} else if (cu->isp_split_type == ISP_VER_SPLIT) { |
|
const int trafo_width = tu_width / cu->num_intra_subpartitions; |
|
for (int i = 0; i < cu->num_intra_subpartitions; i++) { |
|
ret = hls_transform_unit(lc, x0 + trafo_width * i , y0, trafo_width, tu_height, i, 0); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int skipped_transform_tree(VVCLocalContext *lc, int x0, int y0,int tu_width, int tu_height) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const CodingUnit *cu = lc->cu; |
|
const VVCSPS *sps = fc->ps.sps; |
|
|
|
if (tu_width > sps->max_tb_size_y || tu_height > sps->max_tb_size_y) { |
|
const int ver_split_first = tu_width > sps->max_tb_size_y && tu_width > tu_height; |
|
const int trafo_width = ver_split_first ? (tu_width / 2) : tu_width; |
|
const int trafo_height = !ver_split_first ? (tu_height / 2) : tu_height; |
|
|
|
#define SKIPPED_TRANSFORM_TREE(x, y) do { \ |
|
int ret = skipped_transform_tree(lc, x, y, trafo_width, trafo_height); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0) |
|
|
|
SKIPPED_TRANSFORM_TREE(x0, y0); |
|
if (ver_split_first) |
|
SKIPPED_TRANSFORM_TREE(x0 + trafo_width, y0); |
|
else |
|
SKIPPED_TRANSFORM_TREE(x0, y0 + trafo_height); |
|
} else { |
|
TransformUnit *tu = add_tu(fc, lc->cu, x0, y0, tu_width, tu_height); |
|
const int has_chroma = sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA; |
|
const int c_start = cu->tree_type == DUAL_TREE_CHROMA ? CB : LUMA; |
|
const int c_end = has_chroma ? VVC_MAX_SAMPLE_ARRAYS : CB; |
|
|
|
if (!tu) |
|
return AVERROR_INVALIDDATA; |
|
for (int i = c_start; i < c_end; i++) { |
|
TransformBlock *tb = add_tb(tu, lc, x0, y0, tu_width >> sps->hshift[i], tu_height >> sps->vshift[i], i); |
|
if (i != CR) |
|
set_tb_pos(fc, tb); |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
//6.4.1 Allowed quad split process |
|
//6.4.2 Allowed binary split process |
|
//6.4.3 Allowed ternary split process |
|
static void can_split(const VVCLocalContext *lc, int x0, int y0,int cb_width, int cb_height, |
|
int mtt_depth, int depth_offset, int part_idx, VVCSplitMode last_split_mode, |
|
VVCTreeType tree_type, VVCModeType mode_type, VVCAllowedSplit* split) |
|
{ |
|
int min_qt_size, max_bt_size, max_tt_size, max_mtt_depth; |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSH *sh = &lc->sc->sh; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const int chroma = tree_type == DUAL_TREE_CHROMA; |
|
int min_cb_size_y = sps->min_cb_size_y; |
|
int *qt = &split->qt; |
|
int *btv = &split->btv; |
|
int *bth = &split->bth; |
|
int *ttv = &split->ttv; |
|
int *tth = &split->tth; |
|
|
|
*qt = *bth = *btv = *tth = *ttv = 1; |
|
|
|
if (mtt_depth) |
|
*qt = 0; |
|
|
|
min_qt_size = sh->min_qt_size[chroma]; |
|
if (cb_width <= min_qt_size) |
|
*qt = 0; |
|
|
|
if (chroma) { |
|
int chroma_area = (cb_width >> sps->hshift[1]) * (cb_height >> sps->vshift[1]); |
|
int chroma_width = cb_width >> sps->hshift[1]; |
|
|
|
if (chroma_width == 8) |
|
*ttv = 0; |
|
else if (chroma_width <= 4) { |
|
if (chroma_width == 4) |
|
*btv = 0; |
|
*qt = 0; |
|
} |
|
if (mode_type == MODE_TYPE_INTRA) |
|
*qt = *btv = *bth = *ttv = *tth = 0; |
|
if (chroma_area <= 32) { |
|
*ttv = *tth = 0; |
|
if (chroma_area <= 16) |
|
*btv = *bth = 0; |
|
} |
|
} |
|
max_bt_size = sh->max_bt_size[chroma]; |
|
max_tt_size = sh->max_tt_size[chroma]; |
|
max_mtt_depth = sh->max_mtt_depth[chroma] + depth_offset; |
|
|
|
if (mode_type == MODE_TYPE_INTER) { |
|
int area = cb_width * cb_height; |
|
if (area == 32) |
|
*btv = *bth = 0; |
|
else if (area == 64) |
|
*ttv = *tth = 0; |
|
} |
|
if (cb_width <= 2 * min_cb_size_y) { |
|
*ttv = 0; |
|
if (cb_width <= min_cb_size_y) |
|
*btv = 0; |
|
} |
|
if (cb_height <= 2 * min_cb_size_y) { |
|
*tth = 0; |
|
if (cb_height <= min_cb_size_y) |
|
*bth = 0; |
|
} |
|
if (cb_width > max_bt_size || cb_height > max_bt_size) |
|
*btv = *bth = 0; |
|
max_tt_size = FFMIN(64, max_tt_size); |
|
if (cb_width > max_tt_size || cb_height > max_tt_size) |
|
*ttv = *tth = 0; |
|
if (mtt_depth >= max_mtt_depth) |
|
*btv = *bth = *ttv = *tth = 0; |
|
if (x0 + cb_width > pps->width) { |
|
*ttv = *tth = 0; |
|
if (cb_height > 64) |
|
*btv = 0; |
|
if (y0 + cb_height <= pps->height) |
|
*bth = 0; |
|
else if (cb_width > min_qt_size) |
|
*btv = *bth = 0; |
|
} |
|
if (y0 + cb_height > pps->height) { |
|
*btv = *ttv = *tth = 0; |
|
if (cb_width > 64) |
|
*bth = 0; |
|
} |
|
if (mtt_depth > 0 && part_idx == 1) { |
|
if (last_split_mode == SPLIT_TT_VER) |
|
*btv = 0; |
|
else if (last_split_mode == SPLIT_TT_HOR) |
|
*bth = 0; |
|
} |
|
if (cb_width <= 64 && cb_height > 64) |
|
*btv = 0; |
|
if (cb_width > 64 && cb_height <= 64) |
|
*bth = 0; |
|
} |
|
|
|
static int get_num_intra_subpartitions(enum IspType isp_split_type, int cb_width, int cb_height) |
|
{ |
|
if (isp_split_type == ISP_NO_SPLIT) |
|
return 1; |
|
if ((cb_width == 4 && cb_height == 8) || (cb_width == 8 && cb_height == 4)) |
|
return 2; |
|
return 4; |
|
} |
|
|
|
static int get_cclm_enabled(const VVCLocalContext *lc, const int x0, const int y0) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
int enabled = 0; |
|
|
|
if (!sps->r->sps_cclm_enabled_flag) |
|
return 0; |
|
if (!sps->r->sps_qtbtt_dual_tree_intra_flag || !IS_I(lc->sc->sh.r) || sps->ctb_log2_size_y < 6) |
|
return 1; |
|
else { |
|
const int x64 = x0 >> 6 << 6; |
|
const int y64 = y0 >> 6 << 6; |
|
const int y32 = y0 >> 5 << 5; |
|
const int x64_cu = x64 >> fc->ps.sps->min_cb_log2_size_y; |
|
const int y64_cu = y64 >> fc->ps.sps->min_cb_log2_size_y; |
|
const int y32_cu = y32 >> fc->ps.sps->min_cb_log2_size_y; |
|
const int min_cb_width = fc->ps.pps->min_cb_width; |
|
const int depth = SAMPLE_CTB(fc->tab.cqt_depth[1], x64_cu, y64_cu); |
|
const int min_depth = fc->ps.sps->ctb_log2_size_y - 6; |
|
const VVCSplitMode msm64 = (VVCSplitMode)TAB_MSM(fc, 0, x64, y64); |
|
const VVCSplitMode msm32 = (VVCSplitMode)TAB_MSM(fc, 1, x64, y32); |
|
|
|
enabled = SAMPLE_CTB(fc->tab.cb_width[1], x64_cu, y64_cu) == 64 && |
|
SAMPLE_CTB(fc->tab.cb_height[1], x64_cu, y64_cu) == 64; |
|
enabled |= depth == min_depth && msm64 == SPLIT_BT_HOR && |
|
SAMPLE_CTB(fc->tab.cb_width[1], x64_cu, y32_cu) == 64 && |
|
SAMPLE_CTB(fc->tab.cb_height[1], x64_cu, y32_cu) == 32; |
|
enabled |= depth > min_depth; |
|
enabled |= depth == min_depth && msm64 == SPLIT_BT_HOR && msm32 == SPLIT_BT_VER; |
|
|
|
if (enabled) { |
|
const int w = SAMPLE_CTB(fc->tab.cb_width[0], x64_cu, y64_cu); |
|
const int h = SAMPLE_CTB(fc->tab.cb_height[0], x64_cu, y64_cu); |
|
const int depth0 = SAMPLE_CTB(fc->tab.cqt_depth[0], x64_cu, y64_cu); |
|
if ((w == 64 && h == 64 && TAB_ISPMF(fc, x64, y64)) || |
|
((w < 64 || h < 64) && depth0 == min_depth)) |
|
return 0; |
|
} |
|
|
|
} |
|
|
|
return enabled; |
|
} |
|
|
|
static int less(const void *a, const void *b) |
|
{ |
|
return *(const int*)a - *(const int*)b; |
|
} |
|
|
|
//8.4.2 Derivation process for luma intra prediction mode |
|
static enum IntraPredMode luma_intra_pred_mode(VVCLocalContext* lc, const int intra_subpartitions_mode_flag) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
CodingUnit *cu = lc->cu; |
|
const int x0 = cu->x0; |
|
const int y0 = cu->y0; |
|
enum IntraPredMode pred; |
|
int intra_luma_not_planar_flag = 1; |
|
int intra_luma_mpm_remainder = 0; |
|
int intra_luma_mpm_flag = 1; |
|
int intra_luma_mpm_idx = 0; |
|
|
|
if (!cu->intra_luma_ref_idx) |
|
intra_luma_mpm_flag = ff_vvc_intra_luma_mpm_flag(lc); |
|
if (intra_luma_mpm_flag) { |
|
if (!cu->intra_luma_ref_idx) |
|
intra_luma_not_planar_flag = ff_vvc_intra_luma_not_planar_flag(lc, intra_subpartitions_mode_flag); |
|
if (intra_luma_not_planar_flag) |
|
intra_luma_mpm_idx = ff_vvc_intra_luma_mpm_idx(lc); |
|
} else { |
|
intra_luma_mpm_remainder = ff_vvc_intra_luma_mpm_remainder(lc); |
|
} |
|
|
|
if (!intra_luma_not_planar_flag) { |
|
pred = INTRA_PLANAR; |
|
} else { |
|
const VVCSPS *sps = fc->ps.sps; |
|
const int x_a = (x0 - 1) >> sps->min_cb_log2_size_y; |
|
const int y_a = (y0 + cu->cb_height - 1) >> sps->min_cb_log2_size_y; |
|
const int x_b = (x0 + cu->cb_width - 1) >> sps->min_cb_log2_size_y; |
|
const int y_b = (y0 - 1) >> sps->min_cb_log2_size_y; |
|
int min_cb_width = fc->ps.pps->min_cb_width; |
|
int x0b = av_zero_extend(x0, sps->ctb_log2_size_y); |
|
int y0b = av_zero_extend(y0, sps->ctb_log2_size_y); |
|
const int available_l = lc->ctb_left_flag || x0b; |
|
const int available_u = lc->ctb_up_flag || y0b; |
|
|
|
int a, b, cand[5]; |
|
|
|
if (!available_l || (SAMPLE_CTB(fc->tab.cpm[0], x_a, y_a) != MODE_INTRA) || |
|
SAMPLE_CTB(fc->tab.imf, x_a, y_a)) { |
|
a = INTRA_PLANAR; |
|
} else { |
|
a = SAMPLE_CTB(fc->tab.ipm, x_a, y_a); |
|
} |
|
|
|
if (!available_u || (SAMPLE_CTB(fc->tab.cpm[0], x_b, y_b) != MODE_INTRA) || |
|
SAMPLE_CTB(fc->tab.imf, x_b, y_b) || !y0b) { |
|
b = INTRA_PLANAR; |
|
} else { |
|
b = SAMPLE_CTB(fc->tab.ipm, x_b, y_b); |
|
} |
|
|
|
if (a == b && a > INTRA_DC) { |
|
cand[0] = a; |
|
cand[1] = 2 + ((a + 61) % 64); |
|
cand[2] = 2 + ((a - 1) % 64); |
|
cand[3] = 2 + ((a + 60) % 64); |
|
cand[4] = 2 + (a % 64); |
|
} else { |
|
const int minab = FFMIN(a, b); |
|
const int maxab = FFMAX(a, b); |
|
if (a > INTRA_DC && b > INTRA_DC) { |
|
const int diff = maxab - minab; |
|
cand[0] = a; |
|
cand[1] = b; |
|
if (diff == 1) { |
|
cand[2] = 2 + ((minab + 61) % 64); |
|
cand[3] = 2 + ((maxab - 1) % 64); |
|
cand[4] = 2 + ((minab + 60) % 64); |
|
} else if (diff >= 62) { |
|
cand[2] = 2 + ((minab - 1) % 64); |
|
cand[3] = 2 + ((maxab + 61) % 64); |
|
cand[4] = 2 + (minab % 64); |
|
} else if (diff == 2) { |
|
cand[2] = 2 + ((minab - 1) % 64); |
|
cand[3] = 2 + ((minab + 61) % 64); |
|
cand[4] = 2 + ((maxab - 1) % 64); |
|
} else { |
|
cand[2] = 2 + ((minab + 61) % 64); |
|
cand[3] = 2 + ((minab - 1) % 64); |
|
cand[4] = 2 + ((maxab + 61) % 64); |
|
} |
|
} else if (a > INTRA_DC || b > INTRA_DC) { |
|
cand[0] = maxab; |
|
cand[1] = 2 + ((maxab + 61 ) % 64); |
|
cand[2] = 2 + ((maxab - 1) % 64); |
|
cand[3] = 2 + ((maxab + 60 ) % 64); |
|
cand[4] = 2 + (maxab % 64); |
|
} else { |
|
cand[0] = INTRA_DC; |
|
cand[1] = INTRA_VERT; |
|
cand[2] = INTRA_HORZ; |
|
cand[3] = INTRA_VERT - 4; |
|
cand[4] = INTRA_VERT + 4; |
|
} |
|
} |
|
if (intra_luma_mpm_flag) { |
|
pred = cand[intra_luma_mpm_idx]; |
|
} else { |
|
qsort(cand, FF_ARRAY_ELEMS(cand), sizeof(cand[0]), less); |
|
pred = intra_luma_mpm_remainder + 1; |
|
for (int i = 0; i < FF_ARRAY_ELEMS(cand); i++) { |
|
if (pred >= cand[i]) |
|
pred++; |
|
} |
|
} |
|
} |
|
return pred; |
|
} |
|
|
|
static int lfnst_idx_decode(VVCLocalContext *lc) |
|
{ |
|
CodingUnit *cu = lc->cu; |
|
const VVCTreeType tree_type = cu->tree_type; |
|
const VVCSPS *sps = lc->fc->ps.sps; |
|
const int cb_width = cu->cb_width; |
|
const int cb_height = cu->cb_height; |
|
const TransformUnit *tu = cu->tus.head; |
|
int lfnst_width, lfnst_height, min_lfnst; |
|
int lfnst_idx = 0; |
|
|
|
memset(cu->apply_lfnst_flag, 0, sizeof(cu->apply_lfnst_flag)); |
|
|
|
if (!sps->r->sps_lfnst_enabled_flag || cu->pred_mode != MODE_INTRA || FFMAX(cb_width, cb_height) > sps->max_tb_size_y) |
|
return 0; |
|
|
|
while (tu) { |
|
for (int j = 0; j < tu->nb_tbs; j++) { |
|
const TransformBlock *tb = tu->tbs + j; |
|
if (tu->coded_flag[tb->c_idx] && tb->ts) |
|
return 0; |
|
} |
|
tu = tu->next; |
|
} |
|
|
|
if (tree_type == DUAL_TREE_CHROMA) { |
|
lfnst_width = cb_width >> sps->hshift[1]; |
|
lfnst_height = cb_height >> sps->vshift[1]; |
|
} else { |
|
const int vs = cu->isp_split_type == ISP_VER_SPLIT; |
|
const int hs = cu->isp_split_type == ISP_HOR_SPLIT; |
|
lfnst_width = vs ? cb_width / cu->num_intra_subpartitions : cb_width; |
|
lfnst_height = hs ? cb_height / cu->num_intra_subpartitions : cb_height; |
|
} |
|
min_lfnst = FFMIN(lfnst_width, lfnst_height); |
|
if (tree_type != DUAL_TREE_CHROMA && cu->intra_mip_flag && min_lfnst < 16) |
|
return 0; |
|
|
|
if (min_lfnst >= 4) { |
|
if ((cu->isp_split_type != ISP_NO_SPLIT || !lc->parse.lfnst_dc_only) && lc->parse.lfnst_zero_out_sig_coeff_flag) |
|
lfnst_idx = ff_vvc_lfnst_idx(lc, tree_type != SINGLE_TREE); |
|
} |
|
|
|
if (lfnst_idx) { |
|
cu->apply_lfnst_flag[LUMA] = tree_type != DUAL_TREE_CHROMA; |
|
cu->apply_lfnst_flag[CB] = cu->apply_lfnst_flag[CR] = tree_type == DUAL_TREE_CHROMA; |
|
} |
|
|
|
return lfnst_idx; |
|
} |
|
|
|
static MtsIdx mts_idx_decode(VVCLocalContext *lc) |
|
{ |
|
const CodingUnit *cu = lc->cu; |
|
const VVCSPS *sps = lc->fc->ps.sps; |
|
const int cb_width = cu->cb_width; |
|
const int cb_height = cu->cb_height; |
|
const uint8_t transform_skip_flag = cu->tus.head->tbs[0].ts; //fix me |
|
int mts_idx = MTS_DCT2_DCT2; |
|
if (cu->tree_type != DUAL_TREE_CHROMA && !cu->lfnst_idx && |
|
!transform_skip_flag && FFMAX(cb_width, cb_height) <= 32 && |
|
cu->isp_split_type == ISP_NO_SPLIT && !cu->sbt_flag && |
|
lc->parse.mts_zero_out_sig_coeff_flag && !lc->parse.mts_dc_only) { |
|
if ((cu->pred_mode == MODE_INTER && sps->r->sps_explicit_mts_inter_enabled_flag) || |
|
(cu->pred_mode == MODE_INTRA && sps->r->sps_explicit_mts_intra_enabled_flag)) { |
|
mts_idx = ff_vvc_mts_idx(lc); |
|
} |
|
} |
|
|
|
return mts_idx; |
|
} |
|
|
|
static enum IntraPredMode derive_center_luma_intra_pred_mode(const VVCFrameContext *fc, const VVCSPS *sps, const VVCPPS *pps, const CodingUnit *cu) |
|
{ |
|
const int x_center = (cu->x0 + cu->cb_width / 2) >> sps->min_cb_log2_size_y; |
|
const int y_center = (cu->y0 + cu->cb_height / 2) >> sps->min_cb_log2_size_y; |
|
const int min_cb_width = pps->min_cb_width; |
|
const int intra_mip_flag = SAMPLE_CTB(fc->tab.imf, x_center, y_center); |
|
const int cu_pred_mode = SAMPLE_CTB(fc->tab.cpm[0], x_center, y_center); |
|
const int intra_pred_mode_y = SAMPLE_CTB(fc->tab.ipm, x_center, y_center); |
|
|
|
if (intra_mip_flag) { |
|
if (cu->tree_type == SINGLE_TREE && sps->r->sps_chroma_format_idc == CHROMA_FORMAT_444) |
|
return INTRA_INVALID; |
|
return INTRA_PLANAR; |
|
} |
|
if (cu_pred_mode == MODE_IBC || cu_pred_mode == MODE_PLT) |
|
return INTRA_DC; |
|
return intra_pred_mode_y; |
|
} |
|
|
|
static void derive_chroma_intra_pred_mode(VVCLocalContext *lc, |
|
const int cclm_mode_flag, const int cclm_mode_idx, const int intra_chroma_pred_mode) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
CodingUnit *cu = lc->cu; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const int x_cb = cu->x0 >> sps->min_cb_log2_size_y; |
|
const int y_cb = cu->y0 >> sps->min_cb_log2_size_y; |
|
const int min_cb_width = pps->min_cb_width; |
|
const int intra_mip_flag = SAMPLE_CTB(fc->tab.imf, x_cb, y_cb); |
|
enum IntraPredMode luma_intra_pred_mode = SAMPLE_CTB(fc->tab.ipm, x_cb, y_cb); |
|
|
|
if (cu->tree_type == SINGLE_TREE && sps->r->sps_chroma_format_idc == CHROMA_FORMAT_444 && |
|
intra_chroma_pred_mode == 4 && intra_mip_flag) { |
|
cu->mip_chroma_direct_flag = 1; |
|
cu->intra_pred_mode_c = luma_intra_pred_mode; |
|
return; |
|
} |
|
luma_intra_pred_mode = derive_center_luma_intra_pred_mode(fc, sps, pps, cu); |
|
|
|
if (cu->act_enabled_flag) { |
|
cu->intra_pred_mode_c = luma_intra_pred_mode; |
|
return; |
|
} |
|
if (cclm_mode_flag) { |
|
cu->intra_pred_mode_c = INTRA_LT_CCLM + cclm_mode_idx; |
|
} else if (intra_chroma_pred_mode == 4){ |
|
cu->intra_pred_mode_c = luma_intra_pred_mode; |
|
} else { |
|
const static IntraPredMode pred_mode_c[][4 + 1] = { |
|
{INTRA_VDIAG, INTRA_PLANAR, INTRA_PLANAR, INTRA_PLANAR, INTRA_PLANAR}, |
|
{INTRA_VERT, INTRA_VDIAG, INTRA_VERT, INTRA_VERT, INTRA_VERT}, |
|
{INTRA_HORZ, INTRA_HORZ, INTRA_VDIAG, INTRA_HORZ, INTRA_HORZ}, |
|
{INTRA_DC, INTRA_DC, INTRA_DC, INTRA_VDIAG, INTRA_DC}, |
|
}; |
|
const int modes[4] = {INTRA_PLANAR, INTRA_VERT, INTRA_HORZ, INTRA_DC}; |
|
int idx; |
|
|
|
// This workaround is necessary to have 4:4:4 video decode correctly |
|
// See VVC ticket https://jvet.hhi.fraunhofer.de/trac/vvc/ticket/1602 |
|
// and VTM source https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM/-/blob/master/source/Lib/CommonLib/UnitTools.cpp#L736 |
|
if (cu->tree_type == SINGLE_TREE && sps->r->sps_chroma_format_idc == CHROMA_FORMAT_444 && intra_mip_flag) { |
|
idx = 4; |
|
} else { |
|
for (idx = 0; idx < FF_ARRAY_ELEMS(modes); idx++) { |
|
if (modes[idx] == luma_intra_pred_mode) |
|
break; |
|
} |
|
} |
|
|
|
cu->intra_pred_mode_c = pred_mode_c[intra_chroma_pred_mode][idx]; |
|
} |
|
if (sps->r->sps_chroma_format_idc == CHROMA_FORMAT_422 && cu->intra_pred_mode_c <= INTRA_VDIAG) { |
|
const static int mode_map_422[INTRA_VDIAG + 1] = { |
|
0, 1, 61, 62, 63, 64, 65, 66, 2, 3, 5, 6, 8, 10, 12, 13, |
|
14, 16, 18, 20, 22, 23, 24, 26, 28, 30, 31, 33, 34, 35, 36, 37, |
|
38, 39, 40, 41, 41, 42, 43, 43, 44, 44, 45, 45, 46, 47, 48, 48, |
|
49, 49, 50, 51, 51, 52, 52, 53, 54, 55, 55, 56, 56, 57, 57, 58, |
|
59, 59, 60, |
|
}; |
|
cu->intra_pred_mode_c = mode_map_422[cu->intra_pred_mode_c]; |
|
} |
|
} |
|
|
|
static void intra_luma_pred_modes(VVCLocalContext *lc) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
CodingUnit *cu = lc->cu; |
|
const int log2_min_cb_size = sps->min_cb_log2_size_y; |
|
const int x0 = cu->x0; |
|
const int y0 = cu->y0; |
|
const int x_cb = x0 >> log2_min_cb_size; |
|
const int y_cb = y0 >> log2_min_cb_size; |
|
const int cb_width = cu->cb_width; |
|
const int cb_height = cu->cb_height; |
|
|
|
cu->intra_luma_ref_idx = 0; |
|
if (sps->r->sps_bdpcm_enabled_flag && cb_width <= sps->max_ts_size && cb_height <= sps->max_ts_size) |
|
cu->bdpcm_flag[LUMA] = ff_vvc_intra_bdpcm_luma_flag(lc); |
|
if (cu->bdpcm_flag[LUMA]) { |
|
cu->intra_pred_mode_y = ff_vvc_intra_bdpcm_luma_dir_flag(lc) ? INTRA_VERT : INTRA_HORZ; |
|
} else { |
|
if (sps->r->sps_mip_enabled_flag) |
|
cu->intra_mip_flag = ff_vvc_intra_mip_flag(lc, fc->tab.imf); |
|
if (cu->intra_mip_flag) { |
|
int intra_mip_transposed_flag = ff_vvc_intra_mip_transposed_flag(lc); |
|
int intra_mip_mode = ff_vvc_intra_mip_mode(lc); |
|
int x = y_cb * pps->min_cb_width + x_cb; |
|
for (int y = 0; y < (cb_height>>log2_min_cb_size); y++) { |
|
int width = cb_width>>log2_min_cb_size; |
|
memset(&fc->tab.imf[x], cu->intra_mip_flag, width); |
|
fc->tab.imtf[x] = intra_mip_transposed_flag; |
|
fc->tab.imm[x] = intra_mip_mode; |
|
x += pps->min_cb_width; |
|
} |
|
cu->intra_pred_mode_y = intra_mip_mode; |
|
} else { |
|
int intra_subpartitions_mode_flag = 0; |
|
if (sps->r->sps_mrl_enabled_flag && ((y0 % sps->ctb_size_y) > 0)) |
|
cu->intra_luma_ref_idx = ff_vvc_intra_luma_ref_idx(lc); |
|
if (sps->r->sps_isp_enabled_flag && !cu->intra_luma_ref_idx && |
|
(cb_width <= sps->max_tb_size_y && cb_height <= sps->max_tb_size_y) && |
|
(cb_width * cb_height > MIN_TU_SIZE * MIN_TU_SIZE) && |
|
!cu->act_enabled_flag) |
|
intra_subpartitions_mode_flag = ff_vvc_intra_subpartitions_mode_flag(lc); |
|
if (!(x0 & 63) && !(y0 & 63)) |
|
TAB_ISPMF(fc, x0, y0) = intra_subpartitions_mode_flag; |
|
cu->isp_split_type = ff_vvc_isp_split_type(lc, intra_subpartitions_mode_flag); |
|
cu->num_intra_subpartitions = get_num_intra_subpartitions(cu->isp_split_type, cb_width, cb_height); |
|
cu->intra_pred_mode_y = luma_intra_pred_mode(lc, intra_subpartitions_mode_flag); |
|
} |
|
} |
|
set_cb_tab(lc, fc->tab.ipm, cu->intra_pred_mode_y); |
|
} |
|
|
|
static void intra_chroma_pred_modes(VVCLocalContext *lc) |
|
{ |
|
const VVCSPS *sps = lc->fc->ps.sps; |
|
CodingUnit *cu = lc->cu; |
|
const int hs = sps->hshift[CHROMA]; |
|
const int vs = sps->vshift[CHROMA]; |
|
|
|
cu->mip_chroma_direct_flag = 0; |
|
if (sps->r->sps_bdpcm_enabled_flag && |
|
(cu->cb_width >> hs) <= sps->max_ts_size && |
|
(cu->cb_height >> vs) <= sps->max_ts_size) { |
|
cu->bdpcm_flag[CB] = cu->bdpcm_flag[CR] = ff_vvc_intra_bdpcm_chroma_flag(lc); |
|
} |
|
if (cu->bdpcm_flag[CHROMA]) { |
|
cu->intra_pred_mode_c = ff_vvc_intra_bdpcm_chroma_dir_flag(lc) ? INTRA_VERT : INTRA_HORZ; |
|
} else { |
|
const int cclm_enabled = get_cclm_enabled(lc, cu->x0, cu->y0); |
|
int cclm_mode_flag = 0; |
|
int cclm_mode_idx = 0; |
|
int intra_chroma_pred_mode = 0; |
|
|
|
if (cclm_enabled) |
|
cclm_mode_flag = ff_vvc_cclm_mode_flag(lc); |
|
|
|
if (cclm_mode_flag) |
|
cclm_mode_idx = ff_vvc_cclm_mode_idx(lc); |
|
else |
|
intra_chroma_pred_mode = ff_vvc_intra_chroma_pred_mode(lc); |
|
derive_chroma_intra_pred_mode(lc, cclm_mode_flag, cclm_mode_idx, intra_chroma_pred_mode); |
|
} |
|
} |
|
|
|
static PredMode pred_mode_decode(VVCLocalContext *lc, |
|
const VVCTreeType tree_type, |
|
const VVCModeType mode_type) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
CodingUnit *cu = lc->cu; |
|
const VVCSPS *sps = fc->ps.sps; |
|
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; |
|
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))) { |
|
cu->skip_flag = ff_vvc_cu_skip_flag(lc, fc->tab.skip); |
|
} |
|
|
|
if (is_4x4 || mode_type == MODE_TYPE_INTRA || IS_I(rsh)) { |
|
pred_mode_flag = 1; |
|
} else if (mode_type == MODE_TYPE_INTER || cu->skip_flag) { |
|
pred_mode_flag = 0; |
|
} else { |
|
pred_mode_flag = ff_vvc_pred_mode_flag(lc, ch_type); |
|
} |
|
pred_mode = pred_mode_flag ? MODE_INTRA : MODE_INTER; |
|
|
|
if (((IS_I(rsh) && !cu->skip_flag) || |
|
(!IS_I(rsh) && (pred_mode != MODE_INTRA || |
|
((is_4x4 || mode_type == MODE_TYPE_INTRA) && !cu->skip_flag)))) && |
|
!is_128 && mode_type != MODE_TYPE_INTER && sps->r->sps_ibc_enabled_flag && |
|
tree_type != DUAL_TREE_CHROMA) { |
|
pred_mode_ibc_flag = ff_vvc_pred_mode_ibc_flag(lc, ch_type); |
|
} else if (cu->skip_flag && (is_4x4 || mode_type == MODE_TYPE_INTRA)) { |
|
pred_mode_ibc_flag = 1; |
|
} else if (is_128 || mode_type == MODE_TYPE_INTER || tree_type == DUAL_TREE_CHROMA) { |
|
pred_mode_ibc_flag = 0; |
|
} else { |
|
pred_mode_ibc_flag = (IS_I(rsh)) ? sps->r->sps_ibc_enabled_flag : 0; |
|
} |
|
if (pred_mode_ibc_flag) |
|
pred_mode = MODE_IBC; |
|
return pred_mode; |
|
} else { |
|
return MODE_INTRA; |
|
} |
|
} |
|
|
|
static void sbt_info(VVCLocalContext *lc, const VVCSPS *sps) |
|
{ |
|
CodingUnit *cu = lc->cu; |
|
const int cb_width = cu->cb_width; |
|
const int cb_height = cu->cb_height; |
|
|
|
if (cu->pred_mode == MODE_INTER && sps->r->sps_sbt_enabled_flag && !cu->ciip_flag |
|
&& cb_width <= sps->max_tb_size_y && cb_height <= sps->max_tb_size_y) { |
|
const int sbt_ver_h = cb_width >= 8; |
|
const int sbt_hor_h = cb_height >= 8; |
|
cu->sbt_flag = 0; |
|
if (sbt_ver_h || sbt_hor_h) |
|
cu->sbt_flag = ff_vvc_sbt_flag(lc); |
|
if (cu->sbt_flag) { |
|
const int sbt_ver_q = cb_width >= 16; |
|
const int sbt_hor_q = cb_height >= 16; |
|
int cu_sbt_quad_flag = 0; |
|
|
|
if ((sbt_ver_h || sbt_hor_h) && (sbt_ver_q || sbt_hor_q)) |
|
cu_sbt_quad_flag = ff_vvc_sbt_quad_flag(lc); |
|
if (cu_sbt_quad_flag) { |
|
cu->sbt_horizontal_flag = sbt_hor_q; |
|
if (sbt_ver_q && sbt_hor_q) |
|
cu->sbt_horizontal_flag = ff_vvc_sbt_horizontal_flag(lc); |
|
} else { |
|
cu->sbt_horizontal_flag = sbt_hor_h; |
|
if (sbt_ver_h && sbt_hor_h) |
|
cu->sbt_horizontal_flag = ff_vvc_sbt_horizontal_flag(lc); |
|
} |
|
cu->sbt_pos_flag = ff_vvc_sbt_pos_flag(lc); |
|
|
|
{ |
|
const int sbt_min = cu_sbt_quad_flag ? 1 : 2; |
|
lc->parse.sbt_num_fourths_tb0 = cu->sbt_pos_flag ? (4 - sbt_min) : sbt_min; |
|
} |
|
} |
|
} |
|
} |
|
|
|
static int skipped_transform_tree_unit(VVCLocalContext *lc) |
|
{ |
|
const H266RawSPS *rsps = lc->fc->ps.sps->r; |
|
const CodingUnit *cu = lc->cu; |
|
int ret; |
|
|
|
if (cu->tree_type != DUAL_TREE_CHROMA) |
|
set_qp_y(lc, cu->x0, cu->y0, 0); |
|
if (rsps->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA) |
|
set_qp_c(lc); |
|
ret = skipped_transform_tree(lc, cu->x0, cu->y0, cu->cb_width, cu->cb_height); |
|
if (ret < 0) |
|
return ret; |
|
return 0; |
|
} |
|
|
|
static void set_cb_pos(const VVCFrameContext *fc, const CodingUnit *cu) |
|
{ |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const int log2_min_cb_size = sps->min_cb_log2_size_y; |
|
const int x_cb = cu->x0 >> log2_min_cb_size; |
|
const int y_cb = cu->y0 >> log2_min_cb_size; |
|
const int ch_type = cu->ch_type; |
|
int x, y; |
|
|
|
x = y_cb * pps->min_cb_width + x_cb; |
|
for (y = 0; y < (cu->cb_height >> log2_min_cb_size); y++) { |
|
const int width = cu->cb_width >> log2_min_cb_size; |
|
|
|
for (int i = 0; i < width; i++) { |
|
fc->tab.cb_pos_x[ch_type][x + i] = cu->x0; |
|
fc->tab.cb_pos_y[ch_type][x + i] = cu->y0; |
|
} |
|
memset(&fc->tab.cb_width[ch_type][x], cu->cb_width, width); |
|
memset(&fc->tab.cb_height[ch_type][x], cu->cb_height, width); |
|
memset(&fc->tab.cqt_depth[ch_type][x], cu->cqt_depth, width); |
|
|
|
x += pps->min_cb_width; |
|
} |
|
} |
|
|
|
static CodingUnit* alloc_cu(VVCLocalContext *lc, const int x0, const int y0) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const int rx = x0 >> sps->ctb_log2_size_y; |
|
const int ry = y0 >> sps->ctb_log2_size_y; |
|
CTU *ctu = fc->tab.ctus + ry * pps->ctb_width + rx; |
|
CodingUnit *cu = ff_refstruct_pool_get(fc->cu_pool); |
|
|
|
if (!cu) |
|
return NULL; |
|
cu->next = NULL; |
|
|
|
if (lc->cu) |
|
lc->cu->next = cu; |
|
else |
|
ctu->cus = cu; |
|
lc->cu = cu; |
|
|
|
return cu; |
|
} |
|
|
|
static CodingUnit* add_cu(VVCLocalContext *lc, const int x0, const int y0, |
|
const int cb_width, const int cb_height, const int cqt_depth, const VVCTreeType tree_type) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const int ch_type = tree_type == DUAL_TREE_CHROMA ? 1 : 0; |
|
CodingUnit *cu = alloc_cu(lc, x0, y0); |
|
|
|
if (!cu) |
|
return NULL; |
|
|
|
memset(&cu->pu, 0, sizeof(cu->pu)); |
|
|
|
lc->parse.prev_tu_cbf_y = 0; |
|
|
|
cu->sbt_flag = 0; |
|
cu->act_enabled_flag = 0; |
|
|
|
cu->tree_type = tree_type; |
|
cu->x0 = x0; |
|
cu->y0 = y0; |
|
cu->cb_width = cb_width; |
|
cu->cb_height = cb_height; |
|
cu->ch_type = ch_type; |
|
cu->cqt_depth = cqt_depth; |
|
cu->tus.head = cu->tus.tail = NULL; |
|
cu->bdpcm_flag[LUMA] = cu->bdpcm_flag[CB] = cu->bdpcm_flag[CR] = 0; |
|
cu->isp_split_type = ISP_NO_SPLIT; |
|
cu->intra_mip_flag = 0; |
|
cu->ciip_flag = 0; |
|
cu->coded_flag = 1; |
|
cu->num_intra_subpartitions = 1; |
|
cu->pu.dmvr_flag = 0; |
|
|
|
set_cb_pos(fc, cu); |
|
return cu; |
|
} |
|
|
|
static void set_cu_tabs(const VVCLocalContext *lc, const CodingUnit *cu) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const TransformUnit *tu = cu->tus.head; |
|
|
|
if (cu->tree_type != DUAL_TREE_CHROMA) { |
|
set_cb_tab(lc, fc->tab.cpm[LUMA], cu->pred_mode); |
|
set_cb_tab(lc, fc->tab.skip, cu->skip_flag); |
|
} |
|
if (fc->ps.sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA) |
|
set_cb_tab(lc, fc->tab.cpm[CHROMA], cu->pred_mode); |
|
|
|
while (tu) { |
|
for (int j = 0; j < tu->nb_tbs; j++) { |
|
const TransformBlock *tb = tu->tbs + j; |
|
if (tb->c_idx != LUMA) |
|
set_qp_c_tab(lc, tu, tb); |
|
if (tb->c_idx != CR && cu->bdpcm_flag[tb->c_idx]) |
|
set_tb_tab(fc->tab.pcmf[tb->c_idx], 1, fc, tb); |
|
} |
|
tu = tu->next; |
|
} |
|
} |
|
|
|
//8.5.2.7 Derivation process for merge motion vector difference |
|
static void derive_mmvd(const VVCLocalContext *lc, MvField *mvf, const Mv *mmvd_offset) |
|
{ |
|
const SliceContext *sc = lc->sc; |
|
Mv mmvd[2]; |
|
|
|
if (mvf->pred_flag == PF_BI) { |
|
const RefPicList *rpl = sc->rpl; |
|
const int poc = lc->fc->ps.ph.poc; |
|
const int diff[] = { |
|
poc - rpl[L0].refs[mvf->ref_idx[L0]].poc, |
|
poc - rpl[L1].refs[mvf->ref_idx[L1]].poc |
|
}; |
|
const int sign = FFSIGN(diff[0]) != FFSIGN(diff[1]); |
|
|
|
if (diff[0] == diff[1]) { |
|
mmvd[1] = mmvd[0] = *mmvd_offset; |
|
} |
|
else { |
|
const int i = FFABS(diff[0]) < FFABS(diff[1]); |
|
const int o = !i; |
|
mmvd[i] = *mmvd_offset; |
|
if (!rpl[L0].refs[mvf->ref_idx[L0]].is_lt && !rpl[L1].refs[mvf->ref_idx[L1]].is_lt) { |
|
ff_vvc_mv_scale(&mmvd[o], mmvd_offset, diff[i], diff[o]); |
|
} |
|
else { |
|
mmvd[o].x = sign ? -mmvd[i].x : mmvd[i].x; |
|
mmvd[o].y = sign ? -mmvd[i].y : mmvd[i].y; |
|
} |
|
} |
|
mvf->mv[0].x += mmvd[0].x; |
|
mvf->mv[0].y += mmvd[0].y; |
|
mvf->mv[1].x += mmvd[1].x; |
|
mvf->mv[1].y += mmvd[1].y; |
|
} else { |
|
const int idx = mvf->pred_flag - PF_L0; |
|
mvf->mv[idx].x += mmvd_offset->x; |
|
mvf->mv[idx].y += mmvd_offset->y; |
|
} |
|
|
|
} |
|
|
|
static void mvf_to_mi(const MvField *mvf, MotionInfo *mi) |
|
{ |
|
mi->pred_flag = mvf->pred_flag; |
|
mi->bcw_idx = mvf->bcw_idx; |
|
mi->hpel_if_idx = mvf->hpel_if_idx; |
|
for (int i = 0; i < 2; i++) { |
|
const PredFlag mask = i + 1; |
|
if (mvf->pred_flag & mask) { |
|
mi->mv[i][0] = mvf->mv[i]; |
|
mi->ref_idx[i] = mvf->ref_idx[i]; |
|
} |
|
} |
|
} |
|
|
|
static void mv_merge_refine_pred_flag(MvField *mvf, const int width, const int height) |
|
{ |
|
if (mvf->pred_flag == PF_BI && (width + height) == 12) { |
|
mvf->pred_flag = PF_L0; |
|
mvf->bcw_idx = 0; |
|
} |
|
} |
|
|
|
// subblock-based inter prediction data |
|
static void merge_data_subblock(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCPH *ph = &fc->ps.ph; |
|
CodingUnit* cu = lc->cu; |
|
PredictionUnit *pu = &cu->pu; |
|
int merge_subblock_idx = 0; |
|
|
|
set_cb_tab(lc, fc->tab.msf, pu->merge_subblock_flag); |
|
if (ph->max_num_subblock_merge_cand > 1) { |
|
merge_subblock_idx = ff_vvc_merge_subblock_idx(lc, ph->max_num_subblock_merge_cand); |
|
} |
|
ff_vvc_sb_mv_merge_mode(lc, merge_subblock_idx, pu); |
|
} |
|
|
|
static void merge_data_regular(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPH *ph = &fc->ps.ph; |
|
const CodingUnit* cu = lc->cu; |
|
PredictionUnit *pu = &lc->cu->pu; |
|
int merge_idx = 0; |
|
Mv mmvd_offset; |
|
MvField mvf; |
|
|
|
if (sps->r->sps_mmvd_enabled_flag) |
|
pu->mmvd_merge_flag = ff_vvc_mmvd_merge_flag(lc); |
|
if (pu->mmvd_merge_flag) { |
|
int mmvd_cand_flag = 0; |
|
if (sps->max_num_merge_cand > 1) |
|
mmvd_cand_flag = ff_vvc_mmvd_cand_flag(lc); |
|
ff_vvc_mmvd_offset_coding(lc, &mmvd_offset, ph->r->ph_mmvd_fullpel_only_flag); |
|
merge_idx = mmvd_cand_flag; |
|
} else if (sps->max_num_merge_cand > 1) { |
|
merge_idx = ff_vvc_merge_idx(lc); |
|
} |
|
ff_vvc_luma_mv_merge_mode(lc, merge_idx, 0, &mvf); |
|
if (pu->mmvd_merge_flag) |
|
derive_mmvd(lc, &mvf, &mmvd_offset); |
|
mv_merge_refine_pred_flag(&mvf, cu->cb_width, cu->cb_height); |
|
ff_vvc_store_mvf(lc, &mvf); |
|
mvf_to_mi(&mvf, &pu->mi); |
|
} |
|
|
|
static int ciip_flag_decode(VVCLocalContext *lc, const int ciip_avaiable, const int gpm_avaiable, const int is_128) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const CodingUnit *cu = lc->cu; |
|
|
|
if (ciip_avaiable && gpm_avaiable) |
|
return ff_vvc_ciip_flag(lc); |
|
return sps->r->sps_ciip_enabled_flag && !cu->skip_flag && |
|
!is_128 && (cu->cb_width * cu->cb_height >= 64); |
|
} |
|
|
|
static void merge_data_gpm(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
PredictionUnit *pu = &lc->cu->pu; |
|
int merge_gpm_idx[2]; |
|
|
|
pu->merge_gpm_flag = 1; |
|
pu->gpm_partition_idx = ff_vvc_merge_gpm_partition_idx(lc); |
|
merge_gpm_idx[0] = ff_vvc_merge_gpm_idx(lc, 0); |
|
merge_gpm_idx[1] = 0; |
|
if (sps->max_num_gpm_merge_cand > 2) |
|
merge_gpm_idx[1] = ff_vvc_merge_gpm_idx(lc, 1); |
|
|
|
ff_vvc_luma_mv_merge_gpm(lc, merge_gpm_idx, pu->gpm_mv); |
|
ff_vvc_store_gpm_mvf(lc, pu); |
|
} |
|
|
|
static void merge_data_ciip(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext* fc = lc->fc; |
|
const VVCSPS* sps = fc->ps.sps; |
|
CodingUnit *cu = lc->cu; |
|
MotionInfo *mi = &cu->pu.mi; |
|
int merge_idx = 0; |
|
MvField mvf; |
|
|
|
if (sps->max_num_merge_cand > 1) |
|
merge_idx = ff_vvc_merge_idx(lc); |
|
ff_vvc_luma_mv_merge_mode(lc, merge_idx, 1, &mvf); |
|
mv_merge_refine_pred_flag(&mvf, cu->cb_width, cu->cb_height); |
|
ff_vvc_store_mvf(lc, &mvf); |
|
mvf_to_mi(&mvf, mi); |
|
cu->intra_pred_mode_y = cu->intra_pred_mode_c = INTRA_PLANAR; |
|
cu->intra_luma_ref_idx = 0; |
|
cu->intra_mip_flag = 0; |
|
} |
|
|
|
// block-based inter prediction data |
|
static void merge_data_block(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext* fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const H266RawSliceHeader *rsh = lc->sc->sh.r; |
|
CodingUnit *cu = lc->cu; |
|
const int cb_width = cu->cb_width; |
|
const int cb_height = cu->cb_height; |
|
const int is_128 = cb_width == 128 || cb_height == 128; |
|
const int ciip_avaiable = sps->r->sps_ciip_enabled_flag && |
|
!cu->skip_flag && (cb_width * cb_height >= 64); |
|
const int gpm_avaiable = sps->r->sps_gpm_enabled_flag && IS_B(rsh) && |
|
(cb_width >= 8) && (cb_height >=8) && |
|
(cb_width < 8 * cb_height) && (cb_height < 8 *cb_width); |
|
|
|
int regular_merge_flag = 1; |
|
|
|
if (!is_128 && (ciip_avaiable || gpm_avaiable)) |
|
regular_merge_flag = ff_vvc_regular_merge_flag(lc, cu->skip_flag); |
|
if (regular_merge_flag) { |
|
merge_data_regular(lc); |
|
} else { |
|
cu->ciip_flag = ciip_flag_decode(lc, ciip_avaiable, gpm_avaiable, is_128); |
|
if (cu->ciip_flag) |
|
merge_data_ciip(lc); |
|
else |
|
merge_data_gpm(lc); |
|
} |
|
} |
|
|
|
static int merge_data_ibc(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext* fc = lc->fc; |
|
const VVCSPS* sps = fc->ps.sps; |
|
MotionInfo *mi = &lc->cu->pu.mi; |
|
int merge_idx = 0; |
|
int ret; |
|
|
|
mi->pred_flag = PF_IBC; |
|
|
|
if (sps->max_num_ibc_merge_cand > 1) |
|
merge_idx = ff_vvc_merge_idx(lc); |
|
|
|
ret = ff_vvc_luma_mv_merge_ibc(lc, merge_idx, &mi->mv[L0][0]); |
|
if (ret) |
|
return ret; |
|
ff_vvc_store_mv(lc, mi); |
|
|
|
return 0; |
|
} |
|
|
|
static int hls_merge_data(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCPH *ph = &fc->ps.ph; |
|
const CodingUnit *cu = lc->cu; |
|
PredictionUnit *pu = &lc->cu->pu; |
|
int ret; |
|
|
|
pu->merge_gpm_flag = 0; |
|
pu->mi.num_sb_x = pu->mi.num_sb_y = 1; |
|
if (cu->pred_mode == MODE_IBC) { |
|
ret = merge_data_ibc(lc); |
|
if (ret) |
|
return ret; |
|
} else { |
|
if (ph->max_num_subblock_merge_cand > 0 && cu->cb_width >= 8 && cu->cb_height >= 8) |
|
pu->merge_subblock_flag = ff_vvc_merge_subblock_flag(lc); |
|
if (pu->merge_subblock_flag) |
|
merge_data_subblock(lc); |
|
else |
|
merge_data_block(lc); |
|
} |
|
return 0; |
|
} |
|
|
|
static void hls_mvd_coding(VVCLocalContext *lc, Mv* mvd) |
|
{ |
|
int16_t mv[2]; |
|
|
|
for (int i = 0; i < 2; i++) { |
|
mv[i] = ff_vvc_abs_mvd_greater0_flag(lc); |
|
} |
|
|
|
for (int i = 0; i < 2; i++) { |
|
if (mv[i]) |
|
mv[i] += ff_vvc_abs_mvd_greater1_flag(lc); |
|
} |
|
|
|
for (int i = 0; i < 2; i++) { |
|
if (mv[i] > 0) { |
|
if (mv[i] == 2) |
|
mv[i] += ff_vvc_abs_mvd_minus2(lc); |
|
mv[i] = (1 - 2 * ff_vvc_mvd_sign_flag(lc)) * mv[i]; |
|
} |
|
} |
|
mvd->x = mv[0]; |
|
mvd->y = mv[1]; |
|
} |
|
|
|
static int bcw_idx_decode(VVCLocalContext *lc, const MotionInfo *mi, const int cb_width, const int cb_height) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const VVCPH *ph = &fc->ps.ph; |
|
const VVCSH *sh = &lc->sc->sh; |
|
const PredWeightTable *w = pps->r->pps_wp_info_in_ph_flag ? &ph->pwt : &sh->pwt; |
|
int bcw_idx = 0; |
|
|
|
if (sps->r->sps_bcw_enabled_flag && mi->pred_flag == PF_BI && |
|
!w->weight_flag[L0][LUMA][mi->ref_idx[0]] && |
|
!w->weight_flag[L1][LUMA][mi->ref_idx[1]] && |
|
!w->weight_flag[L0][CHROMA][mi->ref_idx[0]] && |
|
!w->weight_flag[L1][CHROMA][mi->ref_idx[1]] && |
|
cb_width * cb_height >= 256) { |
|
bcw_idx = ff_vvc_bcw_idx(lc, ff_vvc_no_backward_pred_flag(lc)); |
|
} |
|
return bcw_idx; |
|
} |
|
|
|
static int8_t ref_idx_decode(VVCLocalContext *lc, const VVCSH *sh, const int sym_mvd_flag, const int lx) |
|
{ |
|
const H266RawSliceHeader *rsh = sh->r; |
|
int ref_idx = 0; |
|
|
|
if (rsh->num_ref_idx_active[lx] > 1 && !sym_mvd_flag) |
|
ref_idx = ff_vvc_ref_idx_lx(lc, rsh->num_ref_idx_active[lx]); |
|
else if (sym_mvd_flag) |
|
ref_idx = sh->ref_idx_sym[lx]; |
|
return ref_idx; |
|
} |
|
|
|
static int mvds_decode(VVCLocalContext *lc, Mv mvds[2][MAX_CONTROL_POINTS], |
|
const int num_cp_mv, const int lx) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCPH *ph = &fc->ps.ph; |
|
const PredictionUnit *pu = &lc->cu->pu; |
|
const MotionInfo *mi = &pu->mi; |
|
int has_no_zero_mvd = 0; |
|
|
|
if (lx == L1 && ph->r->ph_mvd_l1_zero_flag && mi->pred_flag == PF_BI) { |
|
for (int j = 0; j < num_cp_mv; j++) |
|
AV_ZERO64(&mvds[lx][j]); |
|
} else { |
|
Mv *mvd0 = &mvds[lx][0]; |
|
if (lx == L1 && pu->sym_mvd_flag) { |
|
mvd0->x = -mvds[L0][0].x; |
|
mvd0->y = -mvds[L0][0].y; |
|
} else { |
|
hls_mvd_coding(lc, mvd0); |
|
} |
|
has_no_zero_mvd |= (mvd0->x || mvd0->y); |
|
for (int j = 1; j < num_cp_mv; j++) { |
|
Mv *mvd = &mvds[lx][j]; |
|
hls_mvd_coding(lc, mvd); |
|
mvd->x += mvd0->x; |
|
mvd->y += mvd0->y; |
|
has_no_zero_mvd |= (mvd->x || mvd->y); |
|
} |
|
} |
|
return has_no_zero_mvd; |
|
} |
|
|
|
static void mvp_add_difference(MotionInfo *mi, const int num_cp_mv, |
|
const Mv mvds[2][MAX_CONTROL_POINTS], const int amvr_shift) |
|
{ |
|
for (int i = 0; i < 2; i++) { |
|
const PredFlag mask = i + PF_L0; |
|
if (mi->pred_flag & mask) { |
|
for (int j = 0; j < num_cp_mv; j++) { |
|
const Mv *mvd = &mvds[i][j]; |
|
mi->mv[i][j].x += mvd->x * (1 << amvr_shift); |
|
mi->mv[i][j].y += mvd->y * (1 << amvr_shift); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static int mvp_data_ibc(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const CodingUnit *cu = lc->cu; |
|
const PredictionUnit *pu = &lc->cu->pu; |
|
const VVCSPS *sps = fc->ps.sps; |
|
MotionInfo *mi = &lc->cu->pu.mi; |
|
int mvp_l0_flag = 0; |
|
int amvr_shift = 4; |
|
Mv *mv = &mi->mv[L0][0]; |
|
int ret; |
|
|
|
mi->pred_flag = PF_IBC; |
|
mi->num_sb_x = 1; |
|
mi->num_sb_y = 1; |
|
|
|
hls_mvd_coding(lc, mv); |
|
if (sps->max_num_ibc_merge_cand > 1) |
|
mvp_l0_flag = ff_vvc_mvp_lx_flag(lc); |
|
if (sps->r->sps_amvr_enabled_flag && (mv->x || mv->y)) |
|
amvr_shift = ff_vvc_amvr_shift(lc, pu->inter_affine_flag, cu->pred_mode, 1); |
|
|
|
ret = ff_vvc_mvp_ibc(lc, mvp_l0_flag, amvr_shift, mv); |
|
if (ret) |
|
return ret; |
|
ff_vvc_store_mv(lc, mi); |
|
|
|
return 0; |
|
} |
|
|
|
static int mvp_data(VVCLocalContext *lc) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const CodingUnit *cu = lc->cu; |
|
PredictionUnit *pu = &lc->cu->pu; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPH *ph = &fc->ps.ph; |
|
const VVCSH *sh = &lc->sc->sh; |
|
const H266RawSliceHeader *rsh = sh->r; |
|
MotionInfo *mi = &pu->mi; |
|
const int cb_width = cu->cb_width; |
|
const int cb_height = cu->cb_height; |
|
|
|
int mvp_lx_flag[2] = {0}; |
|
int cu_affine_type_flag = 0; |
|
int num_cp_mv; |
|
int amvr_enabled, has_no_zero_mvd = 0, amvr_shift; |
|
Mv mvds[2][MAX_CONTROL_POINTS]; |
|
|
|
mi->pred_flag = ff_vvc_pred_flag(lc, IS_B(rsh)); |
|
if (sps->r->sps_affine_enabled_flag && cb_width >= 16 && cb_height >= 16) { |
|
pu->inter_affine_flag = ff_vvc_inter_affine_flag(lc); |
|
set_cb_tab(lc, fc->tab.iaf, pu->inter_affine_flag); |
|
if (sps->r->sps_6param_affine_enabled_flag && pu->inter_affine_flag) |
|
cu_affine_type_flag = ff_vvc_cu_affine_type_flag(lc); |
|
} |
|
mi->motion_model_idc = pu->inter_affine_flag + cu_affine_type_flag; |
|
num_cp_mv = mi->motion_model_idc + 1; |
|
|
|
if (sps->r->sps_smvd_enabled_flag && !ph->r->ph_mvd_l1_zero_flag && |
|
mi->pred_flag == PF_BI && !pu->inter_affine_flag && |
|
sh->ref_idx_sym[0] > -1 && sh->ref_idx_sym[1] > -1) |
|
pu->sym_mvd_flag = ff_vvc_sym_mvd_flag(lc); |
|
|
|
for (int i = L0; i <= L1; i++) { |
|
const PredFlag pred_flag = PF_L0 + !i; |
|
if (mi->pred_flag != pred_flag) { |
|
mi->ref_idx[i] = ref_idx_decode(lc, sh, pu->sym_mvd_flag, i); |
|
has_no_zero_mvd |= mvds_decode(lc, mvds, num_cp_mv, i); |
|
mvp_lx_flag[i] = ff_vvc_mvp_lx_flag(lc); |
|
} |
|
} |
|
|
|
amvr_enabled = mi->motion_model_idc == MOTION_TRANSLATION ? |
|
sps->r->sps_amvr_enabled_flag : sps->r->sps_affine_amvr_enabled_flag; |
|
amvr_enabled &= has_no_zero_mvd; |
|
|
|
amvr_shift = ff_vvc_amvr_shift(lc, pu->inter_affine_flag, cu->pred_mode, amvr_enabled); |
|
|
|
mi->hpel_if_idx = amvr_shift == 3; |
|
mi->bcw_idx = bcw_idx_decode(lc, mi, cb_width, cb_height); |
|
|
|
if (mi->motion_model_idc) |
|
ff_vvc_affine_mvp(lc, mvp_lx_flag, amvr_shift, mi); |
|
else |
|
ff_vvc_mvp(lc, mvp_lx_flag, amvr_shift, mi); |
|
|
|
mvp_add_difference(mi, num_cp_mv, mvds, amvr_shift); |
|
|
|
if (mi->motion_model_idc) |
|
ff_vvc_store_sb_mvs(lc, pu); |
|
else |
|
ff_vvc_store_mv(lc, &pu->mi); |
|
|
|
return 0; |
|
} |
|
|
|
// derive bdofFlag from 8.5.6 Decoding process for inter blocks |
|
// derive dmvr from 8.5.1 General decoding process for coding units coded in inter prediction mode |
|
static void derive_dmvr_bdof_flag(const VVCLocalContext *lc, PredictionUnit *pu) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const VVCPH *ph = &fc->ps.ph; |
|
const VVCSH *sh = &lc->sc->sh; |
|
const int poc = ph->poc; |
|
const MotionInfo *mi = &pu->mi; |
|
const int8_t *ref_idx = mi->ref_idx; |
|
const VVCRefPic *rp0 = &lc->sc->rpl[L0].refs[ref_idx[L0]]; |
|
const VVCRefPic *rp1 = &lc->sc->rpl[L1].refs[ref_idx[L1]]; |
|
const CodingUnit *cu = lc->cu; |
|
const PredWeightTable *w = pps->r->pps_wp_info_in_ph_flag ? &fc->ps.ph.pwt : &sh->pwt; |
|
|
|
pu->bdof_flag = 0; |
|
|
|
if (mi->pred_flag == PF_BI && |
|
(poc - rp0->poc == rp1->poc - poc) && |
|
!rp0->is_lt && !rp1->is_lt && |
|
!cu->ciip_flag && |
|
!mi->bcw_idx && |
|
!w->weight_flag[L0][LUMA][ref_idx[L0]] && !w->weight_flag[L1][LUMA][ref_idx[L1]] && |
|
!w->weight_flag[L0][CHROMA][ref_idx[L0]] && !w->weight_flag[L1][CHROMA][ref_idx[L1]] && |
|
cu->cb_width >= 8 && cu->cb_height >= 8 && |
|
(cu->cb_width * cu->cb_height >= 128) && |
|
!rp0->is_scaled && !rp1->is_scaled) { |
|
if (!ph->r->ph_bdof_disabled_flag && |
|
mi->motion_model_idc == MOTION_TRANSLATION && |
|
!pu->merge_subblock_flag && |
|
!pu->sym_mvd_flag) |
|
pu->bdof_flag = 1; |
|
if (!ph->r->ph_dmvr_disabled_flag && |
|
pu->general_merge_flag && |
|
!pu->mmvd_merge_flag) |
|
pu->dmvr_flag = 1; |
|
} |
|
} |
|
|
|
// part of 8.5.1 General decoding process for coding units coded in inter prediction mode |
|
static void refine_regular_subblock(const VVCLocalContext *lc) |
|
{ |
|
const CodingUnit *cu = lc->cu; |
|
PredictionUnit *pu = &lc->cu->pu; |
|
|
|
derive_dmvr_bdof_flag(lc, pu); |
|
if (pu->dmvr_flag || pu->bdof_flag) { |
|
pu->mi.num_sb_x = (cu->cb_width > 16) ? (cu->cb_width >> 4) : 1; |
|
pu->mi.num_sb_y = (cu->cb_height > 16) ? (cu->cb_height >> 4) : 1; |
|
} |
|
} |
|
|
|
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, 1); |
|
} else { |
|
const VVCPPS *pps = fc->ps.pps; |
|
const int w = cu->cb_width >> MIN_PU_LOG2; |
|
|
|
for (int y = cu->y0 >> MIN_PU_LOG2; y < (cu->y0 + cu->cb_height) >> MIN_PU_LOG2; y++) { |
|
const int idx = pps->min_pu_width * y + (cu->x0 >> MIN_PU_LOG2); |
|
const MvField *mvf = fc->tab.mvf + idx; |
|
MvField *dmvr_mvf = fc->ref->tab_dmvr_mvf + idx; |
|
|
|
memcpy(dmvr_mvf, mvf, sizeof(MvField) * w); |
|
} |
|
} |
|
} |
|
|
|
static int inter_data(VVCLocalContext *lc) |
|
{ |
|
const CodingUnit *cu = lc->cu; |
|
PredictionUnit *pu = &lc->cu->pu; |
|
const MotionInfo *mi = &pu->mi; |
|
int ret = 0; |
|
|
|
pu->general_merge_flag = 1; |
|
if (!cu->skip_flag) |
|
pu->general_merge_flag = ff_vvc_general_merge_flag(lc); |
|
|
|
if (pu->general_merge_flag) { |
|
hls_merge_data(lc); |
|
} else if (cu->pred_mode == MODE_IBC){ |
|
ret = mvp_data_ibc(lc); |
|
} else { |
|
ret = mvp_data(lc); |
|
} |
|
|
|
if (cu->pred_mode == MODE_IBC) |
|
{ |
|
ff_vvc_update_hmvp(lc, mi); |
|
} else if (!pu->merge_gpm_flag && !pu->inter_affine_flag && !pu->merge_subblock_flag) { |
|
refine_regular_subblock(lc); |
|
ff_vvc_update_hmvp(lc, mi); |
|
} |
|
|
|
if (!pu->dmvr_flag) |
|
fill_dmvr_info(lc); |
|
return ret; |
|
} |
|
|
|
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; |
|
|
|
CodingUnit *cu = add_cu(lc, x0, y0, cb_width, cb_height, cqt_depth, tree_type); |
|
|
|
if (!cu) |
|
return AVERROR(ENOMEM); |
|
|
|
ff_vvc_set_neighbour_available(lc, cu->x0, cu->y0, cu->cb_width, cu->cb_height); |
|
|
|
if (IS_I(rsh) && is_128) |
|
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; |
|
} |
|
if (cu->pred_mode == MODE_INTRA || cu->pred_mode == MODE_PLT) { |
|
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; |
|
} else { |
|
intra_luma_pred_modes(lc); |
|
} |
|
ff_vvc_set_intra_mvf(lc, 0); |
|
} |
|
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; |
|
} else if (!pred_mode_plt_flag) { |
|
if (!cu->act_enabled_flag) |
|
intra_chroma_pred_modes(lc); |
|
} |
|
} |
|
} else if (tree_type != DUAL_TREE_CHROMA) { /* MODE_INTER or MODE_IBC */ |
|
if ((ret = inter_data(lc)) < 0) |
|
return ret; |
|
} |
|
if (cu->pred_mode != MODE_INTRA && !pred_mode_plt_flag && !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); |
|
|
|
if (cu->coded_flag) { |
|
sbt_info(lc, sps); |
|
if (sps->r->sps_act_enabled_flag && cu->pred_mode != MODE_INTRA && tree_type == SINGLE_TREE) { |
|
avpriv_report_missing_feature(fc->log_ctx, "Adaptive Color Transform"); |
|
return AVERROR_PATCHWELCOME; |
|
} |
|
lc->parse.lfnst_dc_only = 1; |
|
lc->parse.lfnst_zero_out_sig_coeff_flag = 1; |
|
lc->parse.mts_dc_only = 1; |
|
lc->parse.mts_zero_out_sig_coeff_flag = 1; |
|
ret = hls_transform_tree(lc, x0, y0, cb_width, cb_height, cu->ch_type); |
|
if (ret < 0) |
|
return ret; |
|
cu->lfnst_idx = lfnst_idx_decode(lc); |
|
cu->mts_idx = mts_idx_decode(lc); |
|
set_qp_c(lc); |
|
} else { |
|
ret = skipped_transform_tree_unit(lc); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
set_cu_tabs(lc, cu); |
|
|
|
return 0; |
|
} |
|
|
|
static int derive_mode_type_condition(const VVCLocalContext *lc, |
|
const VVCSplitMode split, const int cb_width, const int cb_height, const VVCModeType mode_type_curr) |
|
{ |
|
const H266RawSliceHeader *rsh = lc->sc->sh.r; |
|
const VVCSPS *sps = lc->fc->ps.sps; |
|
const int area = cb_width * cb_height; |
|
|
|
if ((IS_I(rsh) && sps->r->sps_qtbtt_dual_tree_intra_flag) || |
|
mode_type_curr != MODE_TYPE_ALL || !sps->r->sps_chroma_format_idc || |
|
sps->r->sps_chroma_format_idc == CHROMA_FORMAT_444) |
|
return 0; |
|
if ((area == 64 && (split == SPLIT_QT || split == SPLIT_TT_HOR || split == SPLIT_TT_VER)) || |
|
(area == 32 && (split == SPLIT_BT_HOR || split == SPLIT_BT_VER))) |
|
return 1; |
|
if ((area == 64 && (split == SPLIT_BT_HOR || split == SPLIT_BT_VER) && sps->r->sps_chroma_format_idc == CHROMA_FORMAT_420) || |
|
(area == 128 && (split == SPLIT_TT_HOR || split == SPLIT_TT_VER) && sps->r->sps_chroma_format_idc == CHROMA_FORMAT_420) || |
|
(cb_width == 8 && split == SPLIT_BT_VER) || (cb_width == 16 && split == SPLIT_TT_VER)) |
|
return 1 + !IS_I(rsh); |
|
|
|
return 0; |
|
} |
|
|
|
static VVCModeType mode_type_decode(VVCLocalContext *lc, const int x0, const int y0, |
|
const int cb_width, const int cb_height, const VVCSplitMode split, const int ch_type, |
|
const VVCModeType mode_type_curr) |
|
{ |
|
VVCModeType mode_type; |
|
const int mode_type_condition = derive_mode_type_condition(lc, split, cb_width, cb_height, mode_type_curr); |
|
|
|
if (mode_type_condition == 1) |
|
mode_type = MODE_TYPE_INTRA; |
|
else if (mode_type_condition == 2) { |
|
mode_type = ff_vvc_non_inter_flag(lc, x0, y0, ch_type) ? MODE_TYPE_INTRA : MODE_TYPE_INTER; |
|
} else { |
|
mode_type = mode_type_curr; |
|
} |
|
|
|
return mode_type; |
|
} |
|
|
|
static int hls_coding_tree(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, int part_idx, |
|
VVCSplitMode last_split_mode, VVCTreeType tree_type_curr, VVCModeType mode_type_curr); |
|
|
|
static int coding_tree_btv(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, |
|
VVCTreeType tree_type, VVCModeType mode_type) |
|
{ |
|
#define CODING_TREE(x, idx) do { \ |
|
ret = hls_coding_tree(lc, x, y0, cb_width / 2, cb_height, \ |
|
qg_on_y, qg_on_c, cb_sub_div + 1, cqt_depth, mtt_depth + 1, \ |
|
depth_offset, idx, SPLIT_BT_VER, tree_type, mode_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0); |
|
|
|
const VVCPPS *pps = lc->fc->ps.pps; |
|
const int x1 = x0 + cb_width / 2; |
|
int ret = 0; |
|
|
|
depth_offset += (x0 + cb_width > pps->width) ? 1 : 0; |
|
CODING_TREE(x0, 0); |
|
if (x1 < pps->width) |
|
CODING_TREE(x1, 1); |
|
|
|
return 0; |
|
|
|
#undef CODING_TREE |
|
} |
|
|
|
static int coding_tree_bth(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, |
|
VVCTreeType tree_type, VVCModeType mode_type) |
|
{ |
|
#define CODING_TREE(y, idx) do { \ |
|
ret = hls_coding_tree(lc, x0, y, cb_width , cb_height / 2, \ |
|
qg_on_y, qg_on_c, cb_sub_div + 1, cqt_depth, mtt_depth + 1, \ |
|
depth_offset, idx, SPLIT_BT_HOR, tree_type, mode_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0); |
|
|
|
const VVCPPS *pps = lc->fc->ps.pps; |
|
const int y1 = y0 + (cb_height / 2); |
|
int ret = 0; |
|
|
|
depth_offset += (y0 + cb_height > pps->height) ? 1 : 0; |
|
CODING_TREE(y0, 0); |
|
if (y1 < pps->height) |
|
CODING_TREE(y1, 1); |
|
|
|
return 0; |
|
|
|
#undef CODING_TREE |
|
} |
|
|
|
static int coding_tree_ttv(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, |
|
VVCTreeType tree_type, VVCModeType mode_type) |
|
{ |
|
#define CODING_TREE(x, w, sub_div, idx) do { \ |
|
ret = hls_coding_tree(lc, x, y0, w, cb_height, \ |
|
qg_on_y, qg_on_c, sub_div, cqt_depth, mtt_depth + 1, \ |
|
depth_offset, idx, SPLIT_TT_VER, tree_type, mode_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0); |
|
|
|
const VVCSH *sh = &lc->sc->sh; |
|
const int x1 = x0 + cb_width / 4; |
|
const int x2 = x0 + cb_width * 3 / 4; |
|
int ret; |
|
|
|
qg_on_y = qg_on_y && (cb_sub_div + 2 <= sh->cu_qp_delta_subdiv); |
|
qg_on_c = qg_on_c && (cb_sub_div + 2 <= sh->cu_chroma_qp_offset_subdiv); |
|
|
|
CODING_TREE(x0, cb_width / 4, cb_sub_div + 2, 0); |
|
CODING_TREE(x1, cb_width / 2, cb_sub_div + 1, 1); |
|
CODING_TREE(x2, cb_width / 4, cb_sub_div + 2, 2); |
|
|
|
return 0; |
|
|
|
#undef CODING_TREE |
|
} |
|
|
|
static int coding_tree_tth(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, |
|
VVCTreeType tree_type, VVCModeType mode_type) |
|
{ |
|
#define CODING_TREE(y, h, sub_div, idx) do { \ |
|
ret = hls_coding_tree(lc, x0, y, cb_width, h, \ |
|
qg_on_y, qg_on_c, sub_div, cqt_depth, mtt_depth + 1, \ |
|
depth_offset, idx, SPLIT_TT_HOR, tree_type, mode_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0); |
|
|
|
const VVCSH *sh = &lc->sc->sh; |
|
const int y1 = y0 + (cb_height / 4); |
|
const int y2 = y0 + (3 * cb_height / 4); |
|
int ret; |
|
|
|
qg_on_y = qg_on_y && (cb_sub_div + 2 <= sh->cu_qp_delta_subdiv); |
|
qg_on_c = qg_on_c && (cb_sub_div + 2 <= sh->cu_chroma_qp_offset_subdiv); |
|
|
|
CODING_TREE(y0, cb_height / 4, cb_sub_div + 2, 0); |
|
CODING_TREE(y1, cb_height / 2, cb_sub_div + 1, 1); |
|
CODING_TREE(y2, cb_height / 4, cb_sub_div + 2, 2); |
|
|
|
return 0; |
|
|
|
#undef CODING_TREE |
|
} |
|
|
|
static int coding_tree_qt(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, |
|
VVCTreeType tree_type, VVCModeType mode_type) |
|
{ |
|
#define CODING_TREE(x, y, idx) do { \ |
|
ret = hls_coding_tree(lc, x, y, cb_width / 2, cb_height / 2, \ |
|
qg_on_y, qg_on_c, cb_sub_div + 2, cqt_depth + 1, 0, 0, \ |
|
idx, SPLIT_QT, tree_type, mode_type); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0); |
|
|
|
const VVCPPS *pps = lc->fc->ps.pps; |
|
const int x1 = x0 + cb_width / 2; |
|
const int y1 = y0 + cb_height / 2; |
|
int ret = 0; |
|
|
|
CODING_TREE(x0, y0, 0); |
|
if (x1 < pps->width) |
|
CODING_TREE(x1, y0, 1); |
|
if (y1 < pps->height) |
|
CODING_TREE(x0, y1, 2); |
|
if (x1 < pps->width && |
|
y1 < pps->height) |
|
CODING_TREE(x1, y1, 3); |
|
|
|
return 0; |
|
|
|
#undef CODING_TREE |
|
} |
|
|
|
typedef int (*coding_tree_fn)(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, |
|
VVCTreeType tree_type, VVCModeType mode_type); |
|
|
|
const static coding_tree_fn coding_tree[] = { |
|
coding_tree_tth, |
|
coding_tree_bth, |
|
coding_tree_ttv, |
|
coding_tree_btv, |
|
coding_tree_qt, |
|
}; |
|
|
|
static int hls_coding_tree(VVCLocalContext *lc, |
|
int x0, int y0, int cb_width, int cb_height, int qg_on_y, int qg_on_c, |
|
int cb_sub_div, int cqt_depth, int mtt_depth, int depth_offset, int part_idx, |
|
VVCSplitMode last_split_mode, VVCTreeType tree_type_curr, VVCModeType mode_type_curr) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const VVCSH *sh = &lc->sc->sh; |
|
const H266RawSliceHeader *rsh = sh->r; |
|
const int ch_type = tree_type_curr == DUAL_TREE_CHROMA; |
|
int ret; |
|
VVCAllowedSplit allowed; |
|
|
|
if (pps->r->pps_cu_qp_delta_enabled_flag && qg_on_y && cb_sub_div <= sh->cu_qp_delta_subdiv) { |
|
lc->parse.is_cu_qp_delta_coded = 0; |
|
lc->parse.cu_qg_top_left_x = x0; |
|
lc->parse.cu_qg_top_left_y = y0; |
|
} |
|
if (rsh->sh_cu_chroma_qp_offset_enabled_flag && qg_on_c && |
|
cb_sub_div <= sh->cu_chroma_qp_offset_subdiv) { |
|
lc->parse.is_cu_chroma_qp_offset_coded = 0; |
|
memset(lc->parse.chroma_qp_offset, 0, sizeof(lc->parse.chroma_qp_offset)); |
|
} |
|
|
|
can_split(lc, x0, y0, cb_width, cb_height, mtt_depth, depth_offset, part_idx, |
|
last_split_mode, tree_type_curr, mode_type_curr, &allowed); |
|
if (ff_vvc_split_cu_flag(lc, x0, y0, cb_width, cb_height, ch_type, &allowed)) { |
|
VVCSplitMode split = ff_vvc_split_mode(lc, x0, y0, cb_width, cb_height, cqt_depth, mtt_depth, ch_type, &allowed); |
|
VVCModeType mode_type = mode_type_decode(lc, x0, y0, cb_width, cb_height, split, ch_type, mode_type_curr); |
|
|
|
VVCTreeType tree_type = (mode_type == MODE_TYPE_INTRA) ? DUAL_TREE_LUMA : tree_type_curr; |
|
|
|
if (split != SPLIT_QT) { |
|
if (!(x0 & 31) && !(y0 & 31) && mtt_depth <= 1) |
|
TAB_MSM(fc, mtt_depth, x0, y0) = split; |
|
} |
|
ret = coding_tree[split - 1](lc, x0, y0, cb_width, cb_height, qg_on_y, qg_on_c, |
|
cb_sub_div, cqt_depth, mtt_depth, depth_offset, tree_type, mode_type); |
|
if (ret < 0) |
|
return ret; |
|
if (mode_type_curr == MODE_TYPE_ALL && mode_type == MODE_TYPE_INTRA) { |
|
ret = hls_coding_tree(lc, x0, y0, cb_width, cb_height, 0, qg_on_c, cb_sub_div, |
|
cqt_depth, mtt_depth, 0, 0, split, DUAL_TREE_CHROMA, mode_type); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
} else { |
|
ret = hls_coding_unit(lc, x0, y0, cb_width, cb_height, cqt_depth, tree_type_curr, mode_type_curr); |
|
if (ret < 0) |
|
return ret; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int dual_tree_implicit_qt_split(VVCLocalContext *lc, |
|
const int x0, const int y0, const int cb_size, const int cqt_depth) |
|
{ |
|
const VVCSH *sh = &lc->sc->sh; |
|
const H266RawSliceHeader *rsh = sh->r; |
|
const VVCPPS *pps = lc->fc->ps.pps; |
|
const int cb_subdiv = 2 * cqt_depth; |
|
int ret; |
|
|
|
if (cb_size > 64) { |
|
#define DUAL_TREE(x, y) do { \ |
|
ret = dual_tree_implicit_qt_split(lc, x, y, cb_size / 2, cqt_depth + 1); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0) |
|
|
|
const int x1 = x0 + (cb_size / 2); |
|
const int y1 = y0 + (cb_size / 2); |
|
if (pps->r->pps_cu_qp_delta_enabled_flag && cb_subdiv <= sh->cu_qp_delta_subdiv) { |
|
lc->parse.is_cu_qp_delta_coded = 0; |
|
lc->parse.cu_qg_top_left_x = x0; |
|
lc->parse.cu_qg_top_left_y = y0; |
|
} |
|
if (rsh->sh_cu_chroma_qp_offset_enabled_flag && cb_subdiv <= sh->cu_chroma_qp_offset_subdiv) { |
|
lc->parse.is_cu_chroma_qp_offset_coded = 0; |
|
memset(lc->parse.chroma_qp_offset, 0, sizeof(lc->parse.chroma_qp_offset)); |
|
} |
|
DUAL_TREE(x0, y0); |
|
if (x1 < pps->width) |
|
DUAL_TREE(x1, y0); |
|
if (y1 < pps->height) |
|
DUAL_TREE(x0, y1); |
|
if (x1 < pps->width && y1 < pps->height) |
|
DUAL_TREE(x1, y1); |
|
#undef DUAL_TREE |
|
} else { |
|
#define CODING_TREE(tree_type) do { \ |
|
const int qg_on_y = tree_type == DUAL_TREE_LUMA; \ |
|
ret = hls_coding_tree(lc, x0, y0, cb_size, cb_size, qg_on_y, !qg_on_y, \ |
|
cb_subdiv, cqt_depth, 0, 0, 0, SPLIT_NONE, tree_type, MODE_TYPE_ALL); \ |
|
if (ret < 0) \ |
|
return ret; \ |
|
} while (0) |
|
CODING_TREE(DUAL_TREE_LUMA); |
|
CODING_TREE(DUAL_TREE_CHROMA); |
|
#undef CODING_TREE |
|
} |
|
return 0; |
|
} |
|
|
|
#define SET_SAO(elem, value) \ |
|
do { \ |
|
if (!sao_merge_up_flag && !sao_merge_left_flag) \ |
|
sao->elem = value; \ |
|
else if (sao_merge_left_flag) \ |
|
sao->elem = CTB(fc->tab.sao, rx-1, ry).elem; \ |
|
else if (sao_merge_up_flag) \ |
|
sao->elem = CTB(fc->tab.sao, rx, ry-1).elem; \ |
|
else \ |
|
sao->elem = 0; \ |
|
} while (0) |
|
|
|
static void hls_sao(VVCLocalContext *lc, const int rx, const int ry) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const H266RawSliceHeader *rsh = lc->sc->sh.r; |
|
int sao_merge_left_flag = 0; |
|
int sao_merge_up_flag = 0; |
|
SAOParams *sao = &CTB(fc->tab.sao, rx, ry); |
|
int c_idx, i; |
|
|
|
if (rsh->sh_sao_luma_used_flag || rsh->sh_sao_chroma_used_flag) { |
|
if (rx > 0) { |
|
if (lc->ctb_left_flag) |
|
sao_merge_left_flag = ff_vvc_sao_merge_flag_decode(lc); |
|
} |
|
if (ry > 0 && !sao_merge_left_flag) { |
|
if (lc->ctb_up_flag) |
|
sao_merge_up_flag = ff_vvc_sao_merge_flag_decode(lc); |
|
} |
|
} |
|
|
|
for (c_idx = 0; c_idx < (fc->ps.sps->r->sps_chroma_format_idc ? 3 : 1); c_idx++) { |
|
const int sao_used_flag = !c_idx ? rsh->sh_sao_luma_used_flag : rsh->sh_sao_chroma_used_flag; |
|
if (!sao_used_flag) { |
|
sao->type_idx[c_idx] = SAO_NOT_APPLIED; |
|
continue; |
|
} |
|
|
|
if (c_idx == 2) { |
|
sao->type_idx[2] = sao->type_idx[1]; |
|
sao->eo_class[2] = sao->eo_class[1]; |
|
} else { |
|
SET_SAO(type_idx[c_idx], ff_vvc_sao_type_idx_decode(lc)); |
|
} |
|
|
|
if (sao->type_idx[c_idx] == SAO_NOT_APPLIED) |
|
continue; |
|
|
|
for (i = 0; i < 4; i++) |
|
SET_SAO(offset_abs[c_idx][i], ff_vvc_sao_offset_abs_decode(lc)); |
|
|
|
if (sao->type_idx[c_idx] == SAO_BAND) { |
|
for (i = 0; i < 4; i++) { |
|
if (sao->offset_abs[c_idx][i]) { |
|
SET_SAO(offset_sign[c_idx][i], |
|
ff_vvc_sao_offset_sign_decode(lc)); |
|
} else { |
|
sao->offset_sign[c_idx][i] = 0; |
|
} |
|
} |
|
SET_SAO(band_position[c_idx], ff_vvc_sao_band_position_decode(lc)); |
|
} else if (c_idx != 2) { |
|
SET_SAO(eo_class[c_idx], ff_vvc_sao_eo_class_decode(lc)); |
|
} |
|
|
|
// Inferred parameters |
|
sao->offset_val[c_idx][0] = 0; |
|
for (i = 0; i < 4; i++) { |
|
sao->offset_val[c_idx][i + 1] = sao->offset_abs[c_idx][i]; |
|
if (sao->type_idx[c_idx] == SAO_EDGE) { |
|
if (i > 1) |
|
sao->offset_val[c_idx][i + 1] = -sao->offset_val[c_idx][i + 1]; |
|
} else if (sao->offset_sign[c_idx][i]) { |
|
sao->offset_val[c_idx][i + 1] = -sao->offset_val[c_idx][i + 1]; |
|
} |
|
sao->offset_val[c_idx][i + 1] *= 1 << (fc->ps.sps->bit_depth - FFMIN(10, fc->ps.sps->bit_depth)); |
|
} |
|
} |
|
} |
|
|
|
static void alf_params(VVCLocalContext *lc, const int rx, const int ry) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const H266RawSliceHeader *sh = lc->sc->sh.r; |
|
ALFParams *alf = &CTB(fc->tab.alf, rx, ry); |
|
|
|
alf->ctb_flag[LUMA] = alf->ctb_flag[CB] = alf->ctb_flag[CR] = 0; |
|
if (sh->sh_alf_enabled_flag) { |
|
alf->ctb_flag[LUMA] = ff_vvc_alf_ctb_flag(lc, rx, ry, LUMA); |
|
if (alf->ctb_flag[LUMA]) { |
|
uint8_t alf_use_aps_flag = 0; |
|
if (sh->sh_num_alf_aps_ids_luma > 0) |
|
alf_use_aps_flag = ff_vvc_alf_use_aps_flag(lc); |
|
if (alf_use_aps_flag) { |
|
alf->ctb_filt_set_idx_y = 16; |
|
if (sh->sh_num_alf_aps_ids_luma > 1) |
|
alf->ctb_filt_set_idx_y += ff_vvc_alf_luma_prev_filter_idx(lc); |
|
} else { |
|
alf->ctb_filt_set_idx_y = ff_vvc_alf_luma_fixed_filter_idx(lc); |
|
} |
|
} |
|
for (int c_idx = CB; c_idx <= CR; c_idx++) { |
|
const uint8_t alf_enabled_flag = |
|
c_idx == CB ? sh->sh_alf_cb_enabled_flag : sh->sh_alf_cr_enabled_flag; |
|
if (alf_enabled_flag) { |
|
const VVCALF *aps = fc->ps.alf_list[sh->sh_alf_aps_id_chroma]; |
|
alf->ctb_flag[c_idx] = ff_vvc_alf_ctb_flag(lc, rx, ry, c_idx); |
|
alf->alf_ctb_filter_alt_idx[c_idx - 1] = 0; |
|
if (alf->ctb_flag[c_idx] && aps->num_chroma_filters > 1) |
|
alf->alf_ctb_filter_alt_idx[c_idx - 1] = ff_vvc_alf_ctb_filter_alt_idx(lc, c_idx, aps->num_chroma_filters); |
|
} |
|
} |
|
} |
|
if (fc->ps.sps->r->sps_ccalf_enabled_flag) { |
|
const uint8_t cc_enabled[] = { sh->sh_alf_cc_cb_enabled_flag, sh->sh_alf_cc_cr_enabled_flag }; |
|
const uint8_t cc_aps_id[] = { sh->sh_alf_cc_cb_aps_id, sh->sh_alf_cc_cr_aps_id }; |
|
for (int i = 0; i < 2; i++) { |
|
alf->ctb_cc_idc[i] = 0; |
|
if (cc_enabled[i]) { |
|
const VVCALF *aps = fc->ps.alf_list[cc_aps_id[i]]; |
|
alf->ctb_cc_idc[i] = ff_vvc_alf_ctb_cc_idc(lc, rx, ry, i, aps->num_cc_filters[i]); |
|
} |
|
} |
|
} |
|
} |
|
|
|
static void deblock_params(VVCLocalContext *lc, const int rx, const int ry) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const VVCSH *sh = &lc->sc->sh; |
|
CTB(fc->tab.deblock, rx, ry) = sh->deblock; |
|
} |
|
|
|
static int hls_coding_tree_unit(VVCLocalContext *lc, |
|
const int x0, const int y0, const int ctu_idx, const int rx, const int ry) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const VVCSH *sh = &lc->sc->sh; |
|
const H266RawSliceHeader *rsh = sh->r; |
|
const unsigned int ctb_size = sps->ctb_size_y; |
|
int ret = 0; |
|
|
|
memset(lc->parse.chroma_qp_offset, 0, sizeof(lc->parse.chroma_qp_offset)); |
|
|
|
hls_sao(lc, x0 >> sps->ctb_log2_size_y, y0 >> sps->ctb_log2_size_y); |
|
alf_params(lc, x0 >> sps->ctb_log2_size_y, y0 >> sps->ctb_log2_size_y); |
|
deblock_params(lc, x0 >> sps->ctb_log2_size_y, y0 >> sps->ctb_log2_size_y); |
|
|
|
if (IS_I(rsh) && sps->r->sps_qtbtt_dual_tree_intra_flag) |
|
ret = dual_tree_implicit_qt_split(lc, x0, y0, ctb_size, 0); |
|
else |
|
ret = hls_coding_tree(lc, x0, y0, ctb_size, ctb_size, |
|
1, 1, 0, 0, 0, 0, 0, SPLIT_NONE, SINGLE_TREE, MODE_TYPE_ALL); |
|
if (ret < 0) |
|
return ret; |
|
|
|
if (rx == pps->ctb_to_col_bd[rx + 1] - 1) { |
|
if (ctu_idx == sh->num_ctus_in_curr_slice - 1) { |
|
const int end_of_slice_one_bit = ff_vvc_end_of_slice_flag_decode(lc); |
|
if (!end_of_slice_one_bit) |
|
return AVERROR_INVALIDDATA; |
|
} else { |
|
if (ry == pps->ctb_to_row_bd[ry + 1] - 1) { |
|
const int end_of_tile_one_bit = ff_vvc_end_of_tile_one_bit(lc); |
|
if (!end_of_tile_one_bit) |
|
return AVERROR_INVALIDDATA; |
|
} else { |
|
if (fc->ps.sps->r->sps_entropy_coding_sync_enabled_flag) { |
|
const int end_of_subset_one_bit = ff_vvc_end_of_subset_one_bit(lc); |
|
if (!end_of_subset_one_bit) |
|
return AVERROR_INVALIDDATA; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int has_inter_luma(const CodingUnit *cu) |
|
{ |
|
return cu->pred_mode != MODE_INTRA && cu->pred_mode != MODE_PLT && cu->tree_type != DUAL_TREE_CHROMA; |
|
} |
|
|
|
static int pred_get_y(const int y0, const Mv *mv, const int height) |
|
{ |
|
return FFMAX(0, y0 + (mv->y >> 4) + height); |
|
} |
|
|
|
static void cu_get_max_y(const CodingUnit *cu, int max_y[2][VVC_MAX_REF_ENTRIES], const VVCFrameContext *fc) |
|
{ |
|
const PredictionUnit *pu = &cu->pu; |
|
|
|
if (pu->merge_gpm_flag) { |
|
for (int i = 0; i < FF_ARRAY_ELEMS(pu->gpm_mv); i++) { |
|
const MvField *mvf = pu->gpm_mv + i; |
|
const int lx = mvf->pred_flag - PF_L0; |
|
const int idx = mvf->ref_idx[lx]; |
|
const int y = pred_get_y(cu->y0, mvf->mv + lx, cu->cb_height); |
|
|
|
max_y[lx][idx] = FFMAX(max_y[lx][idx], y); |
|
} |
|
} else { |
|
const MotionInfo *mi = &pu->mi; |
|
const int max_dmvr_off = (!pu->inter_affine_flag && pu->dmvr_flag) ? 2 : 0; |
|
const int sbw = cu->cb_width / mi->num_sb_x; |
|
const int sbh = cu->cb_height / mi->num_sb_y; |
|
for (int sby = 0; sby < mi->num_sb_y; sby++) { |
|
for (int sbx = 0; sbx < mi->num_sb_x; sbx++) { |
|
const int x0 = cu->x0 + sbx * sbw; |
|
const int y0 = cu->y0 + sby * sbh; |
|
const MvField *mvf = ff_vvc_get_mvf(fc, x0, y0); |
|
for (int lx = 0; lx < 2; lx++) { |
|
const PredFlag mask = 1 << lx; |
|
if (mvf->pred_flag & mask) { |
|
const int idx = mvf->ref_idx[lx]; |
|
const int y = pred_get_y(y0, mvf->mv + lx, sbh); |
|
|
|
max_y[lx][idx] = FFMAX(max_y[lx][idx], y + max_dmvr_off); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
static void ctu_get_pred(VVCLocalContext *lc, const int rs) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const H266RawSliceHeader *rsh = lc->sc->sh.r; |
|
CTU *ctu = fc->tab.ctus + rs; |
|
const CodingUnit *cu = ctu->cus; |
|
|
|
if (IS_I(rsh)) |
|
return; |
|
|
|
for (int lx = 0; lx < 2; lx++) |
|
memset(ctu->max_y[lx], -1, sizeof(ctu->max_y[0][0]) * rsh->num_ref_idx_active[lx]); |
|
|
|
while (cu) { |
|
if (has_inter_luma(cu)) { |
|
cu_get_max_y(cu, ctu->max_y, fc); |
|
ctu->has_dmvr |= cu->pu.dmvr_flag; |
|
} |
|
cu = cu->next; |
|
} |
|
ctu->max_y_idx[0] = ctu->max_y_idx[1] = 0; |
|
} |
|
|
|
int ff_vvc_coding_tree_unit(VVCLocalContext *lc, |
|
const int ctu_idx, const int rs, const int rx, const int ry) |
|
{ |
|
const VVCFrameContext *fc = lc->fc; |
|
const VVCSPS *sps = fc->ps.sps; |
|
const VVCPPS *pps = fc->ps.pps; |
|
const int x_ctb = rx << sps->ctb_log2_size_y; |
|
const int y_ctb = ry << sps->ctb_log2_size_y; |
|
const int ctb_size = 1 << sps->ctb_log2_size_y << sps->ctb_log2_size_y; |
|
EntryPoint* ep = lc->ep; |
|
int ret; |
|
|
|
if (rx == pps->ctb_to_col_bd[rx]) { |
|
ep->num_hmvp = 0; |
|
ep->num_hmvp_ibc = 0; |
|
ep->is_first_qg = ry == pps->ctb_to_row_bd[ry] || !ctu_idx; |
|
} |
|
|
|
lc->coeffs = fc->tab.coeffs + rs * ctb_size * VVC_MAX_SAMPLE_ARRAYS; |
|
lc->cu = NULL; |
|
|
|
ff_vvc_cabac_init(lc, ctu_idx, rx, ry); |
|
ff_vvc_decode_neighbour(lc, x_ctb, y_ctb, rx, ry, rs); |
|
ret = hls_coding_tree_unit(lc, x_ctb, y_ctb, ctu_idx, rx, ry); |
|
if (ret < 0) |
|
return ret; |
|
ctu_get_pred(lc, rs); |
|
|
|
return 0; |
|
} |
|
|
|
void ff_vvc_decode_neighbour(VVCLocalContext *lc, const int x_ctb, const int y_ctb, |
|
const int rx, const int ry, const int rs) |
|
{ |
|
VVCFrameContext *fc = lc->fc; |
|
const int ctb_size = fc->ps.sps->ctb_size_y; |
|
|
|
lc->end_of_tiles_x = fc->ps.pps->width; |
|
lc->end_of_tiles_y = fc->ps.pps->height; |
|
if (fc->ps.pps->ctb_to_col_bd[rx] != fc->ps.pps->ctb_to_col_bd[rx + 1]) |
|
lc->end_of_tiles_x = FFMIN(x_ctb + ctb_size, lc->end_of_tiles_x); |
|
if (fc->ps.pps->ctb_to_row_bd[ry] != fc->ps.pps->ctb_to_row_bd[ry + 1]) |
|
lc->end_of_tiles_y = FFMIN(y_ctb + ctb_size, lc->end_of_tiles_y); |
|
|
|
lc->boundary_flags = 0; |
|
if (rx > 0 && fc->ps.pps->ctb_to_col_bd[rx] != fc->ps.pps->ctb_to_col_bd[rx - 1]) |
|
lc->boundary_flags |= BOUNDARY_LEFT_TILE; |
|
if (rx > 0 && fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - 1]) |
|
lc->boundary_flags |= BOUNDARY_LEFT_SLICE; |
|
if (ry > 0 && fc->ps.pps->ctb_to_row_bd[ry] != fc->ps.pps->ctb_to_row_bd[ry - 1]) |
|
lc->boundary_flags |= BOUNDARY_UPPER_TILE; |
|
if (ry > 0 && fc->tab.slice_idx[rs] != fc->tab.slice_idx[rs - fc->ps.pps->ctb_width]) |
|
lc->boundary_flags |= BOUNDARY_UPPER_SLICE; |
|
if (fc->ps.sps->r->sps_subpic_ctu_top_left_x[lc->sc->sh.r->curr_subpic_idx] == rx) |
|
lc->boundary_flags |= BOUNDARY_LEFT_SUBPIC; |
|
if (fc->ps.sps->r->sps_subpic_ctu_top_left_y[lc->sc->sh.r->curr_subpic_idx] == ry) |
|
lc->boundary_flags |= BOUNDARY_UPPER_SUBPIC; |
|
lc->ctb_left_flag = rx > 0 && !(lc->boundary_flags & BOUNDARY_LEFT_TILE); |
|
lc->ctb_up_flag = ry > 0 && !(lc->boundary_flags & BOUNDARY_UPPER_TILE) && !(lc->boundary_flags & BOUNDARY_UPPER_SLICE); |
|
lc->ctb_up_right_flag = lc->ctb_up_flag && (fc->ps.pps->ctb_to_col_bd[rx] == fc->ps.pps->ctb_to_col_bd[rx + 1]) && |
|
(fc->ps.pps->ctb_to_row_bd[ry] == fc->ps.pps->ctb_to_row_bd[ry - 1]); |
|
lc->ctb_up_left_flag = lc->ctb_left_flag && lc->ctb_up_flag; |
|
} |
|
|
|
void ff_vvc_set_neighbour_available(VVCLocalContext *lc, |
|
const int x0, const int y0, const int w, const int h) |
|
{ |
|
const int log2_ctb_size = lc->fc->ps.sps->ctb_log2_size_y; |
|
const int x0b = av_zero_extend(x0, log2_ctb_size); |
|
const int y0b = av_zero_extend(y0, log2_ctb_size); |
|
|
|
lc->na.cand_up = (lc->ctb_up_flag || y0b); |
|
lc->na.cand_left = (lc->ctb_left_flag || x0b); |
|
lc->na.cand_up_left = (x0b || y0b) ? lc->na.cand_left && lc->na.cand_up : lc->ctb_up_left_flag; |
|
lc->na.cand_up_right_sap = |
|
(x0b + w == 1 << log2_ctb_size) ? lc->ctb_up_right_flag && !y0b : lc->na.cand_up; |
|
lc->na.cand_up_right = lc->na.cand_up_right_sap && (x0 + w) < lc->end_of_tiles_x; |
|
} |
|
|
|
void ff_vvc_ctu_free_cus(CTU *ctu) |
|
{ |
|
CodingUnit **cus = &ctu->cus; |
|
while (*cus) { |
|
CodingUnit *cu = *cus; |
|
TransformUnit **head = &cu->tus.head; |
|
|
|
*cus = cu->next; |
|
|
|
while (*head) { |
|
TransformUnit *tu = *head; |
|
*head = tu->next; |
|
ff_refstruct_unref(&tu); |
|
} |
|
cu->tus.tail = NULL; |
|
|
|
ff_refstruct_unref(&cu); |
|
} |
|
} |
|
|
|
int ff_vvc_get_qPy(const VVCFrameContext *fc, const int xc, const int yc) |
|
{ |
|
const int min_cb_log2_size_y = fc->ps.sps->min_cb_log2_size_y; |
|
const int x = xc >> min_cb_log2_size_y; |
|
const int y = yc >> min_cb_log2_size_y; |
|
return fc->tab.qp[LUMA][x + y * fc->ps.pps->min_cb_width]; |
|
} |
|
|
|
void ff_vvc_ep_init_stat_coeff(EntryPoint *ep, |
|
const int bit_depth, const int persistent_rice_adaptation_enabled_flag) |
|
{ |
|
for (size_t i = 0; i < FF_ARRAY_ELEMS(ep->stat_coeff); ++i) { |
|
ep->stat_coeff[i] = |
|
persistent_rice_adaptation_enabled_flag ? 2 * (av_log2(bit_depth - 10)) : 0; |
|
} |
|
}
|
|
|