Commit e0e6ca1e29 for ffmpeg
commit e0e6ca1e29ef3f6b1e9b7d8656fe341eee8cf647
Author: James Almer <jamrial@gmail.com>
Date: Thu Oct 1 17:35:23 2026 -0300
avcodec/lcevcdec: add support for passing options
Signed-off-by: James Almer <jamrial@gmail.com>
diff --git a/doc/codecs.texi b/doc/codecs.texi
index 8f746dbc24..b85f405cf6 100644
--- a/doc/codecs.texi
+++ b/doc/codecs.texi
@@ -1041,6 +1041,8 @@ Note: The required alignment depends on if @code{AV_CODEC_FLAG_UNALIGNED} is set
CPU. @code{AV_CODEC_FLAG_UNALIGNED} cannot be changed from the command line. Also hardware
decoders will not apply left/top Cropping.
+@item lcevc-dec-params @var{string} (@emph{decoding,video})
+A :-separated list of key=value parameters passed to liblcevc-dec to initialize it.
@end table
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..a2bda77b4a 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"
@@ -320,7 +321,7 @@ static void event_callback(LCEVC_DecoderHandle dec, LCEVC_Event event,
static void lcevc_free(AVRefStructOpaque unused, void *obj)
{
FFLCEVCContext *lcevc = obj;
- if (lcevc->initialized) {
+ if (lcevc->initialized == FF_LCEVCDEC_INIT) {
LCEVC_FlushDecoder(lcevc->decoder);
lcevc_flush_pictures(lcevc);
LCEVC_DestroyDecoder(lcevc->decoder);
@@ -380,16 +381,52 @@ static int lcevc_init(FFLCEVCContext *lcevc)
{
LCEVC_AccelContextHandle dummy = { 0 };
const int32_t event = LCEVC_Log;
+ LCEVC_ReturnCode res;
int level;
+ lcevc->initialized = FF_LCEVCDEC_FAIL;
+
if (LCEVC_CreateDecoder(&lcevc->decoder, dummy) != LCEVC_Success) {
av_log(lcevc, AV_LOG_ERROR, "Failed to create LCEVC decoder\n");
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);
@@ -399,7 +436,7 @@ static int lcevc_init(FFLCEVCContext *lcevc)
return AVERROR_EXTERNAL;
}
- lcevc->initialized = 1;
+ lcevc->initialized = FF_LCEVCDEC_INIT;
return 0;
}
@@ -411,11 +448,12 @@ int ff_lcevc_process(void *logctx, AVFrame *frame)
FFLCEVCContext *lcevc = frame_ctx->lcevc;
int ret;
- if (!lcevc->initialized) {
+ if (lcevc->initialized == FF_LCEVCDEC_UNINIT) {
ret = lcevc_init(lcevc);
if (ret < 0)
return ret;
- }
+ } else if (lcevc->initialized == FF_LCEVCDEC_FAIL)
+ return 0;
av_assert0(frame_ctx->frame);
@@ -477,23 +515,60 @@ 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)
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) {
ret = AVERROR(ENOMEM);
@@ -516,9 +591,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..b757acc3f9 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
@@ -34,6 +34,12 @@ typedef uintptr_t LCEVC_DecoderHandle;
struct CodedBitstreamContext;
struct CodedBitstreamFragment;
+enum {
+ FF_LCEVCDEC_UNINIT = 0,
+ FF_LCEVCDEC_INIT,
+ FF_LCEVCDEC_FAIL,
+};
+
typedef struct FFLCEVCContext {
const AVClass *class;
LCEVC_DecoderHandle decoder;
@@ -42,6 +48,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 +63,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 a329a84db1..83f362a556 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 */
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 65bc52fb24..d8604fd00c 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -30,7 +30,7 @@
#include "version_major.h"
#define LIBAVCODEC_VERSION_MINOR 18
-#define LIBAVCODEC_VERSION_MICRO 100
+#define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \