[PR] avcodec/lcevcdec: move implementations to supported decoders (PR #23999)
James Almer via ffmpeg-devel <[email protected]> Mon, 03 Aug 2026 23:19:53 -0000
| Newsgroups | gmane.comp.video.ffmpeg.devel |
|---|---|
| Message-ID | <178579919409.59.15887553250689985580@29965ddac10e> |
PR #23999 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23999 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23999.patch Remove the code from the generic framework as it's a very hacky way to handle it. Instead, make supported decoders attempt to inject the post-processing. >From 9827b2201a38ccf97a045fd208381b856e848232 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 23 Jul 2026 21:16:57 -0300 Subject: [PATCH 1/2] avcodec/lcevcdec: move implementations to supported decoders Remove the code from the generic framework as it's a very hacky way to handle it. Instead, make supported decoders attempt to inject the post-processing. Signed-off-by: James Almer <[email protected]> --- libavcodec/av1dec.c | 12 ++++ libavcodec/decode.c | 110 +------------------------------------ libavcodec/h264_slice.c | 17 ++++-- libavcodec/hevc/refs.c | 19 ++++--- libavcodec/internal.h | 4 ++ libavcodec/lcevcdec.c | 49 +++++++++++++++-- libavcodec/lcevcdec.h | 8 ++- libavcodec/libaomdec.c | 10 ++++ libavcodec/libdav1d.c | 10 ++++ libavcodec/pthread_frame.c | 3 + libavcodec/vvc/refs.c | 19 ++++--- 11 files changed, 123 insertions(+), 138 deletions(-) diff --git a/libavcodec/av1dec.c b/libavcodec/av1dec.c index e08dbddc48..3e0173ed24 100644 --- a/libavcodec/av1dec.c +++ b/libavcodec/av1dec.c @@ -38,6 +38,7 @@ #include "internal.h" #include "itut35.h" #include "hwconfig.h" +#include "lcevcdec.h" #include "profiles.h" #include "progressframe.h" #include "libavutil/refstruct.h" @@ -1139,6 +1140,17 @@ static int set_output_frame(AVCodecContext *avctx, AVFrame *frame) return ret; } +#if CONFIG_LIBLCEVC_DEC + const AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); + if (avctx->internal->lcevc && sd) { + ret = ff_lcevc_alloc_frame(avctx, avctx->internal->lcevc, frame, sd->buf); + if (ret < 0) { + av_frame_unref(frame); + return ret; + } + } +#endif + if (avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN) { ret = export_film_grain(avctx, frame); if (ret < 0) { diff --git a/libavcodec/decode.c b/libavcodec/decode.c index ba6ff8a9fd..39f483a268 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -95,18 +95,6 @@ typedef struct DecodeContext { * (global or attached to packets) side data over bytestream. */ uint64_t side_data_pref_mask; - -#if CONFIG_LIBLCEVC_DEC - struct { - FFLCEVCContext *ctx; - int frame; - enum AVPixelFormat format; - int base_width; - int base_height; - int width; - int height; - } lcevc; -#endif } DecodeContext; static DecodeContext *decode_ctx(AVCodecInternal *avci) @@ -1638,32 +1626,6 @@ int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) break; } -#if CONFIG_LIBLCEVC_DEC - AVCodecInternal *avci = avctx->internal; - DecodeContext *dc = decode_ctx(avci); - - dc->lcevc.frame = dc->lcevc.ctx && - av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); - - if (dc->lcevc.frame) { - ret = ff_lcevc_parse_frame(dc->lcevc.ctx, frame, &dc->lcevc.format, - &dc->lcevc.width, &dc->lcevc.height); - if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) - return ret; - - // force get_buffer2() to allocate the base frame using the same dimensions - // as the final enhanced frame, in order to prevent reinitializing the buffer - // pools unnecessarely - if (!ret && dc->lcevc.width && dc->lcevc.height) { - dc->lcevc.base_width = frame->width; - dc->lcevc.base_height = frame->height; - frame->width = dc->lcevc.width; - frame->height = dc->lcevc.height; - } else - dc->lcevc.frame = 0; - } -#endif - return 0; } @@ -1714,63 +1676,6 @@ int ff_attach_decode_data(AVCodecContext *avctx, AVFrame *frame) frame->private_ref = fdd; -#if CONFIG_LIBLCEVC_DEC - AVCodecInternal *avci = avctx->internal; - DecodeContext *dc = decode_ctx(avci); - - if (!dc->lcevc.frame) { - dc->lcevc.frame = dc->lcevc.ctx && - av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); - - if (dc->lcevc.frame) { - int ret = ff_lcevc_parse_frame(dc->lcevc.ctx, frame, &dc->lcevc.format, - &dc->lcevc.width, &dc->lcevc.height); - if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) - return ret; - - if (!ret && dc->lcevc.width && dc->lcevc.height) { - dc->lcevc.base_width = frame->width; - dc->lcevc.base_height = frame->height; - } else - dc->lcevc.frame = 0; - } - } - if (dc->lcevc.frame) { - FFLCEVCFrame *frame_ctx; - int ret; - - if (fdd->post_process || !dc->lcevc.width || !dc->lcevc.height) { - dc->lcevc.frame = 0; - return 0; - } - - frame_ctx = av_refstruct_pool_get(dc->lcevc.ctx->frame_pool); - if (!frame_ctx) - return AVERROR(ENOMEM); - - frame_ctx->lcevc = av_refstruct_ref(dc->lcevc.ctx); - frame_ctx->frame->width = dc->lcevc.width; - frame_ctx->frame->height = dc->lcevc.height; - frame_ctx->frame->format = dc->lcevc.format; - avctx->bits_per_raw_sample = av_pix_fmt_desc_get(dc->lcevc.format)->comp[0].depth; - - frame->width = dc->lcevc.base_width; - frame->height = dc->lcevc.base_height; - - ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0); - if (ret < 0) { - av_refstruct_unref(&frame_ctx); - return ret; - } - - validate_avframe_allocation(avctx, frame_ctx->frame); - - fdd->post_process_opaque = frame_ctx; - fdd->post_process = ff_lcevc_process; - } - dc->lcevc.frame = 0; -#endif - return 0; } @@ -2148,7 +2053,7 @@ 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); + ret = ff_lcevc_alloc(&avci->lcevc, av_log_get_level() + avctx->log_level_offset); if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return ret; #endif @@ -2395,22 +2300,11 @@ av_cold void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext * dst_dc->initial_pict_type = src_dc->initial_pict_type; dst_dc->intra_only_flag = src_dc->intra_only_flag; dst_dc->side_data_pref_mask = src_dc->side_data_pref_mask; -#if CONFIG_LIBLCEVC_DEC - av_refstruct_replace(&dst_dc->lcevc.ctx, src_dc->lcevc.ctx); - dst_dc->lcevc.width = src_dc->lcevc.width; - dst_dc->lcevc.height = src_dc->lcevc.height; - dst_dc->lcevc.format = src_dc->lcevc.format; -#endif } av_cold void ff_decode_internal_uninit(AVCodecContext *avctx) { -#if CONFIG_LIBLCEVC_DEC - AVCodecInternal *avci = avctx->internal; - DecodeContext *dc = decode_ctx(avci); - - av_refstruct_unref(&dc->lcevc.ctx); -#endif + return; } static int attach_displaymatrix(AVCodecContext *avctx, AVFrame *frame, int orientation) diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 9b5ed8f77e..0229da1be1 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -41,7 +41,9 @@ #include "h264data.h" #include "h264chroma.h" #include "h264_ps.h" +#include "internal.h" #include "golomb.h" +#include "lcevcdec.h" #include "mathops.h" #include "mpegutils.h" #include "rectangle.h" @@ -191,18 +193,21 @@ static int alloc_picture(H264Context *h, H264Picture *pic) av_assert0(!pic->f->data[0]); - if (h->sei.common.itut_t35.lcevc) { - ret = ff_frame_new_side_data_from_buf(h->avctx, pic->f, AV_FRAME_DATA_LCEVC, &h->sei.common.itut_t35.lcevc); - if (ret < 0) - return ret; - } - pic->tf.f = pic->f; ret = ff_thread_get_ext_buffer(h->avctx, &pic->tf, pic->reference ? AV_GET_BUFFER_FLAG_REF : 0); if (ret < 0) goto fail; +#if CONFIG_LIBLCEVC_DEC + if (h->avctx->internal->lcevc && h->sei.common.itut_t35.lcevc) { + ret = ff_lcevc_alloc_frame(h->avctx, h->avctx->internal->lcevc, pic->f, + h->sei.common.itut_t35.lcevc); + if (ret < 0) + goto fail; + } +#endif + if (pic->needs_fg) { pic->f_grain->format = pic->f->format; pic->f_grain->width = pic->f->width; diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c index 2df3a2ad56..1d4113577f 100644 --- a/libavcodec/hevc/refs.c +++ b/libavcodec/hevc/refs.c @@ -28,6 +28,8 @@ #include "libavcodec/decode.h" #include "hevc.h" #include "hevcdec.h" +#include "libavcodec/internal.h" +#include "libavcodec/lcevcdec.h" #include "libavcodec/progressframe.h" #include "libavcodec/thread.h" #include "libavutil/refstruct.h" @@ -121,14 +123,6 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) if (ret < 0) return NULL; - // Add LCEVC SEI metadata here, as it's needed in get_buffer() - if (s->sei.common.itut_t35.lcevc) { - ret = ff_frame_new_side_data_from_buf(s->avctx, frame->tf.f, - AV_FRAME_DATA_LCEVC, &s->sei.common.itut_t35.lcevc); - if (ret < 0) - goto fail; - } - // add view ID side data if it's nontrivial if (!ff_hevc_is_alpha_video(s) && (vps->nb_layers > 1 || view_id)) { HEVCSEITDRDI *tdrdi = &s->sei.tdrdi; @@ -161,6 +155,15 @@ static HEVCFrame *alloc_frame(HEVCContext *s, HEVCLayerContext *l) if (ret < 0) goto fail; +#if CONFIG_LIBLCEVC_DEC + if (s->avctx->internal->lcevc && s->sei.common.itut_t35.lcevc) { + ret = ff_lcevc_alloc_frame(s->avctx, s->avctx->internal->lcevc, frame->f, + s->sei.common.itut_t35.lcevc); + if (ret < 0) + goto fail; + } +#endif + size_t rpl_bytes; if (av_size_mult(s->pkt.nb_nals, sizeof(*frame->rpl), &rpl_bytes) < 0) goto fail; diff --git a/libavcodec/internal.h b/libavcodec/internal.h index e742b170cf..2750bfc303 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -46,6 +46,8 @@ # define STRIDE_ALIGN 8 #endif +struct FFLCEVCContext; + typedef struct AVCodecInternal { /** * When using frame-threaded decoding, this field is set for the first @@ -149,6 +151,8 @@ typedef struct AVCodecInternal { FFIccContext icc; /* used to read and write embedded ICC profiles */ #endif + struct FFLCEVCContext *lcevc; + /** * Set when the user has been warned about a failed allocation from * a fixed frame pool. diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c index 2e16a5a627..56d55bcdb1 100644 --- a/libavcodec/lcevcdec.c +++ b/libavcodec/lcevcdec.c @@ -29,6 +29,7 @@ #include "lcevc_parse.h" #include "lcevcdec.h" #include "lcevctab.h" +#include "thread.h" static LCEVC_ColorFormat map_format(int format) { @@ -391,7 +392,7 @@ static int lcevc_init(FFLCEVCContext *lcevc) return 0; } -int ff_lcevc_process(void *logctx, AVFrame *frame) +static int lcevc_process(void *logctx, AVFrame *frame) { FrameDecodeData *fdd = frame->private_ref; FFLCEVCFrame *frame_ctx = fdd->post_process_opaque; @@ -406,7 +407,6 @@ int ff_lcevc_process(void *logctx, AVFrame *frame) av_assert0(frame_ctx->frame); - ret = lcevc_send_frame(frame_ctx, frame); if (ret) return ret < 0 ? ret : 0; @@ -420,15 +420,14 @@ int ff_lcevc_process(void *logctx, AVFrame *frame) return 0; } -int ff_lcevc_parse_frame(FFLCEVCContext *lcevc, const AVFrame *frame, - enum AVPixelFormat *format, int *width, int *height) +static int lcevc_parse_frame(FFLCEVCContext *lcevc, AVBufferRef *buf, + enum AVPixelFormat *format, int *width, int *height) { LCEVCRawProcessBlock *block = NULL; const LCEVCRawGlobalConfig *gc; - const AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); int ret; - ret = ff_cbs_read(lcevc->cbc, lcevc->frag, NULL, sd->data, sd->size); + ret = ff_cbs_read(lcevc->cbc, lcevc->frag, NULL, buf->data, buf->size); if (ret < 0) { av_log(lcevc, AV_LOG_ERROR, "Failed to parse Access Unit.\n"); goto end; @@ -459,6 +458,44 @@ end: return ret; } +int ff_lcevc_alloc_frame(AVCodecContext *avctx, FFLCEVCContext *lcevc, + AVFrame *frame, AVBufferRef *buf) +{ + FrameDecodeData *fdd = frame->private_ref; + int ret; + + if (fdd->post_process) + return 0; + + ret = lcevc_parse_frame(lcevc, buf, &lcevc->format, &lcevc->width, &lcevc->height); + if (ret < 0) + return (avctx->err_recognition & AV_EF_EXPLODE) ? ret : 0; + + if (!lcevc->width || !lcevc->height) + return 0; + + FFLCEVCFrame *frame_ctx = av_refstruct_pool_get(lcevc->frame_pool); + if (!frame_ctx) + return AVERROR(ENOMEM); + + frame_ctx->lcevc = av_refstruct_ref(lcevc); + frame_ctx->frame->width = lcevc->width; + frame_ctx->frame->height = lcevc->height; + frame_ctx->frame->format = lcevc->format; + avctx->bits_per_raw_sample = av_pix_fmt_desc_get(lcevc->format)->comp[0].depth; + + ret = ff_thread_get_buffer(avctx, frame_ctx->frame, 0); + if (ret < 0) { + av_refstruct_unref(&frame_ctx); + return ret; + } + + fdd->post_process_opaque = frame_ctx; + fdd->post_process = lcevc_process; + + return 0; +} + static const CodedBitstreamUnitType decompose_unit_types[] = { LCEVC_IDR_NUT, LCEVC_NON_IDR_NUT, diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h index e51d3de989..e3044d4935 100644 --- a/libavcodec/lcevcdec.h +++ b/libavcodec/lcevcdec.h @@ -39,10 +39,14 @@ typedef struct FFLCEVCContext { struct CodedBitstreamContext *cbc; struct CodedBitstreamFragment *frag; struct AVRefStructPool *frame_pool; ///< pool of FFLCEVCFrame + int width, height; + enum AVPixelFormat format; int loglevel; int initialized; } FFLCEVCContext; +struct AVBufferRef; +struct AVCodecContext; struct AVFrame; typedef struct FFLCEVCFrame { @@ -51,8 +55,8 @@ typedef struct FFLCEVCFrame { } FFLCEVCFrame; int ff_lcevc_alloc(FFLCEVCContext **plcevc, int loglevel); +int ff_lcevc_alloc_frame(struct AVCodecContext *avctx, FFLCEVCContext *lcevc, + struct AVFrame *frame, struct AVBufferRef *buf); 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); #endif /* AVCODEC_LCEVCDEC_H */ diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c index 33925d4cb4..70aa829130 100644 --- a/libavcodec/libaomdec.c +++ b/libavcodec/libaomdec.c @@ -36,6 +36,7 @@ #include "codec_internal.h" #include "decode.h" #include "itut35.h" +#include "lcevcdec.h" #include "libaom.h" #include "profiles.h" @@ -229,6 +230,15 @@ static int aom_decode(AVCodecContext *avctx, AVFrame *picture, if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) return ret; +#if CONFIG_LIBLCEVC_DEC + const AVFrameSideData *sd = av_frame_get_side_data(picture, AV_FRAME_DATA_LCEVC); + if (avctx->internal->lcevc && sd) { + ret = ff_lcevc_alloc_frame(c, avctx->internal->lcevc, frame, sd->buf); + if (ret < 0) + return ret; + } +#endif + #ifdef AOM_CTRL_AOMD_GET_FRAME_FLAGS { aom_codec_frame_flags_t flags; diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c index b41b741c0d..5e209dcb7a 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c @@ -38,6 +38,7 @@ #include "dovi_rpu.h" #include "internal.h" #include "itut35.h" +#include "lcevcdec.h" #define FF_DAV1D_VERSION_AT_LEAST(x,y) \ (DAV1D_API_VERSION_MAJOR > (x) || DAV1D_API_VERSION_MAJOR == (x) && DAV1D_API_VERSION_MINOR >= (y)) @@ -555,6 +556,15 @@ static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) if (res < 0) return res; +#if CONFIG_LIBLCEVC_DEC + const AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); + if (c->internal->lcevc && sd) { + res = ff_lcevc_alloc_frame(c, c->internal->lcevc, frame, sd->buf); + if (res < 0) + goto fail; + } +#endif + res = 0; fail: dav1d_picture_unref(p); diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index e6dcc23c15..97e56c264a 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -395,6 +395,7 @@ static int update_context_from_thread(AVCodecContext *dst, const AVCodecContext dst->hwaccel_flags = src->hwaccel_flags; av_refstruct_replace(&dst->internal->pool, src->internal->pool); + av_refstruct_replace(&dst->internal->lcevc, src->internal->lcevc); ff_decode_internal_sync(dst, src); } @@ -775,6 +776,7 @@ av_cold void ff_frame_thread_free(AVCodecContext *avctx, int thread_count) } av_refstruct_unref(&ctx->internal->pool); + av_refstruct_unref(&ctx->internal->lcevc); av_packet_free(&ctx->internal->in_pkt); av_packet_free(&ctx->internal->last_pkt_props); ff_decode_internal_uninit(ctx); @@ -837,6 +839,7 @@ static av_cold int init_thread(PerThreadContext *p, int *threads_to_free, ff_decode_internal_sync(copy, avctx); copy->internal->thread_ctx = p; copy->internal->progress_frame_pool = avctx->internal->progress_frame_pool; + av_refstruct_replace(©->internal->lcevc, avctx->internal->lcevc); copy->delay = avctx->delay; diff --git a/libavcodec/vvc/refs.c b/libavcodec/vvc/refs.c index 15024d7b68..e1b9965e7a 100644 --- a/libavcodec/vvc/refs.c +++ b/libavcodec/vvc/refs.c @@ -28,6 +28,8 @@ #include "libavutil/refstruct.h" #include "libavcodec/thread.h" #include "libavcodec/decode.h" +#include "libavcodec/internal.h" +#include "libavcodec/lcevcdec.h" #include "refs.h" @@ -133,18 +135,19 @@ static VVCFrame *alloc_frame(VVCContext *s, VVCFrameContext *fc) frame->sps = av_refstruct_ref_c(fc->ps.sps); frame->pps = av_refstruct_ref_c(fc->ps.pps); - // Add LCEVC SEI metadata here, as it's needed in get_buffer() - if (fc->sei.common.itut_t35.lcevc) { - ret = ff_frame_new_side_data_from_buf(s->avctx, frame->frame, - AV_FRAME_DATA_LCEVC, &fc->sei.common.itut_t35.lcevc); - if (ret < 0) - goto fail; - } - ret = ff_thread_get_buffer(s->avctx, frame->frame, AV_GET_BUFFER_FLAG_REF); if (ret < 0) return NULL; +#if CONFIG_LIBLCEVC_DEC + if (s->avctx->internal->lcevc && fc->sei.common.itut_t35.lcevc) { + ret = ff_lcevc_alloc_frame(s->avctx, s->avctx->internal->lcevc, frame->frame, + fc->sei.common.itut_t35.lcevc); + if (ret < 0) + goto fail; + } +#endif + frame->rpl = av_refstruct_allocz(s->current_frame.nb_units * sizeof(RefPicListTab)); if (!frame->rpl) goto fail; -- 2.52.0 >From 05e4530d26de3ca857f90e16e0a88974eca77057 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Tue, 28 Jul 2026 23:49:11 -0300 Subject: [PATCH 2/2] avcodec/lcevcdec: add support for passing options Only a hardcoded subset of options is supported, as liblcevc-dec lacks a proper function to either query existing options, or parsing option values passed as strings. Signed-off-by: James Almer <[email protected]> --- libavcodec/decode.c | 7 ++++- libavcodec/h264dec.c | 2 ++ libavcodec/h264dec.h | 2 ++ libavcodec/hevc/hevcdec.c | 2 ++ libavcodec/hevc/hevcdec.h | 2 ++ libavcodec/lcevcdec.c | 63 +++++++++++++++++++++++++++++++++++---- libavcodec/lcevcdec.h | 12 +++++++- libavcodec/libaomdec.c | 15 ++++++++++ libavcodec/libdav1d.c | 3 ++ libavcodec/vvc/dec.c | 15 ++++++++++ libavcodec/vvc/dec.h | 2 ++ 11 files changed, 118 insertions(+), 7 deletions(-) diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 39f483a268..b33d202b19 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -39,6 +39,7 @@ #include "libavutil/internal.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/mem.h" +#include "libavutil/opt.h" #include "libavutil/stereo3d.h" #include "avcodec.h" @@ -2053,7 +2054,11 @@ 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(&avci->lcevc, av_log_get_level() + avctx->log_level_offset); + AVDictionary *options = NULL; + if (avctx->priv_data) + av_opt_get_dict_val(avctx->priv_data, "lcevc-dec-params", 0, &options); + ret = ff_lcevc_alloc(&avci->lcevc, &options, avctx->thread_count, + av_log_get_level() + avctx->log_level_offset); if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return ret; #endif diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index b78b7989ea..0d37fd9451 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -50,6 +50,7 @@ #include "golomb.h" #include "hwaccel_internal.h" #include "hwconfig.h" +#include "lcevcdec.h" #include "mpegutils.h" #include "profiles.h" #include "rectangle.h" @@ -1096,6 +1097,7 @@ static const AVOption h264_options[] = { { "x264_build", "Assume this x264 version if no x264 version found in any SEI", OFFSET(x264_build), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VD }, { "skip_gray", "Do not return gray gap frames", OFFSET(skip_gray), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD }, { "noref_gray", "Avoid using gray gap frames as references", OFFSET(noref_gray), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, VD }, + LCEVCDEC_OPTIONS(H264Context) { NULL }, }; diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 74fd09dfaa..f8461ce9f1 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -577,6 +577,8 @@ typedef struct H264Context { int non_gray; ///< Did we encounter a intra frame after a gray gap frame int noref_gray; int skip_gray; + + AVDictionary *lcevc_params; } H264Context; extern const uint16_t ff_h264_mb_sizes[4]; diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c index 475c2738b1..f027153c9d 100644 --- a/libavcodec/hevc/hevcdec.c +++ b/libavcodec/hevc/hevcdec.c @@ -50,6 +50,7 @@ #include "libavcodec/hwaccel_internal.h" #include "libavcodec/hwconfig.h" #include "libavcodec/internal.h" +#include "libavcodec/lcevcdec.h" #include "libavcodec/profiles.h" #include "libavcodec/progressframe.h" #include "libavcodec/thread.h" @@ -4246,6 +4247,7 @@ static const AVOption options[] = { { "unspecified", .type = AV_OPT_TYPE_CONST, .default_val = { .i64 = AV_STEREO3D_VIEW_UNSPEC }, .unit = "view_pos" }, { "left", .type = AV_OPT_TYPE_CONST, .default_val = { .i64 = AV_STEREO3D_VIEW_LEFT }, .unit = "view_pos" }, { "right", .type = AV_OPT_TYPE_CONST, .default_val = { .i64 = AV_STEREO3D_VIEW_RIGHT }, .unit = "view_pos" }, + LCEVCDEC_OPTIONS(HEVCContext) { NULL }, }; diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h index 8394740c4b..412f931fe5 100644 --- a/libavcodec/hevc/hevcdec.h +++ b/libavcodec/hevc/hevcdec.h @@ -581,6 +581,8 @@ typedef struct HEVCContext { AVBufferRef *rpu_buf; ///< 0 or 1 Dolby Vision RPUs. DOVIContext dovi_ctx; ///< Dolby Vision decoding context + + AVDictionary *lcevc_params; } HEVCContext; /** diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c index 56d55bcdb1..0fa9368405 100644 --- a/libavcodec/lcevcdec.c +++ b/libavcodec/lcevcdec.c @@ -368,6 +368,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) { @@ -378,6 +379,30 @@ static int lcevc_init(FFLCEVCContext *lcevc) 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); @@ -501,22 +526,53 @@ static const CodedBitstreamUnitType decompose_unit_types[] = { LCEVC_NON_IDR_NUT, }; +#define OFFSET(x) offsetof(FFLCEVCContext, x) +static const AVOption lcevc_opts[] = { + { "passthrough_mode", "Set passthrough mode", OFFSET(passthrough_mode), AV_OPT_TYPE_INT, + { .i64 = 0 }, -1, 2, AV_OPT_FLAG_DECODING_PARAM, .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, AV_OPT_FLAG_DECODING_PARAM }, + { "highlight_residuals", "Gighlight residuals", OFFSET(highlight_residuals), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + { "threads", "Thread count", OFFSET(threads), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; 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 threads, int loglevel) { FFLCEVCContext *lcevc = NULL; 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; + lcevc->threads = threads; + + ret = av_opt_set_dict2(lcevc, options, 0); + av_dict_free(options); + if (ret < 0) + return ret; lcevc->frag = av_mallocz(sizeof(*lcevc->frag)); if (!lcevc->frag) { @@ -540,9 +596,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 e3044d4935..892e6b6a10 100644 --- a/libavcodec/lcevcdec.h +++ b/libavcodec/lcevcdec.h @@ -22,6 +22,7 @@ #include "config.h" #include "libavutil/log.h" +#include "libavutil/opt.h" #include <stdint.h> #if CONFIG_LIBLCEVC_DEC @@ -42,6 +43,10 @@ typedef struct FFLCEVCContext { int width, height; enum AVPixelFormat format; int loglevel; + int threads; + int passthrough_mode; + int allow_dithering; + int highlight_residuals; int initialized; } FFLCEVCContext; @@ -54,9 +59,14 @@ typedef struct FFLCEVCFrame { struct AVFrame *frame; } FFLCEVCFrame; -int ff_lcevc_alloc(FFLCEVCContext **plcevc, int loglevel); +int ff_lcevc_alloc(FFLCEVCContext **plcevc, AVDictionary **options, int threads, int loglevel); int ff_lcevc_alloc_frame(struct AVCodecContext *avctx, FFLCEVCContext *lcevc, struct AVFrame *frame, struct AVBufferRef *buf); int ff_lcevc_process(void *logctx, struct AVFrame *frame); +#define LCEVCDEC_OPTIONS(offset) \ + { "lcevc-dec-params", "Configure liblcevc-dec using a :-separated list of key=value parameters", \ + offsetof(offset, lcevc_params), AV_OPT_TYPE_DICT, { 0 }, 0, 0, \ + AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, + #endif /* AVCODEC_LCEVCDEC_H */ diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c index 70aa829130..9484822c32 100644 --- a/libavcodec/libaomdec.c +++ b/libavcodec/libaomdec.c @@ -42,6 +42,7 @@ typedef struct AV1DecodeContext { struct aom_codec_ctx decoder; + AVDictionary *lcevc_params; } AV1DecodeContext; static av_cold int aom_init(AVCodecContext *avctx, @@ -296,11 +297,25 @@ static av_cold int av1_init(AVCodecContext *avctx) return aom_init(avctx, aom_codec_av1_dx()); } +static const AVOption options[] = { + LCEVCDEC_OPTIONS(AV1DecodeContext) + + { NULL }, +}; + +static const AVClass aom_class = { + .class_name = "libaom-av1 decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + const FFCodec ff_libaom_av1_decoder = { .p.name = "libaom-av1", CODEC_LONG_NAME("libaom AV1"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_AV1, + .p.priv_class = &aom_class, .priv_data_size = sizeof(AV1DecodeContext), .init = av1_init, .close = aom_free, diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c index 5e209dcb7a..6a3781faae 100644 --- a/libavcodec/libdav1d.c +++ b/libavcodec/libdav1d.c @@ -55,6 +55,8 @@ typedef struct Libdav1dContext { int apply_grain; int operating_point; int all_layers; + + AVDictionary *lcevc_params; } Libdav1dContext; static const enum AVPixelFormat pix_fmt[][3] = { @@ -602,6 +604,7 @@ static const AVOption libdav1d_options[] = { { "filmgrain", "Apply Film Grain", OFFSET(apply_grain), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD | AV_OPT_FLAG_DEPRECATED }, { "oppoint", "Select an operating point of the scalable bitstream", OFFSET(operating_point), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 31, VD }, { "alllayers", "Output all spatial layers", OFFSET(all_layers), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD }, + LCEVCDEC_OPTIONS(Libdav1dContext) { NULL } }; diff --git a/libavcodec/vvc/dec.c b/libavcodec/vvc/dec.c index 926288e07b..765f94fe30 100644 --- a/libavcodec/vvc/dec.c +++ b/libavcodec/vvc/dec.c @@ -29,6 +29,7 @@ #include "libavcodec/profiles.h" #include "libavutil/refstruct.h" #include "libavcodec/aom_film_grain.h" +#include "libavcodec/lcevcdec.h" #include "libavcodec/thread.h" #include "libavutil/cpu.h" #include "libavutil/mem.h" @@ -1305,11 +1306,25 @@ static av_cold int vvc_decode_init(AVCodecContext *avctx) return 0; } +static const AVOption options[] = { + LCEVCDEC_OPTIONS(VVCContext) + + { NULL }, +}; + +static const AVClass vvc_decoder_class = { + .class_name = "VVC decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + const FFCodec ff_vvc_decoder = { .p.name = "vvc", .p.long_name = NULL_IF_CONFIG_SMALL("VVC (Versatile Video Coding)"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_VVC, + .p.priv_class = &vvc_decoder_class, .priv_data_size = sizeof(VVCContext), .init = vvc_decode_init, .close = vvc_decode_free, diff --git a/libavcodec/vvc/dec.h b/libavcodec/vvc/dec.h index bfb8a2e20d..21f188d5a5 100644 --- a/libavcodec/vvc/dec.h +++ b/libavcodec/vvc/dec.h @@ -250,6 +250,8 @@ typedef struct VVCContext { int nb_delayed; ///< delayed frames H274HashContext *hash_ctx; + + AVDictionary *lcevc_params; } VVCContext ; #endif /* AVCODEC_VVC_DEC_H */ -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]