Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
From: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
To: ffmpeg-devel@ffmpeg.org
Subject: Re: [FFmpeg-devel] [PATCH v4 1/1] avcodec: add external enc libvvenc for H266/VVC
Date: Mon, 3 Jun 2024 15:54:05 +0200
Message-ID: <GV1P250MB07377E9867D56F47422EDA368FFF2@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM> (raw)
In-Reply-To: <20240528162629.28698-2-chris10317h5@gmail.com>

Christian Bartnik:
> From: Thomas Siedel <thomas.ff@spin-digital.com>
> 
> Add external encoder VVenC for H266/VVC encoding.
> Register new encoder libvvenc.
> Add libvvenc to wrap the vvenc interface.
> libvvenc implements encoder option: preset,qp,qpa,period,
> passlogfile,stats,vvenc-params,level,tier.
> Enable encoder by adding --enable-libvvenc in configure step.
> 
> Co-authored-by: Christian Bartnik chris10317h5@gmail.com
> Signed-off-by: Thomas Siedel <thomas.ff@spin-digital.com>
> ---
>  configure                 |   4 +
>  doc/encoders.texi         |  64 +++++
>  fftools/ffmpeg_mux_init.c |   2 +-
>  libavcodec/Makefile       |   1 +
>  libavcodec/allcodecs.c    |   1 +
>  libavcodec/libvvenc.c     | 507 ++++++++++++++++++++++++++++++++++++++
>  6 files changed, 578 insertions(+), 1 deletion(-)
>  create mode 100644 libavcodec/libvvenc.c
> 
> diff --git a/configure b/configure
> index 96b181fd21..082cbca7bb 100755
> --- a/configure
> +++ b/configure
> @@ -293,6 +293,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-libvvenc        enable H.266/VVC encoding via vvenc [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]
> @@ -1966,6 +1967,7 @@ EXTERNAL_LIBRARY_LIST="
>      libvmaf
>      libvorbis
>      libvpx
> +    libvvenc
>      libwebp
>      libxevd
>      libxeve
> @@ -3560,6 +3562,7 @@ libvpx_vp8_decoder_deps="libvpx"
>  libvpx_vp8_encoder_deps="libvpx"
>  libvpx_vp9_decoder_deps="libvpx"
>  libvpx_vp9_encoder_deps="libvpx"
> +libvvenc_encoder_deps="libvvenc"
>  libwebp_encoder_deps="libwebp"
>  libwebp_anim_encoder_deps="libwebp"
>  libx262_encoder_deps="libx262"
> @@ -7030,6 +7033,7 @@ enabled libvpx            && {
>      fi
>  }
>  
> +enabled libvvenc          && require_pkg_config libvvenc "libvvenc >= 1.6.1" "vvenc/vvenc.h" vvenc_get_version
>  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/doc/encoders.texi b/doc/encoders.texi
> index c82f316f94..496852faeb 100644
> --- a/doc/encoders.texi
> +++ b/doc/encoders.texi
> @@ -2378,6 +2378,70 @@ Indicates frame duration
>  For more information about libvpx see:
>  @url{http://www.webmproject.org/}
>  
> +@section libvvenc
> +
> +VVenC H.266/VVC encoder wrapper.
> +
> +This encoder requires the presence of the libvvenc headers and library
> +during configuration. You need to explicitly configure the build with
> +@option{--enable-libvvenc}.
> +
> +The VVenC project website is at
> +@url{https://github.com/fraunhoferhhi/vvenc}.
> +
> +@subsection Supported Pixel Formats
> +
> +VVenC supports only 10-bit color spaces as input. But the internal (encoded)
> +bit depth can be set to 8-bit or 10-bit at runtime.
> +
> +@subsection Options
> +
> +@table @option
> +@item b
> +Sets target video bitrate.
> +
> +@item g
> +Set the GOP size. Currently support for g=1 (Intra only) or default.
> +
> +@item preset
> +Set the VVenC preset.
> +
> +@item levelidc
> +Set level idc.
> +
> +@item tier
> +Set vvc tier.
> +
> +@item qp
> +Set constant quantization parameter.
> +
> +@item subopt @var{boolean}
> +Set subjective (perceptually motivated) optimization. Default is 1 (on).
> +
> +@item bitdepth8 @var{boolean}
> +Set 8bit coding mode instead of using 10bit. Default is 0 (off).
> +
> +@item period
> +set (intra) refresh period in seconds.
> +
> +@item vvenc-params
> +Set vvenc options using a list of @var{key}=@var{value} couples separated
> +by ":". See @command{vvencapp --fullhelp} or @command{vvencFFapp --fullhelp} for a list of options.
> +
> +For example, the options might be provided as:
> +
> +@example
> +intraperiod=64:decodingrefreshtype=idr:poc0idr=1:internalbitdepth=8
> +@end example
> +
> +For example the encoding options might be provided with @option{-vvenc-params}:
> +
> +@example
> +ffmpeg -i input -c:v libvvenc -b 1M -vvenc-params intraperiod=64:decodingrefreshtype=idr:poc0idr=1:internalbitdepth=8 output.mp4
> +@end example
> +
> +@end table
> +
>  @section libwebp
>  
>  libwebp WebP Image encoder wrapper
> diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c
> index 8797265145..ef2922854a 100644
> --- a/fftools/ffmpeg_mux_init.c
> +++ b/fftools/ffmpeg_mux_init.c
> @@ -739,7 +739,7 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
>                       ost->logfile_prefix ? ost->logfile_prefix :
>                                             DEFAULT_PASS_LOGFILENAME_PREFIX,
>                       ost_idx);
> -            if (!strcmp(ost->enc_ctx->codec->name, "libx264")) {
> +            if (!strcmp(ost->enc_ctx->codec->name, "libx264") || !strcmp(ost->enc_ctx->codec->name, "libvvenc")) {
>                  av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE);
>              } else {
>                  if (video_enc->flags & AV_CODEC_FLAG_PASS2) {
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 2443d2c6fd..5d7349090e 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -1153,6 +1153,7 @@ OBJS-$(CONFIG_LIBVPX_VP8_DECODER)         += libvpxdec.o
>  OBJS-$(CONFIG_LIBVPX_VP8_ENCODER)         += libvpxenc.o
>  OBJS-$(CONFIG_LIBVPX_VP9_DECODER)         += libvpxdec.o
>  OBJS-$(CONFIG_LIBVPX_VP9_ENCODER)         += libvpxenc.o
> +OBJS-$(CONFIG_LIBVVENC_ENCODER)           += libvvenc.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 b102a8069e..59d36dbd56 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -800,6 +800,7 @@ extern const FFCodec ff_libvpx_vp8_encoder;
>  extern const FFCodec ff_libvpx_vp8_decoder;
>  extern FFCodec ff_libvpx_vp9_encoder;
>  extern const FFCodec ff_libvpx_vp9_decoder;
> +extern const FFCodec ff_libvvenc_encoder;
>  /* preferred over libwebp */
>  extern const FFCodec ff_libwebp_anim_encoder;
>  extern const FFCodec ff_libwebp_encoder;
> diff --git a/libavcodec/libvvenc.c b/libavcodec/libvvenc.c
> new file mode 100644
> index 0000000000..9de3d8630f
> --- /dev/null
> +++ b/libavcodec/libvvenc.c
> @@ -0,0 +1,507 @@
> +/*
> + * H.266 encoding using the VVenC library
> + *
> + * Copyright (C) 2022, Thomas Siedel
> + *
> + * 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 <vvenc/vvenc.h>
> +#include <vvenc/vvencCfg.h>
> +#include <vvenc/version.h>
> +
> +#include "avcodec.h"
> +#include "codec_internal.h"
> +#include "encode.h"
> +#include "internal.h"
> +#include "packet_internal.h"
> +#include "profiles.h"
> +
> +#include "libavutil/avutil.h"
> +#include "libavutil/mem.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/opt.h"
> +#include "libavutil/common.h"
> +#include "libavutil/imgutils.h"
> +#include "libavutil/frame.h"
> +#include "libavutil/log.h"
> +#include "libavutil/avstring.h"

Should be alphabetical

> +
> +#define VVENC_VERSION_INT  AV_VERSION_INT(VVENC_VERSION_MAJOR, \
> +                                          VVENC_VERSION_MINOR, \
> +                                          VVENC_VERSION_PATCH)
> +
> +typedef struct VVenCContext {
> +    AVClass         *class;
> +    vvencEncoder    *encoder;
> +    vvencAccessUnit *au;
> +    bool             encode_done;
> +    int   preset;
> +    int   qp;
> +    int   qpa;
> +    int   intra_refresh_sec;
> +    char *level;
> +    int   tier;
> +    char *stats;
> +    AVDictionary *vvenc_opts;
> +} VVenCContext;
> +
> +static void vvenc_log_callback(void *ctx, int level,
> +                               const char *fmt, va_list args)
> +{
> +    vvenc_config params;
> +    vvencEncoder *encoder = (vvencEncoder *)ctx;

Unnecessary cast

> +    if (encoder) {
> +        vvenc_config_default(&params);
> +        vvenc_get_config(encoder, &params);
> +        if ((int)params.m_verbosity >= level)
> +            vfprintf(level == 1 ? stderr : stdout, fmt, args);
> +    }
> +}
> +
> +static void vvenc_set_verbository(vvenc_config *params)
> +{
> +    int loglevel = av_log_get_level();
> +    params->m_verbosity = VVENC_SILENT;
> +    if (loglevel >= AV_LOG_DEBUG)
> +        params->m_verbosity = VVENC_DETAILS;
> +    else if (loglevel >= AV_LOG_VERBOSE)
> +        params->m_verbosity = VVENC_NOTICE;
> +    else if (loglevel >= AV_LOG_INFO)
> +        params->m_verbosity = VVENC_WARNING;
> +}
> +
> +static void vvenc_set_pic_format(AVCodecContext *avctx, vvenc_config *params)
> +{
> +    params->m_internChromaFormat = VVENC_CHROMA_420;
> +    params->m_inputBitDepth[0]   = 10;
> +}
> +
> +static void vvenc_set_color_format(AVCodecContext *avctx, vvenc_config *params)
> +{
> +    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED)
> +        params->m_colourPrimaries = (int) avctx->color_primaries;
> +    if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED)
> +        params->m_matrixCoefficients = (int) avctx->colorspace;
> +    if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) {
> +        params->m_transferCharacteristics = (int) avctx->color_trc;
> +
> +        if (avctx->color_trc == AVCOL_TRC_SMPTE2084)
> +            params->m_HdrMode = (avctx->color_primaries == AVCOL_PRI_BT2020) ?
> +                                VVENC_HDR_PQ_BT2020 : VVENC_HDR_PQ;
> +        else if (avctx->color_trc == AVCOL_TRC_BT2020_10 || avctx->color_trc == AVCOL_TRC_ARIB_STD_B67)
> +            params->m_HdrMode = (avctx->color_trc == AVCOL_TRC_BT2020_10 ||
> +                                 avctx->color_primaries == AVCOL_PRI_BT2020 ||
> +                                 avctx->colorspace == AVCOL_SPC_BT2020_NCL ||
> +                                 avctx->colorspace == AVCOL_SPC_BT2020_CL) ?
> +                                VVENC_HDR_HLG_BT2020 : VVENC_HDR_HLG;
> +    }
> +
> +    if (params->m_HdrMode == VVENC_HDR_OFF &&
> +        (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) {
> +        params->m_vuiParametersPresent = 1;
> +        params->m_colourDescriptionPresent = true;
> +    }
> +}
> +
> +static void vvenc_set_framerate(AVCodecContext *avctx, vvenc_config *params)
> +{
> +    if (avctx->framerate.num > 0 && avctx->framerate.den > 0) {
> +        params->m_FrameRate = avctx->framerate.num;
> +        params->m_FrameScale = avctx->framerate.den;
> +    } else {
> +        params->m_FrameRate = avctx->time_base.den;
> +        params->m_FrameScale = avctx->time_base.num;
> +    }
> +
> +FF_DISABLE_DEPRECATION_WARNINGS
> +
> +#if FF_API_TICKS_PER_FRAME
> +    if (avctx->ticks_per_frame == 1) {
> +#endif
> +        params->m_TicksPerSecond = -1;   /* auto mode for ticks per frame = 1 */
> +#if FF_API_TICKS_PER_FRAME
> +    } else {
> +        params->m_TicksPerSecond =
> +            ceil((avctx->time_base.den / (double) avctx->time_base.num) *
> +                 (double) avctx->ticks_per_frame);
> +    }
> +#endif
> +FF_ENABLE_DEPRECATION_WARNINGS
> +}
> +
> +static int vvenc_parse_vvenc_params(AVCodecContext *avctx, vvenc_config *params)
> +{
> +    int parse_ret, ret;
> +    VVenCContext *s;
> +    const AVDictionaryEntry *en = NULL;
> +    s = avctx->priv_data;

Should be directly initialized

> +    ret = 0;
> +
> +    while ((en = av_dict_iterate(s->vvenc_opts, en))) {
> +        av_log(avctx, AV_LOG_DEBUG, "vvenc_set_param: '%s:%s'\n", en->key,
> +               en->value);
> +        parse_ret = vvenc_set_param(params, en->key, en->value);
> +        switch (parse_ret) {
> +        case VVENC_PARAM_BAD_NAME:
> +            av_log(avctx, AV_LOG_ERROR, "Unknown vvenc option: %s.\n", en->key);
> +            ret = AVERROR(EINVAL);
> +            break;
> +        case VVENC_PARAM_BAD_VALUE:
> +            av_log(avctx, AV_LOG_ERROR, "Invalid vvenc value for %s: %s.\n", en->key, en->value);
> +            ret = AVERROR(EINVAL);
> +            break;
> +        default:
> +            break;
> +        }
> +
> +        if (!av_strcasecmp(en->key, "rcstatsfile")) {
> +            av_log(avctx, AV_LOG_ERROR, "vvenc-params 2pass option 'rcstatsfile' "
> +                   "not available. Use option 'passlogfile'\n");
> +            ret = AVERROR(EINVAL);
> +        }
> +        if (!av_strcasecmp(en->key, "passes") || !av_strcasecmp(en->key, "pass")) {
> +            av_log(avctx, AV_LOG_ERROR, "vvenc-params 2pass option '%s' "
> +                   "not available. Use option 'pass'\n", en->key);
> +            ret = AVERROR(EINVAL);
> +        }
> +    }
> +    return ret;
> +}
> +
> +static int vvenc_set_rc_mode(AVCodecContext *avctx, vvenc_config *params)
> +{
> +    params->m_RCNumPasses = 1;
> +    if ((avctx->flags & AV_CODEC_FLAG_PASS1 || avctx->flags & AV_CODEC_FLAG_PASS2)) {
> +        if (!avctx->bit_rate) {
> +            av_log(avctx, AV_LOG_ERROR, "A bitrate must be set to use two pass mode.\n");
> +            return AVERROR(EINVAL);
> +        }
> +        params->m_RCNumPasses = 2;
> +        if (avctx->flags & AV_CODEC_FLAG_PASS1)
> +            params->m_RCPass = 1;
> +        else
> +            params->m_RCPass = 2;
> +    }
> +
> +    if (avctx->rc_max_rate) {
> +#if VVENC_VERSION_INT >= AV_VERSION_INT(1,8,0)
> +        params->m_RCMaxBitrate = avctx->rc_max_rate;
> +#endif
> +
> +#if VVENC_VERSION_INT < AV_VERSION_INT(1,11,0)
> +        /* rc_max_rate without a bit_rate enables capped CQF mode.
> +        (QP + subj. optimization + max. bitrate) */
> +        if (!avctx->bit_rate) {
> +            av_log(avctx, AV_LOG_ERROR, "Capped Constant Quality Factor mode (capped CQF) "
> +                   "needs at least vvenc version >= 1.11.0 (current version %s)\n", vvenc_get_version());
> +            return AVERROR(EINVAL);
> +        }
> +#endif
> +    }
> +    return 0;
> +}
> +
> +static int vvenc_init_extradata(AVCodecContext *avctx, VVenCContext *s)
> +{
> +    int ret;
> +    if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) {
> +        ret = vvenc_get_headers(s->encoder, s->au);
> +        if (0 != ret) {
> +            av_log(avctx, AV_LOG_ERROR, "cannot get (SPS,PPS) headers: %s\n",
> +                   vvenc_get_last_error(s->encoder));
> +            return AVERROR(EINVAL);
> +        }
> +
> +        if (s->au->payloadUsedSize <= 0) {
> +            return AVERROR_INVALIDDATA;
> +        }
> +
> +        avctx->extradata_size = s->au->payloadUsedSize;
> +        avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
> +        if (!avctx->extradata) {
> +            return AVERROR(ENOMEM);
> +        }
> +
> +        memcpy(avctx->extradata, s->au->payload, avctx->extradata_size);
> +    }
> +    return 0;
> +}
> +
> +static av_cold int vvenc_init(AVCodecContext *avctx)
> +{
> +    int ret;
> +    int framerate;
> +    VVenCContext *s;
> +    vvenc_config params;
> +    vvencPresetMode preset;
> +
> +    s = avctx->priv_data;
> +    preset = (vvencPresetMode) s->preset;

These can be directly initialized

> +
> +    if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) {
> +        av_log(avctx, AV_LOG_ERROR, "interlaced not supported\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    vvenc_config_default(&params);
> +
> +    if (avctx->framerate.num > 0 && avctx->framerate.den > 0)
> +        framerate = avctx->framerate.num / avctx->framerate.den;
> +    else
> +        framerate = avctx->time_base.den / avctx->time_base.num;
> +
> +    vvenc_init_default(&params, avctx->width, avctx->height, framerate,
> +                       avctx->bit_rate, s->qp, preset);
> +
> +    vvenc_set_verbository(&params);
> +
> +    if (avctx->thread_count > 0)
> +        params.m_numThreads = avctx->thread_count;
> +
> +    /* GOP settings (IDR/CRA) */
> +    if (avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)
> +        params.m_DecodingRefreshType = VVENC_DRT_IDR;
> +
> +    if (avctx->gop_size == 1) {
> +        params.m_GOPSize = 1;
> +        params.m_IntraPeriod = 1;
> +    } else
> +        params.m_IntraPeriodSec = s->intra_refresh_sec;
> +
> +    params.m_AccessUnitDelimiter = true;
> +    params.m_usePerceptQPA = s->qpa;
> +    params.m_levelTier     = (vvencTier) s->tier;
> +
> +    if (avctx->level > 0)
> +        params.m_level = (vvencLevel)avctx->level;
> +
> +    if (s->level) {
> +        if (VVENC_PARAM_BAD_VALUE == vvenc_set_param(&params, "level", s->level)) {
> +            av_log(avctx, AV_LOG_ERROR, "Invalid level_idc: %s.\n", s->level);
> +            return AVERROR(EINVAL);
> +        }
> +    }
> +
> +    vvenc_set_framerate(avctx, &params);
> +
> +    vvenc_set_pic_format(avctx, &params);
> +
> +    vvenc_set_color_format(avctx, &params);
> +
> +    if ((ret = vvenc_parse_vvenc_params(avctx, &params)) != 0)
> +        return ret;
> +
> +    if ((ret = vvenc_set_rc_mode(avctx, &params)) != 0)
> +        return ret;
> +
> +    s->encoder = vvenc_encoder_create();
> +    if (!s->encoder) {
> +        av_log(avctx, AV_LOG_ERROR, "cannot create libvvenc encoder\n");
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    vvenc_set_msg_callback(&params, s->encoder, vvenc_log_callback);
> +    if ((ret = vvenc_encoder_open(s->encoder, &params)) != 0) {
> +        av_log(avctx, AV_LOG_ERROR, "cannot open libvvenc encoder: %s\n",
> +               vvenc_get_last_error(s->encoder));
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    vvenc_get_config(s->encoder, &params);     /* get the adapted config */
> +
> +    av_log(avctx, AV_LOG_INFO, "libvvenc version: %s\n", vvenc_get_version());
> +    if (av_log_get_level() >= AV_LOG_VERBOSE)
> +        av_log(avctx, AV_LOG_INFO, "%s\n", vvenc_get_config_as_string(&params, params.m_verbosity));
> +
> +    if (params.m_RCNumPasses == 2) {
> +        if ((ret = vvenc_init_pass(s->encoder, params.m_RCPass - 1, s->stats)) != 0) {
> +            av_log(avctx, AV_LOG_ERROR, "cannot init pass %d: %s\n",  params.m_RCPass,
> +                   vvenc_get_last_error(s->encoder));
> +            return AVERROR_EXTERNAL;
> +        }
> +    }
> +
> +    s->au = vvenc_accessUnit_alloc();
> +    if (!s->au) {
> +        av_log(avctx, AV_LOG_FATAL, "cannot allocate memory for AU payload\n");
> +        return AVERROR(ENOMEM);
> +    }
> +    vvenc_accessUnit_alloc_payload(s->au, avctx->width * avctx->height);
> +    if (!s->au->payload) {
> +        av_log(avctx, AV_LOG_FATAL, "cannot allocate payload memory of size %d\n",
> +               avctx->width * avctx->height);
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    if ((ret = vvenc_init_extradata(avctx, s)) != 0)
> +        return ret;
> +
> +    s->encode_done = false;
> +    return 0;
> +}
> +
> +static av_cold int vvenc_close(AVCodecContext *avctx)
> +{
> +    VVenCContext *s = avctx->priv_data;
> +
> +    if (s->au)
> +        vvenc_accessUnit_free(s->au, true);
> +
> +    if (s->encoder) {
> +        vvenc_print_summary(s->encoder);
> +
> +        if (0 != vvenc_encoder_close(s->encoder))
> +            return AVERROR_EXTERNAL;
> +    }
> +
> +    return 0;
> +}
> +
> +static av_cold int vvenc_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame,
> +                               int *got_packet)
> +{
> +    VVenCContext *s = avctx->priv_data;
> +    vvencYUVBuffer *pyuvbuf;
> +    vvencYUVBuffer yuvbuf;
> +    int pict_type;
> +    int ret;
> +
> +    pyuvbuf = NULL;
> +    if (frame && avctx->pix_fmt == AV_PIX_FMT_YUV420P10) {

The pix_fmt check is redundant.

> +        vvenc_YUVBuffer_default(&yuvbuf);
> +        yuvbuf.planes[0].ptr = (int16_t *) frame->data[0];
> +        yuvbuf.planes[1].ptr = (int16_t *) frame->data[1];
> +        yuvbuf.planes[2].ptr = (int16_t *) frame->data[2];
> +
> +        yuvbuf.planes[0].width  = frame->width;
> +        yuvbuf.planes[0].height = frame->height;
> +        yuvbuf.planes[0].stride = frame->linesize[0] >> 1; /* stride is used in 16bit samples in vvenc */
> +
> +        yuvbuf.planes[1].width  = frame->width >> 1;
> +        yuvbuf.planes[1].height = frame->height >> 1;
> +        yuvbuf.planes[1].stride = frame->linesize[1] >> 1;
> +
> +        yuvbuf.planes[2].width  = frame->width >> 1;
> +        yuvbuf.planes[2].height = frame->height >> 1;
> +        yuvbuf.planes[2].stride = frame->linesize[2] >> 1;
> +
> +        yuvbuf.cts = frame->pts;
> +        yuvbuf.ctsValid = true;
> +        pyuvbuf = &yuvbuf;
> +    }
> +
> +    if (!s->encode_done) {
> +        if (vvenc_encode(s->encoder, pyuvbuf, s->au, &s->encode_done) != 0)
> +            return AVERROR_EXTERNAL;
> +    } else
> +        return 0;
> +
> +    if (s->au->payloadUsedSize > 0) {
> +        if ((ret = ff_get_encode_buffer(avctx, pkt, s->au->payloadUsedSize, 0)) < 0)

ret = ff_get_encode_buffer();
if (ret < 0)
    return ret;
Improves readability and is less error-prone.

> +            return ret;
> +
> +        memcpy(pkt->data, s->au->payload, s->au->payloadUsedSize);
> +
> +        if (s->au->ctsValid)
> +            pkt->pts = s->au->cts;
> +        if (s->au->dtsValid)
> +            pkt->dts = s->au->dts;
> +        pkt->flags |= AV_PKT_FLAG_KEY * s->au->rap;
> +
> +        switch (s->au->sliceType) {
> +        case VVENC_I_SLICE:
> +            pict_type = AV_PICTURE_TYPE_I;
> +            break;
> +        case VVENC_P_SLICE:
> +            pict_type = AV_PICTURE_TYPE_P;
> +            break;
> +        case VVENC_B_SLICE:
> +            pict_type = AV_PICTURE_TYPE_B;
> +            break;
> +        default:
> +            av_log(avctx, AV_LOG_ERROR, "Unknown picture type encountered.\n");
> +            return AVERROR_EXTERNAL;
> +        }
> +
> +        ff_side_data_set_encoder_stats(pkt, 0, NULL, 0, pict_type);

As has already been said: You do not have meaningful stats. The only
thing you attach to this packet is the slice type, something which could
also be recovered from the packet by parsing it (in contrast to proper
encoder stats for which this is not true).

> +
> +        *got_packet = 1;
> +        return 0;
> +    }
> +
> +    return 0;
> +}
> +
> +static const enum AVPixelFormat pix_fmts_vvenc[] = {
> +    AV_PIX_FMT_YUV420P10,
> +    AV_PIX_FMT_NONE
> +};
> +
> +#define OFFSET(x) offsetof(VVenCContext, x)
> +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> +static const AVOption options[] = {
> +    { "preset",       "set encoding preset", OFFSET(preset), AV_OPT_TYPE_INT, {.i64 = 2}, 0, 4, VE, "preset"},
> +    { "faster",       "0", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_FASTER}, INT_MIN, INT_MAX, VE, "preset" },
> +    { "fast",         "1", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_FAST},   INT_MIN, INT_MAX, VE, "preset" },
> +    { "medium",       "2", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_MEDIUM}, INT_MIN, INT_MAX, VE, "preset" },
> +    { "slow",         "3", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOW},   INT_MIN, INT_MAX, VE, "preset" },
> +    { "slower",       "4", 0, AV_OPT_TYPE_CONST, {.i64 = VVENC_SLOWER}, INT_MIN, INT_MAX, VE, "preset" },
> +    { "qp",           "set quantization",          OFFSET(qp), AV_OPT_TYPE_INT,  {.i64 = 32}, -1, 63, VE },
> +    { "qpa",          "set subjective (perceptually motivated) optimization", OFFSET(qpa), AV_OPT_TYPE_BOOL, {.i64 = 1},  0, 1, VE},
> +    { "passlogfile",  "Filename for 2 pass stats", OFFSET(stats), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, VE},
> +    { "stats",        "Filename for 2 pass stats", OFFSET(stats), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, VE},
> +    { "period",       "set (intra) refresh period in seconds", OFFSET(intra_refresh_sec), AV_OPT_TYPE_INT,  {.i64 = 1},  1, INT_MAX, VE },
> +    { "vvenc-params", "set the vvenc configuration using a :-separated list of key=value parameters", OFFSET(vvenc_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE },
> +    { "level",        "Specify level (as defined by Annex A)", OFFSET(level), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, VE},
> +    { "tier",         "set vvc tier", OFFSET(tier), AV_OPT_TYPE_INT, {.i64 = 0},  0, 1, VE, "tier"},
> +    { "main",         "main", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, VE, "tier"},
> +    { "high",         "high", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, INT_MIN, INT_MAX, VE, "tier"},
> +    {NULL}
> +};
> +
> +static const AVClass class = {
> +    .class_name = "libvvenc",
> +    .item_name  = av_default_item_name,
> +    .option     = options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +static const FFCodecDefault vvenc_defaults[] = {
> +    { "b", "0" },
> +    { "g", "-1" },
> +    { NULL },
> +};
> +
> +const FFCodec ff_libvvenc_encoder = {
> +    .p.name         = "libvvenc",
> +    CODEC_LONG_NAME("libvvenc H.266 / VVC"),
> +    .p.type         = AVMEDIA_TYPE_VIDEO,
> +    .p.id           = AV_CODEC_ID_VVC,
> +    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY |
> +                      AV_CODEC_CAP_OTHER_THREADS,
> +    .p.profiles     = NULL_IF_CONFIG_SMALL(ff_vvc_profiles),
> +    .p.priv_class   = &class,
> +    .p.wrapper_name = "libvvenc",
> +    .priv_data_size = sizeof(VVenCContext),
> +    .p.pix_fmts     = pix_fmts_vvenc,
> +    .init           = vvenc_init,
> +    FF_CODEC_ENCODE_CB(vvenc_frame),
> +    .close          = vvenc_close,
> +    .defaults       = vvenc_defaults,
> +    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS
> +};

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".

  parent reply	other threads:[~2024-06-03 14:10 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-28 16:26 [FFmpeg-devel] [PATCH v4 0/1] Add support for H266/VVC encoding Christian Bartnik
2024-05-28 16:26 ` [FFmpeg-devel] [PATCH v4 1/1] avcodec: add external enc libvvenc for H266/VVC Christian Bartnik
2024-06-03 13:23   ` Nuo Mi
2024-06-03 13:54   ` Andreas Rheinhardt [this message]
2024-06-04  9:21   ` Anton Khirnov
2024-06-04 14:33     ` Christian

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=GV1P250MB07377E9867D56F47422EDA368FFF2@GV1P250MB0737.EURP250.PROD.OUTLOOK.COM \
    --to=andreas.rheinhardt@outlook.com \
    --cc=ffmpeg-devel@ffmpeg.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
		ffmpegdev@gitmailbox.com
	public-inbox-index ffmpegdev

Example config snippet for mirrors.


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git