[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