PR #24843 opened by James Almer (jamrial)
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24843
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24843.patch

Alternative to !23999, without moving the LCEVC decoding implementation to a 
handful of decoders.


>From ca1e4e39e23488a7d0272cd48f6da42b73406c5f Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Thu, 1 Oct 2026 17:03:53 -0300
Subject: [PATCH 1/2] avcodec: allow adding AVOption enabled butt non-public
 fields to AVCodecContext

Making AVCodecInternal fields AVOption enabled requires extra considerations
in av_codec_context_class, and they will only be settable with an open context
or by passing the options directly as part of avcodec_open2().
They also would require to allow searching children classes, which in the case
of a fake object results in looking at every single underlying decoder/encoder
option.
Instead of that, extend AVCodecContext internally the same way we did for other
contexts like AVFormatContext, and add fields outside the public part.

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/avcodec_internal.h | 13 ++++++++++++-
 libavcodec/options.c          |  8 ++++++--
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/libavcodec/avcodec_internal.h b/libavcodec/avcodec_internal.h
index 06645e91a0..ebd9458120 100644
--- a/libavcodec/avcodec_internal.h
+++ b/libavcodec/avcodec_internal.h
@@ -27,9 +27,20 @@
 
 #include "libavutil/frame.h"
 
+#include "avcodec.h"
 #include "packet.h"
 
-struct AVCodecContext;
+typedef struct FFCodecContext {
+    /**
+     * The public context.
+     */
+    AVCodecContext pub;
+} FFCodecContext;
+
+static av_always_inline FFCodecContext *ffcodeccontext(AVCodecContext *avctx)
+{
+    return (FFCodecContext*)avctx;
+}
 
 typedef struct SideDataMap {
     enum AVPacketSideDataType packet;
diff --git a/libavcodec/options.c b/libavcodec/options.c
index 834beb5757..d85137a99e 100644
--- a/libavcodec/options.c
+++ b/libavcodec/options.c
@@ -148,11 +148,15 @@ static int init_context_defaults(AVCodecContext *s, const 
AVCodec *codec)
 
 AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
 {
-    AVCodecContext *avctx= av_malloc(sizeof(AVCodecContext));
+    FFCodecContext *ffavc;
+    AVCodecContext *avctx;
 
-    if (!avctx)
+    ffavc = av_mallocz(sizeof(*ffavc));
+    if (!ffavc)
         return NULL;
 
+    avctx = &ffavc->pub;
+
     if (init_context_defaults(avctx, codec) < 0) {
         av_free(avctx);
         return NULL;
-- 
2.52.0


>From 422ae94e6c740bcacf82064dd06ae85af55ac8a2 Mon Sep 17 00:00:00 2001
From: James Almer <[email protected]>
Date: Thu, 1 Oct 2026 17:35:23 -0300
Subject: [PATCH 2/2] avcodec/lcevcdec: add support for passing options

Signed-off-by: James Almer <[email protected]>
---
 libavcodec/avcodec_internal.h |  2 +
 libavcodec/decode.c           |  4 +-
 libavcodec/lcevcdec.c         | 81 ++++++++++++++++++++++++++++++++---
 libavcodec/lcevcdec.h         |  9 +++-
 libavcodec/options_table.h    |  6 +++
 5 files changed, 94 insertions(+), 8 deletions(-)

diff --git a/libavcodec/avcodec_internal.h b/libavcodec/avcodec_internal.h
index ebd9458120..d009138665 100644
--- a/libavcodec/avcodec_internal.h
+++ b/libavcodec/avcodec_internal.h
@@ -35,6 +35,8 @@ typedef struct FFCodecContext {
      * The public context.
      */
     AVCodecContext pub;
+
+    struct AVDictionary *lcevc_params;
 } FFCodecContext;
 
 static av_always_inline FFCodecContext *ffcodeccontext(AVCodecContext *avctx)
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 94dfc06a84..627ad9420a 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -2152,7 +2152,9 @@ av_cold int ff_decode_preinit(AVCodecContext *avctx)
     if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_ENHANCEMENTS)) {
         if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) {
 #if CONFIG_LIBLCEVC_DEC
-            ret = ff_lcevc_alloc(&dc->lcevc.ctx, av_log_get_level() + 
avctx->log_level_offset);
+            FFCodecContext *ffavc = ffcodeccontext(avctx);
+            ret = ff_lcevc_alloc(&dc->lcevc.ctx, &ffavc->lcevc_params,
+                                 av_log_get_level() + avctx->log_level_offset);
             if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE))
                 return ret;
 #endif
diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c
index d62adfba13..c7872b5016 100644
--- a/libavcodec/lcevcdec.c
+++ b/libavcodec/lcevcdec.c
@@ -21,6 +21,7 @@
 #include "libavutil/imgutils.h"
 #include "libavutil/log.h"
 #include "libavutil/mem.h"
+#include "libavutil/opt.h"
 #include "libavutil/refstruct.h"
 
 #include "cbs.h"
@@ -380,6 +381,7 @@ static int lcevc_init(FFLCEVCContext *lcevc)
 {
     LCEVC_AccelContextHandle dummy = { 0 };
     const int32_t event = LCEVC_Log;
+    LCEVC_ReturnCode res;
     int level;
 
     if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
@@ -387,9 +389,42 @@ static int lcevc_init(FFLCEVCContext *lcevc)
         return AVERROR_EXTERNAL;
     }
 
+    if (lcevc->pipeline) {
+        res = LCEVC_ConfigureDecoderString(lcevc->decoder, "pipeline", 
lcevc->pipeline);
+        if (res != LCEVC_Success) {
+            av_log(lcevc, AV_LOG_ERROR, "Failed to set pipeline to \"%s\"\n", 
lcevc->pipeline);
+            LCEVC_DestroyDecoder(lcevc->decoder);
+            return AVERROR_EXTERNAL;
+        }
+    }
+
     level = get_log_level(lcevc->loglevel);
 
     LCEVC_ConfigureDecoderInt(lcevc->decoder, "log_level", level);
+    res = LCEVC_ConfigureDecoderInt(lcevc->decoder, "threads", lcevc->threads);
+    if (res != LCEVC_Success) {
+        av_log(lcevc, AV_LOG_ERROR, "Failed to set threads to %d\n", 
lcevc->threads);
+        LCEVC_DestroyDecoder(lcevc->decoder);
+        return AVERROR_EXTERNAL;
+    }
+    res = LCEVC_ConfigureDecoderInt(lcevc->decoder, "passthrough_mode", 
lcevc->passthrough_mode);
+    if (res != LCEVC_Success) {
+        av_log(lcevc, AV_LOG_ERROR, "Failed to set passthrough_mode to %d\n", 
lcevc->passthrough_mode);
+        LCEVC_DestroyDecoder(lcevc->decoder);
+        return AVERROR_EXTERNAL;
+    }
+    res = LCEVC_ConfigureDecoderBool(lcevc->decoder, "allow_dithering", 
lcevc->allow_dithering);
+    if (res != LCEVC_Success) {
+        av_log(lcevc, AV_LOG_ERROR, "Failed to set allow_dithering to %d\n", 
lcevc->allow_dithering);
+        LCEVC_DestroyDecoder(lcevc->decoder);
+        return AVERROR_EXTERNAL;
+    }
+    res = LCEVC_ConfigureDecoderBool(lcevc->decoder, "highlight_residuals", 
lcevc->highlight_residuals);
+    if (res != LCEVC_Success) {
+        av_log(lcevc, AV_LOG_ERROR, "Failed to set highlight_residuals to 
%d\n", lcevc->highlight_residuals);
+        LCEVC_DestroyDecoder(lcevc->decoder);
+        return AVERROR_EXTERNAL;
+    }
     LCEVC_ConfigureDecoderIntArray(lcevc->decoder, "events", 1, &event);
     LCEVC_SetDecoderEventCallback(lcevc->decoder, event_callback, lcevc);
 
@@ -477,22 +512,61 @@ static const CodedBitstreamUnitType 
decompose_unit_types[] = {
     LCEVC_NON_IDR_NUT,
 };
 
+#define OFFSET(x) offsetof(FFLCEVCContext, x)
+#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_DECODING_PARAM)
+static const AVOption lcevc_opts[] = {
+    { "passthrough_mode", "Set passthrough mode", OFFSET(passthrough_mode), 
AV_OPT_TYPE_INT,
+            { .i64 = 0 }, -1, 2, FLAGS, .unit = "passthrough_mode" },
+        { "disable", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, .unit = 
"passthrough_mode" },
+        { "allow",   NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 },  .unit = 
"passthrough_mode" },
+        { "force",   NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 },  .unit = 
"passthrough_mode" },
+        { "scale",   NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 },  .unit = 
"passthrough_mode" },
+    { "allow_dithering", "Allow dithering", OFFSET(allow_dithering), 
AV_OPT_TYPE_BOOL,
+            { .i64 = 1 }, 0, 1, FLAGS },
+    { "highlight_residuals", "Highlight residuals", 
OFFSET(highlight_residuals), AV_OPT_TYPE_BOOL,
+            { .i64 = 0 }, 0, 1, FLAGS },
+    { "threads", "Thread count", OFFSET(threads), AV_OPT_TYPE_INT,
+            { .i64 = 1 }, 0, INT_MAX, FLAGS },
+    { "pipeline", "Decoding pipeline", OFFSET(pipeline), AV_OPT_TYPE_STRING,
+            { .str = NULL }, 0, 0, FLAGS },
+    { NULL },
+};
+#undef OFFSET
+#undef FLAGS
 
 static const AVClass lcevcdec_context_class = {
     .class_name     = "liblcevc_dec",
     .item_name      = av_default_item_name,
+    .option         = lcevc_opts,
     .version        = LIBAVUTIL_VERSION_INT,
     .category       = AV_CLASS_CATEGORY_DECODER,
 };
 
-int ff_lcevc_alloc(FFLCEVCContext **plcevc, int loglevel)
+int ff_lcevc_alloc(FFLCEVCContext **plcevc, AVDictionary **options, int 
loglevel)
 {
     FFLCEVCContext *lcevc = NULL;
+    const AVDictionaryEntry *t;
     int ret;
 
     lcevc = av_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free);
-    if (!lcevc)
+    if (!lcevc) {
+        av_dict_free(options);
         return AVERROR(ENOMEM);
+    }
+
+    lcevc->class = &lcevcdec_context_class;
+    av_opt_set_defaults(lcevc);
+
+    lcevc->loglevel = loglevel;
+
+    ret = av_opt_set_dict2(lcevc, options, 0);
+    if (ret < 0)
+        return ret;
+
+    if (t = av_dict_iterate(*options, NULL)) {
+        av_log(NULL, AV_LOG_FATAL, "liblcevc-dec option %s not found.\n", 
t->key);
+        return AVERROR_OPTION_NOT_FOUND;
+    }
 
     lcevc->frag = av_mallocz(sizeof(*lcevc->frag));
     if (!lcevc->frag) {
@@ -516,9 +590,6 @@ int ff_lcevc_alloc(FFLCEVCContext **plcevc, int loglevel)
         goto fail;
     }
 
-    lcevc->class = &lcevcdec_context_class;
-    lcevc->loglevel = loglevel;
-
     *plcevc = lcevc;
     return 0;
 fail:
diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h
index b53547f112..b2132123ea 100644
--- a/libavcodec/lcevcdec.h
+++ b/libavcodec/lcevcdec.h
@@ -22,7 +22,7 @@
 #include "config.h"
 
 #include "libavutil/log.h"
-#include "libavutil/pixfmt.h"
+#include "libavutil/dict.h"
 
 #include <stdint.h>
 #if CONFIG_LIBLCEVC_DEC
@@ -42,6 +42,11 @@ typedef struct FFLCEVCContext {
     struct AVRefStructPool *frame_pool; ///< pool of FFLCEVCFrame
     int64_t last_pts;
     int loglevel;
+    int threads;
+    int passthrough_mode;
+    int allow_dithering;
+    int highlight_residuals;
+    uint8_t *pipeline;
     int initialized;
 } FFLCEVCContext;
 
@@ -52,7 +57,7 @@ typedef struct FFLCEVCFrame {
     struct AVFrame *frame;
 } FFLCEVCFrame;
 
-int ff_lcevc_alloc(FFLCEVCContext **plcevc, int loglevel);
+int ff_lcevc_alloc(FFLCEVCContext **plcevc, AVDictionary **options, int 
loglevel);
 int ff_lcevc_process(void *logctx, struct AVFrame *frame);
 int ff_lcevc_parse_frame(FFLCEVCContext *lcevc, const struct AVFrame *frame,
                          enum AVPixelFormat *format, int *width, int *height);
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h
index 100095b24c..bdda81aae5 100644
--- a/libavcodec/options_table.h
+++ b/libavcodec/options_table.h
@@ -30,8 +30,10 @@
 
 #include "libavutil/opt.h"
 #include "avcodec.h"
+#include "avcodec_internal.h"
 #include "version_major.h"
 
+#define FFOFFSET(x) offsetof(FFCodecContext,x)
 #define OFFSET(x) offsetof(AVCodecContext,x)
 #define DEFAULT 0 //should be NAN but it does not work as it is not a constant 
in glibc as required by ANSI/ISO C
 //these names are too long to be readable
@@ -420,6 +422,9 @@ static const AVOption avcodec_options[] = {
     {"content_light_level",         .default_val.i64 = 
AV_PKT_DATA_CONTENT_LIGHT_LEVEL,         .type = AV_OPT_TYPE_CONST, .flags = 
A|D, .unit = "side_data_pkt" },
     {"icc_profile",                 .default_val.i64 = 
AV_PKT_DATA_ICC_PROFILE,                 .type = AV_OPT_TYPE_CONST, .flags = 
A|D, .unit = "side_data_pkt" },
     {"exif",                        .default_val.i64 = AV_PKT_DATA_EXIF,       
                 .type = AV_OPT_TYPE_CONST, .flags = A|D, .unit = 
"side_data_pkt" },
+
+// FFCodecContext options
+{ "lcevc-dec-params", "Configure liblcevc-dec using a :-separated list of 
key=value parameters", FFOFFSET(lcevc_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, 
V|D },
 {NULL},
 };
 
@@ -431,5 +436,6 @@ static const AVOption avcodec_options[] = {
 #undef CC
 #undef DEFAULT
 #undef OFFSET
+#undef FFOFFSET
 
 #endif /* AVCODEC_OPTIONS_TABLE_H */
-- 
2.52.0

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

Reply via email to