ffmpeg/libavcodec/vvc/vvc_ctu.c
Frank Plowman dfcf5f828d lavc/vvc: Fix check whether QG is in first tile col
The second part of this condition is intended to check whether the
current quantisation group is in the first CTU column of the current
tile.  The issue is that ctb_to_col_bd gives the x-ordinate of the first
column of the current tile *in CTUs*, while xQg gives the x-ordinate of
the quantisation group *in samples*.  Rectify this by shifting xQg by
ctb_log2_size to get xQg in CTUs before comparing.

Fixes FFVVC issues #201 and #203.
2024-03-20 22:27:19 +08:00

2554 lines
96 KiB
C

/*
* 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 "vvc_cabac.h"
#include "vvc_ctu.h"
#include "vvc_inter.h"
#include "vvc_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 x_ctb = cu->x0 >> ctb_log2_size;
const int y_ctb = cu->y0 >> ctb_log2_size;
const int in_same_ctb_a = ((xQg - 1) >> ctb_log2_size) == x_ctb && (yQg >> ctb_log2_size) == y_ctb;
const int in_same_ctb_b = (xQg >> ctb_log2_size) == x_ctb && ((yQg - 1) >> ctb_log2_size) == y_ctb;
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_mod_uintp2(x0, sps->ctb_log2_size_y);
int y0b = av_mod_uintp2(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;
} else {
pred_mode_flag = is_4x4 || mode_type == MODE_TYPE_INTRA ||
mode_type != MODE_TYPE_INTER || IS_I(rsh);
pred_mode = pred_mode_flag ? MODE_INTRA : MODE_INTER;
}
return pred_mode;
}
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[0].list[mvf->ref_idx[0]],
poc - rpl[1].list[mvf->ref_idx[1]]
};
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[0].isLongTerm[mvf->ref_idx[0]] && !rpl[1].isLongTerm[mvf->ref_idx[1]]) {
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 void 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;
mi->pred_flag = PF_IBC;
if (sps->max_num_ibc_merge_cand > 1)
merge_idx = ff_vvc_merge_idx(lc);
ff_vvc_luma_mv_merge_ibc(lc, merge_idx, &mi->mv[L0][0]);
ff_vvc_store_mv(lc, mi);
}
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;
pu->merge_gpm_flag = 0;
pu->mi.num_sb_x = pu->mi.num_sb_y = 1;
if (cu->pred_mode == MODE_IBC) {
merge_data_ibc(lc);
} 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];
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);
ff_vvc_mvp_ibc(lc, mvp_l0_flag, amvr_shift, mv);
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 RefPicList *rpl0 = lc->sc->rpl + L0;
const RefPicList *rpl1 = lc->sc->rpl + L1;
const int8_t *ref_idx = pu->mi.ref_idx;
const MotionInfo *mi = &pu->mi;
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 - rpl0->list[ref_idx[L0]] == rpl1->list[ref_idx[L1]] - poc) &&
!rpl0->isLongTerm[ref_idx[L0]] && !rpl1->isLongTerm[ref_idx[L1]] &&
!cu->ciip_flag &&
!mi->bcw_idx &&
!w->weight_flag[L0][LUMA][mi->ref_idx[L0]] && !w->weight_flag[L1][LUMA][mi->ref_idx[L1]] &&
!w->weight_flag[L0][CHROMA][mi->ref_idx[L0]] && !w->weight_flag[L1][CHROMA][mi->ref_idx[L1]] &&
cu->cb_width >= 8 && cu->cb_height >= 8 &&
(cu->cb_width * cu->cb_height >= 128)) {
// fixme: for RprConstraintsActiveFlag
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);
if (ret < 0)
return ret;
} 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;
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_mod_uintp2(x0, log2_ctb_size);
const int y0b = av_mod_uintp2(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;
}
}