PR #22693 opened by sohamukute
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22693
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/22693.patch

Fixes #22686

liboapv advertises several APV pixel formats, but in practice only yuv422p10le 
encoded successfully. The wrapper was leaving profile_idc at liboapvs default 
422-10, so the other advertised formats reached oapve_encode() with the wrong 
APV profile and failed.

This series fixes that by deriving the default APV profile from avctx->pix_fmt 
and validating explicit overrides.

While validating the fix, I also found that APV profile names were not exposed 
through FFmpegs generic -profile:v handling or the APV codec descriptor. The 
second commit wires that up so named APV profiles work properly

Split as:
  1. fix the actual liboapv encode failure
  2. expose APV profile names and improve profile mismatch reporting


>From a4f1c224aed1102258e5bbf26eaf00a78d1c109d Mon Sep 17 00:00:00 2001
From: Soham Kute <[email protected]>
Date: Fri, 3 Apr 2026 00:30:41 +0530
Subject: [PATCH 1/2] avcodec/liboapvenc: derive APV profile from pixel format

The liboapv wrapper advertises gray10, 422-12, 444-10/12 and 4444-10/12 
support, but it leaves profile_idc at the liboapv default set by 
oapve_param_default(), which is 422-10. As a result only yuv422p10le can be 
encoded successfully and the other advertised formats fail in oapve_encode().

Resolve this by deriving the default APV profile from avctx->pix_fmt, 
validating any explicit profile override after parsing oapv-params, and writing 
the resolved profile back to avctx. Also use ifrms.num_frms in the close path 
so the allocated input image buffer is actually released.

Fixes #22686.
---
 libavcodec/liboapvenc.c | 59 ++++++++++++++++++++++++++++++++++++++---
 1 file changed, 56 insertions(+), 3 deletions(-)

diff --git a/libavcodec/liboapvenc.c b/libavcodec/liboapvenc.c
index 84bd175ef6..3337513900 100644
--- a/libavcodec/liboapvenc.c
+++ b/libavcodec/liboapvenc.c
@@ -59,8 +59,6 @@ typedef struct ApvEncContext {
 
     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]
@@ -129,6 +127,53 @@ static inline int get_color_format(enum AVPixelFormat 
pix_fmt)
     return cf;
 }
 
+static inline int get_profile(enum AVPixelFormat pix_fmt)
+{
+    int profile = AV_PROFILE_UNKNOWN;
+
+    switch (pix_fmt) {
+    case AV_PIX_FMT_GRAY10:
+        profile = AV_PROFILE_APV_400_10;
+        break;
+    case AV_PIX_FMT_YUV422P10:
+        profile = AV_PROFILE_APV_422_10;
+        break;
+    case AV_PIX_FMT_YUV422P12:
+        profile = AV_PROFILE_APV_422_12;
+        break;
+    case AV_PIX_FMT_YUV444P10:
+        profile = AV_PROFILE_APV_444_10;
+        break;
+    case AV_PIX_FMT_YUV444P12:
+        profile = AV_PROFILE_APV_444_12;
+        break;
+    case AV_PIX_FMT_YUVA444P10:
+        profile = AV_PROFILE_APV_4444_10;
+        break;
+    case AV_PIX_FMT_YUVA444P12:
+        profile = AV_PROFILE_APV_4444_12;
+        break;
+    default:
+        av_assert0(profile != AV_PROFILE_UNKNOWN);
+    }
+
+    return profile;
+}
+
+static int validate_profile(AVCodecContext *avctx, int profile)
+{
+    const int expected = get_profile(avctx->pix_fmt);
+
+    if (profile != expected) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Profile %d is incompatible with pixel format %s; expected 
%d\n",
+               profile, av_get_pix_fmt_name(avctx->pix_fmt), expected);
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
 static oapv_imgb_t *apv_imgb_create(AVCodecContext *avctx)
 {
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
@@ -228,6 +273,8 @@ static int get_conf(AVCodecContext *avctx, oapve_cdesc_t 
*cdsc)
         cdsc->param[FRM_IDX].fps_den = avctx->time_base.num;
     }
 
+    cdsc->param[FRM_IDX].profile_idc = avctx->profile == AV_PROFILE_UNKNOWN ?
+                                       get_profile(avctx->pix_fmt) : 
avctx->profile;
     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) {
@@ -275,6 +322,12 @@ static int get_conf(AVCodecContext *avctx, oapve_cdesc_t 
*cdsc)
             av_log(avctx, AV_LOG_WARNING, "Error parsing option '%s = %s'.\n", 
en->key, en->value);
     }
 
+    ret = validate_profile(avctx, cdsc->param[FRM_IDX].profile_idc);
+    if (ret < 0)
+        return ret;
+
+    avctx->profile = cdsc->param[FRM_IDX].profile_idc;
+
     return 0;
 }
 
@@ -426,7 +479,7 @@ static av_cold int liboapve_close(AVCodecContext *avctx)
 {
     ApvEncContext *apv = avctx->priv_data;
 
-    for (int i = 0; i < apv->num_frames; i++) {
+    for (int i = 0; i < apv->ifrms.num_frms; 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;
-- 
2.52.0


>From 9efa2942ba2c0374566ada8a42d27cfa2f71a162 Mon Sep 17 00:00:00 2001
From: Soham Kute <[email protected]>
Date: Fri, 3 Apr 2026 00:31:16 +0530
Subject: [PATCH 2/2] avcodec/liboapvenc: expose APV profile names

While fixing #22686, it became clear that FFmpeg does not expose APV profile 
names through the generic avctx.profile option handling or the APV codec 
descriptor.

Register the APV profile names so -profile:v 422-10/444-10 and the other APV 
profile values are accepted by name, expose the APV profile table through the 
codec descriptor, and use those names in liboapv profile validation errors.

This follow-up is not required for the implicit pix_fmt-driven fix itself, but 
it resolves the additional profile handling issue uncovered while validating it.
---
 libavcodec/codec_desc.c | 1 +
 libavcodec/liboapvenc.c | 9 +++++++--
 libavcodec/profiles.h   | 9 +++++++++
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index b3f4e73e1d..a1fb0d41d4 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -1991,6 +1991,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
         .name      = "apv",
         .long_name = NULL_IF_CONFIG_SMALL("Advanced Professional Video"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+        .profiles  = NULL_IF_CONFIG_SMALL(ff_apv_profiles),
     },
     {
         .id        = AV_CODEC_ID_PRORES_RAW,
diff --git a/libavcodec/liboapvenc.c b/libavcodec/liboapvenc.c
index 3337513900..6a0033155a 100644
--- a/libavcodec/liboapvenc.c
+++ b/libavcodec/liboapvenc.c
@@ -163,11 +163,15 @@ static inline int get_profile(enum AVPixelFormat pix_fmt)
 static int validate_profile(AVCodecContext *avctx, int profile)
 {
     const int expected = get_profile(avctx->pix_fmt);
+    const char *profile_name = avcodec_profile_name(AV_CODEC_ID_APV, profile);
+    const char *expected_name = avcodec_profile_name(AV_CODEC_ID_APV, 
expected);
 
     if (profile != expected) {
         av_log(avctx, AV_LOG_ERROR,
-               "Profile %d is incompatible with pixel format %s; expected 
%d\n",
-               profile, av_get_pix_fmt_name(avctx->pix_fmt), expected);
+               "Profile %s (%d) is incompatible with pixel format %s; expected 
%s (%d)\n",
+               profile_name ? profile_name : "unknown", profile,
+               av_get_pix_fmt_name(avctx->pix_fmt),
+               expected_name ? expected_name : "unknown", expected);
         return AVERROR(EINVAL);
     }
 
@@ -528,6 +532,7 @@ static const AVOption liboapv_options[] = {
     { "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 },
+    FF_APV_PROFILE_OPTS
     { "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 }
 };
diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h
index 6f4011ff0c..eb2683bc99 100644
--- a/libavcodec/profiles.h
+++ b/libavcodec/profiles.h
@@ -58,6 +58,15 @@
     FF_AVCTX_PROFILE_OPTION("high",          NULL, VIDEO, AV_PROFILE_AV1_HIGH)\
     FF_AVCTX_PROFILE_OPTION("professional",  NULL, VIDEO, 
AV_PROFILE_AV1_PROFESSIONAL)\
 
+#define FF_APV_PROFILE_OPTS \
+    FF_AVCTX_PROFILE_OPTION("422-10",        NULL, VIDEO, 
AV_PROFILE_APV_422_10)\
+    FF_AVCTX_PROFILE_OPTION("422-12",        NULL, VIDEO, 
AV_PROFILE_APV_422_12)\
+    FF_AVCTX_PROFILE_OPTION("444-10",        NULL, VIDEO, 
AV_PROFILE_APV_444_10)\
+    FF_AVCTX_PROFILE_OPTION("444-12",        NULL, VIDEO, 
AV_PROFILE_APV_444_12)\
+    FF_AVCTX_PROFILE_OPTION("4444-10",       NULL, VIDEO, 
AV_PROFILE_APV_4444_10)\
+    FF_AVCTX_PROFILE_OPTION("4444-12",       NULL, VIDEO, 
AV_PROFILE_APV_4444_12)\
+    FF_AVCTX_PROFILE_OPTION("400-10",        NULL, VIDEO, 
AV_PROFILE_APV_400_10)\
+
 extern const AVProfile ff_aac_profiles[];
 extern const AVProfile ff_dca_profiles[];
 extern const AVProfile ff_eac3_profiles[];
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to