[FFmpeg-devel] [PATCH v2 11/11] avcodec: add vvdec H.266/VVC decoder
Nuo Mi
nuomi2021 at gmail.com
Sat Jan 9 09:42:45 EET 2021
According to James and Lynne, merge this patch needs further discussion.
I send out it just to make sure the metadata bsf workable.
A basic bsf command like this need a workable decoder:
"ffmpeg -i in.bin -c:v copy -bsf vvc_metadata out.266"
On Sat, Jan 9, 2021 at 3:35 PM Nuo Mi <nuomi2021 at gmail.com> wrote:
> you can download test clips here:
>
> https://www.itu.int/wftp3/av-arch/jvet-site/bitstream_exchange/VVC/under_test/VTM-11.0/
>
> 76.71% (191/249) clips are md5 matched with VTM 11:
>
> passed:
>
> 10b400_A_Bytedance_2.bit
> 10b400_B_Bytedance_2.bit
> 8b400_A_Bytedance_2.bit
> 8b400_B_Bytedance_2.bit
> 8b420_A_Bytedance_2.bit
> 8b420_B_Bytedance_2.bit
> ACTPIC_A_Huawei_3.bit
> ACTPIC_B_Huawei_3.bit
> ACTPIC_C_Huawei_3.bit
> AFF_A_HUAWEI_2.bit
> AFF_B_HUAWEI_2.bit
> ALF_A_Huawei_3.bit
> ALF_B_Huawei_3.bit
> ALF_C_KDDI_2.bit
> ALF_D_Qualcomm_2.bit
> AMVR_A_HHI_3.bit
> AMVR_B_HHI_3.bit
> APSALF_A_Qualcomm_2.bit
> APSLMCS_A_Dolby_3.bit
> APSLMCS_B_Dolby_3.bit
> APSLMCS_C_Dolby_2.bit
> APSMULT_A_MediaTek_3.bit
> APSMULT_B_MediaTek_3.bit
> AUD_A_Broadcom_3.bit
> BCW_A_MediaTek_3.bit
> BCW_A_MediaTek_4.bit
> BDOF_A_MediaTek_3.bit
> BDOF_A_MediaTek_4.bit
> BDPCM_A_Orange_2.bit
> CCALF_A_Sharp_3.bit
> CCALF_B_Sharp_3.bit
> CCALF_C_Sharp_3.bit
> CCALF_D_Sharp_3.bit
> CCLM_A_KDDI_1.bit
> CIIP_A_MediaTek_3.bit
> CIIP_A_MediaTek_4.bit
> CodingToolsSets_A_Tencent_2.bit
> CodingToolsSets_B_Tencent_2.bit
> CodingToolsSets_C_Tencent_2.bit
> CodingToolsSets_D_Tencent_2.bit
> CROP_A_Panasonic_3.bit
> CROP_B_Panasonic_4.bit
> CST_A_MediaTek_3.bit
> CTU_A_MediaTek_3.bit
> CTU_A_MediaTek_4.bit
> CTU_B_MediaTek_3.bit
> CTU_B_MediaTek_4.bit
> CTU_C_MediaTek_3.bit
> CTU_C_MediaTek_4.bit
> CUBEMAP_A_MediaTek_3.bit
> CUBEMAP_B_MediaTek_3.bit
> CUBEMAP_C_MediaTek_3.bit
> DEBLOCKING_A_Sharp_3.bit
> DEBLOCKING_B_Sharp_2.bit
> DEBLOCKING_C_Huawei_3.bit
> DEBLOCKING_E_Ericsson_2.bit
> DEBLOCKING_E_Ericsson_3.bit
> DEBLOCKING_F_Ericsson_1.bit
> DEBLOCKING_F_Ericsson_2.bit
> DMVR_A_Huawei_3.bit
> DMVR_B_KDDI_3.bit
> DPB_A_Sharplabs_2.bit
> DPB_B_Sharplabs_2.bit
> DQ_A_HHI_3.bit
> ENT444HIGHTIER_A_Sony_3.bit
> ENT444HIGHTIER_B_Sony_3.bit
> ENT444HIGHTIER_C_Sony_3.bit
> ENT444HIGHTIER_D_Sony_3.bit
> ENT444MAINTIER_A_Sony_3.bit
> ENT444MAINTIER_B_Sony_3.bit
> ENT444MAINTIER_C_Sony_3.bit
> ENT444MAINTIER_D_Sony_3.bit
> ENTHIGHTIER_A_Sony_3.bit
> ENTHIGHTIER_B_Sony_3.bit
> ENTHIGHTIER_C_Sony_3.bit
> ENTHIGHTIER_D_Sony_3.bit
> ENTMAINTIER_A_Sony_3.bit
> ENTMAINTIER_B_Sony_3.bit
> ENTMAINTIER_C_Sony_3.bit
> ENTMAINTIER_D_Sony_3.bit
> ENTROPY_A_Chipsnmedia_2.bit
> ENTROPY_A_Qualcomm_2.bit
> ENTROPY_B_Sharp_2.bit
> ERP_A_MediaTek_3.bit
> FILLER_A_Bytedance_1.bit
> GPM_A_Alibaba_3.bit
> HLG_A_NHK_2.bit
> HLG_B_NHK_2.bit
> HRD_A_Fujitsu_3.bit
> HRD_B_Fujitsu_2.bit
> IBC_A_Tencent_2.bit
> IBC_B_Tencent_2.bit
> IBC_C_Tencent_2.bit
> IBC_D_Tencent_2.bit
> IP_B_Nokia_1.bit
> ISP_A_HHI_3.bit
> ISP_B_HHI_3.bit
> JCCR_A_Nokia_2.bit
> JCCR_B_Nokia_2.bit
> JCCR_C_HHI_3.bit
> JCCR_E_Nokia_1.bit
> JCCR_F_Nokia_1.bit
> LFNST_A_LGE_3.bit
> LFNST_B_LGE_3.bit
> LFNST_C_HHI_3.bit
> LMCS_A_Dolby_3.bit
> LOSSLESS_A_HHI_3.bit
> LOSSLESS_B_HHI_3.bit
> LTRP_A_ERICSSON_2.bit
> MERGE_A_Qualcomm_2.bit
> MERGE_B_Qualcomm_2.bit
> MERGE_C_Qualcomm_2.bit
> MERGE_D_Qualcomm_2.bit
> MERGE_E_Qualcomm_2.bit
> MERGE_F_Qualcomm_2.bit
> MERGE_G_Qualcomm_2.bit
> MERGE_H_Qualcomm_2.bit
> MERGE_I_Qualcomm_2.bit
> MERGE_J_Qualcomm_2.bit
> MIP_A_HHI_3.bit
> MIP_B_HHI_3.bit
> MPM_A_LGE_3.bit
> MRLP_A_HHI_2.bit
> MRLP_B_HHI_2.bit
> MTS_A_LGE_3.bit
> MTS_B_LGE_3.bit
> MTS_LFNST_A_LGE_3.bit
> MTS_LFNST_B_LGE_3.bit
> MVCOMP_A_Sharp_2.bit
> PDPC_A_Qualcomm_3.bit
> PDPC_B_Qualcomm_3.bit
> PDPC_C_Qualcomm_2.bit
> PHSH_B_Sharp_1.bit
> POC_A_Nokia_1.bit
> POUT_A_Sharplabs_2.bit
> PPS_B_Bytedance_1.bit
> PPS_C_Bytedance_1.bit
> PQ_A_Dolby_1.bit
> PROF_A_Interdigital_3.bit
> PROF_B_Interdigital_3.bit
> PSEXT_A_Nokia_2.bit
> PSEXT_B_Nokia_2.bit
> QTBTT_A_MediaTek_3.bit
> QTBTT_A_MediaTek_4.bit
> QUANT_A_Huawei_2.bit
> QUANT_B_Huawei_2.bit
> QUANT_C_Huawei_2.bit
> QUANT_D_Huawei_2.bit
> RAP_C_HHI_1.bit
> RAP_D_HHI_1.bit
> RPL_A_ERICSSON_2.bit
> SAO_A_SAMSUNG_3.bit
> SAO_B_SAMSUNG_3.bit
> SAO_C_SAMSUNG_3.bit
> SbTMVP_A_Bytedance_3.bit
> SbTMVP_B_Bytedance_3.bit
> SBT_A_HUAWEI_2.bit
> SCALING_A_InterDigital_1.bit
> SCALING_B_InterDigital_1.bit
> SCALING_C_InterDigital_1.bit
> SDH_A_Dolby_2.bit
> SLICES_A_HUAWEI_2.bit
> SMVD_A_HUAWEI_2.bit
> SPS_A_Bytedance_1.bit
> SPS_B_Bytedance_1.bit
> SPS_C_Bytedance_1.bit
> TEMPSCAL_A_Panasonic_4.bit
> TEMPSCAL_C_Panasonic_3.bit
> TILE_A_Nokia_2.bit
> TILE_B_Nokia_2.bit
> TILE_C_Nokia_2.bit
> TILE_D_Nokia_2.bit
> TILE_E_Nokia_2.bit
> TILE_F_Nokia_2.bit
> TILE_G_Nokia_2.bit
> TMVP_A_Chipsnmedia_3.bit
> TMVP_B_Chipsnmedia_3.bit
> TMVP_C_Chipsnmedia_3.bit
> TMVP_D_Chipsnmedia_3.bit
> TRANS_A_Chipsnmedia_2.bit
> TRANS_B_Chipsnmedia_2.bit
> TRANS_C_Chipsnmedia_2.bit
> TRANS_D_Chipsnmedia_2.bit
> WPP_A_Sharp_3.bit
> WPP_B_Sharp_2.bit
> WP_A_InterDigital_3.bit
> WP_B_InterDigital_3.bit
> WRAP_A_InterDigital_4.bit
> WRAP_B_InterDigital_4.bit
> WRAP_C_InterDigital_4.bit
> WRAP_D_InterDigital_4.bit
> ---
> configure | 5 +-
> libavcodec/Makefile | 1 +
> libavcodec/allcodecs.c | 1 +
> libavcodec/libvvdec.cpp | 244 ++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 250 insertions(+), 1 deletion(-)
> create mode 100644 libavcodec/libvvdec.cpp
>
> diff --git a/configure b/configure
> index b41f2af151..cefdff75fe 100755
> --- a/configure
> +++ b/configure
> @@ -285,6 +285,7 @@ External library support:
> --enable-libvorbis enable Vorbis en/decoding via libvorbis,
> native implementation exists [no]
> --enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no]
> + --enable-libvvdec enable VVC video decoding via libvvdec [no]
> --enable-libwebp enable WebP encoding via libwebp [no]
> --enable-libx264 enable H.264 encoding via x264 [no]
> --enable-libx265 enable HEVC encoding via x265 [no]
> @@ -1816,6 +1817,7 @@ EXTERNAL_LIBRARY_LIST="
> libvmaf
> libvorbis
> libvpx
> + libvvdec
> libwebp
> libxml2
> libzimg
> @@ -3284,6 +3286,7 @@ libvpx_vp8_decoder_deps="libvpx"
> libvpx_vp8_encoder_deps="libvpx"
> libvpx_vp9_decoder_deps="libvpx"
> libvpx_vp9_encoder_deps="libvpx"
> +libvvdec_decoder_deps="libvvdec"
> libwebp_encoder_deps="libwebp"
> libwebp_anim_encoder_deps="libwebp"
> libx262_encoder_deps="libx262"
> @@ -6461,7 +6464,7 @@ enabled libvpx && {
> die "libvpx enabled but no supported decoders found"
> fi
> }
> -
> +enabled libvvdec && require_pkg_config libvvdec "libvvdec >=
> 0.1.2" vvdec/version.h VVDEC_VERSION_MAJOR
> enabled libwebp && {
> enabled libwebp_encoder && require_pkg_config libwebp "libwebp
> >= 0.2.0" webp/encode.h WebPGetEncoderVersion
> enabled libwebp_anim_encoder && check_pkg_config libwebp_anim_encoder
> "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; }
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index d4cd64e43c..cf734144f6 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -1059,6 +1059,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_DECODER) +=
> libvpxdec.o
> OBJS-$(CONFIG_LIBVPX_VP8_ENCODER) += libvpxenc.o
> OBJS-$(CONFIG_LIBVPX_VP9_DECODER) += libvpxdec.o libvpx.o
> OBJS-$(CONFIG_LIBVPX_VP9_ENCODER) += libvpxenc.o libvpx.o
> +OBJS-$(CONFIG_LIBVVDEC_DECODER) += libvvdec.o
> OBJS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.o
> libwebpenc.o
> OBJS-$(CONFIG_LIBWEBP_ANIM_ENCODER) += libwebpenc_common.o
> libwebpenc_animencoder.o
> OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o
> diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
> index f00d524747..545c38f541 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -752,6 +752,7 @@ extern AVCodec ff_libvpx_vp8_encoder;
> extern AVCodec ff_libvpx_vp8_decoder;
> extern AVCodec ff_libvpx_vp9_encoder;
> extern AVCodec ff_libvpx_vp9_decoder;
> +extern AVCodec ff_libvvdec_decoder;
> /* preferred over libwebp */
> extern AVCodec ff_libwebp_anim_encoder;
> extern AVCodec ff_libwebp_encoder;
> diff --git a/libavcodec/libvvdec.cpp b/libavcodec/libvvdec.cpp
> new file mode 100644
> index 0000000000..4229d45701
> --- /dev/null
> +++ b/libavcodec/libvvdec.cpp
> @@ -0,0 +1,244 @@
> +/*
> + * vvdec H.266/VVC decoder
> + * Copyright (c) 2020 Nuo Mi <nuomi2021 at gmail.com>
> + *
> + * 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
> + */
> +
> +/**
> + * @file
> + * VVC decoder support via libvvdec
> + */
> +
> +#include "vvdec/vvdec.h"
> +
> +extern "C" {
> +
> +#include "libavutil/common.h"
> +#include "libavutil/imgutils.h"
> +#include "libavutil/internal.h"
> +
> +#include "avcodec.h"
> +#include "h2645_parse.h"
> +#include "internal.h"
> +#include "profiles.h"
> +
> +typedef struct VVDecContext {
> + AVCodecContext *avctx;
> + vvdec::VVDec* vvdec;
> +
> + H2645Packet pkt;
> + int is_nalff; ///< this flag is != 0 if bitstream is
> encapsulated
> + ///< as a format defined in 14496-15
> + int nal_length_size; ///< Number of bytes used for nal length (1,
> 2 or 4)
> +} VVDecContext;
> +
> +}
> +
> +static int map_error(int vret)
> +{
> + switch(vret)
> + {
> + case vvdec::VVDEC_OK : return 0;
> + case vvdec::VVDEC_ERR_UNSPECIFIED: return AVERROR_UNKNOWN;
> + case vvdec::VVDEC_ERR_INITIALIZE: return AVERROR_BUG;
> + case vvdec::VVDEC_ERR_ALLOCATE: return AVERROR(ENOMEM);
> + case vvdec::VVDEC_NOT_ENOUGH_MEM: return AVERROR(ENOMEM);
> + case vvdec::VVDEC_ERR_PARAMETER: return AVERROR(EINVAL);
> + case vvdec::VVDEC_ERR_NOT_SUPPORTED: return AVERROR(ENOSYS);
> + case vvdec::VVDEC_ERR_RESTART_REQUIRED: return AVERROR_BUG;
> + case vvdec::VVDEC_ERR_CPU: return AVERROR(ENOSYS);
> + case vvdec::VVDEC_TRY_AGAIN: return AVERROR(EAGAIN);
> + case vvdec::VVDEC_EOF: return AVERROR(EOF);
> + default: return AVERROR_UNKNOWN;
> + }
> +}
> +
> +static int check_vret(VVDecContext* s, int vret) {
> + vvdec::VVDec* vvdec = s->vvdec;
> + if (vret && vret != vvdec::VVDEC_EOF) {
> + av_log(s->avctx, AV_LOG_ERROR, "vvdec returns error: %s\n",
> vvdec->getErrorMsg(vret));
> + }
> + return map_error(vret);
> +}
> +
> +static const enum AVPixelFormat pix_fmts_8bit[] = {
> + AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUV420P,
> + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P
> +};
> +
> +static const enum AVPixelFormat pix_fmts_10bit[] = {
> + AV_PIX_FMT_GRAY10, AV_PIX_FMT_YUV420P10,
> + AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10
> +};
> +
> +static AVPixelFormat get_format(const vvdec::Frame* frame)
> +{
> + if (frame->m_eColorFormat != vvdec::VVC_CF_INVALID) {
> + switch (frame->m_uiBitDepth) {
> + case 8:
> + return pix_fmts_8bit[frame->m_eColorFormat];
> + case 10:
> + return pix_fmts_10bit[frame->m_eColorFormat];
> + }
> + }
> + return AV_PIX_FMT_NONE;
> +}
> +
> +static int set_pix_fmt(VVDecContext* s, const vvdec::Frame* frame)
> +{
> + AVPixelFormat format = get_format(frame);
> + if (format == AV_PIX_FMT_NONE) {
> + av_log(s->avctx, AV_LOG_ERROR,
> + "unsupported, depth = %d, color format = %d.\n",
> frame->m_uiBitDepth, frame->m_eColorFormat);
> + return AVERROR_INVALIDDATA;
> + }
> + s->avctx->pix_fmt = format;
> + return 0;
> +}
> +
> +static int copy_to_avframe(VVDecContext* s, const vvdec::Frame* src,
> AVFrame *dest)
> +{
> + AVCodecContext* avctx = s->avctx;
> + int i, ret, width, height;
> + uint8_t *data[4];
> + int linesize[4];
> +
> + ret = set_pix_fmt(s, src);
> + if (ret < 0)
> + return ret;
> + width = (int)src->m_uiWidth;
> + height = (int)src->m_uiHeight;
> + if (width != avctx->width || height != avctx->height) {
> + av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n",
> + avctx->width, avctx->height, width, height);
> + if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
> + return ret;
> + }
> + if ((ret = ff_get_buffer(avctx, dest, 0)) < 0)
> + return ret;
> +
> + for (i = 0; i < 3; i++) {
> + const vvdec::Component& plane = src->m_cComponent[i];
> + data[i] = plane.m_pucBuffer;
> + linesize[i] = plane.m_iStride;
> + }
> + data[3] = 0; linesize[3] = 0;
> +
> + //TODO: conformance window?
> + av_image_copy(dest->data, dest->linesize, (const uint8_t **)data,
> linesize,
> + avctx->pix_fmt, width, height);
> + return 0;
> +}
> +
> +static int vvdec_decode(AVCodecContext *avctx, void *data, int *got_frame,
> + AVPacket *avpkt)
> +{
> + VVDecContext *s = (VVDecContext *)avctx->priv_data;
> + vvdec::VVDec* vvdec = s->vvdec;
> + AVFrame *picture = (AVFrame*)data;
> + int vret, ret = 0;
> + vvdec::Frame* frame = NULL;
> +
> + if (!avpkt->size) {
> + vret = vvdec->flush(&frame);
> + if ((ret = check_vret(s, vret)) < 0) {
> + goto error_out;
> + }
> + } else {
> + uint8_t *new_extradata;
> + int new_extradata_size;
> + new_extradata = av_packet_get_side_data(avpkt,
> AV_PKT_DATA_NEW_EXTRADATA,
> + &new_extradata_size);
> + if (new_extradata && new_extradata_size > 0) {
> + return AVERROR_PATCHWELCOME;
> + }
> +
> + vvdec::AccessUnit au;
> + au.m_pucBuffer = (unsigned char*)avpkt->data;
> + au.m_iUsedSize = avpkt->size;
> + au.m_uiCts = avpkt->pts;
> + au.m_bCtsValid = true;
> + vret = vvdec->decode(au, &frame);
> + if (vret && vret != vvdec::VVDEC_TRY_AGAIN) {
> + if ((ret = check_vret(s, vret)) < 0) {
> + goto error_out;
> + }
> + }
> +
> + }
> + if (frame) {
> + ret = copy_to_avframe(s, frame, picture);
> + if (ret < 0)
> + goto error_out;
> + *got_frame = 1;
> + }
> + return 0;
> +error_out:
> + if (frame) {
> + vvdec->objectUnref(frame);
> + }
> + return ret;
> +}
> +
> +static av_cold int vvdec_free(AVCodecContext *avctx)
> +{
> + VVDecContext *ctx = (VVDecContext *)avctx->priv_data;
> + vvdec::VVDec* vvdec = ctx->vvdec;
> + if (vvdec) {
> + vvdec->uninit();
> + delete vvdec;
> + }
> + return 0;
> +}
> +
> +static av_cold int vvdec_init(AVCodecContext *avctx)
> +{
> + VVDecContext *s = (VVDecContext *)avctx->priv_data;
> + vvdec::VVDecParameter param;
> + vvdec::VVDec* vvdec = new vvdec::VVDec;
> + int vret, ret = 0;
> +
> + av_log(avctx, AV_LOG_INFO, "VVDec version: %s\n",
> vvdec->getVersionNumber());
> +
> + s->avctx = avctx;
> + s->vvdec = vvdec;
> + vret = vvdec->init(param);
> + if ((ret = check_vret(s, vret)) < 0) {
> + delete vvdec;
> + s->vvdec = NULL;
> + }
> + return ret;
> +}
> +
> +extern "C" {
> +
> +AVCodec ff_libvvdec_decoder = {
> + .name = "libvvdec",
> + .long_name = NULL_IF_CONFIG_SMALL("Fraunhofer Versatile Video
> Decoder (VVdeC)"),
> + .type = AVMEDIA_TYPE_VIDEO,
> + .id = AV_CODEC_ID_VVC,
> + .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1 |
> AV_CODEC_CAP_DELAY,
> + .profiles = NULL_IF_CONFIG_SMALL(ff_vvc_profiles),
> + .wrapper_name = "libvvdec",
> + .priv_data_size = sizeof(VVDecContext),
> + .init = vvdec_init,
> + .decode = vvdec_decode,
> + .close = vvdec_free,
> +};
> +
> +}
> --
> 2.25.1
>
>
More information about the ffmpeg-devel
mailing list