Commit 9edc0748b6 for ffmpeg

commit 9edc0748b680b1325cc0c1a49e8f1baaba6bb038
Author: Romain Beauxis <romain.beauxis@gmail.com>
Date:   Sat Oct 17 12:24:58 2026 +0200

    tests/api: add a test of the samples skipped and discarded by decoders

    Decode one PCM packet carrying AV_PKT_DATA_SKIP_SAMPLES and print how
    many samples are output, for samples skipped at the start of the frame
    and padding discarded at its end, alone, together, overlapping, and with
    a padding larger than the frame.

    The reference records the current behaviour.

diff --git a/tests/api/Makefile b/tests/api/Makefile
index e51dc6c583..7da5f6da32 100644
--- a/tests/api/Makefile
+++ b/tests/api/Makefile
@@ -9,6 +9,7 @@ APITESTPROGS-yes += api-seek api-dump-stream-meta
 APITESTPROGS-$(call DEMDEC, H263, H263) += api-band
 APITESTPROGS-$(HAVE_THREADS) += api-threadmessage
 APITESTPROGS-$(CONFIG_AVCODEC) += api-enc-info
+APITESTPROGS-$(CONFIG_PCM_S16LE_DECODER) += api-skip-samples
 APITESTPROGS-$(call ALLYES, H261_ENCODER H261_PARSER) += api-enc-parser
 APITESTPROGS += $(APITESTPROGS-yes)

diff --git a/tests/api/api-skip-samples-test.c b/tests/api/api-skip-samples-test.c
new file mode 100644
index 0000000000..7ae2dc8d4f
--- /dev/null
+++ b/tests/api/api-skip-samples-test.c
@@ -0,0 +1,114 @@
+/*
+ * 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
+ */
+
+/**
+ * Decode one packet carrying AV_PKT_DATA_SKIP_SAMPLES and print how many
+ * samples are output, for skips at the start and padding at the end of the
+ * frame, alone, together and overlapping.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "libavcodec/avcodec.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/macros.h"
+
+#define FRAME_SAMPLES 1000
+
+static int decoded_samples(uint32_t skip, uint32_t discard)
+{
+    const AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_PCM_S16LE);
+    AVCodecContext *ctx = NULL;
+    AVPacket *pkt = NULL;
+    AVFrame *frame = NULL;
+    uint8_t *side;
+    int nb_samples = 0;
+    int ret;
+
+    ctx   = avcodec_alloc_context3(codec);
+    pkt   = av_packet_alloc();
+    frame = av_frame_alloc();
+    if (!ctx || !pkt || !frame) {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+
+    ctx->sample_rate  = 48000;
+    ctx->pkt_timebase = (AVRational){ 1, 48000 };
+    av_channel_layout_default(&ctx->ch_layout, 1);
+    ret = avcodec_open2(ctx, codec, NULL);
+    if (ret < 0)
+        goto end;
+
+    ret = av_new_packet(pkt, FRAME_SAMPLES * 2);
+    if (ret < 0)
+        goto end;
+    memset(pkt->data, 0, pkt->size);
+    pkt->pts = 0;
+    side = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
+    if (!side) {
+        ret = AVERROR(ENOMEM);
+        goto end;
+    }
+    AV_WL32(side, skip);
+    AV_WL32(side + 4, discard);
+
+    ret = avcodec_send_packet(ctx, pkt);
+    if (ret < 0)
+        goto end;
+    ret = avcodec_send_packet(ctx, NULL);
+    if (ret < 0)
+        goto end;
+    while ((ret = avcodec_receive_frame(ctx, frame)) >= 0) {
+        nb_samples += frame->nb_samples;
+        av_frame_unref(frame);
+    }
+    ret = ret == AVERROR_EOF ? nb_samples : ret;
+
+end:
+    av_frame_free(&frame);
+    av_packet_free(&pkt);
+    avcodec_free_context(&ctx);
+    return ret;
+}
+
+int main(void)
+{
+    static const uint32_t cases[][2] = {
+        {   0,    0 },
+        { 300,    0 },
+        {   0,  400 },
+        { 300,  400 },
+        { 300,  700 },
+        { 300,  800 },
+        { 300, 1100 },
+    };
+
+    for (int i = 0; i < FF_ARRAY_ELEMS(cases); i++) {
+        int ret = decoded_samples(cases[i][0], cases[i][1]);
+        if (ret < 0) {
+            fprintf(stderr, "decoding failed: %s\n", av_err2str(ret));
+            return 1;
+        }
+        printf("frame %d skip %4"PRIu32" discard %4"PRIu32": %d samples\n",
+               FRAME_SAMPLES, cases[i][0], cases[i][1], ret);
+    }
+    return 0;
+}
diff --git a/tests/fate/api.mak b/tests/fate/api.mak
index ca836a40e3..7b90e3dd3b 100644
--- a/tests/fate/api.mak
+++ b/tests/fate/api.mak
@@ -7,6 +7,10 @@ fate-api-flac: $(APITESTSDIR)/api-flac-test$(EXESUF)
 fate-api-flac: CMD = run $(APITESTSDIR)/api-flac-test$(EXESUF)
 fate-api-flac: CMP = null

+FATE_API_LIBAVCODEC-$(CONFIG_PCM_S16LE_DECODER) += fate-api-skip-samples
+fate-api-skip-samples: $(APITESTSDIR)/api-skip-samples-test$(EXESUF)
+fate-api-skip-samples: CMD = run $(APITESTSDIR)/api-skip-samples-test$(EXESUF)
+
 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)
diff --git a/tests/ref/fate/api-skip-samples b/tests/ref/fate/api-skip-samples
new file mode 100644
index 0000000000..b182d5dcdf
--- /dev/null
+++ b/tests/ref/fate/api-skip-samples
@@ -0,0 +1,7 @@
+frame 1000 skip    0 discard    0: 1000 samples
+frame 1000 skip  300 discard    0: 700 samples
+frame 1000 skip    0 discard  400: 600 samples
+frame 1000 skip  300 discard  400: 300 samples
+frame 1000 skip  300 discard  700: 0 samples
+frame 1000 skip  300 discard  800: 700 samples
+frame 1000 skip  300 discard 1100: 700 samples