[FFmpeg-cvslog] avcodec: add APV encoder using liboapv

Dawid Kozinski git at videolan.org
Sun May 4 22:30:44 EEST 2025


ffmpeg | branch: master | Dawid Kozinski <d.kozinski at samsung.com> | Wed Apr 23 16:13:29 2025 +0200| [fab691edaf53bbf10429ef3448f1f274e5078395] | committer: James Almer

avcodec: add APV encoder using liboapv

Co-authored-by: James Almer <jamrial at gmail.com>
Signed-off-by: James Almer <jamrial at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=fab691edaf53bbf10429ef3448f1f274e5078395
---

 Changelog               |   1 +
 configure               |   4 +
 doc/encoders.texi       |  36 ++++
 libavcodec/Makefile     |   1 +
 libavcodec/allcodecs.c  |   1 +
 libavcodec/defs.h       |   8 +
 libavcodec/liboapvenc.c | 483 ++++++++++++++++++++++++++++++++++++++++++++++++
 libavcodec/profiles.c   |  11 ++
 libavcodec/profiles.h   |   1 +
 libavcodec/version.h    |   2 +-
 10 files changed, 547 insertions(+), 1 deletion(-)

diff --git a/Changelog b/Changelog
index f73e4b45ee..2eb785fe44 100644
--- a/Changelog
+++ b/Changelog
@@ -15,6 +15,7 @@ version <next>:
 - pngenc: set default prediction method to PAETH
 - APV decoder and APV raw bitstream muxing and demuxing
 - APV parser
+- APV encoding support through a libopenapv wrapper
 
 
 version 7.1:
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..f6f6c096ec 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -1889,6 +1889,42 @@ 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.
+ at end float
+
+The apv project website is at @url{https://github.com/AcademySoftwareFoundation/openapv}.
+
+ at subsection Options
+
+The following options are supported by the liboapv wrapper.
+
+ at float NOTE
+To get a more extensive documentation of the liboapv options, consult the
+liboapv documentation.
+ at end float
+
+ at table @option
+ at item preset
+Set the quality-speed tradeoff [fastest, fast, medium, slow, placebo, default]
+
+ at item qp
+Set the quantization parameter value for CQP rate control mode.
+
+ at item oapv-params (@emph{parse_apv_params})
+Set liboapvenc options using a list of @var{key}=@var{value} pairs separated
+by ":". See the liboapv encoder user guide for a list of accepted parameters.
+ 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..cd4f6ecd59 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -787,6 +787,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/defs.h b/libavcodec/defs.h
index 24250f8af5..e0df60213b 100644
--- a/libavcodec/defs.h
+++ b/libavcodec/defs.h
@@ -194,6 +194,14 @@
 #define AV_PROFILE_EVC_BASELINE             0
 #define AV_PROFILE_EVC_MAIN                 1
 
+#define AV_PROFILE_APV_422_10  33
+#define AV_PROFILE_APV_422_12  44
+#define AV_PROFILE_APV_444_10  55
+#define AV_PROFILE_APV_444_12  66
+#define AV_PROFILE_APV_4444_10 77
+#define AV_PROFILE_APV_4444_12 88
+#define AV_PROFILE_APV_400_10  99
+
 
 #define AV_LEVEL_UNKNOWN                  -99
 
diff --git a/libavcodec/liboapvenc.c b/libavcodec/liboapvenc.c
new file mode 100644
index 0000000000..67230956cc
--- /dev/null
+++ b/libavcodec/liboapvenc.c
@@ -0,0 +1,483 @@
+/*
+ * 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/avassert.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/mem.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/pixfmt.h"
+
+#include "avcodec.h"
+#include "apv.h"
+#include "codec_internal.h"
+#include "encode.h"
+#include "packet_internal.h"
+#include "profiles.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,63]
+
+    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;
+}
+
+/**
+ * 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:
+        av_assert0(cf != OAPV_CF_UNKNOWN);
+    }
+
+    return cf;
+}
+
+static oapv_imgb_t *apv_imgb_create(AVCodecContext *avctx)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
+    oapv_imgb_t *imgb;
+    int input_depth;
+    int cfmt;  // color format
+    int cs;
+
+    av_assert0(desc);
+
+    imgb = av_mallocz(sizeof(oapv_imgb_t));
+    if (!imgb)
+        goto fail;
+
+    input_depth = desc->comp[0].depth;
+    cfmt = get_color_format(avctx->pix_fmt);
+    cs = OAPV_CS_SET(cfmt, input_depth, AV_HAVE_BIGENDIAN);
+
+    imgb->np = desc->nb_components;
+
+    for (int i = 0; i < imgb->np; i++) {
+        imgb->w[i]  = avctx->width >> ((i == 1 || i == 2) ? desc->log2_chroma_w : 0);
+        imgb->h[i]  = avctx->height;
+        imgb->aw[i] = FFALIGN(imgb->w[i], OAPV_MB_W);
+        imgb->ah[i] = FFALIGN(imgb->h[i], OAPV_MB_H);
+        imgb->s[i]  = imgb->aw[i] * OAPV_CS_GET_BYTE_DEPTH(cs);
+
+        imgb->bsize[i] = imgb->e[i] = imgb->s[i] * imgb->ah[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(avctx, 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;
+}
+
+/**
+ * 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, "bit_rate and rc_max_rate > %d000 is not supported\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;
+        cdsc->param[FRM_IDX].color_description_present_flag = 1;
+    }
+
+    if (avctx->color_trc != AVCOL_TRC_UNSPECIFIED) {
+        cdsc->param[FRM_IDX].transfer_characteristics = avctx->color_trc;
+        cdsc->param[FRM_IDX].color_description_present_flag = 1;
+    }
+
+    if (avctx->colorspace != AVCOL_SPC_UNSPECIFIED) {
+        cdsc->param[FRM_IDX].matrix_coefficients = avctx->colorspace;
+        cdsc->param[FRM_IDX].color_description_present_flag = 1;
+    }
+
+    if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED) {
+        cdsc->param[FRM_IDX].full_range_flag = (avctx->color_range == AVCOL_RANGE_JPEG);
+        cdsc->param[FRM_IDX].color_description_present_flag = 1;
+    }
+
+    cdsc->max_bs_buf_size = MAX_BS_BUF; /* maximum bitstream buffer size */
+    cdsc->max_num_frms = MAX_NUM_FRMS;
+
+    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);
+    }
+
+    return 0;
+}
+
+/**
+ * @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 ret;
+
+    /* 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;
+    }
+
+    /* 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;
+    }
+
+    apv->ifrms.frm[FRM_IDX].imgb = apv_imgb_create(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;
+    const oapve_cdesc_t *cdsc = &apv->cdsc;
+    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 changes are 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) {
+        uint8_t *data = apv->bitb.addr;
+        int size = apv->stat.write;
+
+        // The encoder may return a "Raw bitstream" formated AU, including au_size.
+        // Discard it as we only need the access_unit() structure.
+        if (size > 4 && AV_RB32(data) != APV_SIGNATURE) {
+            data += 4;
+            size -= 4;
+        }
+
+        ret = ff_get_encode_buffer(avctx, avpkt, size, 0);
+        if (ret < 0)
+            return ret;
+
+        memcpy(avpkt->data, data, size);
+        avpkt->pts = avpkt->dts = frame->pts;
+        avpkt->flags |= AV_PKT_FLAG_KEY;
+
+        if (cdsc->param[FRM_IDX].qp)
+            ff_side_data_set_encoder_stats(avpkt, cdsc->param[FRM_IDX].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, 63, 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,
+    .p.profiles         = NULL_IF_CONFIG_SMALL(ff_apv_profiles),
+    .caps_internal      = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_AUTO_THREADS | FF_CODEC_CAP_NOT_INIT_THREADSAFE,
+};
diff --git a/libavcodec/profiles.c b/libavcodec/profiles.c
index 3cef82be3b..991f24135d 100644
--- a/libavcodec/profiles.c
+++ b/libavcodec/profiles.c
@@ -203,4 +203,15 @@ const AVProfile ff_evc_profiles[] = {
     { AV_PROFILE_UNKNOWN },
 };
 
+const AVProfile ff_apv_profiles[] = {
+    { AV_PROFILE_APV_422_10,             "422-10"          },
+    { AV_PROFILE_APV_422_12,             "422-12"          },
+    { AV_PROFILE_APV_444_10,             "444-10"          },
+    { AV_PROFILE_APV_444_12,             "444-12"          },
+    { AV_PROFILE_APV_4444_10,            "4444-10"         },
+    { AV_PROFILE_APV_4444_12,            "4444-12"         },
+    { AV_PROFILE_APV_400_10,             "400-10"          },
+    { AV_PROFILE_UNKNOWN },
+};
+
 #endif /* !CONFIG_SMALL */
diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h
index 33b7ffc17a..4892388149 100644
--- a/libavcodec/profiles.h
+++ b/libavcodec/profiles.h
@@ -77,5 +77,6 @@ extern const AVProfile ff_prores_profiles[];
 extern const AVProfile ff_mjpeg_profiles[];
 extern const AVProfile ff_arib_caption_profiles[];
 extern const AVProfile ff_evc_profiles[];
+extern const AVProfile ff_apv_profiles[];
 
 #endif /* AVCODEC_PROFILES_H */
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 0550d7b0d8..43794ea588 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,7 +29,7 @@
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR   2
+#define LIBAVCODEC_VERSION_MINOR   3
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \



More information about the ffmpeg-cvslog mailing list