diff --git a/libavcodec/vvc/vvc_intra.c b/libavcodec/vvc/vvc_intra.c index fb001d6713..58dd492478 100644 --- a/libavcodec/vvc/vvc_intra.c +++ b/libavcodec/vvc/vvc_intra.c @@ -20,11 +20,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "libavutil/frame.h" +#include "libavutil/imgutils.h" #include "vvc_data.h" #include "vvc_inter.h" #include "vvc_intra.h" #include "vvc_itx_1d.h" +#include "vvc_mvs.h" static int is_cclm(enum IntraPredMode mode) { @@ -580,6 +582,81 @@ static int reconstruct(VVCLocalContext *lc) return 0; } +#define POS(c_idx, x, y) \ + &fc->frame->data[c_idx][((y) >> fc->ps.sps->vshift[c_idx]) * fc->frame->linesize[c_idx] + \ + (((x) >> fc->ps.sps->hshift[c_idx]) << fc->ps.sps->pixel_shift)] + +#define IBC_POS(c_idx, x, y) \ + (fc->tab.ibc_vir_buf[c_idx] + \ + (x << ps) + (y + ((cu->y0 & ~(sps->ctb_size_y - 1)) >> vs)) * ibc_stride) +#define IBC_X(x) ((x) & ((fc->tab.sz.ibc_buffer_width >> hs) - 1)) +#define IBC_Y(y) ((y) & ((1 << sps->ctb_log2_size_y >> vs) - 1)) + +static void intra_block_copy(const VVCLocalContext *lc, const int c_idx) +{ + const CodingUnit *cu = lc->cu; + const PredictionUnit *pu = &cu->pu; + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const Mv *bv = &pu->mi.mv[L0][0]; + const int hs = sps->hshift[c_idx]; + const int vs = sps->vshift[c_idx]; + const int ps = sps->pixel_shift; + const int ref_x = IBC_X((cu->x0 >> hs) + (bv->x >> (4 + hs))); + const int ref_y = IBC_Y((cu->y0 >> vs) + (bv->y >> (4 + vs))); + const int w = cu->cb_width >> hs; + const int h = cu->cb_height >> vs; + const int ibc_buf_width = fc->tab.sz.ibc_buffer_width >> hs; ///< IbcBufWidthY and IbcBufWidthC + const int rw = FFMIN(w, ibc_buf_width - ref_x); + const int ibc_stride = ibc_buf_width << ps; + const int dst_stride = fc->frame->linesize[c_idx]; + const uint8_t *ibc_buf = IBC_POS(c_idx, ref_x, ref_y); + uint8_t *dst = POS(c_idx, cu->x0, cu->y0); + + av_image_copy_plane(dst, dst_stride, ibc_buf, ibc_stride, rw << ps, h); + + if (w > rw) { + //wrap around, left part + ibc_buf = IBC_POS(c_idx, 0, ref_y); + dst += rw << ps; + av_image_copy_plane(dst, dst_stride, ibc_buf, ibc_stride, (w - rw) << ps, h); + } +} + +static void vvc_predict_ibc(const VVCLocalContext *lc) +{ + const H266RawSPS *rsps = lc->fc->ps.sps->r; + + intra_block_copy(lc, LUMA); + if (lc->cu->tree_type == SINGLE_TREE && rsps->sps_chroma_format_idc) { + intra_block_copy(lc, CB); + intra_block_copy(lc, CR); + } +} + +static void ibc_fill_vir_buf(const VVCLocalContext *lc, const CodingUnit *cu) +{ + const VVCFrameContext *fc = lc->fc; + const VVCSPS *sps = fc->ps.sps; + const int has_chroma = sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA; + const int start = cu->tree_type == DUAL_TREE_CHROMA; + const int end = has_chroma ? CR : LUMA; + + for (int c_idx = start; c_idx <= end; c_idx++) { + const int hs = sps->hshift[c_idx]; + const int vs = sps->vshift[c_idx]; + const int ps = sps->pixel_shift; + const int x = IBC_X(cu->x0 >> hs); + const int y = IBC_Y(cu->y0 >> vs); + const int src_stride = fc->frame->linesize[c_idx]; + const int ibc_stride = fc->tab.sz.ibc_buffer_width >> hs << ps; + const uint8_t *src = POS(c_idx, cu->x0, cu->y0); + uint8_t *ibc_buf = IBC_POS(c_idx, x, y); + + av_image_copy_plane(ibc_buf, ibc_stride, src, src_stride, cu->cb_width >> hs << ps , cu->cb_height >> vs); + } +} + int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const int ry) { const VVCFrameContext *fc = lc->fc; @@ -599,6 +676,8 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in if (cu->ciip_flag) ff_vvc_predict_ciip(lc); + else if (cu->pred_mode == MODE_IBC) + vvc_predict_ibc(lc); if (cu->coded_flag) { ret = reconstruct(lc); } else { @@ -607,6 +686,8 @@ int ff_vvc_reconstruct(VVCLocalContext *lc, const int rs, const int rx, const in if (sps->r->sps_chroma_format_idc && cu->tree_type != DUAL_TREE_LUMA) add_reconstructed_area(lc, CHROMA, cu->x0, cu->y0, cu->cb_width, cu->cb_height); } + if (sps->r->sps_ibc_enabled_flag) + ibc_fill_vir_buf(lc, cu); cu = cu->next; } ff_vvc_ctu_free_cus(ctu); diff --git a/libavcodec/vvc/vvcdec.c b/libavcodec/vvc/vvcdec.c index e88e746de4..f024cbd067 100644 --- a/libavcodec/vvc/vvcdec.c +++ b/libavcodec/vvc/vvcdec.c @@ -262,6 +262,31 @@ static void ispmf_tl_init(TabList *l, VVCFrameContext *fc) TL_ADD(ispmf, w64 * h64); } +static void ibc_tl_init(TabList *l, VVCFrameContext *fc) +{ + const VVCSPS *sps = fc->ps.sps; + const VVCPPS *pps = fc->ps.pps; + const int ctu_height = pps ? pps->ctb_height : 0; + const int ctu_size = sps ? sps->ctb_size_y : 0; + const int ps = sps ? sps->pixel_shift : 0; + const int chroma_idc = sps ? sps->r->sps_chroma_format_idc : 0; + const int has_ibc = sps ? sps->r->sps_ibc_enabled_flag : 0; + const int changed = fc->tab.sz.chroma_format_idc != chroma_idc || + fc->tab.sz.ctu_height != ctu_height || + fc->tab.sz.ctu_size != ctu_size || + fc->tab.sz.pixel_shift != ps; + + fc->tab.sz.ibc_buffer_width = ctu_size ? 2 * MAX_CTU_SIZE * MAX_CTU_SIZE / ctu_size : 0; + + tl_init(l, has_ibc, changed); + + for (int i = LUMA; i < VVC_MAX_SAMPLE_ARRAYS; i++) { + const int hs = sps ? sps->hshift[i] : 0; + const int vs = sps ? sps->vshift[i] : 0; + TL_ADD(ibc_vir_buf[i], fc->tab.sz.ibc_buffer_width * ctu_size * ctu_height << ps >> hs >> vs); + } +} + typedef void (*tl_init_fn)(TabList *l, VVCFrameContext *fc); static int frame_context_for_each_tl(VVCFrameContext *fc, int (*unary_fn)(TabList *l)) @@ -276,6 +301,7 @@ static int frame_context_for_each_tl(VVCFrameContext *fc, int (*unary_fn)(TabLis pixel_buffer_nz_tl_init, msm_tl_init, ispmf_tl_init, + ibc_tl_init, }; for (int i = 0; i < FF_ARRAY_ELEMS(init); i++) { diff --git a/libavcodec/vvc/vvcdec.h b/libavcodec/vvc/vvcdec.h index 4f7ef3a32f..aa3d715524 100644 --- a/libavcodec/vvc/vvcdec.h +++ b/libavcodec/vvc/vvcdec.h @@ -170,6 +170,8 @@ typedef struct VVCFrameContext { int *coeffs; struct CTU *ctus; + uint8_t *ibc_vir_buf[VVC_MAX_SAMPLE_ARRAYS]; ///< IbcVirBuf[] + //used in arrays_init only struct { int ctu_count; @@ -185,6 +187,7 @@ typedef struct VVCFrameContext { int pixel_shift; int bs_width; int bs_height; + int ibc_buffer_width; ///< IbcBufWidth } sz; } tab; } VVCFrameContext;