This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch release/8.1 in repository ffmpeg.
commit 9abdfda6f2cda9b397078ad4ce72741caf425ad1 Author: James Almer <[email protected]> AuthorDate: Mon Mar 9 20:22:27 2026 -0300 Commit: James Almer <[email protected]> CommitDate: Wed Mar 18 13:35:56 2026 -0300 avcodec/lcevcdec: don't try to derive final dimensions from SAR Not only do some sources not provide an aspect ratio, as is the case of MPEG-TS, but also some enhanced streams have no change in dimensions, and this heuristic would generate bugus values. Instead, we need to parse the LCEVC bitstream for a Global Config process block in order to get the actual dimensions. This add a little overhead, but it can't be avoided. Signed-off-by: James Almer <[email protected]> (cherry picked from commit 49d75d81f6753623a3d1f5e8c5c6aa8bf669f744) --- libavcodec/decode.c | 44 +++++++++++++++++++------- libavcodec/lcevcdec.c | 79 +++++++++++++++++++++++++++++++++++++++++++++- libavcodec/lcevcdec.h | 9 +++++- libavcodec/pthread_frame.c | 1 + 4 files changed, 120 insertions(+), 13 deletions(-) diff --git a/libavcodec/decode.c b/libavcodec/decode.c index ca1adfa386..5de5a84038 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -98,6 +98,8 @@ typedef struct DecodeContext { struct { FFLCEVCContext *ctx; int frame; + int base_width; + int base_height; int width; int height; } lcevc; @@ -1661,7 +1663,7 @@ int ff_attach_decode_data(AVFrame *frame) return 0; } -static void update_frame_props(AVCodecContext *avctx, AVFrame *frame) +static int update_frame_props(AVCodecContext *avctx, AVFrame *frame) { #if CONFIG_LIBLCEVC_DEC AVCodecInternal *avci = avctx->internal; @@ -1671,12 +1673,23 @@ static void update_frame_props(AVCodecContext *avctx, AVFrame *frame) av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); if (dc->lcevc.frame) { - dc->lcevc.width = frame->width; - dc->lcevc.height = frame->height; - frame->width = frame->width * 2 / FFMAX(frame->sample_aspect_ratio.den, 1); - frame->height = frame->height * 2 / FFMAX(frame->sample_aspect_ratio.num, 1); + int ret = ff_lcevc_parse_frame(dc->lcevc.ctx, frame, + &dc->lcevc.width, &dc->lcevc.height, avctx); + if (ret < 0) + 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 (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; + } } #endif + return 0; } static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) @@ -1690,6 +1703,11 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) FFLCEVCFrame *frame_ctx; int ret; + if (!dc->lcevc.width || !dc->lcevc.height) { + dc->lcevc.frame = 0; + return 0; + } + frame_ctx = av_mallocz(sizeof(*frame_ctx)); if (!frame_ctx) return AVERROR(ENOMEM); @@ -1701,12 +1719,12 @@ static int attach_post_process_data(AVCodecContext *avctx, AVFrame *frame) } frame_ctx->lcevc = av_refstruct_ref(dc->lcevc.ctx); - frame_ctx->frame->width = frame->width; - frame_ctx->frame->height = frame->height; + frame_ctx->frame->width = dc->lcevc.width; + frame_ctx->frame->height = dc->lcevc.height; frame_ctx->frame->format = frame->format; - frame->width = dc->lcevc.width; - frame->height = dc->lcevc.height; + frame->width = dc->lcevc.base_width; + frame->height = dc->lcevc.base_height; ret = avctx->get_buffer2(avctx, frame_ctx->frame, 0); if (ret < 0) { @@ -1771,7 +1789,9 @@ int ff_get_buffer(AVCodecContext *avctx, AVFrame *frame, int flags) } } else { avctx->sw_pix_fmt = avctx->pix_fmt; - update_frame_props(avctx, frame); + ret = update_frame_props(avctx, frame); + if (ret < 0) + goto fail; } ret = avctx->get_buffer2(avctx, frame, flags); @@ -2091,7 +2111,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); + ret = ff_lcevc_alloc(&dc->lcevc.ctx, avctx); if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) return ret; #endif @@ -2338,6 +2358,8 @@ av_cold void ff_decode_internal_sync(AVCodecContext *dst, const AVCodecContext * 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; #endif } diff --git a/libavcodec/lcevcdec.c b/libavcodec/lcevcdec.c index 036b700775..69a73866fe 100644 --- a/libavcodec/lcevcdec.c +++ b/libavcodec/lcevcdec.c @@ -23,8 +23,12 @@ #include "libavutil/mem.h" #include "libavutil/refstruct.h" +#include "cbs.h" +#include "cbs_lcevc.h" #include "decode.h" +#include "lcevc_parse.h" #include "lcevcdec.h" +#include "lcevctab.h" static LCEVC_ColorFormat map_format(int format) { @@ -191,6 +195,15 @@ static int generate_output(void *logctx, FFLCEVCFrame *frame_ctx, AVFrame *out) out->width = desc.width + out->crop_left + out->crop_right; out->height = desc.height + out->crop_top + out->crop_bottom; + av_log(logctx, AV_LOG_DEBUG, "out PTS %"PRId64", %dx%d, " + "%zu/%zu/%zu/%zu, " + "SAR %d:%d, " + "hasEnhancement %d, enhanced %d\n", + out->pts, out->width, out->height, + out->crop_top, out->crop_bottom, out->crop_left, out->crop_right, + out->sample_aspect_ratio.num, out->sample_aspect_ratio.den, + info.hasEnhancement, info.enhanced); + res = LCEVC_FreePicture(lcevc->decoder, picture); if (res != LCEVC_Success) return AVERROR_EXTERNAL; @@ -256,6 +269,10 @@ static void lcevc_free(AVRefStructOpaque unused, void *obj) lcevc_flush_pictures(lcevc); LCEVC_DestroyDecoder(lcevc->decoder); } + if (lcevc->frag) + ff_cbs_fragment_free(lcevc->frag); + av_freep(&lcevc->frag); + ff_cbs_close(&lcevc->cbc); memset(lcevc, 0, sizeof(*lcevc)); } @@ -313,14 +330,74 @@ int ff_lcevc_process(void *logctx, AVFrame *frame) return 0; } -int ff_lcevc_alloc(FFLCEVCContext **plcevc) +int ff_lcevc_parse_frame(FFLCEVCContext *lcevc, const AVFrame *frame, + int *width, int *height, void *logctx) +{ + LCEVCRawProcessBlock *block = NULL; + LCEVCRawGlobalConfig *gc = NULL; + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_LCEVC); + int ret; + + ret = ff_cbs_read(lcevc->cbc, lcevc->frag, sd->buf, sd->data, sd->size); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "Failed to parse Access Unit.\n"); + goto end; + } + + ret = ff_cbs_lcevc_find_process_block(lcevc->cbc, lcevc->frag, + LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG, &block); + if (ret < 0) { + ret = 0; + goto end; + } + + gc = block->payload; + if (gc->resolution_type < 63) { + *width = ff_lcevc_resolution_type[gc->resolution_type].width; + *height = ff_lcevc_resolution_type[gc->resolution_type].height; + } else { + *width = gc->custom_resolution_width; + *height = gc->custom_resolution_height; + } + + ret = 0; +end: + ff_cbs_fragment_reset(lcevc->frag); + + return ret; +} + +static const CodedBitstreamUnitType decompose_unit_types[] = { + LCEVC_IDR_NUT, +}; + +int ff_lcevc_alloc(FFLCEVCContext **plcevc, void *logctx) { FFLCEVCContext *lcevc = NULL; + int ret; + lcevc = av_refstruct_alloc_ext(sizeof(*lcevc), 0, NULL, lcevc_free); if (!lcevc) return AVERROR(ENOMEM); + + lcevc->frag = av_mallocz(sizeof(*lcevc->frag)); + if (!lcevc->frag) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = ff_cbs_init(&lcevc->cbc, AV_CODEC_ID_LCEVC, logctx); + if (ret < 0) + goto fail; + + lcevc->cbc->decompose_unit_types = decompose_unit_types; + lcevc->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); + *plcevc = lcevc; return 0; +fail: + av_refstruct_unref(&lcevc); + return ret; } void ff_lcevc_unref(void *opaque) diff --git a/libavcodec/lcevcdec.h b/libavcodec/lcevcdec.h index 62014132d9..a65214344d 100644 --- a/libavcodec/lcevcdec.h +++ b/libavcodec/lcevcdec.h @@ -28,8 +28,13 @@ typedef uintptr_t LCEVC_DecoderHandle; #endif +struct CodedBitstreamContext; +struct CodedBitstreamFragment; + typedef struct FFLCEVCContext { LCEVC_DecoderHandle decoder; + struct CodedBitstreamContext *cbc; + struct CodedBitstreamFragment *frag; int initialized; } FFLCEVCContext; @@ -40,7 +45,9 @@ typedef struct FFLCEVCFrame { struct AVFrame *frame; } FFLCEVCFrame; -int ff_lcevc_alloc(FFLCEVCContext **plcevc); +int ff_lcevc_alloc(FFLCEVCContext **plcevc, void *logctx); int ff_lcevc_process(void *logctx, struct AVFrame *frame); +int ff_lcevc_parse_frame(FFLCEVCContext *lcevc, const struct AVFrame *frame, + int *width, int *height, void *logctx); void ff_lcevc_unref(void *opaque); #endif /* AVCODEC_LCEVCDEC_H */ diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 2115d4204d..c2853086ce 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -403,6 +403,7 @@ FF_ENABLE_DEPRECATION_WARNINGS dst->hwaccel_flags = src->hwaccel_flags; av_refstruct_replace(&dst->internal->pool, src->internal->pool); + ff_decode_internal_sync(dst, src); } if (for_user) { _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
