PR #24436 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24436 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24436.patch
>From 7caa4d585b28d42e2283f0b5a770cb523023d022 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 10 Sep 2026 00:03:40 -0300 Subject: [PATCH 1/4] avcodec/libxevd: set picture type and keyframe flag on the correct frames The picture returned by xevd_pull() is not necessarely the one generated from the packet last sent with xevd_decode(). Signed-off-by: James Almer <[email protected]> --- libavcodec/libxevd.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/libavcodec/libxevd.c b/libavcodec/libxevd.c index 520fdab7d8..28f3cc529c 100644 --- a/libavcodec/libxevd.c +++ b/libavcodec/libxevd.c @@ -27,6 +27,7 @@ #include "libavutil/internal.h" #include "libavutil/common.h" +#include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" #include "libavutil/imgutils.h" @@ -295,7 +296,8 @@ static int libxevd_return_frame(AVCodecContext *avctx, AVFrame *frame, frame->pkt_dts = imgb->ts[XEVD_TS_DTS]; frame->pts = imgb->ts[XEVD_TS_PTS]; - av_packet_free(&pkt_au_imgb); + av_packet_free((AVPacket**)&imgb->pdata[0]); + av_freep(&imgb->pdata[1]); // xevd_pull uses pool of objects of type XEVD_IMGB. // The pool size is equal MAX_PB_SIZE (26), so release object when it is no more needed @@ -364,13 +366,20 @@ static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame) bitb.addr = pkt_au->data + bs_read_pos; bitb.ssize = nalu_size; bitb.pdata[0] = pkt_au; + bitb.pdata[1] = av_mallocz(sizeof(stat.stype)); bitb.ts[XEVD_TS_DTS] = pkt_au->dts; + if (!bitb.pdata[1]) { + av_packet_free(&pkt_au); + return AVERROR(ENOMEM); + } + /* main decoding block */ xevd_ret = xevd_decode(xectx->id, &bitb, &stat); if (XEVD_FAILED(xevd_ret)) { av_log(avctx, AV_LOG_ERROR, "Failed to decode bitstream\n"); av_packet_free(&pkt_au); + av_freep(&bitb.pdata[1]); return AVERROR_EXTERNAL; } @@ -391,6 +400,8 @@ static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame) // stat.fnum - has negative value if the decoded data is not frame if (stat.fnum >= 0) { + // store stat.stype into the bitb.pdata[1] that will be retrieved in an image + *(int*)bitb.pdata[1] = stat.stype; xevd_ret = xevd_pull(xectx->id, &imgb); // The function returns a valid image only if the return code is XEVD_OK @@ -413,7 +424,7 @@ static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame) return AVERROR(EAGAIN); } } else { - if (stat.stype == XEVD_ST_I) { + if (*(int*)imgb->pdata[1] == XEVD_ST_I) { frame->pict_type = AV_PICTURE_TYPE_I; frame->flags |= AV_FRAME_FLAG_KEY; } @@ -441,6 +452,10 @@ static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame) return AVERROR_EXTERNAL; } + if (*(int*)imgb->pdata[1] == XEVD_ST_I) { + frame->pict_type = AV_PICTURE_TYPE_I; + frame->flags |= AV_FRAME_FLAG_KEY; + } return libxevd_return_frame(avctx, frame, imgb, NULL); } } -- 2.52.0 >From ea0b99e8b4b613b94a50d108ac07c09e281ece0b Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 10 Sep 2026 00:04:22 -0300 Subject: [PATCH 2/4] avcodec/libxevd: rename to libxevd "evc" must be used only by an eventual native decoder. Signed-off-by: James Almer <[email protected]> --- libavcodec/libxevd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/libxevd.c b/libavcodec/libxevd.c index 28f3cc529c..ab7a2ebee2 100644 --- a/libavcodec/libxevd.c +++ b/libavcodec/libxevd.c @@ -484,7 +484,7 @@ static av_cold int libxevd_close(AVCodecContext *avctx) } const FFCodec ff_libxevd_decoder = { - .p.name = "evc", + .p.name = "libxevd", CODEC_LONG_NAME("EVC / MPEG-5 Essential Video Coding (EVC)"), .p.type = AVMEDIA_TYPE_VIDEO, .p.id = AV_CODEC_ID_EVC, -- 2.52.0 >From e8bca7e6ba56be673b80ebca0ad4b3eb9aedfe46 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 10 Sep 2026 00:14:12 -0300 Subject: [PATCH 3/4] avcodec/libxevd: fix draining code when unexpected codes are returned libxevd appears to return positive values other than XEVD_OK in some circumstances, which resulted in an endless loop of the decoder returning AVERROR_EXTERNAL until stopped. Signed-off-by: James Almer <[email protected]> --- libavcodec/libxevd.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/libavcodec/libxevd.c b/libavcodec/libxevd.c index ab7a2ebee2..5810f6676c 100644 --- a/libavcodec/libxevd.c +++ b/libavcodec/libxevd.c @@ -435,28 +435,32 @@ static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame) } } else { // decoder draining mode handling - xevd_ret = xevd_pull(xectx->id, &imgb); + while (1) { + xevd_ret = xevd_pull(xectx->id, &imgb); - if (xevd_ret == XEVD_ERR_UNEXPECTED) { // draining process completed - av_log(avctx, AV_LOG_DEBUG, "Draining process completed\n"); + if (xevd_ret == XEVD_ERR_UNEXPECTED) { // draining process completed + av_log(avctx, AV_LOG_DEBUG, "Draining process completed\n"); - return AVERROR_EOF; - } else if (XEVD_FAILED(xevd_ret)) { // handle all other errors - av_log(avctx, AV_LOG_ERROR, "Failed to pull the decoded image (xevd error code: %d)\n", xevd_ret); - - return AVERROR_EXTERNAL; - } else { // XEVD_OK - if (!imgb) { - av_log(avctx, AV_LOG_ERROR, "Invalid decoded image data\n"); + return AVERROR_EOF; + } else if (XEVD_FAILED(xevd_ret)) { // handle all other errors + av_log(avctx, AV_LOG_ERROR, "Failed to pull the decoded image (xevd error code: %d)\n", xevd_ret); return AVERROR_EXTERNAL; - } + } else if (xevd_ret == XEVD_OK) { + if (!imgb) { + av_log(avctx, AV_LOG_ERROR, "Invalid decoded image data\n"); - if (*(int*)imgb->pdata[1] == XEVD_ST_I) { - frame->pict_type = AV_PICTURE_TYPE_I; - frame->flags |= AV_FRAME_FLAG_KEY; + continue; + } + + if (*(int*)imgb->pdata[1] == XEVD_ST_I) { + frame->pict_type = AV_PICTURE_TYPE_I; + frame->flags |= AV_FRAME_FLAG_KEY; + } + return libxevd_return_frame(avctx, frame, imgb, NULL); } - return libxevd_return_frame(avctx, frame, imgb, NULL); + av_log(avctx, AV_LOG_WARNING, "Unexpected return code while draining (xevd error code: %d)\n", xevd_ret); + return AVERROR_EOF; } } -- 2.52.0 >From fafb0c72f026c93bf2d6b56a806fa8a20487a05d Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 10 Sep 2026 00:19:39 -0300 Subject: [PATCH 4/4] avcodec/libxevd: remove unused draining_mode variable Signed-off-by: James Almer <[email protected]> --- libavcodec/libxevd.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/libavcodec/libxevd.c b/libavcodec/libxevd.c index 5810f6676c..dd8ffb2f6a 100644 --- a/libavcodec/libxevd.c +++ b/libavcodec/libxevd.c @@ -52,7 +52,6 @@ typedef struct XevdContext { // If end of stream occurs it is required "flushing" (aka draining) the codec, // as the codec might buffer multiple frames or packets internally. - int draining_mode; // The flag is set if codec enters draining mode. AVPacket *pkt; // access unit (a set of NAL units that are consecutive in decoding order and containing exactly one encoded image) } XevdContext; @@ -236,7 +235,6 @@ static av_cold int libxevd_init(AVCodecContext *avctx) return AVERROR_EXTERNAL; } - xectx->draining_mode = 0; xectx->pkt = av_packet_alloc(); if (!xectx->pkt) { av_log(avctx, AV_LOG_ERROR, "Cannot allocate memory for AVPacket\n"); @@ -329,10 +327,6 @@ static int libxevd_receive_frame(AVCodecContext *avctx, AVFrame *frame) av_packet_unref(pkt); return ret; - } else if(ret == AVERROR_EOF && xectx->draining_mode == 0) { // End of stream situations. Enter draining mode - - xectx->draining_mode = 1; - av_packet_unref(pkt); } if (pkt->size > 0) { @@ -481,7 +475,6 @@ static av_cold int libxevd_close(AVCodecContext *avctx) xectx->id = NULL; } - xectx->draining_mode = 0; av_packet_free(&xectx->pkt); return 0; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
