From b6c604a15bc340a727fc0218fb1ee1f499bfa495 Mon Sep 17 00:00:00 2001 From: touki Date: Fri, 31 Jul 2026 23:42:10 +0800 Subject: [PATCH 1/2] Convert P010/P016 hardware-decoder frames to 8-bit before analysis Hardware decoders emit P010LE (not YUV420P10LE) for 10-bit HEVC, so the 8-bit conversion from #143 was skipped and frames were processed as a double-width 8-bit buffer, corrupting brightness, uniformity and logo metrics on Main10 sources. --- mpeg2dec.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mpeg2dec.c b/mpeg2dec.c index c1d586d..314950c 100755 --- a/mpeg2dec.c +++ b/mpeg2dec.c @@ -1388,7 +1388,10 @@ static int prev_strange_framenum = 0; { frameFinished = 1; // convert to 8bit - if (is->pFrame->format == AV_PIX_FMT_YUV420P10LE) { + if (is->pFrame->format == AV_PIX_FMT_YUV420P10LE || + is->pFrame->format == AV_PIX_FMT_P010LE || + is->pFrame->format == AV_PIX_FMT_P016LE || + is->pFrame->format == AV_PIX_FMT_YUV420P12LE) { is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx, is->pFrame->width, is->pFrame->height, is->pFrame->format, is->pFrame->width, is->pFrame->height, AV_PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL); AVFrame *newframe = av_frame_alloc(); av_frame_copy_props(newframe, is->pFrame); From fa73f626d46a0a8e5b37631cd62307f199eb8cc2 Mon Sep 17 00:00:00 2001 From: Eric Lindvall Date: Sun, 30 Aug 2026 11:29:47 -0700 Subject: [PATCH 2/2] Convert any frame without 8-bit luma, free the replaced frame Decide the 8-bit conversion by the pixel format's luma depth instead of listing formats, so 12-bit and 4:4:4 hardware outputs are covered too. Free the decoder frame it replaces, which leaked one AVFrame per converted frame, and skip the frame when allocation fails. SubmitFrame refuses a frame that is still not 8-bit instead of reading it as a wider buffer. --- mpeg2dec.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/mpeg2dec.c b/mpeg2dec.c index 314950c..d37823b 100755 --- a/mpeg2dec.c +++ b/mpeg2dec.c @@ -1020,9 +1020,12 @@ int SubmitFrame(AVStream *video_st, AVFrame *pFrame , double pts) int res=0; int changed = 0; int line = 0; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pFrame->format); - if (pFrame->format == AV_PIX_FMT_YUV420P10LE) { - line = 1; + if (!desc || desc->comp[0].depth != 8) { + Debug(1, "Panic: frame format %s is not 8-bit\n", desc ? desc->name : "?"); + frame_ptr = NULL; + return(0); } // bitrate = pFrame->bit_rate; @@ -1387,20 +1390,29 @@ static int prev_strange_framenum = 0; while ((len1 = avcodec_receive_frame(is->dec_ctx, is->pFrame)) >= 0) { frameFinished = 1; - // convert to 8bit - if (is->pFrame->format == AV_PIX_FMT_YUV420P10LE || - is->pFrame->format == AV_PIX_FMT_P010LE || - is->pFrame->format == AV_PIX_FMT_P016LE || - is->pFrame->format == AV_PIX_FMT_YUV420P12LE) { + // convert anything without 8-bit luma to 8-bit + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(is->pFrame->format); + if (desc && desc->comp[0].depth != 8) { is->img_convert_ctx = sws_getCachedContext(is->img_convert_ctx, is->pFrame->width, is->pFrame->height, is->pFrame->format, is->pFrame->width, is->pFrame->height, AV_PIX_FMT_YUV420P, SWS_POINT, NULL, NULL, NULL); AVFrame *newframe = av_frame_alloc(); + if (!is->img_convert_ctx || !newframe) { + Debug(1, "Cannot convert %s frames to 8-bit\n", desc->name); + av_frame_free(&newframe); + av_frame_unref(is->pFrame); + continue; + } av_frame_copy_props(newframe, is->pFrame); newframe->format = AV_PIX_FMT_YUV420P; newframe->width = is->pFrame->width; newframe->height = is->pFrame->height; - av_frame_get_buffer(newframe, 0); + if (av_frame_get_buffer(newframe, 0) < 0) { + Debug(1, "Cannot allocate an 8-bit frame\n"); + av_frame_free(&newframe); + av_frame_unref(is->pFrame); + continue; + } sws_scale(is->img_convert_ctx, (const uint8_t * const *)is->pFrame->data, is->pFrame->linesize, 0, is->pFrame->height, newframe->data, newframe->linesize); - av_frame_unref(is->pFrame); + av_frame_free(&is->pFrame); is->pFrame = newframe; }