From: Dawid Kozinski <d.kozin...@samsung.com>

Co-authored-by: James Almer <jamr...@gmail.com>
Signed-off-by: James Almer <jamr...@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.

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
 
+@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
+@option{--enable-liboapv}.
+
+@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.
+@end float
+
+The apv project website is at 
@url{https://github.com/AcademySoftwareFoundation/openapv}.
+
+@subsection Options
+
+The following options are supported by the liboapv wrapper.
+The apv-equivalent options or values are listed in parentheses for easy 
migration.
+
+@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
+@ref{codec-options,,the Codec Options chapter}.
+@end float
+
+@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.
+@end float
+
+@table @option
+@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.
+
+@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.kozin...@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@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".
  • ... James Almer
    • ... Dawid Kozinski/Multimedia (PLT) /SRPOL/Staff Engineer/Samsung Electronics
      • ... James Almer

Reply via email to