mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-11-06 05:17:42 +00:00
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:
1 parent
c5aa31d252
commit
49d75d81f6
4 files changed
+120
-13
No files matched your search
+33
-11
@@ -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
@@ -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)
|
||||
|
||||
@@ -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 */
|
||||
@@ -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) {
|
||||
|
||||
Reference in new issue
Block a user