1161 lines · 33.5 KB · C
RawDownload
/* * VVC video decoder * * Copyright (C) 2021 Nuo Mi * Copyright (C) 2022 Xu Mu * * 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/codec_internal.h"#include "libavcodec/decode.h"#include "libavcodec/hwaccel_internal.h"#include "libavcodec/hwconfig.h"#include "libavcodec/profiles.h"#include "libavutil/refstruct.h"#include "libavutil/cpu.h"#include "libavutil/mem.h"#include "libavutil/thread.h" #include "dec.h"#include "ctu.h"#include "data.h"#include "refs.h"#include "thread.h"#include "config_components.h" #define TAB_MAX 32 typedef struct Tab {    void **tab;    size_t size;} Tab; typedef struct TabList {    Tab tabs[TAB_MAX];    int nb_tabs;     int zero;    int realloc;} TabList; #define TL_ADD(t, s) do {                                \    av_assert0(l->nb_tabs < TAB_MAX);                    \    l->tabs[l->nb_tabs].tab  = (void**)&fc->tab.t;       \    l->tabs[l->nb_tabs].size = sizeof(*fc->tab.t) * (s); \    l->nb_tabs++;                                        \} while (0) static void tl_init(TabList *l, const int zero, const int realloc){    l->nb_tabs = 0;    l->zero = zero;    l->realloc = realloc;} static int tl_free(TabList *l){    for (int i = 0; i < l->nb_tabs; i++)        av_freep(l->tabs[i].tab);     return 0;} static int tl_create(TabList *l){    if (l->realloc) {        tl_free(l);         for (int i = 0; i < l->nb_tabs; i++) {            Tab *t = l->tabs + i;            *t->tab = l->zero ? av_mallocz(t->size) : av_malloc(t->size);            if (!*t->tab)                return AVERROR(ENOMEM);        }    }    return 0;} static int tl_zero(TabList *l){    if (l->zero) {        for (int i = 0; i < l->nb_tabs; i++) {            Tab *t = l->tabs + i;            memset(*t->tab, 0, t->size);        }    }    return 0;} static void ctu_nz_tl_init(TabList *l, VVCFrameContext *fc){    const VVCSPS *sps   = fc->ps.sps;    const VVCPPS *pps   = fc->ps.pps;    const int ctu_size  = sps ? (1 << sps->ctb_log2_size_y << sps->ctb_log2_size_y) : 0;    const int ctu_count = pps ? pps->ctb_count : 0;    const int changed   = fc->tab.sz.ctu_count != ctu_count || fc->tab.sz.ctu_size != ctu_size;     tl_init(l, 0, changed);     TL_ADD(cus,     ctu_count);    TL_ADD(ctus,    ctu_count);    TL_ADD(deblock, ctu_count);    TL_ADD(sao,     ctu_count);    TL_ADD(alf,     ctu_count);    TL_ADD(slice_idx, ctu_count);    TL_ADD(coeffs,    ctu_count * ctu_size * VVC_MAX_SAMPLE_ARRAYS);} static void min_cb_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps            = fc->ps.pps;    const int pic_size_in_min_cb = pps ? pps->min_cb_width * pps->min_cb_height : 0;    const int changed            = fc->tab.sz.pic_size_in_min_cb != pic_size_in_min_cb;     tl_init(l, 1, changed);     TL_ADD(imf,  pic_size_in_min_cb);     for (int i = LUMA; i <= CHROMA; i++)        TL_ADD(cb_width[i],  pic_size_in_min_cb);   //is_a0_available requires this} static void min_cb_nz_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps            = fc->ps.pps;    const int pic_size_in_min_cb = pps ? pps->min_cb_width * pps->min_cb_height : 0;    const int changed            = fc->tab.sz.pic_size_in_min_cb != pic_size_in_min_cb;     tl_init(l, 0, changed);     TL_ADD(skip, pic_size_in_min_cb);    TL_ADD(ipm,  pic_size_in_min_cb);     for (int i = LUMA; i <= CHROMA; i++) {        TL_ADD(cqt_depth[i], pic_size_in_min_cb);        TL_ADD(cb_pos_x[i],  pic_size_in_min_cb);        TL_ADD(cb_pos_y[i],  pic_size_in_min_cb);        TL_ADD(cb_height[i], pic_size_in_min_cb);        TL_ADD(cp_mv[i],     pic_size_in_min_cb * MAX_CONTROL_POINTS);        TL_ADD(cpm[i],       pic_size_in_min_cb);        TL_ADD(pcmf[i],      pic_size_in_min_cb);    }    // For luma, qp can only change at the CU level, so the qp tab size is related to the CU.    TL_ADD(qp[LUMA], pic_size_in_min_cb);} static void min_pu_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps            = fc->ps.pps;    const int pic_size_in_min_pu = pps ? pps->min_pu_width * pps->min_pu_height : 0;    const int changed            = fc->tab.sz.pic_size_in_min_pu != pic_size_in_min_pu;     tl_init(l, 1, changed);     TL_ADD(iaf, pic_size_in_min_pu);} static void min_pu_nz_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps            = fc->ps.pps;    const int pic_size_in_min_pu = pps ? pps->min_pu_width * pps->min_pu_height : 0;    const int changed            = fc->tab.sz.pic_size_in_min_pu != pic_size_in_min_pu;     tl_init(l, 0, changed);     TL_ADD(msf, pic_size_in_min_pu);    TL_ADD(mmi, pic_size_in_min_pu);    TL_ADD(mvf, pic_size_in_min_pu);} static void min_tu_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps            = fc->ps.pps;    const int pic_size_in_min_tu = pps ? pps->min_tu_width * pps->min_tu_height : 0;    const int changed            = fc->tab.sz.pic_size_in_min_tu != pic_size_in_min_tu;     tl_init(l, 1, changed);     TL_ADD(tu_joint_cbcr_residual_flag, pic_size_in_min_tu);     for (int i = 0; i < VVC_MAX_SAMPLE_ARRAYS; i++) {        TL_ADD(tu_coded_flag[i], pic_size_in_min_tu);         for (int vertical = 0; vertical < 2; vertical++)            TL_ADD(bs[vertical][i], pic_size_in_min_tu);    }} static void min_tu_nz_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps            = fc->ps.pps;    const int pic_size_in_min_tu = pps ? pps->min_tu_width * pps->min_tu_height : 0;    const int changed            = fc->tab.sz.pic_size_in_min_tu != pic_size_in_min_tu;     tl_init(l, 0, changed);     for (int i = LUMA; i <= CHROMA; i++) {        TL_ADD(tb_width[i],  pic_size_in_min_tu);        TL_ADD(tb_height[i], pic_size_in_min_tu);    }     for (int vertical = 0; vertical < 2; vertical++) {        TL_ADD(max_len_p[vertical], pic_size_in_min_tu);        TL_ADD(max_len_q[vertical], pic_size_in_min_tu);    }     // For chroma, considering the joint CbCr, the QP tab size is related to the TU.    for (int i = CB; i < VVC_MAX_SAMPLE_ARRAYS; i++)        TL_ADD(qp[i], pic_size_in_min_tu);} static void pixel_buffer_nz_tl_init(TabList *l, VVCFrameContext *fc){    const VVCSPS *sps    = fc->ps.sps;    const VVCPPS *pps    = fc->ps.pps;    const int width      = pps ? pps->width : 0;    const int height     = pps ? pps->height : 0;    const int ctu_width  = pps ? pps->ctb_width : 0;    const int ctu_height = pps ? pps->ctb_height : 0;    const int chroma_idc = sps ? sps->r->sps_chroma_format_idc : 0;    const int ps         = sps ? sps->pixel_shift : 0;    const int c_end      = chroma_idc ? VVC_MAX_SAMPLE_ARRAYS : 1;    const int changed    = fc->tab.sz.chroma_format_idc != chroma_idc ||        fc->tab.sz.width != width || fc->tab.sz.height != height ||        fc->tab.sz.ctu_width != ctu_width || fc->tab.sz.ctu_height != ctu_height ||        fc->tab.sz.pixel_shift != ps;     tl_init(l, 0, changed);     for (int c_idx = 0; c_idx < c_end; c_idx++) {        const int w = width  >> (sps ? sps->hshift[c_idx] : 0);        const int h = height >> (sps ? sps->vshift[c_idx] : 0);        TL_ADD(sao_pixel_buffer_h[c_idx], (w * 2 * ctu_height) << ps);        TL_ADD(sao_pixel_buffer_v[c_idx], (h * 2 * ctu_width)  << ps);    }     for (int c_idx = 0; c_idx < c_end; c_idx++) {        const int w = width  >> (sps ? sps->hshift[c_idx] : 0);        const int h = height >> (sps ? sps->vshift[c_idx] : 0);        const int border_pixels = c_idx ? ALF_BORDER_CHROMA : ALF_BORDER_LUMA;        for (int i = 0; i < 2; i++) {            TL_ADD(alf_pixel_buffer_h[c_idx][i], (w * border_pixels * ctu_height) << ps);            TL_ADD(alf_pixel_buffer_v[c_idx][i], h * ALF_PADDING_SIZE * ctu_width);        }    }} static void msm_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps = fc->ps.pps;    const int w32     = pps ? AV_CEIL_RSHIFT(pps->width,  5) : 0;    const int h32     = pps ? AV_CEIL_RSHIFT(pps->height, 5) : 0;    const int changed = AV_CEIL_RSHIFT(fc->tab.sz.width,  5) != w32 ||        AV_CEIL_RSHIFT(fc->tab.sz.height,  5) != h32;     tl_init(l, 1, changed);     for (int i = LUMA; i <= CHROMA; i++)        TL_ADD(msm[i], w32 * h32);} static void ispmf_tl_init(TabList *l, VVCFrameContext *fc){    const VVCPPS *pps = fc->ps.pps;    const int w64     = pps ? AV_CEIL_RSHIFT(pps->width,  6) : 0;    const int h64     = pps ? AV_CEIL_RSHIFT(pps->height, 6) : 0;    const int changed = AV_CEIL_RSHIFT(fc->tab.sz.width,  6) != w64 ||        AV_CEIL_RSHIFT(fc->tab.sz.height,  6) != h64;     tl_init(l, 1, changed);     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)){    const tl_init_fn init[] = {        ctu_nz_tl_init,        min_cb_tl_init,        min_cb_nz_tl_init,        min_pu_tl_init,        min_pu_nz_tl_init,        min_tu_tl_init,        min_tu_nz_tl_init,        pixel_buffer_nz_tl_init,        msm_tl_init,        ispmf_tl_init,        ibc_tl_init,    };     for (int i = 0; i < FF_ARRAY_ELEMS(init); i++) {        TabList l;        int ret;         init[i](&l, fc);        ret = unary_fn(&l);        if (ret < 0)            return ret;    }    return 0;} static void free_cus(VVCFrameContext *fc){    if (fc->tab.cus) {        for (int i = 0; i < fc->tab.sz.ctu_count; i++)            ff_vvc_ctu_free_cus(fc->tab.cus + i);    }} static void pic_arrays_free(VVCFrameContext *fc){    free_cus(fc);    frame_context_for_each_tl(fc, tl_free);    av_refstruct_pool_uninit(&fc->rpl_tab_pool);    av_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool);     memset(&fc->tab.sz, 0, sizeof(fc->tab.sz));} static int pic_arrays_init(VVCContext *s, VVCFrameContext *fc){    const VVCSPS *sps            = fc->ps.sps;    const VVCPPS *pps            = fc->ps.pps;    const int ctu_count          = pps->ctb_count;    const int pic_size_in_min_pu = pps->min_pu_width * pps->min_pu_height;    int ret;     free_cus(fc);     ret = frame_context_for_each_tl(fc, tl_create);    if (ret < 0)        return ret;     // for error handling case, we may call free_cus before VVC_TASK_STAGE_INIT, so we need to set cus to 0 here    memset(fc->tab.cus, 0, sizeof(*fc->tab.cus) * ctu_count);     memset(fc->tab.slice_idx, -1, sizeof(*fc->tab.slice_idx) * ctu_count);     if (fc->tab.sz.ctu_count != ctu_count) {        av_refstruct_pool_uninit(&fc->rpl_tab_pool);        fc->rpl_tab_pool = av_refstruct_pool_alloc(ctu_count * sizeof(RefPicListTab), 0);        if (!fc->rpl_tab_pool)            return AVERROR(ENOMEM);    }     if (fc->tab.sz.pic_size_in_min_pu != pic_size_in_min_pu) {        av_refstruct_pool_uninit(&fc->tab_dmvr_mvf_pool);        fc->tab_dmvr_mvf_pool = av_refstruct_pool_alloc(            pic_size_in_min_pu * sizeof(MvField), AV_REFSTRUCT_POOL_FLAG_ZERO_EVERY_TIME);        if (!fc->tab_dmvr_mvf_pool)            return AVERROR(ENOMEM);    }     fc->tab.sz.ctu_count          = pps->ctb_count;    fc->tab.sz.ctu_size           = 1 << sps->ctb_log2_size_y << sps->ctb_log2_size_y;    fc->tab.sz.pic_size_in_min_cb = pps->min_cb_width * pps->min_cb_height;    fc->tab.sz.pic_size_in_min_pu = pic_size_in_min_pu;    fc->tab.sz.pic_size_in_min_tu = pps->min_tu_width * pps->min_tu_height;    fc->tab.sz.width              = pps->width;    fc->tab.sz.height             = pps->height;    fc->tab.sz.ctu_width          = pps->ctb_width;    fc->tab.sz.ctu_height         = pps->ctb_height;    fc->tab.sz.chroma_format_idc  = sps->r->sps_chroma_format_idc;    fc->tab.sz.pixel_shift        = sps->pixel_shift;     return 0;} int ff_vvc_per_frame_init(VVCFrameContext *fc){    return frame_context_for_each_tl(fc, tl_zero);} static int min_positive(const int idx, const int diff, const int min_diff){    return diff > 0 && (idx < 0 || diff < min_diff);} static int max_negtive(const int idx, const int diff, const int max_diff){    return diff < 0 && (idx < 0 || diff > max_diff);} typedef int (*smvd_find_fxn)(const int idx, const int diff, const int old_diff); static int8_t smvd_find(const VVCFrameContext *fc, const SliceContext *sc, int lx, smvd_find_fxn find){    const H266RawSliceHeader *rsh = sc->sh.r;    const RefPicList *rpl         = sc->rpl + lx;    const int poc                 = fc->ref->poc;    int8_t idx                    = -1;    int old_diff                  = -1;    for (int i = 0; i < rsh->num_ref_idx_active[lx]; i++) {        if (!rpl->refs[i].is_lt) {            int diff = poc - rpl->refs[i].poc;            if (find(idx, diff, old_diff)) {                idx = i;                old_diff = diff;            }        }    }    return idx;} static void smvd_ref_idx(const VVCFrameContext *fc, SliceContext *sc){    VVCSH *sh = &sc->sh;    if (IS_B(sh->r)) {        sh->ref_idx_sym[0] = smvd_find(fc, sc, 0, min_positive);        sh->ref_idx_sym[1] = smvd_find(fc, sc, 1, max_negtive);        if (sh->ref_idx_sym[0] == -1 || sh->ref_idx_sym[1] == -1) {            sh->ref_idx_sym[0] = smvd_find(fc, sc, 0, max_negtive);            sh->ref_idx_sym[1] = smvd_find(fc, sc, 1, min_positive);        }    }} static void eps_free(SliceContext *slice){    av_freep(&slice->eps);    slice->nb_eps = 0;} static void slices_free(VVCFrameContext *fc){    if (fc->slices) {        for (int i = 0; i < fc->nb_slices_allocated; i++) {            SliceContext *slice = fc->slices[i];            if (slice) {                av_refstruct_unref(&slice->ref);                av_refstruct_unref(&slice->sh.r);                eps_free(slice);                av_free(slice);            }        }        av_freep(&fc->slices);    }    fc->nb_slices_allocated = 0;    fc->nb_slices = 0;} static int slices_realloc(VVCFrameContext *fc){    void *p;    const int size = (fc->nb_slices_allocated + 1) * 3 / 2;     if (fc->nb_slices < fc->nb_slices_allocated)        return 0;     p = av_realloc_array(fc->slices, size, sizeof(*fc->slices));    if (!p)        return AVERROR(ENOMEM);     fc->slices = p;    for (int i = fc->nb_slices_allocated; i < size; i++) {        fc->slices[i] = av_mallocz(sizeof(*fc->slices[0]));        if (!fc->slices[i]) {            fc->nb_slices_allocated = i;            return AVERROR(ENOMEM);

Lines 1–500 of 1161.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t