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 <jamrial@gmail.com>
This commit is contained in:
James Almer committed 2026-03-13 09:18:42 -03:00
1 parent c5aa31d252
commit 49d75d81f6
4 files changed
+120 -13

No files matched your search

+33 -11
View File
@@ -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
}
+78 -1
View File
@@ -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)
+8 -1
View File
@@ -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 */
+1
View File
@@ -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) {