[FFmpeg-devel] [PATCH] avcodec: add APV encoder using liboapv

Dawid Kozinski/Multimedia (PLT) /SRPOL/Staff Engineer/Samsung Electronics d.kozinski at samsung.com
Wed Apr 30 17:03:57 EEST 2025




> -----Original Message-----
> From: ffmpeg-devel <ffmpeg-devel-bounces at ffmpeg.org> On Behalf Of James
> Almer
> Sent: środa, 30 kwietnia 2025 02:40
> To: ffmpeg-devel at ffmpeg.org
> Subject: [FFmpeg-devel] [PATCH] avcodec: add APV encoder using liboapv
> 
> From: Dawid Kozinski <d.kozinski at samsung.com>
> 
> Co-authored-by: James Almer <jamrial at gmail.com>
> Signed-off-by: James Almer <jamrial at gmail.com>
> ---
> Touched up Dawid's patch to fix several issues. The most important one
being
> the image rescaling code that's out of place in an encoder.
> liboapv does not seem to properly support 12bit content yet (Which is why
the
> scaling code was added, to reduce the input to 10bit), so i removed it
> altogether. Same with all the references to GRAY, 420P, A444P, and Y210,
which
> are also not supported.
> 
Thank you for the review and your changes. We are aware that the encoder is
not the best place for data rescaling. However, the oapve_encode() function
requires data which size is a multiple of 16. Any suggestions for resolving
this problem?

A bit off-topic.
I am still working on the implementation of the MOV muxer. The patch should
be submitted soon.

> Also removed the ad-hock atomics. If the library needs the reference
counting
> to be atomic, it needs to handle it itself. Their own CLI implementation
doesn't
> even bother with it.
> 
>  configure               |   4 +
>  doc/encoders.texi       |  41 ++++
>  libavcodec/Makefile     |   1 +
>  libavcodec/allcodecs.c  |   2 +
>  libavcodec/liboapvenc.c | 490 ++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 538 insertions(+)
>  create mode 100644 libavcodec/liboapvenc.c
> 
> diff --git a/configure b/configure
> index e285061742..4717836aff 100755
> --- a/configure
> +++ b/configure
> @@ -250,6 +250,7 @@ External library support:
>    --enable-liblensfun      enable lensfun lens correction [no]
>    --enable-libmodplug      enable ModPlug via libmodplug [no]
>    --enable-libmp3lame      enable MP3 encoding via libmp3lame [no]
> +  --enable-liboapv         enable APV encoding/decoding via liboapv [no]
>    --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-
> amrnb [no]
>    --enable-libopencore-amrwb enable AMR-WB decoding via libopencore-
> amrwb [no]
>    --enable-libopencv       enable video filtering via libopencv [no]
> @@ -1951,6 +1952,7 @@ EXTERNAL_LIBRARY_LIST="
>      libmodplug
>      libmp3lame
>      libmysofa
> +    liboapv
>      libopencv
>      libopenh264
>      libopenjpeg
> @@ -3590,6 +3592,7 @@ liblc3_encoder_select="audio_frame_queue"
>  libmodplug_demuxer_deps="libmodplug"
>  libmp3lame_encoder_deps="libmp3lame"
>  libmp3lame_encoder_select="audio_frame_queue mpegaudioheader"
> +liboapv_encoder_deps="liboapv"
>  libopencore_amrnb_decoder_deps="libopencore_amrnb"
>  libopencore_amrnb_encoder_deps="libopencore_amrnb"
>  libopencore_amrnb_encoder_select="audio_frame_queue"
> @@ -6930,6 +6933,7 @@ enabled jni               && { [ $target_os =
"android" ] &&
> check_headers jni.h
>  enabled ladspa            && require_headers "ladspa.h dlfcn.h"
>  enabled lcms2             && require_pkg_config lcms2 "lcms2 >= 2.13"
lcms2.h
> cmsCreateContext
>  enabled libaom            && require_pkg_config libaom "aom >= 2.0.0"
> aom/aom_codec.h aom_codec_version
> +enabled liboapv           && require_pkg_config liboapv "oapv >= 0.1.13"
> "oapv/oapv.h" oapve_encode
>  enabled libaribb24        && { check_pkg_config libaribb24 "aribb24 >
1.0.3"
> "aribb24/aribb24.h" arib_instance_new ||
>                                 { enabled gpl && require_pkg_config
libaribb24 aribb24
> "aribb24/aribb24.h" arib_instance_new; } ||
>                                 die "ERROR: libaribb24 requires version
higher than 1.0.3 or --
> enable-gpl."; } diff --git a/doc/encoders.texi b/doc/encoders.texi index
> 128e81a2e7..f5d6d69246 100644
> --- a/doc/encoders.texi
> +++ b/doc/encoders.texi
> @@ -1889,6 +1889,47 @@ ffmpeg -i input -c:v libaom-av1 -b:v 500K -aom-
> params tune=psnr:enable-tpl-model
> 
>  @end table
> 
> + at section liboapv
> +
> +Advanced Professional Video codec encoder wrapper.
> +
> +This encoder requires the presence of the liboapv headers and library
> +during configuration. You need to explicitly configure the build with
> + at option{--enable-liboapv}.
> +
> + at float NOTE
> +Many liboapv encoder options are mapped to FFmpeg global codec options,
> +while unique encoder options are provided through private options.
> +Additionally the apv-params private options allows one to pass a list
> +of key=value tuples as accepted by the liboapv @code{parse_apv_params}
> function.
> + at end float
> +
> +The apv project website is at
> @url{https://protect2.fireeye.com/v1/url?k=0ac15afb-6bbaf073-0ac0d1b4-
> 74fe4860018a-8320254a0f21174c&q=1&e=b2c8d30c-5c3a-4ef3-af4f-
> bd15f74e89f9&u=https%3A%2F%2Fgithub.com%2FAcademySoftwareFoundatio
> n%2Fopenapv%257D.
> +
> + at subsection Options
> +
> +The following options are supported by the liboapv wrapper.
> +The apv-equivalent options or values are listed in parentheses for easy
> migration.
> +
> + at float NOTE
> +To reduce the duplication of documentation, only the private options
> +and some others requiring special attention are documented here. For
> +the documentation of the undocumented generic options, see
> + at ref{codec-options,,the Codec Options chapter}.
> + at end float
> +
> + at float NOTE
> +To get a more accurate and extensive documentation of the liboapv
> +options, invoke the command  @code{apv_app_enc --help} or consult the
> liboapv documentation.
> + at end float
> +
> + at table @option
> + at item b (@emph{bitrate})
> +Set target video bitrate in bits/s.
> +Note that FFmpeg's b option is expressed in bits/s, while apv's bitrate
is in
> kilobits/s.
> +
> + at end table
> +
>  @section libsvtav1
> 
>  SVT-AV1 encoder wrapper.
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile index
> cc142bbae2..cae8f3a9f1 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -1151,6 +1151,7 @@ OBJS-$(CONFIG_LIBKVAZAAR_ENCODER)         +=
> libkvazaar.o
>  OBJS-$(CONFIG_LIBLC3_ENCODER)             += liblc3enc.o
>  OBJS-$(CONFIG_LIBLC3_DECODER)             += liblc3dec.o
>  OBJS-$(CONFIG_LIBMP3LAME_ENCODER)         += libmp3lame.o
> +OBJS-$(CONFIG_LIBOAPV_ENCODER)            += liboapvenc.o
>  OBJS-$(CONFIG_LIBOPENCORE_AMRNB_DECODER)  += libopencore-amr.o
>  OBJS-$(CONFIG_LIBOPENCORE_AMRNB_ENCODER)  += libopencore-amr.o
>  OBJS-$(CONFIG_LIBOPENCORE_AMRWB_DECODER)  += libopencore-amr.o diff
> --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index
> 09f06c71d6..3cb04a2462 100644
> --- a/libavcodec/allcodecs.c
> +++ b/libavcodec/allcodecs.c
> @@ -764,6 +764,7 @@ extern const FFCodec ff_pcm_mulaw_at_decoder;
> extern const FFCodec ff_qdmc_at_decoder;  extern const FFCodec
> ff_qdm2_at_decoder;  extern FFCodec ff_libaom_av1_encoder;
> +
>  /* preferred over libaribb24 */
>  extern const FFCodec ff_libaribcaption_decoder;  extern const FFCodec
> ff_libaribb24_decoder; @@ -787,6 +788,7 @@ extern const FFCodec
> ff_libjxl_encoder;  extern const FFCodec ff_liblc3_encoder;  extern const
> FFCodec ff_liblc3_decoder;  extern const FFCodec ff_libmp3lame_encoder;
> +extern const FFCodec ff_liboapv_encoder;
>  extern const FFCodec ff_libopencore_amrnb_encoder;  extern const FFCodec
> ff_libopencore_amrnb_decoder;  extern const FFCodec
> ff_libopencore_amrwb_decoder; diff --git a/libavcodec/liboapvenc.c
> b/libavcodec/liboapvenc.c new file mode 100644 index
0000000000..01fb20ecff
> --- /dev/null
> +++ b/libavcodec/liboapvenc.c
> @@ -0,0 +1,490 @@
> +/*
> + * liboapv encoder
> + * Advanced Professional Video codec library
> + *
> + * Copyright (C) 2025 Dawid Kozinski <d.kozinski at samsung.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  */
> +
> +#include <stdint.h>
> +#include <stdlib.h>
> +
> +#include <oapv/oapv.h>
> +
> +#include "libavutil/opt.h"
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/pixfmt.h"
> +#include "libavutil/mem.h"
> +#include "libavutil/avassert.h"
> +#include "libavutil/imgutils.h"
> +
> +#include "avcodec.h"
> +#include "packet_internal.h"
> +#include "codec_internal.h"
> +#include "encode.h"
> +
> +#define MAX_BS_BUF   (128 * 1024 * 1024)
> +#define MAX_NUM_FRMS (1)           // supports only 1-frame in an access
unit
> +#define FRM_IDX      (0)           // supports only 1-frame in an access
unit
> +#define MAX_NUM_CC   (OAPV_MAX_CC) // Max number of color componets
> (upto 4:4:4:4)
> +
> +/**
> + * The structure stores all the states associated with the instance of
> +APV encoder  */ typedef struct ApvEncContext {
> +    const AVClass *class;
> +
> +    oapve_t id;             // APV instance identifier
> +    oapvm_t mid;
> +    oapve_cdesc_t   cdsc;   // coding parameters i.e profile, width &
height of
> input frame, num of therads, frame rate ...
> +    oapv_bitb_t     bitb;   // bitstream buffer (output)
> +    oapve_stat_t    stat;   // encoding status (output)
> +
> +    oapv_frms_t ifrms;      // frames for input
> +
> +    int num_frames;         // number of frames in an access unit
> +
> +    int preset_id;          // preset of apv ( fastest, fast, medium,
slow, placebo)
> +
> +    int qp;                 // quantization parameter (QP) [0,51]
> +
> +    AVDictionary *oapv_params;
> +} ApvEncContext;
> +
> +static int apv_imgb_release(oapv_imgb_t *imgb) {
> +    int refcnt = --imgb->refcnt;
> +    if (refcnt == 0) {
> +        for (int i = 0; i < imgb->np; i++)
> +            av_freep(&imgb->baddr[i]);
> +        av_free(imgb);
> +    }
> +
> +    return refcnt;
> +}
> +
> +static int apv_imgb_addref(oapv_imgb_t * imgb) {
> +    int refcnt = ++imgb->refcnt;
> +    return refcnt;
> +}
> +
> +static int apv_imgb_getref(oapv_imgb_t * imgb) {
> +    return imgb->refcnt;
> +}
> +
> +static oapv_imgb_t *apv_imgb_create(int w, int h, int cs, void *logctx)
> +{
> +    oapv_imgb_t *imgb;
> +    int i, bd;
> +
> +    imgb = av_mallocz(sizeof(oapv_imgb_t));
> +    if (!imgb)
> +        goto fail;
> +
> +    bd = OAPV_CS_GET_BYTE_DEPTH(cs); /* byte unit */
> +
> +    imgb->w[0] = w;
> +    imgb->h[0] = h;
> +    switch(OAPV_CS_GET_FORMAT(cs)) {
> +    case OAPV_CF_YCBCR422:
> +        imgb->w[1] = imgb->w[2] = (w + 1) >> 1;
> +        imgb->h[1] = imgb->h[2] = h;
> +        imgb->np = 3;
> +        break;
> +    case OAPV_CF_YCBCR444:
> +        imgb->w[1] = imgb->w[2] = w;
> +        imgb->h[1] = imgb->h[2] = h;
> +        imgb->np = 3;
> +        break;
> +    default:
> +        av_log(logctx, AV_LOG_ERROR, "unsupported color format\n");
> +        goto fail;
> +    }
> +
> +    for (i = 0; i < imgb->np; i++) {
> +        imgb->aw[i] = FFALIGN(imgb->w[i], OAPV_MB_W);
> +        imgb->s[i] = imgb->aw[i] * bd;
> +        imgb->ah[i] = FFALIGN(imgb->h[i], OAPV_MB_H);
> +        imgb->e[i] = imgb->ah[i];
> +
> +        imgb->bsize[i] = imgb->s[i] * imgb->e[i];
> +        imgb->a[i] = imgb->baddr[i] = av_mallocz(imgb->bsize[i]);
> +        if (imgb->a[i] == NULL)
> +             goto fail;
> +    }
> +    imgb->cs = cs;
> +    imgb->addref = apv_imgb_addref;
> +    imgb->getref = apv_imgb_getref;
> +    imgb->release = apv_imgb_release;
> +
> +    imgb->refcnt = 1;
> +
> +    return imgb;
> +fail:
> +    av_log(logctx, AV_LOG_ERROR, "cannot create image buffer\n");
> +    if (imgb) {
> +        for (int i = 0; i < imgb->np; i++)
> +            av_freep(&imgb->a[i]);
> +    }
> +    av_freep(&imgb);
> +    return NULL;
> +}
> +
> +/**
> + * Convert FFmpeg pixel format (AVPixelFormat) into APV pre-defined
> +color format
> + *
> + * @return APV pre-defined color format (@see oapv.h) on success,
> +OAPV_CF_UNKNOWN on failure  */ static inline int get_color_format(enum
> +AVPixelFormat pix_fmt) {
> +    int cf = OAPV_CF_UNKNOWN;
> +
> +    switch (pix_fmt) {
> +    case AV_PIX_FMT_YUV422P10:
> +        cf = OAPV_CF_YCBCR422;
> +        break;
> +    case AV_PIX_FMT_YUV444P10:
> +        cf = OAPV_CF_YCBCR444;
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    return cf;
> +}
> +
> +/**
> + * The function returns a pointer to the object of the oapve_cdesc_t
type.
> + * oapve_cdesc_t contains all encoder parameters that should be
initialized
> before the encoder is used.
> + *
> + * The field values of the oapve_cdesc_t structure are populated based
on:
> + * - the corresponding field values of the AvCodecConetxt structure,
> + * - the apv encoder specific option values,
> + *
> + * The order of processing input data and populating the apve_cdsc
> +structure
> + * 1) first, the fields of the AVCodecContext structure corresponding to
the
> provided input options are processed,
> + *    (i.e -pix_fmt yuv422p -s:v 1920x1080 -r 30 -profile:v 0)
> + * 2) then apve-specific options added as AVOption to the apv AVCodec
> implementation
> + *    (i.e -preset 0)
> + *
> + * Keep in mind that, there are options that can be set in different
ways.
> + * In this case, please follow the above-mentioned order of processing.
> + * The most recent assignments overwrite the previous values.
> + *
> + * @param[in] avctx codec context (AVCodecContext)
> + * @param[out] cdsc contains all APV encoder encoder parameters that
> +should be initialized before the encoder is use
> + *
> + * @return 0 on success, negative error code on failure  */ static int
> +get_conf(AVCodecContext *avctx, oapve_cdesc_t *cdsc) {
> +    ApvEncContext *apv = avctx->priv_data;
> +
> +    /* initialize apv_param struct with default values */
> +    int ret = oapve_param_default(&cdsc->param[FRM_IDX]);
> +    if (OAPV_FAILED(ret)) {
> +        av_log(avctx, AV_LOG_ERROR, "Cannot set default parameter\n");
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    /* read options from AVCodecContext */
> +    if (avctx->width > 0)
> +        cdsc->param[FRM_IDX].w = avctx->width;
> +
> +    if (avctx->height > 0)
> +        cdsc->param[FRM_IDX].h = avctx->height;
> +
> +    if (avctx->framerate.num > 0) {
> +        cdsc->param[FRM_IDX].fps_num = avctx->framerate.num;
> +        cdsc->param[FRM_IDX].fps_den = avctx->framerate.den;
> +    } else if (avctx->time_base.num > 0) {
> +        cdsc->param[FRM_IDX].fps_num = avctx->time_base.den;
> +        cdsc->param[FRM_IDX].fps_den = avctx->time_base.num;
> +    }
> +
> +    cdsc->param[FRM_IDX].preset = apv->preset_id;
> +    cdsc->param[FRM_IDX].qp = apv->qp;
> +    if (avctx->bit_rate / 1000 > INT_MAX || avctx->rc_max_rate / 1000 >
> INT_MAX) {
> +        av_log(avctx, AV_LOG_ERROR, "Not supported bitrate bit_rate and
> rc_max_rate > %d000\n", INT_MAX);
> +        return AVERROR(EINVAL);
> +    }
> +    cdsc->param[FRM_IDX].bitrate = (int)(avctx->bit_rate / 1000);
> +    if (cdsc->param[FRM_IDX].bitrate) {
> +        if (cdsc->param[FRM_IDX].qp) {
> +            av_log(avctx, AV_LOG_WARNING, "You cannot set both the
bitrate and
> the QP parameter at the same time.\n"
> +                                          "If the bitrate is set, the
rate control type is set to ABR,
> which means that the QP value is ignored.\n");
> +        }
> +        cdsc->param[FRM_IDX].rc_type = OAPV_RC_ABR;
> +    }
> +
> +    cdsc->threads = avctx->thread_count;
> +
> +    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED)
> +        cdsc->param[FRM_IDX].color_primaries = avctx->color_primaries;
> +
> +    if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED)
> +        cdsc->param[FRM_IDX].transfer_characteristics =
> + avctx->color_trc;
> +
> +    if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED)
> +        cdsc->param[FRM_IDX].matrix_coefficients = avctx->colorspace;
> +
> +    if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED)
> +        cdsc->param[FRM_IDX].full_range_flag = (avctx->color_range ==
> + AVCOL_RANGE_JPEG);
> +
> +    cdsc->max_bs_buf_size = MAX_BS_BUF; /* maximum bitstream buffer size
> */
> +    cdsc->max_num_frms = MAX_NUM_FRMS;
> +
> +    return 0;
> +}
> +
> +static int get_bit_depth(enum AVPixelFormat pixel_format) {
> +     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixel_format);
> +     av_assert0(desc);
> +     return desc->comp[0].depth;
> +}
> +
> +/**
> + * @brief Initialize APV codec
> + * Create an encoder instance and allocate all the needed resources
> + *
> + * @param avctx codec context
> + * @return 0 on success, negative error code on failure  */ static
> +av_cold int liboapve_init(AVCodecContext *avctx) {
> +    ApvEncContext *apv = avctx->priv_data;
> +    oapve_cdesc_t *cdsc = &apv->cdsc;
> +    unsigned char *bs_buf;
> +    int input_depth;
> +    int cfmt;  // color format
> +    int ret;
> +
> +    apv->id = NULL;
> +    apv->mid = NULL;
> +    apv->bitb.addr = NULL;
> +
> +    /* allocate bitstream buffer */
> +    bs_buf = (unsigned char *)av_malloc(MAX_BS_BUF);
> +    if (bs_buf == NULL) {
> +        av_log(avctx, AV_LOG_ERROR, "Cannot allocate bitstream buffer,
> size=%d\n", MAX_BS_BUF);
> +        return AVERROR(ENOMEM);
> +    }
> +    apv->bitb.addr = bs_buf;
> +    apv->bitb.bsize = MAX_BS_BUF;
> +
> +    /* read configurations and set values for created descriptor
(APV_CDSC) */
> +    ret = get_conf(avctx, cdsc);
> +    if (ret < 0) {
> +        av_log(avctx, AV_LOG_ERROR, "Cannot get OAPV configuration\n");
> +        return ret;
> +    }
> +
> +    const AVDictionaryEntry *en = NULL;
> +    while (en = av_dict_iterate(apv->oapv_params, en)) {
> +        ret = oapve_param_parse(&cdsc->param[FRM_IDX], en->key,
en->value);
> +        if (ret < 0)
> +            av_log(avctx, AV_LOG_WARNING, "Error parsing option '%s =
%s'.\n",
> en->key, en->value);
> +    }
> +
> +    /* create encoder */
> +    apv->id = oapve_create(cdsc, &ret);
> +    if (apv->id == NULL) {
> +        av_log(avctx, AV_LOG_ERROR, "Cannot create OAPV encoder\n");
> +        if (ret == OAPV_ERR_INVALID_LEVEL)
> +            av_log(avctx, AV_LOG_ERROR, "Invalid level idc: %d\n", cdsc-
> >param[0].level_idc);
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    /* create metadata handler */
> +    apv->mid = oapvm_create(&ret);
> +    if (apv->mid == NULL || OAPV_FAILED(ret)) {
> +        av_log(avctx, AV_LOG_ERROR, "cannot create OAPV metadata
> handler\n");
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    input_depth = get_bit_depth(avctx->pix_fmt);
> +    cfmt = get_color_format(avctx->pix_fmt);
> +
> +    apv->ifrms.frm[FRM_IDX].imgb = apv_imgb_create(avctx->width, avctx-
> >height,
> +                                                   OAPV_CS_SET(cfmt,
input_depth,
> AV_HAVE_BIGENDIAN), avctx);
> +    if (apv->ifrms.frm[FRM_IDX].imgb == NULL)
> +        return AVERROR(ENOMEM);
> +    apv->ifrms.num_frms++;
> +
> +     /* color description values */
> +    if (cdsc->param[FRM_IDX].color_description_present_flag) {
> +        avctx->color_primaries = cdsc->param[FRM_IDX].color_primaries;
> +        avctx->color_trc = cdsc->param[FRM_IDX].transfer_characteristics;
> +        avctx->colorspace = cdsc->param[FRM_IDX].matrix_coefficients;
> +        avctx->color_range = (cdsc->param[FRM_IDX].full_range_flag) ?
> AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
> +    }
> +
> +    return 0;
> +}
> +
> +/**
> +  * Encode raw data frame into APV packet
> +  *
> +  * @param[in]  avctx codec context
> +  * @param[out] avpkt output AVPacket containing encoded data
> +  * @param[in]  frame AVFrame containing the raw data to be encoded
> +  * @param[out] got_packet encoder sets to 0 or 1 to indicate that a
> +  *                         non-empty packet was returned in pkt
> +  *
> +  * @return 0 on success, negative error code on failure
> +  */
> +static int liboapve_encode(AVCodecContext *avctx, AVPacket *avpkt,
> +                          const AVFrame *frame, int *got_packet) {
> +    ApvEncContext *apv =  avctx->priv_data;
> +    oapv_frm_t *frm = &apv->ifrms.frm[FRM_IDX];
> +    oapv_imgb_t *imgb = frm->imgb;
> +    int ret;
> +
> +    if (avctx->width != frame->width || avctx->height != frame->height ||
avctx-
> >pix_fmt != frame->format) {
> +        av_log(avctx, AV_LOG_ERROR, "Dimension change is not
supported\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    av_image_copy((uint8_t **)imgb->a, imgb->s, (const uint8_t **)frame-
> >data, frame->linesize,
> +                  frame->format, frame->width, frame->height);
> +
> +    imgb->ts[0] = frame->pts;
> +
> +    frm->group_id = 1; // @todo FIX-ME : need to set properly in case of
multi-
> frame
> +    frm->pbu_type = OAPV_PBU_TYPE_PRIMARY_FRAME;
> +
> +    ret = oapve_encode(apv->id, &apv->ifrms, apv->mid, &apv->bitb, &apv-
> >stat, NULL);
> +    if (OAPV_FAILED(ret)) {
> +        av_log(avctx, AV_LOG_ERROR, "oapve_encode() failed\n");
> +        return AVERROR_EXTERNAL;
> +    }
> +
> +    /* store bitstream */
> +    if (OAPV_SUCCEEDED(ret) && apv->stat.write > 0) {
> +        ret = ff_get_encode_buffer(avctx, avpkt, apv->stat.write - 4, 0);
> +        if (ret < 0)
> +            return ret;
> +
> +        // The encoder returns a "Raw bitstream" formated AU, including
au_size.
> +        // Discard it as we only need the access_unit() structure.
> +        memcpy(avpkt->data, (uint8_t *)apv->bitb.addr + 4,
> + apv->stat.write - 4);
> +
> +        avpkt->time_base.num = apv->cdsc.param->fps_num;
> +        avpkt->time_base.den = apv->cdsc.param->fps_den;
> +
> +        avpkt->pts = avpkt->dts = frame->pts;
> +        avpkt->flags |= AV_PKT_FLAG_KEY;
> +
> +        ff_side_data_set_encoder_stats(avpkt, apv->qp * FF_QP2LAMBDA,
> + NULL, 0, AV_PICTURE_TYPE_I);
> +
> +        *got_packet = 1;
> +    }
> +
> +    return 0;
> +}
> +
> +/**
> + * Destroy the encoder and release all the allocated resources
> + *
> + * @param avctx codec context
> + * @return 0 on success, negative error code on failure  */ static
> +av_cold int liboapve_close(AVCodecContext *avctx) {
> +    ApvEncContext *apv = avctx->priv_data;
> +
> +    for (int i = 0; i < apv->num_frames; i++) {
> +        if (apv->ifrms.frm[i].imgb != NULL)
> +            apv->ifrms.frm[i].imgb->release(apv->ifrms.frm[i].imgb);
> +        apv->ifrms.frm[i].imgb = NULL;
> +    }
> +
> +    if (apv->mid) {
> +        oapvm_rem_all(apv->mid);
> +    }
> +
> +    if (apv->id) {
> +        oapve_delete(apv->id);
> +        apv->id = NULL;
> +    }
> +
> +    if (apv->mid) {
> +        oapvm_delete(apv->mid);
> +        apv->mid = NULL;
> +    }
> +
> +    av_freep(&apv->bitb.addr); /* release bitstream buffer */
> +
> +    return 0;
> +}
> +
> +#define OFFSET(x) offsetof(ApvEncContext, x) #define VE
> +AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
> +
> +static const enum AVPixelFormat supported_pixel_formats[] = {
> +    AV_PIX_FMT_YUV422P10,
> +    AV_PIX_FMT_YUV444P10,
> +    AV_PIX_FMT_NONE
> +};
> +
> +static const AVOption liboapv_options[] = {
> +    { "preset", "Encoding preset for setting encoding speed (optimization
level
> control)", OFFSET(preset_id), AV_OPT_TYPE_INT, { .i64 =
> OAPV_PRESET_DEFAULT }, OAPV_PRESET_FASTEST, OAPV_PRESET_PLACEBO,
> VE, .unit = "preset" },
> +    { "fastest", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FASTEST
> },    INT_MIN, INT_MAX, VE, .unit = "preset" },
> +    { "fast",    NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_FAST },
> INT_MIN, INT_MAX, VE, .unit = "preset" },
> +    { "medium",  NULL, 0, AV_OPT_TYPE_CONST, { .i64 =
> OAPV_PRESET_MEDIUM },  INT_MIN, INT_MAX, VE, .unit = "preset" },
> +    { "slow",    NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OAPV_PRESET_SLOW },
> INT_MIN, INT_MAX, VE, .unit = "preset" },
> +    { "placebo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 =
> OAPV_PRESET_PLACEBO }, INT_MIN, INT_MAX, VE, .unit = "preset" },
> +    { "default", NULL, 0, AV_OPT_TYPE_CONST, { .i64 =
> +OAPV_PRESET_DEFAULT }, INT_MIN, INT_MAX, VE, .unit = "preset" },
> +
> +    { "qp", "Quantization parameter value for CQP rate control mode",
> OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 32 }, 0, 51, VE },
> +    { "oapv-params",  "Override the apv configuration using a :-separated
list of
> key=value parameters", OFFSET(oapv_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0,
> VE },
> +    { NULL }
> +};
> +
> +static const AVClass liboapve_class = {
> +    .class_name = "liboapv",
> +    .item_name  = av_default_item_name,
> +    .option     = liboapv_options,
> +    .version    = LIBAVUTIL_VERSION_INT,
> +};
> +
> +static const FFCodecDefault liboapve_defaults[] = {
> +    { "b", "0" },       // bitrate in terms of kilo-bits per second
(support for bit-rates
> from a few hundred Mbps to a few Gbps for 2K, 4K and 8K resolution
content)
> +    { NULL },
> +};
> +
> +const FFCodec ff_liboapv_encoder = {
> +    .p.name             = "liboapv",
> +    .p.long_name        = NULL_IF_CONFIG_SMALL("liboapv APV"),
> +    .p.type             = AVMEDIA_TYPE_VIDEO,
> +    .p.id               = AV_CODEC_ID_APV,
> +    .init               = liboapve_init,
> +    FF_CODEC_ENCODE_CB(liboapve_encode),
> +    .close              = liboapve_close,
> +    .priv_data_size     = sizeof(ApvEncContext),
> +    .p.priv_class       = &liboapve_class,
> +    .defaults           = liboapve_defaults,
> +    .p.capabilities     = AV_CODEC_CAP_OTHER_THREADS |
> AV_CODEC_CAP_DR1,
> +    .p.wrapper_name     = "liboapv",
> +    .p.pix_fmts         = supported_pixel_formats,
> +    .caps_internal      = FF_CODEC_CAP_INIT_CLEANUP |
> FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_NOT_INIT_THREADSAFE,
> +};
> --
> 2.49.0
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://protect2.fireeye.com/v1/url?k=c2a62f8e-a3dd8506-c2a7a4c1-
> 74fe4860018a-499384c6081a622b&q=1&e=b2c8d30c-5c3a-4ef3-af4f-
> bd15f74e89f9&u=https%3A%2F%2Fffmpeg.org%2Fmailman%2Flistinfo%2Fffmp
> eg-devel
> 
> To unsubscribe, visit link above, or email ffmpeg-devel-request at ffmpeg.org
> with subject "unsubscribe".




More information about the ffmpeg-devel mailing list