- Added APV encoder wrapper
- Changes in project configuration file and libavcodec Makefile
- Added documentation for oapv wrapper

Signed-off-by: Dawid Kozinski <d.kozin...@samsung.com>
---
 configure                 |   4 +
 doc/encoders.texi         |  41 +++
 doc/general_contents.texi |  11 +
 libavcodec/Makefile       |   1 +
 libavcodec/allcodecs.c    |   2 +
 libavcodec/apv_imgb.c     | 332 ++++++++++++++++++++
 libavcodec/apv_imgb.h     |  34 +++
 libavcodec/libapvenc.c    | 617 ++++++++++++++++++++++++++++++++++++++
 8 files changed, 1042 insertions(+)
 create mode 100644 libavcodec/apv_imgb.c
 create mode 100644 libavcodec/apv_imgb.h
 create mode 100644 libavcodec/libapvenc.c

diff --git a/configure b/configure
index 294f7e4a9d..fa125d383d 100755
--- a/configure
+++ b/configure
@@ -214,6 +214,7 @@ External library support:
   --enable-ladspa          enable LADSPA audio filtering [no]
   --enable-lcms2           enable ICC profile support via LittleCMS 2 [no]
   --enable-libaom          enable AV1 video encoding/decoding via libaom [no]
+  --enable-liboapv         enable APV encoding/decoding via liboapv [no]
   --enable-libaribb24      enable ARIB text and caption decoding via 
libaribb24 [no]
   --enable-libaribcaption  enable ARIB text and caption decoding via 
libaribcaption [no]
   --enable-libass          enable libass subtitles rendering,
@@ -1923,6 +1924,7 @@ EXTERNAL_LIBRARY_LIST="
     ladspa
     lcms2
     libaom
+    liboapv
     libaribcaption
     libass
     libbluray
@@ -3559,6 +3561,7 @@ prores_videotoolbox_encoder_select="videotoolbox_encoder"
 libaom_av1_decoder_deps="libaom"
 libaom_av1_encoder_deps="libaom"
 libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc"
+libapv_encoder_deps="liboapv"
 libaribb24_decoder_deps="libaribb24"
 libaribcaption_decoder_deps="libaribcaption"
 libcelt_decoder_deps="libcelt"
@@ -6928,6 +6931,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/doc/general_contents.texi b/doc/general_contents.texi
index 5faf89815b..66fe245050 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -35,6 +35,14 @@ package(amdgru-pro contains, but does not install 
automatically) are required.
 
 This driver can be installed using amdgpu-pro-install script in official amd 
driver archive.
 
+@section Advanced Professional Video codec (APV)
+
+FFmpeg can make use of the APV library for APV video encoding and decoding.
+
+Go to @url{https://github.com/AcademySoftwareFoundation/openapv} and follow 
the instructions for
+installing the APV library. Then pass @code{--enable-liboapv} to configure to
+enable it.
+
 @section AviSynth
 
 FFmpeg can read AviSynth scripts as input. To enable support, pass
@@ -627,6 +635,7 @@ library:
 @item raw APAC                  @tab   @tab X
 @item raw aptX                  @tab X @tab X
 @item raw aptX HD               @tab X @tab X
+@item raw apv                   @tab X @tab X
 @item raw Bonk                  @tab   @tab X
 @item raw Chinese AVS video     @tab X @tab X
 @item raw DFPWM                 @tab X @tab X
@@ -895,6 +904,8 @@ following image formats are supported:
     @tab fourcc: apch,apcn,apcs,apco,ap4h,ap4x
 @item Apple QuickDraw        @tab     @tab  X
     @tab fourcc: qdrw
+@item Advanced Professional Video codec     @tab  X  @tab  X
+    @tab encoding and decoding supported through external library liboapv
 @item Argonaut Video         @tab     @tab  X
     @tab Used in some Argonaut games.
 @item Asus v1                @tab  X  @tab  X
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3ae6dd17ea..7350f4ce07 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1129,6 +1129,7 @@ OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER)        += 
audiotoolboxenc.o
 OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER)       += audiotoolboxenc.o
 OBJS-$(CONFIG_LIBAOM_AV1_DECODER)         += libaomdec.o libaom.o
 OBJS-$(CONFIG_LIBAOM_AV1_ENCODER)         += libaomenc.o libaom.o
+OBJS-$(CONFIG_LIBAPV_ENCODER)             += libapvenc.o apv_imgb.o
 OBJS-$(CONFIG_LIBARIBB24_DECODER)         += libaribb24.o ass.o
 OBJS-$(CONFIG_LIBARIBCAPTION_DECODER)     += libaribcaption.o ass.o
 OBJS-$(CONFIG_LIBCELT_DECODER)            += libcelt_dec.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f10519617e..4aec580366 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -763,6 +763,8 @@ 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;
+extern const FFCodec ff_libapv_encoder;
+
 /* preferred over libaribb24 */
 extern const FFCodec ff_libaribcaption_decoder;
 extern const FFCodec ff_libaribb24_decoder;
diff --git a/libavcodec/apv_imgb.c b/libavcodec/apv_imgb.c
new file mode 100644
index 0000000000..967b512e35
--- /dev/null
+++ b/libavcodec/apv_imgb.c
@@ -0,0 +1,332 @@
+/*
+ * 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 <libavcodec/avcodec.h>
+
+/* assert function */
+#include <assert.h>
+
+#include "apv_imgb.h"
+
+#if defined(_MSC_VER) // Microsoft Visual C++
+#include <intrin.h>
+#define apv_atomic_inc(pcnt) _InterlockedIncrement(pcnt)
+#define apv_atomic_dec(pcnt) _InterlockedDecrement(pcnt)
+
+#elif defined(__GNUC__) || defined(__clang__) // GCC i Clang
+#define apv_atomic_inc(pcnt) __sync_fetch_and_add(pcnt, 1) + 1
+#define apv_atomic_dec(pcnt) __sync_fetch_and_sub(pcnt, 1) - 1
+
+#else // In other cases, use mutexes
+#include <pthread.h>
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int apv_atomic_inc(volatile int* pcnt) {
+    pthread_mutex_lock(&lock);
+    int new_value = ++(*pcnt);
+    pthread_mutex_unlock(&lock);
+    return new_value;
+}
+
+static int apv_atomic_dec(volatile int* pcnt) {
+    pthread_mutex_lock(&lock);
+    int new_value = --(*pcnt);
+    pthread_mutex_unlock(&lock);
+    return new_value;
+}
+#endif
+
+#define assert_rv(x,r) {if(!(x)){assert(x); return (r);}}
+
+#define OAPV_IMG_CLIP_VAL(n, min, max) (((n) > (max)) ? (max) : (((n) < (min)) 
? (min) : (n)))
+#define OAPV_IMG_ALIGN_VAL(val, align) ((((val) + (align) - 1) / (align)) * 
(align))
+
+static void * apv_picbuf_alloc(int size)
+{
+    return malloc(size);
+}
+
+static void apv_picbuf_free(void* p)
+{
+    if (p) {free(p);}
+}
+
+static void apv_imgb_cpy_plane(oapv_imgb_t *dst, oapv_imgb_t *src)
+{
+    int            i, j;
+    unsigned char *s, *d;
+    int            numbyte = OAPV_CS_GET_BYTE_DEPTH(src->cs);
+
+    for(i = 0; i < src->np; i++) {
+        s = (unsigned char *)src->a[i];
+        d = (unsigned char *)dst->a[i];
+
+        for(j = 0; j < src->ah[i]; j++) {
+            memcpy(d, s, numbyte * src->aw[i]);
+            s += src->s[i];
+            d += dst->s[i];
+        }
+    }
+}
+
+static void apv_imgb_cpy_shift_left_8b(oapv_imgb_t *dst, oapv_imgb_t *src, int 
shift)
+{
+    int            i, j, k;
+
+    unsigned char *s;
+    short         *d;
+
+    for(i = 0; i < dst->np; i++) {
+        s = (unsigned char *)src->a[i];
+        d = (short *)dst->a[i];
+
+        for(j = 0; j < src->ah[i]; j++) {
+            for(k = 0; k < src->aw[i]; k++) {
+                d[k] = (short)(s[k] << shift);
+            }
+            s = s + src->s[i];
+            d = (short *)(((unsigned char *)d) + dst->s[i]);
+        }
+    }
+}
+
+static void apv_imgb_cpy_shift_right_8b(oapv_imgb_t *dst, oapv_imgb_t *src, 
int shift)
+{
+    int            i, j, k, t0, add;
+
+    short         *s;
+    unsigned char *d;
+
+    if(shift)
+        add = 1 << (shift - 1);
+    else
+        add = 0;
+
+    for(i = 0; i < dst->np; i++) {
+        s = (short *)src->a[i];
+        d = (unsigned char *)dst->a[i];
+
+        for(j = 0; j < src->ah[i]; j++) {
+            for(k = 0; k < src->aw[i]; k++) {
+                t0 = ((s[k] + add) >> shift);
+                d[k] = (unsigned char)(OAPV_IMG_CLIP_VAL(t0, 0, 255));
+            }
+            s = (short *)(((unsigned char *)s) + src->s[i]);
+            d = d + dst->s[i];
+        }
+    }
+}
+
+static void apv_imgb_cpy_shift_left(oapv_imgb_t *dst, oapv_imgb_t *src, int 
shift)
+{
+    int             i, j, k;
+
+    unsigned short *s;
+    unsigned short *d;
+
+    for(i = 0; i < dst->np; i++) {
+        s = (unsigned short *)src->a[i];
+        d = (unsigned short *)dst->a[i];
+
+        for(j = 0; j < src->h[i]; j++) {
+            for(k = 0; k < src->w[i]; k++) {
+                d[k] = (unsigned short)(s[k] << shift);
+            }
+            s = (unsigned short *)(((unsigned char *)s) + src->s[i]);
+            d = (unsigned short *)(((unsigned char *)d) + dst->s[i]);
+        }
+    }
+}
+
+static void apv_imgb_cpy_shift_right(oapv_imgb_t *dst, oapv_imgb_t *src, int 
shift)
+{
+    int             i, j, k, t0, add;
+
+    int             clip_min = 0;
+    int             clip_max = 0;
+
+    unsigned short *s;
+    unsigned short *d;
+
+    if(shift)
+        add = 1 << (shift - 1);
+    else
+        add = 0;
+
+    clip_max = (1 << (OAPV_CS_GET_BIT_DEPTH(dst->cs))) - 1;
+
+    for(i = 0; i < dst->np; i++) {
+        s = (unsigned short *)src->a[i];
+        d = (unsigned short *)dst->a[i];
+
+        for(j = 0; j < src->h[i]; j++) {
+            for(k = 0; k < src->w[i]; k++) {
+                t0 = ((s[k] + add) >> shift);
+                d[k] = (OAPV_IMG_CLIP_VAL(t0, clip_min, clip_max));
+            }
+            s = (unsigned short *)(((unsigned char *)s) + src->s[i]);
+            d = (unsigned short *)(((unsigned char *)d) + dst->s[i]);
+        }
+    }
+}
+
+oapv_imgb_t * apv_imgb_create(int w, int h, int cs, AVCodecContext *avctx)
+{
+    int i, bd;
+    oapv_imgb_t * imgb;
+
+    imgb = (oapv_imgb_t *)malloc(sizeof(oapv_imgb_t));
+    if(imgb == NULL) goto ERR;
+    memset(imgb, 0, sizeof(oapv_imgb_t));
+
+    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_YCBCR400:
+        imgb->w[1] = imgb->w[2] = w;
+        imgb->h[1] = imgb->h[2] = h;
+        imgb->np = 1;
+        break;
+    case OAPV_CF_YCBCR420:
+        imgb->w[1] = imgb->w[2] = (w + 1) >> 1;
+        imgb->h[1] = imgb->h[2] = (h + 1) >> 1;
+        imgb->np = 3;
+        break;
+    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;
+   case OAPV_CF_YCBCR4444:
+        imgb->w[1] = imgb->w[2] = imgb->w[3] = w;
+        imgb->h[1] = imgb->h[2] = imgb->h[3] = h;
+        imgb->np = 4;
+        break;
+    case OAPV_CF_PLANAR2:
+        imgb->w[1] = w;
+        imgb->h[1] = h;
+        imgb->np = 2;
+        break;
+    default:
+        av_log(avctx, AV_LOG_ERROR, "unsupported color format\n");
+        goto ERR;
+    }
+
+    for(i = 0; i < imgb->np; i++)
+    {
+        imgb->aw[i] = OAPV_IMG_ALIGN_VAL(imgb->w[i], OAPV_MB_W);
+        imgb->s[i] = imgb->aw[i] * bd;
+        imgb->ah[i] = OAPV_IMG_ALIGN_VAL(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] = apv_picbuf_alloc(imgb->bsize[i]);
+        if(imgb->a[i] == NULL) goto ERR;
+
+        memset(imgb->a[i], 0, imgb->bsize[i]);
+    }
+    imgb->cs = cs;
+    imgb->addref = apv_imgb_addref;
+    imgb->getref = apv_imgb_getref;
+    imgb->release = apv_imgb_release;
+
+    imgb->addref(imgb); /* increase reference count */
+    return imgb;
+
+ERR:
+    av_log(avctx, AV_LOG_ERROR, "cannot create image buffer\n");
+    if(imgb)
+    {
+        for (int i = 0; i < OAPV_MAX_CC; i++)
+        {
+            if(imgb->a[i]) free(imgb->a[i]);
+        }
+        free(imgb);
+    }
+    return NULL;
+}
+
+int apv_imgb_release(oapv_imgb_t * imgb)
+{
+    int refcnt, i;
+    assert_rv(imgb, OAPV_ERR_INVALID_ARGUMENT);
+    refcnt = apv_atomic_dec(&imgb->refcnt);
+    if(refcnt == 0) {
+        for(i=0; i<OAPV_MAX_CC; i++) {
+            if (imgb->baddr[i]) apv_picbuf_free(imgb->baddr[i]);
+        }
+        free(imgb);
+    }
+
+    return refcnt;
+}
+
+void apv_imgb_cpy(oapv_imgb_t *dst, oapv_imgb_t *src, AVCodecContext *avctx)
+{
+    int i, bd_src, bd_dst;
+    bd_src = OAPV_CS_GET_BIT_DEPTH(src->cs);
+    bd_dst = OAPV_CS_GET_BIT_DEPTH(dst->cs);
+
+    if(src->cs == dst->cs) {
+        apv_imgb_cpy_plane(dst, src);
+    }
+    else if(bd_src == 8 && bd_dst > 8) {
+        apv_imgb_cpy_shift_left_8b(dst, src, bd_dst - bd_src);
+    }
+    else if(bd_src > 8 && bd_dst == 8) {
+        apv_imgb_cpy_shift_right_8b(dst, src, bd_src - bd_dst);
+    }
+    else if(bd_src < bd_dst) {
+        apv_imgb_cpy_shift_left(dst, src, bd_dst - bd_src);
+    }
+    else if(bd_src > bd_dst) {
+        apv_imgb_cpy_shift_right(dst, src, bd_src - bd_dst);
+    }
+    else {
+        av_log(avctx, AV_LOG_ERROR, "ERROR: unsupported image copy\n");
+        return;
+    }
+    for(i = 0; i < OAPV_MAX_CC; i++) {
+        dst->x[i] = src->x[i];
+        dst->y[i] = src->y[i];
+        dst->w[i] = src->w[i];
+        dst->h[i] = src->h[i];
+        dst->ts[i] = src->ts[i];
+    }
+}
+
+int apv_imgb_addref(oapv_imgb_t * imgb)
+{
+    assert_rv(imgb, OAPV_ERR_INVALID_ARGUMENT);
+    return apv_atomic_inc(&imgb->refcnt);
+}
+
+int apv_imgb_getref(oapv_imgb_t * imgb)
+{
+    assert_rv(imgb, OAPV_ERR_INVALID_ARGUMENT);
+    return imgb->refcnt;
+}
\ No newline at end of file
diff --git a/libavcodec/apv_imgb.h b/libavcodec/apv_imgb.h
new file mode 100644
index 0000000000..fe12bb228d
--- /dev/null
+++ b/libavcodec/apv_imgb.h
@@ -0,0 +1,34 @@
+/*
+ * 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
+ */
+
+#ifndef AVCODEC_APV_IMGB_H
+#define AVCODEC_APV_IMGB_H
+
+#include <oapv/oapv.h>
+
+oapv_imgb_t* apv_imgb_create(int w, int h, int cs, AVCodecContext *avctx);
+int apv_imgb_release(oapv_imgb_t* imgb);
+
+void apv_imgb_cpy(oapv_imgb_t *dst, oapv_imgb_t *src, AVCodecContext *avctx);
+
+int apv_imgb_addref(oapv_imgb_t* imgb);
+int apv_imgb_getref(oapv_imgb_t* imgb);
+
+#endif // AVCODEC_APV_IMGB_H
diff --git a/libavcodec/libapvenc.c b/libavcodec/libapvenc.c
new file mode 100644
index 0000000000..819cd6c310
--- /dev/null
+++ b/libavcodec/libapvenc.c
@@ -0,0 +1,617 @@
+/*
+ * 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 <float.h>
+#include <stdlib.h>
+
+#include <oapv/oapv.h>
+
+#include "libavutil/internal.h"
+#include "libavutil/common.h"
+#include "libavutil/opt.h"
+#include "libavutil/pixdesc.h"
+#include "libavutil/pixfmt.h"
+#include "libavutil/time.h"
+#include "libavutil/cpu.h"
+#include "libavutil/avstring.h"
+#include "libavutil/mem.h"
+#include "libavutil/avassert.h"
+#include <libavutil/imgutils.h>
+
+#include "avcodec.h"
+#include "internal.h"
+#include "packet_internal.h"
+#include "codec_internal.h"
+#include "profiles.h"
+#include "encode.h"
+#include "apv_imgb.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_imgb_t *imgb_r;    // image buffer for read
+    oapv_imgb_t *imgb_i;    // image buffer for input
+    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]
+
+    int input_depth;        // input data bit depth (8, 10)
+    int input_csp;          // input data color space (chroma format)
+                            //  - 0: YUV400
+                            //  - 1: YUV420
+                            //  - 2: YUV422
+                            //  - 3: YUV444
+
+    AVDictionary *oapv_params;
+} ApvEncContext;
+
+static int align_to_16(int value) {
+    return (value + 15) & ~15; // Rounding to the nearest value divisible by 16
+}
+
+static AVFrame* copy_and_align_avframe_to_16(const AVFrame* src_frame) {
+    AVFrame* dst_frame = NULL;
+    int ret = 0;
+
+    if (!src_frame) {
+        return NULL;
+    }
+
+    // Allocate a new AVFrame
+    dst_frame = av_frame_alloc();
+    if (!dst_frame) {
+        return NULL;
+    }
+
+    // Set parameters for the new frame
+    dst_frame->format = src_frame->format;
+    dst_frame->width = align_to_16(src_frame->width);
+    dst_frame->height = align_to_16(src_frame->height);
+
+    // Memory allocation for a new frame
+    ret = av_frame_get_buffer(dst_frame, 16);
+    if (ret < 0) {
+        av_frame_free(&dst_frame);
+        return NULL;
+    }
+
+    // Data copying
+    av_frame_copy(dst_frame, src_frame);
+    
+    return dst_frame;
+}
+
+/**
+ * Convert FFmpeg pixel format (AVPixelFormat) into APV pre-defined color 
format
+ *
+ * @param[in] px_fmt pixel format (@see 
https://ffmpeg.org/doxygen/trunk/pixfmt_8h.html#a9a8e335cf3be472042bc9f0cf80cd4c5)
+ *
+ * @return APV pre-defined color format (@see oapv.h) on success, 
OAPV_CF_UNKNOWN on failure
+ */
+static int libapve_apv_color_format(enum AVPixelFormat av_pix_fmt)
+{
+    int cf = OAPV_CF_UNKNOWN;
+
+    switch (av_pix_fmt) {
+    case AV_PIX_FMT_GRAY10:
+        cf = OAPV_CF_YCBCR400;
+        break;
+    case AV_PIX_FMT_GRAY12:
+        cf = OAPV_CF_YCBCR400;
+        break;
+    case AV_PIX_FMT_YUV420P10:
+        cf = OAPV_CF_YCBCR420;
+        break;
+    case AV_PIX_FMT_YUV422P10:
+        cf = OAPV_CF_YCBCR422;
+        break;
+    case AV_PIX_FMT_YUV444P10:
+        cf = OAPV_CF_YCBCR444;
+        break;
+    case AV_PIX_FMT_YUV422P12:
+        cf = OAPV_CF_YCBCR422;
+        break;
+    case AV_PIX_FMT_YUV444P12:
+        cf = OAPV_CF_YCBCR444;
+        break;
+    case AV_PIX_FMT_YUVA444P10:
+        cf = OAPV_CF_YCBCR4444;
+        break;
+    case AV_PIX_FMT_YUVA444P12:
+        cf = OAPV_CF_YCBCR4444;
+        break;
+    default:
+        cf = OAPV_CF_UNKNOWN;
+        break;
+    }
+
+    return cf;
+}
+
+/**
+ * Convert FFmpeg pixel format (AVPixelFormat) into APV pre-defined color space
+ *
+ * @param[in] px_fmt pixel format (@see 
https://ffmpeg.org/doxygen/trunk/pixfmt_8h.html#a9a8e335cf3be472042bc9f0cf80cd4c5)
+ *
+ * @return APV pre-defined color space (@see oapv.h) on success, 
OAPV_CS_UNKNOWN on failure
+ */
+static int libapve_apv_color_space(enum AVPixelFormat av_pix_fmt)
+{
+    int cs = OAPV_CS_UNKNOWN;
+
+    switch (av_pix_fmt) {
+    case AV_PIX_FMT_YUV422P10:
+        cs = OAPV_CS_SET(OAPV_CF_YCBCR422, 10, AV_HAVE_BIGENDIAN);
+        break;
+    case AV_PIX_FMT_YUV444P10:
+        cs = OAPV_CS_SET(OAPV_CF_YCBCR444, 10, AV_HAVE_BIGENDIAN);
+        break;
+    case AV_PIX_FMT_YUV422P12:
+        cs = OAPV_CS_SET(OAPV_CF_YCBCR422, 12, AV_HAVE_BIGENDIAN);
+        break;
+    case AV_PIX_FMT_YUV444P12:
+        cs = OAPV_CS_SET(OAPV_CF_YCBCR444, 12, AV_HAVE_BIGENDIAN);
+        break;
+    default:
+        cs = OAPV_CS_UNKNOWN;
+        break;
+    }
+
+    return cs;
+}
+
+/**
+ * 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 full list of options available for apv encoder is displayed after 
executing the command ./ffmpeg --help encoder = liboapv)
+ *
+ * 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 *apvctx = NULL;
+    int ret;
+
+    const char *option_name = "qp";
+    uint8_t qp_default_value = 0;
+    const AVOption *option = NULL;
+    
+    apvctx = avctx->priv_data;
+    option = av_opt_find(&apvctx->class, option_name, NULL, 0, 0);
+
+    if (option) {
+        uint64_t default_value;
+        av_opt_get_int(avctx->priv_data, option_name, 0, &default_value);
+
+        if (default_value) {
+            qp_default_value = (uint8_t)default_value;
+        }
+    }
+
+    for(int i=0;i<OAPV_MAX_NUM_FRAMES;i++) {
+
+        /* initialize apv_param struct with default values */
+        ret = oapve_param_default(&cdsc->param[i]);
+        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[i].w = avctx->width;
+
+        if (avctx->height > 0)
+            cdsc->param[i].h = avctx->height;
+
+        if (avctx->framerate.num > 0) {
+            cdsc->param[i].fps_num = avctx->framerate.num;
+            cdsc->param[i].fps_den = avctx->framerate.den;
+        }
+
+        cdsc->param[i].preset = apvctx->preset_id;
+        cdsc->param[i].qp = apvctx->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_INVALIDDATA;
+        }
+        cdsc->param[i].bitrate = (int)(avctx->bit_rate / 1000);
+        if(cdsc->param[i].bitrate) {
+            if(cdsc->param[i].qp!=qp_default_value) {
+                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[i].rc_type = OAPV_RC_ABR;
+        }
+
+        cdsc->threads = OAPV_CDESC_THREADS_AUTO;
+
+        if(avctx->color_primaries!=AVCOL_PRI_UNSPECIFIED)
+            cdsc->param[i].color_primaries = avctx->color_primaries;
+        
+        if(avctx->color_trc!=AVCOL_TRC_UNSPECIFIED)
+            cdsc->param[i].transfer_characteristics = avctx->color_trc;
+
+        if(avctx->colorspace!=AVCOL_SPC_UNSPECIFIED)    
+            cdsc->param[i].matrix_coefficients = avctx->colorspace;
+
+        if(avctx->color_range!=AVCOL_RANGE_UNSPECIFIED)    
+            cdsc->param[i].full_range_flag = 
(avctx->color_range==AVCOL_RANGE_JPEG)?1:0;
+    }
+
+    apvctx->input_csp = libapve_apv_color_space(avctx->pix_fmt);
+    if(apvctx->input_csp == OAPV_CS_UNKNOWN) {
+        av_log(avctx, AV_LOG_ERROR, "Not supported pixel format: %s\n", 
av_get_pix_fmt_name (avctx->pix_fmt));
+        return AVERROR_INVALIDDATA;
+    }
+
+    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(AVCodecContext *avctx, enum AVPixelFormat 
pixel_format)
+ {
+     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pixel_format);
+     if (desc == NULL) {
+         av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format (%s)\n", 
av_get_pix_fmt_name(pixel_format));
+         return AVERROR_EXTERNAL;
+     }
+     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 libapve_init(AVCodecContext *avctx)
+{
+    ApvEncContext *apvctx = avctx->priv_data;
+    unsigned char *bs_buf = NULL;
+    int cfmt = OAPV_CF_UNKNOWN;  // color format
+    oapve_cdesc_t *cdsc =  &(apvctx->cdsc);
+    int ret = 0;
+
+    apvctx->id = NULL;
+    apvctx->mid = NULL;
+    apvctx->bitb.addr = NULL;
+    memset(cdsc, 0, sizeof(oapve_cdesc_t));
+
+    /* 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);
+    }
+    apvctx->bitb.addr = bs_buf;
+    apvctx->bitb.bsize = MAX_BS_BUF;
+
+    /* read configurations and set values for created descriptor (APV_CDSC) */
+    if ((ret = get_conf(avctx, cdsc)) != 0) {
+        av_log(avctx, AV_LOG_ERROR, "Cannot get OAPV configuration\n");
+        return AVERROR(EINVAL);
+    }
+
+    {
+        const AVDictionaryEntry *en = NULL;
+        while (en = av_dict_iterate(apvctx->oapv_params, en)) {
+            for(int i=0; i<OAPV_MAX_NUM_FRAMES; i++) {
+                if ((ret = oapve_param_parse(&cdsc->param[i], en->key, 
en->value)) < 0) {
+                    av_log(avctx, AV_LOG_WARNING, "Error parsing option '%s = 
%s'.\n", en->key, en->value);
+                }
+            }
+        }
+    }
+
+    /* create encoder */
+    apvctx->id = oapve_create(cdsc, &ret);
+    if (apvctx->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 */
+    apvctx->mid = oapvm_create(&ret);
+    if(apvctx->mid == NULL || OAPV_FAILED(ret)) {
+        av_log(avctx, AV_LOG_ERROR, "cannot create OAPV metadata handler\n");
+        return AVERROR_EXTERNAL;
+    }
+
+    apvctx->input_depth = get_bit_depth(avctx, avctx->pix_fmt);
+    if(apvctx->input_depth != 10 && apvctx->input_depth != 12)  {
+        av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format (%s)n", 
av_get_pix_fmt_name(avctx->pix_fmt));
+        return AVERROR(EINVAL); 
+    }
+
+    apvctx->imgb_r = NULL; // image buffer for read
+    apvctx->imgb_i = NULL; // image buffer for input
+    apvctx->num_frames = MAX_NUM_FRMS; // number of frames in an access unit
+
+    cfmt = libapve_apv_color_format(avctx->pix_fmt);
+
+    // create input and reconstruction image buffers
+    memset(&apvctx->ifrms, 0, sizeof(oapv_frms_t));
+    
+    for(int i = 0; i < apvctx->num_frames; i++) {
+        if(apvctx->input_depth  == 10) {
+            apvctx->ifrms.frm[FRM_IDX].imgb = apv_imgb_create(avctx->width, 
avctx->height, OAPV_CS_SET(cfmt, apvctx->input_depth, 0), avctx);
+        }
+        else {
+            apvctx->imgb_r = apv_imgb_create(avctx->width, avctx->height, 
OAPV_CS_SET(cfmt, apvctx->input_depth, 0), avctx);
+            apvctx->ifrms.frm[FRM_IDX].imgb = apv_imgb_create(avctx->width, 
avctx->height, OAPV_CS_SET(cfmt, 10, 0), avctx);
+        }
+        apvctx->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 libapve_encode(AVCodecContext *avctx, AVPacket *avpkt,
+                          const AVFrame *frame, int *got_packet)
+{
+    ApvEncContext *apvctx =  avctx->priv_data;
+    AVFrame* tmp_frame = NULL;
+    int  ret = -1;
+
+    if (frame==NULL) {
+        return 0;
+    }
+
+    if(apvctx->input_depth == 10) {
+        apvctx->imgb_i = apvctx->ifrms.frm[FRM_IDX].imgb;
+    }
+    else {
+        apvctx->imgb_i = apvctx->imgb_r;
+    }
+
+    // The liboapv library requires that the frame size be a multiple of 16
+    tmp_frame = copy_and_align_avframe_to_16(frame);
+    for (int i = 0; i < apvctx->imgb_i->np; i++) {
+        memcpy(apvctx->imgb_i->a[i], tmp_frame->data[i], 
tmp_frame->linesize[i]*tmp_frame->height);
+    }
+    av_frame_free(&tmp_frame);
+
+    // @todo Possibility of optimization (skipping memory allocation for an 
additional temporary object of type AVFrame).
+    //
+    // int h_chroma, v_chroma;
+    // int frame_height[4];
+
+    // av_pix_fmt_get_chroma_subsample(frame->format, &h_chroma, &v_chroma);
+
+    // frame_height[0] = frame->height;
+    // frame_height[1] = frame->height / v_chroma;
+    // frame_height[2] = frame->height / v_chroma;
+    // frame_height[3] = 0;
+
+    // for (int i = 0; i < apvctx->imgb_i->np; i++) {
+    //     for(int j=0; j < frame_height[i]; j++) {
+    //         memcpy(apvctx->imgb_i->a[i]+j*apvctx->imgb_i->s[i], 
frame->data[i]+j*frame->linesize[i], frame->linesize[i]);    
+    //     }
+    // }
+
+    if(apvctx->input_depth != 10) {
+        apv_imgb_cpy(apvctx->ifrms.frm[FRM_IDX].imgb, apvctx->imgb_i, avctx);
+    }
+
+    apvctx->ifrms.frm[FRM_IDX].imgb->ts[0] = frame->pts;
+
+    apvctx->ifrms.frm[FRM_IDX].group_id = 1; // @todo FIX-ME : need to set 
properly in case of multi-frame
+    apvctx->ifrms.frm[FRM_IDX].pbu_type = OAPV_PBU_TYPE_PRIMARY_FRAME;
+    
+    ret = oapve_encode(apvctx->id, &apvctx->ifrms, apvctx->mid, 
&(apvctx->bitb), &(apvctx->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)) {
+        if(apvctx->stat.write > 0) {
+            ret = ff_get_encode_buffer(avctx, avpkt, apvctx->stat.write, 0);
+            if (ret < 0)
+                return ret;
+
+            memcpy(avpkt->data, apvctx->bitb.addr, apvctx->stat.write);
+
+            avpkt->time_base.num = apvctx->cdsc.param->fps_num;
+            avpkt->time_base.den = apvctx->cdsc.param->fps_den;
+
+            avpkt->pts = avpkt->dts = frame->pts;
+            avpkt->flags |= AV_PKT_FLAG_KEY;
+
+            ff_side_data_set_encoder_stats(avpkt, apvctx->qp * FF_QP2LAMBDA, 
NULL, 0, AV_PICTURE_TYPE_I);
+
+            *got_packet = 1;
+        } else {
+            *got_packet = 0;
+        }
+    } 
+    
+    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 libapve_close(AVCodecContext *avctx)
+{
+    ApvEncContext *apvctx = avctx->priv_data;
+    (void)apvctx;
+
+    if(apvctx->imgb_r != NULL)
+        apvctx->imgb_r->release(apvctx->imgb_r);
+
+    for(int i = 0; i < apvctx->num_frames; i++) {
+        if(apvctx->ifrms.frm[i].imgb != NULL) {
+            apvctx->ifrms.frm[i].imgb->release(apvctx->ifrms.frm[i].imgb);
+        }
+    }
+    
+    if (apvctx->mid) {
+        oapvm_rem_all(apvctx->mid);
+    }
+
+    if (apvctx->id) {
+        oapve_delete(apvctx->id);
+        apvctx->id = NULL;
+    }
+
+    if (apvctx->mid) {
+        oapvm_delete(apvctx->mid);
+        apvctx->mid = NULL;
+    }
+
+    av_free(apvctx->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_YUV422P12,
+    AV_PIX_FMT_YUV444P12,
+    AV_PIX_FMT_NONE
+};
+
+// Consider using following options (./ffmpeg --help encoder=liboapv)
+//
+// Using oapv-params: 
+// ffmpeg -f rawvideo -pix_fmt yuv422p10le -i ${INPUT_FILE} -c:v liboapv 
-oapv-params 
"profile=422-10:level=7.1:band=3:preset=medium:width=352:height=288:fps=24:qp=63:bitrate=1M"
 -f rawvideo ${OUTPUT_FILE}
+//
+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 libapve_class = {
+    .class_name = "liboapv",
+    .item_name  = av_default_item_name,
+    .option     = liboapv_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+/**
+ *  libavcodec generic global options, which can be set on all the encoders 
and decoders
+ *  @see https://www.ffmpeg.org/ffmpeg-codecs.html#Codec-Options
+ */
+static const FFCodecDefault libapve_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)
+    { "threads", "0"},  // number of threads to be used (0: automatically 
select the number of threads to set)
+    { NULL },
+};
+
+const FFCodec ff_libapv_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               = libapve_init,
+    FF_CODEC_ENCODE_CB(libapve_encode),
+    .close              = libapve_close,
+    .priv_data_size     = sizeof(ApvEncContext),
+    .p.priv_class       = &libapve_class,
+    .defaults           = libapve_defaults,
+    .p.capabilities     = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_OTHER_THREADS | 
AV_CODEC_CAP_DR1,
+    .p.wrapper_name     = "liboapv",
+    .p.profiles         = NULL_IF_CONFIG_SMALL(ff_apv_profiles),
+    .p.pix_fmts         = supported_pixel_formats,
+    .caps_internal      = FF_CODEC_CAP_INIT_CLEANUP | 
FF_CODEC_CAP_NOT_INIT_THREADSAFE,
+};
-- 
2.34.1

_______________________________________________
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".

Reply via email to