PR #24744 opened by Forgejo_Fairy
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24744
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24744.patch

Fixes #23945.

Subtitle decoders use the dedicated `decode_sub` callback and return 
`AVSubtitle`, while the send/receive API is defined for audio and video 
`AVFrame` output. Calling `avcodec_send_packet()` on an opened subtitle decoder 
currently enters the frame decoding path, invokes the callback union through 
its incompatible `decode` member, and reaches an unconditional assertion.

Reject media types other than audio and video at the public packet-submission 
boundary. Also clarify the API documentation and add a FATE API regression test 
using the PGS subtitle decoder.

Before the change, the regression test aborts in `decode_simple_internal()` 
with exit status 134. After the change, `avcodec_send_packet()` returns 
`AVERROR(EINVAL)`.

Tested with:

- `make fate-api-send-packet-media-type`
- `make fate-api`
- `make fate` under a minimal PGS-decoder configuration


>From a5643a08348a60e01d857e20262cb0e0f707314d Mon Sep 17 00:00:00 2001
From: Michael Niedermayer <[email protected]>
Date: Sun, 27 Sep 2026 20:51:31 +0000
Subject: [PATCH] avcodec/decode: reject non-audio/video send_packet calls

The send/receive API outputs AVFrames and does not support subtitle decoders. 
Reject unsupported media types before entering the frame decoding path, where a 
subtitle decoder would otherwise be invoked through the wrong callback union 
member and reach an assertion.

Add an API regression test and clarify the public API documentation.

Assisted-by: Fairy
---
 libavcodec/avcodec.h                        |  5 +-
 libavcodec/decode.c                         |  4 ++
 tests/api/Makefile                          |  1 +
 tests/api/api-send-packet-media-type-test.c | 52 +++++++++++++++++++++
 tests/fate/api.mak                          |  4 ++
 tests/ref/fate/api-send-packet-media-type   |  1 +
 6 files changed, 65 insertions(+), 2 deletions(-)
 create mode 100644 tests/api/api-send-packet-media-type-test.c
 create mode 100644 tests/ref/fate/api-send-packet-media-type

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 1b3eaa799c..a6a86e5dad 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -2354,7 +2354,7 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, 
AVSubtitle *sub,
                              int *got_sub_ptr, const AVPacket *avpkt);
 
 /**
- * Supply raw packet data as input to a decoder.
+ * Supply raw packet data as input to an audio or video decoder.
  *
  * Internally, this call will copy relevant AVCodecContext fields, which can
  * influence decoding per-packet, and apply them when the packet is actually
@@ -2395,7 +2395,8 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, 
AVSubtitle *sub,
  * @retval AVERROR_EOF       the decoder has been flushed, and no new packets 
can be
  *                           sent to it (also returned if more than 1 flush
  *                           packet is sent)
- * @retval AVERROR(EINVAL)   codec not opened, it is an encoder, or requires 
flush
+ * @retval AVERROR(EINVAL)   codec not opened, it is an encoder, its media 
type is
+ *                           neither audio nor video, or it requires flush
  * @retval AVERROR(ENOMEM)   failed to add packet to internal queue, or similar
  * @retval "another negative error code" legitimate decoding errors
  */
diff --git a/libavcodec/decode.c b/libavcodec/decode.c
index 94dfc06a84..797606f6d0 100644
--- a/libavcodec/decode.c
+++ b/libavcodec/decode.c
@@ -740,6 +740,10 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext 
*avctx, const AVPacke
     if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec))
         return AVERROR(EINVAL);
 
+    if (avctx->codec_type != AVMEDIA_TYPE_VIDEO &&
+        avctx->codec_type != AVMEDIA_TYPE_AUDIO)
+        return AVERROR(EINVAL);
+
     if (dc->draining_started)
         return AVERROR_EOF;
 
diff --git a/tests/api/Makefile b/tests/api/Makefile
index f2738d4cba..0950fe99ed 100644
--- a/tests/api/Makefile
+++ b/tests/api/Makefile
@@ -4,6 +4,7 @@ APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264
 APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264-slice
 APITESTPROGS-$(CONFIG_MOV_MUXER)        += api-movenc
 APITESTPROGS-$(CONFIG_MOVTEXT_ENCODER)  += api-movtext
+APITESTPROGS-$(CONFIG_PGSSUB_DECODER)   += api-send-packet-media-type
 APITESTPROGS-yes += api-seek api-dump-stream-meta
 APITESTPROGS-$(call DEMDEC, H263, H263) += api-band
 APITESTPROGS-$(HAVE_THREADS) += api-threadmessage
diff --git a/tests/api/api-send-packet-media-type-test.c 
b/tests/api/api-send-packet-media-type-test.c
new file mode 100644
index 0000000000..53ba92e7e7
--- /dev/null
+++ b/tests/api/api-send-packet-media-type-test.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+
+#include "libavcodec/avcodec.h"
+#include "libavutil/error.h"
+
+int main(void)
+{
+    const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_HDMV_PGS_SUBTITLE);
+    AVCodecContext *ctx = NULL;
+    AVPacket *pkt = NULL;
+    int ret = 1;
+
+    if (!codec)
+        goto end;
+
+    ctx = avcodec_alloc_context3(codec);
+    pkt = av_packet_alloc();
+    if (!ctx || !pkt)
+        goto end;
+
+    if (avcodec_open2(ctx, codec, NULL) < 0 ||
+        av_new_packet(pkt, 1) < 0)
+        goto end;
+    pkt->data[0] = 0;
+
+    ret = avcodec_send_packet(ctx, pkt);
+    printf("send_packet: %s\n", av_err2str(ret));
+    ret = ret < 0 ? 0 : 1;
+
+end:
+    av_packet_free(&pkt);
+    avcodec_free_context(&ctx);
+    return ret;
+}
diff --git a/tests/fate/api.mak b/tests/fate/api.mak
index a10edfe4da..1657d35032 100644
--- a/tests/fate/api.mak
+++ b/tests/fate/api.mak
@@ -11,6 +11,10 @@ FATE_API_LIBAVCODEC-$(CONFIG_MOVTEXT_ENCODER) += 
fate-api-movtext
 fate-api-movtext: $(APITESTSDIR)/api-movtext-test$(EXESUF)
 fate-api-movtext: CMD = run $(APITESTSDIR)/api-movtext-test$(EXESUF)
 
+FATE_API_LIBAVCODEC-$(CONFIG_PGSSUB_DECODER) += fate-api-send-packet-media-type
+fate-api-send-packet-media-type: 
$(APITESTSDIR)/api-send-packet-media-type-test$(EXESUF)
+fate-api-send-packet-media-type: CMD = run 
$(APITESTSDIR)/api-send-packet-media-type-test$(EXESUF)
+
 FATE_API_LIBAVCODEC-$(call ALLYES, H261_ENCODER H261_PARSER) += 
fate-api-enc-parser fate-api-enc-parser-cif
 fate-api-enc-parser: $(APITESTSDIR)/api-enc-parser-test$(EXESUF)
 fate-api-enc-parser: CMD = run $(APITESTSDIR)/api-enc-parser-test$(EXESUF) 
h261 176 144
diff --git a/tests/ref/fate/api-send-packet-media-type 
b/tests/ref/fate/api-send-packet-media-type
new file mode 100644
index 0000000000..f5f20447d0
--- /dev/null
+++ b/tests/ref/fate/api-send-packet-media-type
@@ -0,0 +1 @@
+send_packet: Invalid argument
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to