From patchwork Sat Jan 9 07:34:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuo Mi X-Patchwork-Id: 24860 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id 4D7B144AF8E for ; Sat, 9 Jan 2021 09:35:29 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 2361A68A760; Sat, 9 Jan 2021 09:35:29 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.181]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id D3E8168A68F for ; Sat, 9 Jan 2021 09:35:27 +0200 (EET) Received: by mail-pf1-f181.google.com with SMTP id q20so4448339pfu.8 for ; Fri, 08 Jan 2021 23:35:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=69pu1zFGtZ/ejEbHhyh5vY+d00MC95wa1KJ7i99yJys=; b=VYho7zaFER/zsziUNodLZMsKxdeElEKwT/sk9mQjK2PHVFLL9wCbHMuRhxaThrrh+8 4xkd56mh5PYHFgpdcQg8wiecvUZ2bm/DwOuFvKfM5tw61jD6azkPaQcji3jFwnoWsDhg JzX0La6Xg/h8j9PHrGZPzneWL+yfqpd/ilXHBtF+ySSnhw9QWO7gF+/B3BPFKV8N1trj ObUDRFr7+cspNgcWVyYIx60Qe3FgJvwGkYX20zbQ8bgwtlGgWc9m7vKAxYcgX3ZDuut4 uXouxdx/9JIR4wo7yNXx+HkB+4ga/ifveDsXNYcXuzNJRqTVGXUNCINGa9LB7+ctlbgG 5Bdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=69pu1zFGtZ/ejEbHhyh5vY+d00MC95wa1KJ7i99yJys=; b=FuTo4L8HNkwRqStrKqePNtCq2uEm/zKvTkU38lO++6Fl6pWZjLOPn2TdJldJGOhhqq LBity+U8fyd5+rlq3CHgPLvPd/pPQo6k7VEaLdx8c6e7ZRHOXclld5g6r87OpjvW+lBV XUe2uE8H8drEXzhwRqYBmMBBjwJ8zx3xjlM/IwHae/fb31IfEAPhsFjZ8jkuYatODvM7 7BFbdDqrvIzE3EJ9iIRzVVv85qOz8KkEWhrXfZO+VqbSxFz5EFE1lJqJBLFarHWWXFX6 r6EFyvjyX4cpmObLFcP405q1bdzDEKFNQmDmxcfIpj34diUmDD29AhIxihUrLo8b2Qy6 sgkg== X-Gm-Message-State: AOAM531+O9xHnDZz2Rr2o95Qrrn5x0nr5zvjQs2u9hP9HGHjCDirv3dU 56ldORzt1aXt2KxT2FUTUS4Re9I6y4ARqw== X-Google-Smtp-Source: ABdhPJwhxxWi8i2CTUQJeBxTQrBnEwgRFCi1lVH2h6MI/cNb0DmAEXtAt5hQGWOGZasZh4+InWhk3A== X-Received: by 2002:a63:4764:: with SMTP id w36mr10572262pgk.127.1610177725616; Fri, 08 Jan 2021 23:35:25 -0800 (PST) Received: from Guangxin-PC.localdomain (23.83.245.51.16clouds.com. [23.83.245.51]) by smtp.gmail.com with ESMTPSA id m15sm11640120pfa.72.2021.01.08.23.35.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 08 Jan 2021 23:35:25 -0800 (PST) From: Nuo Mi To: ffmpeg-devel@ffmpeg.org Date: Sat, 9 Jan 2021 15:34:21 +0800 Message-Id: <20210109073421.23721-12-nuomi2021@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20210109073421.23721-1-nuomi2021@gmail.com> References: <20210109073421.23721-1-nuomi2021@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2 11/11] avcodec: add vvdec H.266/VVC decoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Nuo Mi Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" 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 + * + * 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, +}; + +}