avcodec/vvcdec: alf, support virtual boundaries

see https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9503377

passed files:
    GDR_A_ERICSSON_2.bit
    GDR_B_NOKIA_2.bit
    GDR_C_NOKIA_2.bit
    VIRTUAL_A_MediaTek_3.bit
    VIRTUAL_B_MediaTek_3.bit
This commit is contained in:
Nuo Mi 2024-06-17 00:40:14 -04:00
parent 3bac5ba861
commit 23531c9776
3 changed files with 97 additions and 45 deletions

View File

@ -463,6 +463,13 @@ typedef struct ALFParams {
uint8_t ctb_cc_idc[2]; ///< alf_ctb_cc_cb_idc, alf_ctb_cc_cr_idc
} ALFParams;
typedef struct VVCRect {
int l; // left
int t; // top
int r; // right
int b; // bottom
} VVCRect;
/**
* parse a CTU
* @param lc local context for CTU

View File

@ -56,6 +56,9 @@ static const uint8_t betatable[64] = {
58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88,
};
// One vertical and one horizontal virtual boundary in a CTU at most. The CTU will be divided into 4 subblocks.
#define MAX_VBBS 4
static int get_virtual_boundary(const VVCFrameContext *fc, const int ctu_pos, const int vertical)
{
const VVCSPS *sps = fc->ps.sps;
@ -1129,58 +1132,107 @@ static void alf_get_edges(const VVCLocalContext *lc, int edges[MAX_EDGES], const
edges[RIGHT] = edges[RIGHT] || fc->ps.sps->r->sps_subpic_ctu_top_left_x[subpic_idx] + fc->ps.sps->r->sps_subpic_width_minus1[subpic_idx] == rx;
edges[BOTTOM] = edges[BOTTOM] || fc->ps.sps->r->sps_subpic_ctu_top_left_y[subpic_idx] + fc->ps.sps->r->sps_subpic_height_minus1[subpic_idx] == ry;
}
if (sps->r->sps_virtual_boundaries_enabled_flag) {
edges[LEFT] = edges[LEFT] || is_virtual_boundary(fc, rx << sps->ctb_log2_size_y, 1);
edges[TOP] = edges[TOP] || is_virtual_boundary(fc, ry << sps->ctb_log2_size_y, 0);
edges[RIGHT] = edges[RIGHT] || is_virtual_boundary(fc, (rx + 1) << sps->ctb_log2_size_y, 1);
edges[BOTTOM] = edges[BOTTOM] || is_virtual_boundary(fc, (ry + 1) << sps->ctb_log2_size_y, 0);
}
}
static void alf_init_subblock(VVCRect *sb, int sb_edges[MAX_EDGES], const VVCRect *b, const int edges[MAX_EDGES])
{
*sb = *b;
memcpy(sb_edges, edges, sizeof(int) * MAX_EDGES);
}
static void alf_get_subblock(VVCRect *sb, int edges[MAX_EDGES], const int bx, const int by, const int vb_pos[2], const int has_vb[2])
{
int *pos[] = { &sb->l, &sb->t, &sb->r, &sb->b };
for (int vertical = 0; vertical <= 1; vertical++) {
if (has_vb[vertical]) {
const int c = vertical ? (bx ? LEFT : RIGHT) : (by ? TOP : BOTTOM);
*pos[c] = vb_pos[vertical];
edges[c] = 1;
}
}
}
static void alf_get_subblocks(const VVCLocalContext *lc, VVCRect sbs[MAX_VBBS], int sb_edges[MAX_VBBS][MAX_EDGES], int *nb_sbs,
const int x0, const int y0, const int rx, const int ry)
{
VVCFrameContext *fc = lc->fc;
const VVCSPS *sps = fc->ps.sps;
const VVCPPS *pps = fc->ps.pps;
const int ctu_size_y = sps->ctb_size_y;
const int vb_pos[] = { get_virtual_boundary(fc, ry, 0), get_virtual_boundary(fc, rx, 1) };
const int has_vb[] = { vb_pos[0] > y0, vb_pos[1] > x0 };
const VVCRect b = { x0, y0, FFMIN(x0 + ctu_size_y, pps->width), FFMIN(y0 + ctu_size_y, pps->height) };
int edges[MAX_EDGES] = { !rx, !ry, rx == pps->ctb_width - 1, ry == pps->ctb_height - 1 };
int i = 0;
alf_get_edges(lc, edges, rx, ry);
for (int by = 0; by <= has_vb[0]; by++) {
for (int bx = 0; bx <= has_vb[1]; bx++, i++) {
alf_init_subblock(sbs + i, sb_edges[i], &b, edges);
alf_get_subblock(sbs + i, sb_edges[i], bx, by, vb_pos, has_vb);
}
}
*nb_sbs = i;
}
void ff_vvc_alf_filter(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 >> fc->ps.sps->ctb_log2_size_y;
const int ry = y0 >> fc->ps.sps->ctb_log2_size_y;
const int ctb_size_y = fc->ps.sps->ctb_size_y;
const int ps = fc->ps.sps->pixel_shift;
const int rx = x0 >> sps->ctb_log2_size_y;
const int ry = y0 >> sps->ctb_log2_size_y;
const int ps = sps->pixel_shift;
const int padded_stride = EDGE_EMU_BUFFER_STRIDE << ps;
const int padded_offset = padded_stride * ALF_PADDING_SIZE + (ALF_PADDING_SIZE << ps);
const int c_end = sps->r->sps_chroma_format_idc ? VVC_MAX_SAMPLE_ARRAYS : 1;
const int ctu_end = y0 + sps->ctb_size_y;
const ALFParams *alf = &CTB(fc->tab.alf, rx, ry);
int edges[MAX_EDGES] = { rx == 0, ry == 0, rx == pps->ctb_width - 1, ry == pps->ctb_height - 1 };
int sb_edges[MAX_VBBS][MAX_EDGES], nb_sbs;
VVCRect sbs[MAX_VBBS];
alf_get_edges(lc, edges, rx, ry);
alf_get_subblocks(lc, sbs, sb_edges, &nb_sbs, x0, y0, rx, ry);
for (int c_idx = 0; c_idx < c_end; c_idx++) {
const int hs = fc->ps.sps->hshift[c_idx];
const int vs = fc->ps.sps->vshift[c_idx];
const int ctb_size_h = ctb_size_y >> hs;
const int ctb_size_v = ctb_size_y >> vs;
const int x = x0 >> hs;
const int y = y0 >> vs;
const int pic_width = fc->ps.pps->width >> hs;
const int pic_height = fc->ps.pps->height >> vs;
const int width = FFMIN(pic_width - x, ctb_size_h);
const int height = FFMIN(pic_height - y, ctb_size_v);
const int src_stride = fc->frame->linesize[c_idx];
uint8_t *src = POS(c_idx, x0, y0);
uint8_t *padded;
for (int i = 0; i < nb_sbs; i++) {
const VVCRect *sb = sbs + i;
for (int c_idx = 0; c_idx < c_end; c_idx++) {
const int hs = fc->ps.sps->hshift[c_idx];
const int vs = fc->ps.sps->vshift[c_idx];
const int x = sb->l >> hs;
const int y = sb->t >> vs;
const int width = (sb->r - sb->l) >> hs;
const int height = (sb->b - sb->t) >> vs;
const int src_stride = fc->frame->linesize[c_idx];
uint8_t *src = POS(c_idx, sb->l, sb->t);
uint8_t *padded;
if (alf->ctb_flag[c_idx] || (!c_idx && (alf->ctb_cc_idc[0] || alf->ctb_cc_idc[1]))) {
padded = (c_idx ? lc->alf_buffer_chroma : lc->alf_buffer_luma) + padded_offset;
alf_prepare_buffer(fc, padded, src, x, y, rx, ry, width, height,
padded_stride, src_stride, c_idx, edges);
}
if (alf->ctb_flag[c_idx]) {
if (!c_idx) {
alf_filter_luma(lc, src, padded, src_stride, padded_stride, x, y,
width, height, y + ctb_size_v - ALF_VB_POS_ABOVE_LUMA, alf);
} else {
alf_filter_chroma(lc, src, padded, src_stride, padded_stride, c_idx,
width, height, ctb_size_v - ALF_VB_POS_ABOVE_CHROMA, alf);
if (alf->ctb_flag[c_idx] || (!c_idx && (alf->ctb_cc_idc[0] || alf->ctb_cc_idc[1]))) {
padded = (c_idx ? lc->alf_buffer_chroma : lc->alf_buffer_luma) + padded_offset;
alf_prepare_buffer(fc, padded, src, x, y, rx, ry, width, height,
padded_stride, src_stride, c_idx, sb_edges[i]);
}
if (alf->ctb_flag[c_idx]) {
if (!c_idx) {
alf_filter_luma(lc, src, padded, src_stride, padded_stride, x, y,
width, height, ctu_end - ALF_VB_POS_ABOVE_LUMA, alf);
} else {
alf_filter_chroma(lc, src, padded, src_stride, padded_stride, c_idx,
width, height, ((ctu_end - sb->t) >> vs) - ALF_VB_POS_ABOVE_CHROMA, alf);
}
}
if (c_idx && alf->ctb_cc_idc[c_idx - 1]) {
padded = lc->alf_buffer_luma + padded_offset;
alf_filter_cc(lc, src, padded, src_stride, padded_stride, c_idx,
width, height, hs, vs, ctu_end - sb->t - ALF_VB_POS_ABOVE_LUMA, alf);
}
}
if (c_idx && alf->ctb_cc_idc[c_idx - 1]) {
padded = lc->alf_buffer_luma + padded_offset;
alf_filter_cc(lc, src, padded, src_stride, padded_stride, c_idx,
width, height, hs, vs, (ctb_size_v << vs) - ALF_VB_POS_ABOVE_LUMA, alf);
}
}
}

View File

@ -30,13 +30,6 @@
#define PROF_TEMP_OFFSET (MAX_PB_SIZE + 32)
static const int bcw_w_lut[] = {4, 5, 3, 10, -2};
typedef struct VVCRect {
int l; // left
int t; // top
int r; // right
int b; // bottom
} VVCRect;
static void subpic_get_rect(VVCRect *r, const VVCFrame *src_frame, const int subpic_idx, const int is_chroma)
{
const VVCSPS *sps = src_frame->sps;