This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

The following commit(s) were added to refs/heads/master by this push:
     new 3a165c77dc bsf: add trim filter.
3a165c77dc is described below

commit 3a165c77dce7fac8c54f9f9aaab5447590433748
Author:     Romain Beauxis <[email protected]>
AuthorDate: Fri Jul 17 11:24:47 2026 -0500
Commit:     Romain Beauxis <[email protected]>
CommitDate: Thu Sep 10 18:23:50 2026 +0000

    bsf: add trim filter.
    
    Drop packets outside a range given as a pts, dts, packet index, millisecond 
or
    duration bound, trimming a packet that straddles a boundary through skip
    samples side data for audio and shifted timestamps otherwise.
    
    Set preroll to export the packets a decoder needs to start on a cut made 
inside
    a group of pictures, flagged for discard so the frames it produces still 
begin
    at the bound.
---
 doc/bitstream_filters.texi                         | 172 +++++
 libavcodec/bitstream_filters.c                     |   1 +
 libavcodec/bsf/Makefile                            |   1 +
 libavcodec/bsf/trim.c                              | 798 +++++++++++++++++++++
 tests/fate/ffmpeg.mak                              | 136 ++++
 tests/ref/fate/ffmpeg-trim-bsf-dts                 |   9 +
 tests/ref/fate/ffmpeg-trim-bsf-dts-duration        |   6 +
 tests/ref/fate/ffmpeg-trim-bsf-dts-pts             |  13 +
 tests/ref/fate/ffmpeg-trim-bsf-duration-zero       |   5 +
 tests/ref/fate/ffmpeg-trim-bsf-gap-end             |   6 +
 tests/ref/fate/ffmpeg-trim-bsf-gap-start           |   6 +
 tests/ref/fate/ffmpeg-trim-bsf-msec                |  24 +
 tests/ref/fate/ffmpeg-trim-bsf-opus-gap-end        |   7 +
 tests/ref/fate/ffmpeg-trim-bsf-opus-gap-start      |   8 +
 tests/ref/fate/ffmpeg-trim-bsf-pkt                 |  15 +
 tests/ref/fate/ffmpeg-trim-bsf-pkt-rel             |  10 +
 tests/ref/fate/ffmpeg-trim-bsf-priming             |  39 +
 tests/ref/fate/ffmpeg-trim-bsf-priming-duration    |  10 +
 tests/ref/fate/ffmpeg-trim-bsf-priming-gap         |   8 +
 .../ref/fate/ffmpeg-trim-bsf-priming-gap-duration  |   7 +
 tests/ref/fate/ffmpeg-trim-bsf-priming-nodur       |   9 +
 tests/ref/fate/ffmpeg-trim-bsf-priming-nopts       |   8 +
 tests/ref/fate/ffmpeg-trim-bsf-priming-untrimmed   |   9 +
 tests/ref/fate/ffmpeg-trim-bsf-pts                 |  14 +
 tests/ref/fate/ffmpeg-trim-bsf-pts-dts             |  10 +
 tests/ref/fate/ffmpeg-trim-bsf-pts-duration        |   6 +
 tests/ref/fate/ffmpeg-trim-bsf-rel                 |   6 +
 tests/ref/fate/ffmpeg-trim-bsf-samples             |  15 +
 tests/ref/fate/ffmpeg-trim-bsf-skip-samples        |   6 +
 tests/ref/fate/ffmpeg-trim-bsf-skip-samples-empty  |   5 +
 tests/ref/fate/ffmpeg-trim-bsf-untrimmed           |  14 +
 tests/ref/fate/ffmpeg-trim-bsf-video-dts           |   9 +
 tests/ref/fate/ffmpeg-trim-bsf-video-dts-duration  |   7 +
 tests/ref/fate/ffmpeg-trim-bsf-video-dts-pts       |  13 +
 tests/ref/fate/ffmpeg-trim-bsf-video-flush         |  71 ++
 tests/ref/fate/ffmpeg-trim-bsf-video-flush-rel     |  69 ++
 tests/ref/fate/ffmpeg-trim-bsf-video-mixed-axes    |   6 +
 .../fate/ffmpeg-trim-bsf-video-mixed-axes-empty    |   5 +
 .../ref/fate/ffmpeg-trim-bsf-video-nopts-duration  |   7 +
 tests/ref/fate/ffmpeg-trim-bsf-video-nopts-empty   |   5 +
 tests/ref/fate/ffmpeg-trim-bsf-video-nopts-rel     |  12 +
 .../ffmpeg-trim-bsf-video-partial-dts-duration     |   8 +
 tests/ref/fate/ffmpeg-trim-bsf-video-pkt           |  15 +
 tests/ref/fate/ffmpeg-trim-bsf-video-preroll       |  31 +
 .../ref/fate/ffmpeg-trim-bsf-video-preroll-decoded |  22 +
 .../fate/ffmpeg-trim-bsf-video-preroll-keyframe    |  20 +
 .../fate/ffmpeg-trim-bsf-video-preroll-on-keyframe |  20 +
 .../fate/ffmpeg-trim-bsf-video-preroll-overflow    |  23 +
 tests/ref/fate/ffmpeg-trim-bsf-video-pts           |  14 +
 tests/ref/fate/ffmpeg-trim-bsf-video-pts-dts       |  10 +
 tests/ref/fate/ffmpeg-trim-bsf-video-pts-duration  |   7 +
 tests/ref/fate/ffmpeg-trim-bsf-video-reordered     |  10 +
 .../ref/fate/ffmpeg-trim-bsf-video-reordered-count |   9 +
 .../ref/fate/ffmpeg-trim-bsf-video-reordered-nodts |  10 +
 tests/ref/fate/ffmpeg-trim-bsf-video-samples       |   8 +
 tests/ref/fate/ffmpeg-trim-bsf-video-untrimmed     |   7 +
 56 files changed, 1801 insertions(+)

diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi
index c6705bbd39..a00757d315 100644
--- a/doc/bitstream_filters.texi
+++ b/doc/bitstream_filters.texi
@@ -1045,6 +1045,178 @@ This can be useful for debugging low-level stream 
issues.
 Supports AV1, H.264, H.265, (M)JPEG, MPEG-2 and VP9, but depending
 on the build only a subset of these may be available.
 
+@section trim
+
+Drop packets outside a given range, similar to the trim and atrim
+filters, but operating on packets instead of decoded frames.
+
+The range is described by a @option{start} and an @option{end} bound. At least
+one of them must be set. Each bound is fully described by three independent
+choices:
+
+@itemize @bullet
+@item
+The discriminant it is compared against: the packet's presentation timestamp,
+its decoding timestamp, or its index. The two bounds need not use the same one,
+for instance a @code{dts} start with a @code{pts} end.
+@item
+The unit its value is given in: the stream time base, milliseconds, or packets.
+@item
+What it is counted from: zero, or its reference packet when @option{start_rel}
+/ @option{end_rel} is set. For @option{start} the reference packet is the first
+packet carrying that discriminant. For @option{end} it is the first exported
+packet.
+@end itemize
+
+The @option{start_type} and @option{end_type} options name a combination of the
+three. The @code{dur_ts} and @code{dur_t_msec} end types are the always 
relative
+forms of @code{pts} and @code{msec_pt}. A zero duration therefore produces an
+empty stream.
+
+Every packet is judged on its own discriminant, and on nothing else. A packet
+not carrying the discriminant its bound uses cannot be placed, and is dropped.
+
+@option{start_rel} makes @option{start} an offset from a reference packet
+instead of an absolute value. The reference is the first packet carrying the
+discriminant that bound uses. Its value is added to the offset once, and the
+bound stays there for the rest of the stream.
+
+@option{end_rel} anchors on the first exported packet instead, at the position
+@option{start} trimmed it to. The two bounds therefore move together.
+
+Only a discriminant that cannot come back into the range ends the stream, 
namely
+the packet index or the decoding timestamp. End of stream is signaled once one
+of those passes the @option{end} bound. A presentation timestamp past the end
+only drops its packet, so that later packets still inside the range are not
+lost.
+
+A bound given in a time unit can fall inside a packet rather than between two.
+Such a packet is trimmed. Set @option{trim_packets} to false to keep every
+packet exactly as it came in: exported whole if its own value is inside the
+range, dropped otherwise.
+
+Audio is trimmed in sample space, through skip samples side data. The 
timestamps
+and duration are left untouched, and a decoder discards the signaled samples on
+output. This needs a sample rate and a time base. Audio missing either is
+rejected rather than trimmed on the timeline. Every other media type is trimmed
+by shifting the packet timestamps and shortening its duration.
+
+Trimming inside an audio packet needs the number of samples it decodes to. 
Where
+the codec does not give that number, the packet is handled as though
+@option{trim_packets} were false.
+
+A skip larger than the packet carrying it continues into the packets after it.
+Dropping such a packet carries the remainder over to the next one. A skip that
+packet already carries replaces the remainder, as a decoder would, and the
+larger of it and this filter's own trim wins.
+
+By default a packet outside the range is dropped, whether or not later packets
+depend on it. Streams of independent frames, such as ADTS or intra only video,
+can be cut anywhere. Cutting an inter coded stream inside a group of pictures
+leaves the first packets in range undecodable.
+
+Set @option{preroll} to export the packets those first packets depend on as
+well. They are flagged for a decoder to decode and then drop, so the frames it
+outputs still begin at the @option{start} bound. Only a decoder acts on that
+flag. Use @option{preroll} where the stream is decoded. A muxer writes the 
extra
+packets like any other. A remux then covers more than the requested range.
+
+@option{preroll} covers the start of the range only. On a stream with B-frames
+an @option{end} bound on the presentation timestamp can drop a packet the last
+frames in the range need. Those frames then decode incorrectly.
+
+It accepts the following parameters:
+@table @option
+@item start
+Time or index marking the start of the accepted range. Packets before it are
+dropped. A packet straddling it is trimmed at its start, or dropped when
+@option{trim_packets} is false.
+
+@item start_type
+How to interpret @option{start}:
+@table @samp
+@item pts
+Presentation timestamp, in stream time base (default).
+@item dts
+Decoding timestamp, in stream time base.
+@item pkt_index
+Packet index, counting from zero.
+@item msec_pt
+Milliseconds, matched against the presentation timestamp.
+@item msec_dt
+Milliseconds, matched against the decoding timestamp.
+@end table
+
+@item start_rel
+Count @option{start} from the reference packet rather than from zero. Has no
+effect on @samp{pkt_index}, whose first packet is already zero. Default false.
+
+@item end
+Time or index marking the end of the accepted range. Signals end of stream when
+reached. A packet straddling it is trimmed at its end, or exported untouched
+when @option{trim_packets} is false.
+
+@item end_type
+How to interpret @option{end}. Same values as @option{start_type}, plus:
+@table @samp
+@item dur_ts
+Duration in stream time base. Same as @samp{pts} with @option{end_rel} set.
+@item dur_t_msec
+Duration in milliseconds. Same as @samp{msec_pt} with @option{end_rel} set.
+@end table
+
+@item end_rel
+Count @option{end} from the first exported packet rather than from zero. The
+reference is that packet's value on the discriminant @option{end_type} names. 
On
+a timestamp it is taken at the position the packet is trimmed to. For audio 
that
+is the time of its first retained sample. The skip that packet carries can push
+it past the packet itself. With @samp{pkt_index} it exports a fixed number of
+packets, which can be combined with a timestamp-based @option{start}. Always 
set
+for the duration types. Default false.
+
+@item trim_packets
+Trim packets straddling a boundary. When false, packets are exported exactly as
+they came in, with no timestamp adjustment and no skip samples side data. A
+packet is then exported untouched if its value falls inside the range, and
+dropped otherwise. Default true.
+
+@item preroll
+Export the packets a decoder needs to decode the first packet in range, rather
+than dropping them for falling before the @option{start} bound. The filter 
holds
+every packet from the last keyframe on. It exports them ahead of the first
+packet in range, carrying @code{AV_PKT_FLAG_DISCARD}.
+
+Video only. Default false.
+
+@item preroll_size
+Maximum number of packets held for @option{preroll}. A group of pictures longer
+than this is dropped whole, with a warning naming the count to raise it past.
+Default 300, which covers the keyframe intervals encoders commonly default to.
+@end table
+
+For example, to keep only the 10 first packets of an ADTS stream:
+@example
+ffmpeg -i INPUT.aac -c copy -bsf:a trim=end=10:end_type=pkt_index OUTPUT.aac
+@end example
+
+To keep 5 seconds starting 1.5 seconds into the stream:
+@example
+ffmpeg -i INPUT.aac -c copy -bsf:a 
trim=start=1500:start_type=msec_pt:end=5000:end_type=dur_t_msec OUTPUT.aac
+@end example
+
+The same, expressed relative to the first packet so it works regardless of the
+stream's starting timestamp:
+@example
+ffmpeg -i INPUT.aac -c copy -bsf:a 
trim=start=1500:start_type=msec_pt:start_rel=1:end=5000:end_type=dur_t_msec 
OUTPUT.aac
+@end example
+
+To start on a keyframeless point of an inter coded video stream, re-encoding it
+so that the preroll is decoded rather than written out. The filter must run
+before the decoder, so it is given before the input:
+@example
+ffmpeg -bsf:v 
trim=start=17000:start_type=msec_pt:end=30000:end_type=dur_t_msec:preroll=1 -i 
INPUT.mp4 OUTPUT.mp4
+@end example
+
 @section truehd_core
 
 Extract the core from a TrueHD stream, dropping ATMOS data.
diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c
index a9f3218f0f..f57c2632a0 100644
--- a/libavcodec/bitstream_filters.c
+++ b/libavcodec/bitstream_filters.c
@@ -69,6 +69,7 @@ extern const FFBitStreamFilter ff_showinfo_bsf;
 extern const FFBitStreamFilter ff_smpte436m_to_eia608_bsf;
 extern const FFBitStreamFilter ff_text2movsub_bsf;
 extern const FFBitStreamFilter ff_trace_headers_bsf;
+extern const FFBitStreamFilter ff_trim_bsf;
 extern const FFBitStreamFilter ff_truehd_core_bsf;
 extern const FFBitStreamFilter ff_vp9_metadata_bsf;
 extern const FFBitStreamFilter ff_vp9_raw_reorder_bsf;
diff --git a/libavcodec/bsf/Makefile b/libavcodec/bsf/Makefile
index abbd4be49e..ec224e8774 100644
--- a/libavcodec/bsf/Makefile
+++ b/libavcodec/bsf/Makefile
@@ -50,6 +50,7 @@ OBJS-$(CONFIG_SHOWINFO_BSF)               += bsf/showinfo.o
 OBJS-$(CONFIG_SMPTE436M_TO_EIA608_BSF)    += bsf/smpte436m_to_eia608.o
 OBJS-$(CONFIG_TEXT2MOVSUB_BSF)            += bsf/movsub.o
 OBJS-$(CONFIG_TRACE_HEADERS_BSF)          += bsf/trace_headers.o
+OBJS-$(CONFIG_TRIM_BSF)                   += bsf/trim.o
 OBJS-$(CONFIG_TRUEHD_CORE_BSF)            += bsf/truehd_core.o
 OBJS-$(CONFIG_VP9_METADATA_BSF)           += bsf/vp9_metadata.o
 OBJS-$(CONFIG_VP9_RAW_REORDER_BSF)        += bsf/vp9_raw_reorder.o
diff --git a/libavcodec/bsf/trim.c b/libavcodec/bsf/trim.c
new file mode 100644
index 0000000000..a9a54a9410
--- /dev/null
+++ b/libavcodec/bsf/trim.c
@@ -0,0 +1,798 @@
+/*
+ * 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 "libavutil/fifo.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "libavutil/timestamp.h"
+
+#include "libavcodec/bsf.h"
+#include "libavcodec/bsf_internal.h"
+
+enum TrimType {
+    TRIM_PTS,
+    TRIM_DTS,
+    TRIM_PKT_INDEX,
+    TRIM_MSEC_PT,
+    TRIM_MSEC_DT,
+    TRIM_DUR_TS,
+    TRIM_DUR_T_MSEC,
+};
+
+/* The packet discriminant a bound is compared against; the indexes count 
consumed
+ * and exported packets. */
+enum TrimAxis {
+    AXIS_PTS,
+    AXIS_DTS,
+    AXIS_INDEX,
+    AXIS_OUT_INDEX,
+};
+
+/* An axis, a unit, and whether the value is relative; the duration types are
+ * the relative forms of pts and msec_pt. */
+static const struct {
+    enum TrimAxis axis;
+    int msec;
+    int relative;
+} trim_types[] = {
+    [TRIM_PTS]        = { AXIS_PTS,   0, 0 },
+    [TRIM_DTS]        = { AXIS_DTS,   0, 0 },
+    [TRIM_PKT_INDEX]  = { AXIS_INDEX, 0, 0 },
+    [TRIM_MSEC_PT]    = { AXIS_PTS,   1, 0 },
+    [TRIM_MSEC_DT]    = { AXIS_DTS,   1, 0 },
+    [TRIM_DUR_TS]     = { AXIS_PTS,   0, 1 },
+    [TRIM_DUR_T_MSEC] = { AXIS_PTS,   1, 1 },
+};
+
+typedef struct TrimBound {
+    /* Resolved from the options, immutable once init returns. */
+    int active;         ///< the option was set at all
+    enum TrimAxis axis;
+    int relative;       ///< offset is measured from the reference packet
+    int64_t offset;     ///< option value converted to axis units
+
+    /* Rebuilt from the fields above by every reset. */
+    int64_t value;      ///< resolved bound, meaningful once pending is clear
+    int pending;        ///< the reference packet has not been seen yet
+} TrimBound;
+
+typedef struct TrimContext {
+    const AVClass *class;
+
+    int64_t start;
+    int64_t end;
+    int start_type;
+    int end_type;
+    int start_rel;
+    int end_rel;
+    int trim_packets;
+
+    TrimBound start_bound;
+    TrimBound end_bound;
+
+    int audio;          ///< trim through skip samples side data
+    int64_t pkt_idx;    ///< packets consumed so far
+    int64_t out_idx;    ///< packets exported so far
+    int64_t skip_carry;  ///< samples of head skip left over by dropped packets
+    uint8_t skip_reason; ///< reason that head skip came with
+
+    int preroll;
+    int preroll_size;
+
+    AVFifo *preroll_fifo;  ///< packets held since the last keyframe, NULL 
when off
+    AVPacket *pending;     ///< in-range packet waiting for the preroll to 
drain
+    int preroll_full;      ///< the group overflowed, so hold nothing until 
the next one
+
+    int64_t nb_exported;   ///< packets that left the filter
+    int64_t last_pts;      ///< the last of them, kept for the closing summary
+    int64_t last_dts;
+    int last_key;
+} TrimContext;
+
+/* Bounds mix option values with stream values; either can overflow. */
+static int add_checked(AVBSFContext *ctx, int64_t *acc, int64_t delta,
+                       const char *what)
+{
+    if ((delta > 0 && *acc > INT64_MAX - delta) ||
+        (delta < 0 && *acc < INT64_MIN - delta)) {
+        av_log(ctx, AV_LOG_ERROR, "%s is not representable\n", what);
+        return AVERROR(ERANGE);
+    }
+
+    *acc += delta;
+
+    return 0;
+}
+
+static int64_t packet_axis(const TrimContext *s, const AVPacket *pkt,
+                           enum TrimAxis axis)
+{
+    switch (axis) {
+    case AXIS_PTS:       return pkt->pts;
+    case AXIS_DTS:       return pkt->dts;
+    case AXIS_OUT_INDEX: return s->out_idx;
+    default:             return s->pkt_idx;
+    }
+}
+
+/* The dts stands in for the pts, being monotonic and never above it. */
+static enum TrimAxis monotonic_axis(enum TrimAxis axis)
+{
+    return axis == AXIS_PTS ? AXIS_DTS : axis;
+}
+
+/* An index counts whole packets, so only time places a bound inside one. */
+static int axis_is_time(enum TrimAxis axis)
+{
+    return axis == AXIS_PTS || axis == AXIS_DTS;
+}
+
+/* Nothing converted here is ever negative, so a negative result is the
+ * INT64_MIN av_rescale_q reports for one it cannot represent. */
+static int convert_checked(AVBSFContext *ctx, int64_t *value, AVRational from,
+                           AVRational to, const char *what)
+{
+    int64_t converted = av_rescale_q(*value, from, to);
+
+    if (converted < 0) {
+        av_log(ctx, AV_LOG_ERROR, "%s is not representable\n", what);
+        return AVERROR(ERANGE);
+    }
+
+    *value = converted;
+
+    return 0;
+}
+
+static int time_base_to_samples(AVBSFContext *ctx, int64_t *value,
+                                const char *what)
+{
+    return convert_checked(ctx, value, ctx->time_base_in,
+                           (AVRational){ 1, ctx->par_in->sample_rate }, what);
+}
+
+static int samples_to_time_base(AVBSFContext *ctx, int64_t *value,
+                                const char *what)
+{
+    return convert_checked(ctx, value, (AVRational){ 1, 
ctx->par_in->sample_rate },
+                           ctx->time_base_in, what);
+}
+
+/* The samples a packet decodes to, zero where the codec does not give them. */
+static int64_t packet_samples(AVBSFContext *ctx, const AVPacket *pkt)
+{
+    return FFMAX(av_get_audio_frame_duration2(ctx->par_in, pkt->size), 0);
+}
+
+/* A skip reaching past a dropped packet only needs how much of itself that
+ * packet used up, which a duration still estimates closely enough. */
+static int64_t packet_skip_consumed(AVBSFContext *ctx, const AVPacket *pkt)
+{
+    int64_t nb_samples = packet_samples(ctx, pkt);
+
+    if (nb_samples > 0)
+        return nb_samples;
+
+    nb_samples = av_rescale_q(pkt->duration, ctx->time_base_in,
+                              (AVRational){ 1, ctx->par_in->sample_rate });
+
+    return FFMAX(nb_samples, 0);
+}
+
+/* How far a packet reaches past its axis value. Audio reaches as far as the
+ * samples it decodes to, a duration also covering any gap after them; without
+ * them it reaches nowhere, so no bound can fall inside it. */
+static int packet_span(AVBSFContext *ctx, const AVPacket *pkt,
+                       enum TrimAxis axis, int64_t *span)
+{
+    TrimContext *s = ctx->priv_data;
+
+    *span = 0;
+
+    if (!axis_is_time(axis))
+        return 0;
+
+    if (s->audio) {
+        *span = packet_samples(ctx, pkt);
+        return samples_to_time_base(ctx, span, "packet span");
+    }
+
+    *span = FFMAX(pkt->duration, 0);
+
+    return 0;
+}
+
+static int bound_init(AVBSFContext *ctx, TrimBound *b, int active,
+                      int64_t value, int type, int rel, const char *name)
+{
+    b->active = active;
+    if (!active)
+        return 0;
+
+    b->axis     = trim_types[type].axis;
+    b->relative = rel || trim_types[type].relative;
+
+    if (trim_types[type].relative && value < 0) {
+        av_log(ctx, AV_LOG_ERROR, "%s duration must not be negative\n", name);
+        return AVERROR(EINVAL);
+    }
+
+    if (trim_types[type].msec) {
+        int64_t ts = av_rescale_q(value, (AVRational){ 1, 1000 },
+                                  ctx->time_base_in);
+        if (ts == INT64_MIN) {
+            av_log(ctx, AV_LOG_ERROR, "%s of %"PRId64" ms is not representable 
"
+                   "in the stream time base\n", name, value);
+            return AVERROR(ERANGE);
+        }
+        value = ts;
+    }
+
+    b->offset = value;
+
+    return 0;
+}
+
+static void bound_reset(TrimBound *b)
+{
+    b->value   = b->offset;
+    b->pending = b->relative;
+}
+
+static int bound_resolve(AVBSFContext *ctx, TrimBound *b, int64_t ref,
+                         const char *name)
+{
+    int ret = add_checked(ctx, &b->value, ref, name);
+
+    if (ret < 0)
+        return ret;
+
+    b->pending = 0;
+
+    return 0;
+}
+
+/* How much of the packet lies before the start bound, EAGAIN when all of it
+ * does. */
+static int trim_head(AVBSFContext *ctx, const AVPacket *pkt, int64_t *head)
+{
+    TrimContext *s = ctx->priv_data;
+    int64_t v, span;
+    int ret;
+
+    if (!s->start_bound.active)
+        return 0;
+
+    /* A packet without the discriminant a bound uses cannot be placed. */
+    v = packet_axis(s, pkt, s->start_bound.axis);
+    if (v == AV_NOPTS_VALUE)
+        return AVERROR(EAGAIN);
+
+    /* The start is measured from the first packet of the stream. */
+    if (s->start_bound.pending) {
+        ret = bound_resolve(ctx, &s->start_bound, v, "start bound");
+        if (ret < 0)
+            return ret;
+    }
+
+    if (v >= s->start_bound.value)
+        return 0;
+
+    ret = packet_span(ctx, pkt, s->start_bound.axis, &span);
+    if (ret < 0)
+        return ret;
+
+    if (!s->trim_packets || av_sat_add64(v, span) <= s->start_bound.value)
+        return AVERROR(EAGAIN);
+    *head = s->start_bound.value - v;
+
+    return 0;
+}
+
+/* How much of the packet lies past the end bound, measured from head, where it
+ * starts contributing. EAGAIN when none of it is inside, EOF once nothing 
later
+ * can be. */
+static int trim_tail(AVBSFContext *ctx, const AVPacket *pkt, int64_t head,
+                     int64_t *tail)
+{
+    TrimContext *s = ctx->priv_data;
+    int64_t v;
+    int ret;
+
+    if (!s->end_bound.active)
+        return 0;
+
+    /* The end is measured from the first exported packet, at the point it is
+     * trimmed to. */
+    if (s->end_bound.pending) {
+        int64_t ref = packet_axis(s, pkt, s->end_bound.axis);
+
+        if (ref == AV_NOPTS_VALUE)
+            return AVERROR(EAGAIN);
+        if (axis_is_time(s->end_bound.axis)) {
+            ret = add_checked(ctx, &ref, head, "end anchor");
+            if (ret < 0)
+                return ret;
+        }
+        ret = bound_resolve(ctx, &s->end_bound, ref, "end bound");
+        if (ret < 0)
+            return ret;
+    }
+
+    /* Only a discriminant that cannot come back into range may end the 
stream. */
+    v = packet_axis(s, pkt, monotonic_axis(s->end_bound.axis));
+    if (v != AV_NOPTS_VALUE && v >= s->end_bound.value)
+        return AVERROR_EOF;
+
+    v = packet_axis(s, pkt, s->end_bound.axis);
+    if (v == AV_NOPTS_VALUE)
+        return AVERROR(EAGAIN);
+
+    /* Reordering can still bring in-range packets after this one. */
+    if (v >= s->end_bound.value)
+        return AVERROR(EAGAIN);
+
+    if (s->trim_packets) {
+        int64_t span, past;
+
+        ret = packet_span(ctx, pkt, s->end_bound.axis, &span);
+        if (ret < 0)
+            return ret;
+
+        past = av_sat_add64(v, span);
+        if (past > s->end_bound.value)
+            *tail = past - s->end_bound.value;
+    }
+
+    return 0;
+}
+
+/* Audio is trimmed in sample space through skip samples side data, leaving the
+ * timestamps untouched. */
+static int trim_audio(AVBSFContext *ctx, AVPacket *pkt, int64_t head, int keep)
+{
+    TrimContext *s = ctx->priv_data;
+    int64_t nb_samples = packet_samples(ctx, pkt);
+    int64_t tail = 0, anchor, input_head;
+    int trimming = head != 0;
+    uint8_t head_reason = 0, tail_reason = 0, input_reason;
+    size_t size;
+    uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES,
+                                            &size);
+    int ret;
+
+    ret = time_base_to_samples(ctx, &head, "head trim");
+    if (ret < 0)
+        return ret;
+
+    /* A decoder replaces the skip it carries with any nonzero one a packet
+     * brings, whether larger or smaller, so resolve the incoming skip first. 
*/
+    input_head   = s->skip_carry;
+    input_reason = s->skip_reason;
+
+    if (side && size >= 8 && AV_RL32(side)) {
+        input_head   = AV_RL32(side);
+        input_reason = size >= 10 ? AV_RL8(side + 8) : 0;
+    }
+
+    /* That skip and this filter's trim are offsets from the same boundary, so
+     * the larger wins and brings its own reason; the trim has none. */
+    if (input_head >= head) {
+        head        = input_head;
+        head_reason = input_reason;
+    }
+
+    /* Only a trim of this filter collapses a packet; one already covered by 
its
+     * own skip is passed through. */
+    if (!keep || (trimming && nb_samples > 0 && head >= nb_samples))
+        goto drop;
+
+    /* A bound measured from this packet is anchored past its composed skip. */
+    anchor = head;
+    ret = samples_to_time_base(ctx, &anchor, "end anchor");
+    if (ret < 0)
+        return ret;
+
+    ret = trim_tail(ctx, pkt, anchor, &tail);
+    if (ret < 0) {
+        if (ret != AVERROR(EAGAIN))
+            return ret;
+        goto drop;
+    }
+
+    trimming |= tail != 0;
+    ret = time_base_to_samples(ctx, &tail, "tail trim");
+    if (ret < 0)
+        return ret;
+    if (side && size >= 8 && AV_RL32(side + 4) >= tail) {
+        tail        = AV_RL32(side + 4);
+        tail_reason = size >= 10 ? AV_RL8(side + 9) : 0;
+    }
+
+    if (trimming && nb_samples > 0 && head >= nb_samples - tail)
+        goto drop;
+
+    /* The side data below carries any excess from here on. */
+    s->skip_carry  = 0;
+    s->skip_reason = 0;
+
+    if (!head && !tail)
+        return 0;
+
+    if (head > UINT32_MAX || tail > UINT32_MAX) {
+        av_log(ctx, AV_LOG_ERROR, "skip samples count is not representable\n");
+        return AVERROR(ERANGE);
+    }
+
+    if (!side || size < 10) {
+        side = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
+        if (!side)
+            return AVERROR(ENOMEM);
+    }
+
+    AV_WL32(side,     head);
+    AV_WL32(side + 4, tail);
+    AV_WL8 (side + 8, head_reason);
+    AV_WL8 (side + 9, tail_reason);
+
+    return 0;
+
+drop:
+    /* A decoder subtracts the samples of every frame it discards and carries
+     * the rest, so do the same across dropped packets. */
+    if (head > 0) {
+        int64_t consumed = packet_skip_consumed(ctx, pkt);
+
+        if (consumed <= 0) {
+            av_log(ctx, AV_LOG_ERROR, "cannot carry a %"PRId64" sample skip 
past "
+                   "a dropped packet of unknown sample count\n", head);
+            return AVERROR(EINVAL);
+        }
+        s->skip_carry  = FFMAX(head - consumed, 0);
+        s->skip_reason = s->skip_carry ? head_reason : 0;
+    }
+
+    return AVERROR(EAGAIN);
+}
+
+/* Everything but audio is trimmed on the timeline itself, which no side data
+ * can express. */
+static int trim_shift(AVBSFContext *ctx, AVPacket *pkt, int64_t head)
+{
+    int64_t tail = 0;
+    int ret;
+
+    ret = trim_tail(ctx, pkt, head, &tail);
+    if (ret < 0)
+        return ret;
+
+    if (!head && !tail)
+        return 0;
+
+    /* Bounds on different axes can select disjoint parts of one packet, and
+     * each trim is below the duration, so the subtraction cannot overflow. */
+    if (head >= pkt->duration - tail)
+        return AVERROR(EAGAIN);
+
+    if (pkt->pts != AV_NOPTS_VALUE) {
+        ret = add_checked(ctx, &pkt->pts, head, "packet pts");
+        if (ret < 0)
+            return ret;
+    }
+    if (pkt->dts != AV_NOPTS_VALUE) {
+        ret = add_checked(ctx, &pkt->dts, head, "packet dts");
+        if (ret < 0)
+            return ret;
+    }
+    pkt->duration -= head + tail;
+
+    return 0;
+}
+
+static void preroll_clear(AVBSFContext *ctx)
+{
+    TrimContext *s = ctx->priv_data;
+    AVPacket *held;
+
+    while (s->preroll_fifo && av_fifo_read(s->preroll_fifo, &held, 1) >= 0)
+        av_packet_free(&held);
+}
+
+/* A held packet is decoded for the frames after it to reference and dropped
+ * before output, so the exported stream still begins at the bound. */
+static void preroll_export(AVBSFContext *ctx, AVPacket *pkt)
+{
+    TrimContext *s = ctx->priv_data;
+    AVPacket *held;
+
+    if (av_fifo_read(s->preroll_fifo, &held, 1) >= 0) {
+        av_packet_move_ref(pkt, held);
+        av_packet_free(&held);
+        pkt->flags |= AV_PKT_FLAG_DISCARD;
+        return;
+    }
+
+    av_packet_move_ref(pkt, s->pending);
+    av_packet_free(&s->pending);
+}
+
+static int preroll_hold(AVBSFContext *ctx, AVPacket *pkt)
+{
+    TrimContext *s = ctx->priv_data;
+    AVPacket *held;
+    int ret;
+
+    if (s->preroll_full)
+        return AVERROR(EAGAIN);
+
+    held = av_packet_alloc();
+    if (!held)
+        return AVERROR(ENOMEM);
+
+    av_packet_move_ref(held, pkt);
+    ret = av_fifo_write(s->preroll_fifo, &held, 1);
+    if (ret < 0) {
+        av_packet_move_ref(pkt, held);
+        av_packet_free(&held);
+        if (ret != AVERROR(ENOSPC))
+            return ret;
+
+        /* A group too long to hold is dropped whole rather than exported as a
+         * fragment no decoder can start from. */
+        av_log(ctx, AV_LOG_WARNING, "preroll exceeds %d packets, the first "
+               "packets in range will not be decodable\n", s->preroll_size);
+        preroll_clear(ctx);
+        s->preroll_full = 1;
+    }
+
+    return AVERROR(EAGAIN);
+}
+
+static void log_exported_packet(AVBSFContext *ctx, const char *which,
+                                int64_t idx, int64_t pts, int64_t dts, int key)
+{
+    av_log(ctx, AV_LOG_VERBOSE, "%s exported packet: output index %"PRId64", "
+           "pts %s, dts %s, keyframe %d\n", which, idx, av_ts2str(pts),
+           av_ts2str(dts), key);
+}
+
+static void packet_exported(AVBSFContext *ctx, const AVPacket *pkt)
+{
+    TrimContext *s = ctx->priv_data;
+
+    s->last_pts = pkt->pts;
+    s->last_dts = pkt->dts;
+    s->last_key = !!(pkt->flags & AV_PKT_FLAG_KEY);
+
+    if (!s->nb_exported++)
+        log_exported_packet(ctx, "first", 0, s->last_pts, s->last_dts,
+                            s->last_key);
+}
+
+/* Only the flush or close ending the stream can tell which packet was last. */
+static void trim_report(AVBSFContext *ctx)
+{
+    TrimContext *s = ctx->priv_data;
+
+    if (s->nb_exported)
+        log_exported_packet(ctx, "last", s->nb_exported - 1, s->last_pts,
+                            s->last_dts, s->last_key);
+    else if (s->pkt_idx)
+        av_log(ctx, AV_LOG_WARNING, "no packet was in range, the output is "
+               "empty\n");
+}
+
+static int trim_filter(AVBSFContext *ctx, AVPacket *pkt)
+{
+    TrimContext *s = ctx->priv_data;
+    int64_t head = 0;
+    int ret;
+
+    /* The preroll an in-range packet needs is exported ahead of it. */
+    if (s->pending) {
+        preroll_export(ctx, pkt);
+        packet_exported(ctx, pkt);
+        return 0;
+    }
+
+    ret = ff_bsf_get_packet_ref(ctx, pkt);
+    if (ret < 0)
+        return ret;
+
+    /* Only the group the start bound falls in is worth keeping, so the window
+     * starts over at every keyframe. */
+    if (s->preroll_fifo && pkt->flags & AV_PKT_FLAG_KEY) {
+        preroll_clear(ctx);
+        s->preroll_full = 0;
+    }
+
+    ret = trim_head(ctx, pkt, &head);
+
+    /* A packet before the start still composes with the skip it carries, so 
the
+     * audio path runs on it too and is told the verdict instead. */
+    if (s->audio && (!ret || ret == AVERROR(EAGAIN)))
+        ret = trim_audio(ctx, pkt, head, !ret);
+    else if (!ret)
+        ret = trim_shift(ctx, pkt, head);
+    else if (ret == AVERROR(EAGAIN) && s->preroll_fifo)
+        ret = preroll_hold(ctx, pkt);
+
+    s->pkt_idx++;
+    if (ret < 0) {
+        av_packet_unref(pkt);
+        return ret;
+    }
+
+    s->out_idx++;
+    if (s->preroll_fifo && av_fifo_can_read(s->preroll_fifo)) {
+        s->pending = av_packet_alloc();
+        if (!s->pending) {
+            av_packet_unref(pkt);
+            return AVERROR(ENOMEM);
+        }
+        av_packet_move_ref(s->pending, pkt);
+        preroll_export(ctx, pkt);
+    }
+
+    packet_exported(ctx, pkt);
+
+    return 0;
+}
+
+/* Runtime state is derived from the options, so a flush restores it exactly. 
*/
+static void trim_reset(AVBSFContext *ctx)
+{
+    TrimContext *s = ctx->priv_data;
+
+    bound_reset(&s->start_bound);
+    bound_reset(&s->end_bound);
+
+    s->pkt_idx     = 0;
+    s->out_idx     = 0;
+    s->nb_exported = 0;
+    s->skip_carry  = 0;
+    s->skip_reason = 0;
+
+    preroll_clear(ctx);
+    av_packet_free(&s->pending);
+    s->preroll_full = 0;
+}
+
+static void trim_flush(AVBSFContext *ctx)
+{
+    trim_report(ctx);
+    trim_reset(ctx);
+}
+
+static void trim_close(AVBSFContext *ctx)
+{
+    TrimContext *s = ctx->priv_data;
+
+    trim_report(ctx);
+    preroll_clear(ctx);
+    av_packet_free(&s->pending);
+    av_fifo_freep2(&s->preroll_fifo);
+}
+
+static int trim_init(AVBSFContext *ctx)
+{
+    TrimContext *s = ctx->priv_data;
+    int ret;
+
+    if (s->start == INT64_MIN && s->end == INT64_MAX) {
+        av_log(ctx, AV_LOG_ERROR, "At least one of start or end must be 
set\n");
+        return AVERROR(EINVAL);
+    }
+
+    ret = bound_init(ctx, &s->start_bound, s->start != INT64_MIN, s->start,
+                     s->start_type, s->start_rel, "start");
+    if (ret < 0)
+        return ret;
+
+    ret = bound_init(ctx, &s->end_bound, s->end != INT64_MAX, s->end,
+                     s->end_type, s->end_rel, "end");
+    if (ret < 0)
+        return ret;
+
+    /* A packet count measured from the first exported packet is a promise 
about
+     * the exported stream, so it is counted there. */
+    if (s->end_bound.axis == AXIS_INDEX && s->end_bound.relative)
+        s->end_bound.axis = AXIS_OUT_INDEX;
+
+    /* Shifting the timeline leaves the samples where they were, so audio with
+     * no sample space to be trimmed in cannot be trimmed at all. */
+    if (s->trim_packets && ctx->par_in->codec_type == AVMEDIA_TYPE_AUDIO) {
+        if (ctx->par_in->sample_rate <= 0 || ctx->time_base_in.num <= 0 ||
+            ctx->time_base_in.den <= 0) {
+            av_log(ctx, AV_LOG_ERROR, "audio is trimmed through skip samples "
+                   "side data, which needs a sample rate and a time base\n");
+            return AVERROR(EINVAL);
+        }
+        s->audio = 1;
+    }
+
+    /* The window is bounded by a keyframe, which only video has. Audio needs a
+     * preroll counted in samples, which is not the one this would give. */
+    if (s->preroll && s->start_bound.active &&
+        ctx->par_in->codec_type == AVMEDIA_TYPE_VIDEO) {
+        s->preroll_fifo = av_fifo_alloc2(1, sizeof(AVPacket *),
+                                         AV_FIFO_FLAG_AUTO_GROW);
+        if (!s->preroll_fifo)
+            return AVERROR(ENOMEM);
+        av_fifo_auto_grow_limit(s->preroll_fifo, s->preroll_size);
+    }
+
+    trim_reset(ctx);
+
+    return 0;
+}
+
+#define OFFSET(x) offsetof(TrimContext, x)
+#define FLAGS 
(AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_BSF_PARAM)
+static const AVOption trim_options[] = {
+    { "start", "time or index marking the start of the accepted range", 
OFFSET(start),
+        AV_OPT_TYPE_INT64, { .i64 = INT64_MIN }, INT64_MIN, INT64_MAX, FLAGS },
+    { "start_type", "how to interpret start", OFFSET(start_type),
+        AV_OPT_TYPE_INT, { .i64 = TRIM_PTS }, 0, TRIM_MSEC_DT, FLAGS, .unit = 
"start_type" },
+        { "pts",       "stream time base pts",              0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_PTS },       0, 0, FLAGS, .unit = "start_type" 
},
+        { "dts",       "stream time base dts",              0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_DTS },       0, 0, FLAGS, .unit = "start_type" 
},
+        { "pkt_index", "packet index",                      0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_PKT_INDEX }, 0, 0, FLAGS, .unit = "start_type" 
},
+        { "msec_pt",   "milliseconds, matched against pts", 0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_PT },   0, 0, FLAGS, .unit = "start_type" 
},
+        { "msec_dt",   "milliseconds, matched against dts", 0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_DT },   0, 0, FLAGS, .unit = "start_type" 
},
+    { "start_rel", "interpret start relative to the first packet of the 
stream", OFFSET(start_rel),
+        AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
+    { "end", "time or index marking the end of the accepted range", 
OFFSET(end),
+        AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS },
+    { "end_type", "how to interpret end", OFFSET(end_type),
+        AV_OPT_TYPE_INT, { .i64 = TRIM_PTS }, 0, TRIM_DUR_T_MSEC, FLAGS, .unit 
= "end_type" },
+        { "pts",        "stream time base pts",              0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_PTS },         0, 0, FLAGS, .unit = "end_type" 
},
+        { "dts",        "stream time base dts",              0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_DTS },         0, 0, FLAGS, .unit = "end_type" 
},
+        { "pkt_index",  "packet index",                      0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_PKT_INDEX },   0, 0, FLAGS, .unit = "end_type" 
},
+        { "msec_pt",    "milliseconds, matched against pts", 0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_PT },     0, 0, FLAGS, .unit = "end_type" 
},
+        { "msec_dt",    "milliseconds, matched against dts", 0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_MSEC_DT },     0, 0, FLAGS, .unit = "end_type" 
},
+        { "dur_ts",     "duration in stream time base",      0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_DUR_TS },      0, 0, FLAGS, .unit = "end_type" 
},
+        { "dur_t_msec", "duration in milliseconds",          0, 
AV_OPT_TYPE_CONST, { .i64 = TRIM_DUR_T_MSEC },  0, 0, FLAGS, .unit = "end_type" 
},
+    { "end_rel", "interpret end relative to the first exported packet", 
OFFSET(end_rel),
+        AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
+    { "trim_packets", "trim packets straddling a boundary instead of exporting 
them "
+                      "untouched or dropping them", OFFSET(trim_packets),
+        AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS },
+    { "preroll", "export the packets the first packet in range needs to be 
decodable, "
+                 "flagged for the decoder to drop them after decoding", 
OFFSET(preroll),
+        AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
+    { "preroll_size", "maximum number of packets held for preroll", 
OFFSET(preroll_size),
+        AV_OPT_TYPE_INT, { .i64 = 300 }, 1, INT_MAX, FLAGS },
+    { NULL },
+};
+
+static const AVClass trim_class = {
+    .class_name = "trim",
+    .item_name  = av_default_item_name,
+    .option     = trim_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+const FFBitStreamFilter ff_trim_bsf = {
+    .p.name         = "trim",
+    .p.priv_class   = &trim_class,
+    .priv_data_size = sizeof(TrimContext),
+    .init           = trim_init,
+    .close          = trim_close,
+    .flush          = trim_flush,
+    .filter         = trim_filter,
+};
diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak
index ad8e5c775f..e255cdcc0b 100644
--- a/tests/fate/ffmpeg.mak
+++ b/tests/fate/ffmpeg.mak
@@ -229,6 +229,142 @@ fate-ffmpeg-bsf-remove-e: CMD = transcode "mpeg" 
$(TARGET_SAMPLES)/mpeg2/matrixb
 FATE_SAMPLES_FFMPEG-$(call DEMMUX, APNG, FRAMECRC, SETTS_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-setts-bsf
 fate-ffmpeg-setts-bsf: CMD = framecrc -i $(TARGET_SAMPLES)/apng/clock.png -c:v 
copy -bsf:v 
"setts=duration=if(eq(NEXT_PTS\,NOPTS)\,PREV_OUTDURATION\,(NEXT_PTS-PTS)/2):ts=PTS/2"
 -fflags +bitexact
 
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, AAC, FRAMECRC, AAC_PARSER TRIM_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-pts fate-ffmpeg-trim-bsf-dts 
fate-ffmpeg-trim-bsf-pkt fate-ffmpeg-trim-bsf-dts-pts 
fate-ffmpeg-trim-bsf-pts-dts fate-ffmpeg-trim-bsf-pts-duration 
fate-ffmpeg-trim-bsf-dts-duration fate-ffmpeg-trim-bsf-samples 
fate-ffmpeg-trim-bsf-msec fate-ffmpeg-trim-bsf-rel 
fate-ffmpeg-trim-bsf-duration-zero fate-ffmpeg-trim-bsf-pkt-rel 
fate-ffmpeg-trim-bsf-untrimmed
+fate-ffmpeg-trim-bsf-pts: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=1806336:end=18063360
+fate-ffmpeg-trim-bsf-dts: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=3612672:start_type=dts:end=10838016:end_type=dts
+fate-ffmpeg-trim-bsf-dts-pts: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=3612672:start_type=dts:end=18063360
+fate-ffmpeg-trim-bsf-pts-dts: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=1806336:end=10838016:end_type=dts
+fate-ffmpeg-trim-bsf-pts-duration: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=1806336:end=1000:end_type=dur_ts
+fate-ffmpeg-trim-bsf-dts-duration: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=3612672:start_type=dts:end=1000:end_type=dur_ts
+fate-ffmpeg-trim-bsf-pkt: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=5:start_type=pkt_index:end=15:end_type=pkt_index
+fate-ffmpeg-trim-bsf-samples: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=903168:end=17160192
+fate-ffmpeg-trim-bsf-msec: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=1000:start_type=msec_pt:end=5000:end_type=dur_t_msec
+fate-ffmpeg-trim-bsf-rel: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=1806336:start_rel=1:end=1000:end_type=dur_ts
+fate-ffmpeg-trim-bsf-duration-zero: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=1806336:end=0:end_type=dur_ts
+fate-ffmpeg-trim-bsf-pkt-rel: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=1806336:end=5:end_type=pkt_index:end_rel=1
+fate-ffmpeg-trim-bsf-untrimmed: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=903168:end=17160192:trim_packets=0
+
+# Both trims land on the same 1024 sample packet, 256 off each end. The 
composed
+# skip leaves a 512 sample frame.
+FATE_SAMPLES_FFMPEG-$(call FRAMECRC, AAC, AAC, AAC_PARSER TRIM_BSF 
ARESAMPLE_FILTER) += fate-ffmpeg-trim-bsf-skip-samples
+fate-ffmpeg-trim-bsf-skip-samples: CMD = framecrc -bsf:a 
trim=start=2257920,trim=end=3161088 -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a 
pcm_s16le -af aresample
+
+# Both bounds fall in a presentation gap the first packet's duration is 
stretched
+# over, where only the decoded sample count places them.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, AAC, FRAMECRC, AAC_PARSER TRIM_BSF 
SETTS_BSF PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-gap-end 
fate-ffmpeg-trim-bsf-gap-start
+fate-ffmpeg-trim-bsf-gap-end: CMD = framecrc -copyts -bsf:a 
"setts=duration=if(eq(N\,0)\,18063360\,DURATION):pts=PTS+if(gte(N\,1)\,16257024\,0),trim=end=9031680"
 -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a 
copy
+fate-ffmpeg-trim-bsf-gap-start: CMD = framecrc -copyts -bsf:a 
"setts=duration=if(eq(N\,0)\,18063360\,DURATION):pts=PTS+if(gte(N\,1)\,16257024\,0),trim=start=9031680"
 -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a 
copy -frames:a 1
+
+# The same gap where the size gives no sample count, so no bound falls inside 
the
+# packet and it is judged whole.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, OGG, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-opus-gap-end 
fate-ffmpeg-trim-bsf-opus-gap-start
+fate-ffmpeg-trim-bsf-opus-gap-end: CMD = framecrc -copyts -bsf:a 
"setts=duration=if(eq(N\,0)\,10000\,DURATION):pts=PTS+if(gte(N\,1)\,9040\,0),trim=end=9188"
 -i $(TARGET_SAMPLES)/audiomatch/tones_opus_48000_stereo.opus -c:a copy
+fate-ffmpeg-trim-bsf-opus-gap-start: CMD = framecrc -copyts -bsf:a 
"setts=duration=if(eq(N\,0)\,10000\,DURATION):pts=PTS+if(gte(N\,1)\,9040\,0),trim=start=9188"
 -i $(TARGET_SAMPLES)/audiomatch/tones_opus_48000_stereo.opus -c:a copy 
-frames:a 2
+
+# The 2112 sample priming spans three packets, so a trim from 512 stays inside
+# it and carries the 1088 samples left over to the second packet.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-priming
+fate-ffmpeg-trim-bsf-priming: CMD = framecrc -copyts -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy 
-bsf:a trim=start=512
+
+# Same priming with the durations erased. The codec frame size still leaves the
+# packet at 1024, carrying 1088 samples of priming rather than the whole 2112.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-priming-nodur
+fate-ffmpeg-trim-bsf-priming-nodur: CMD = framecrc -copyts -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy 
-bsf:a setts=duration=0,trim=start=1:start_type=pkt_index -frames:a 3
+
+# The skip counts decoded samples, so a gap opened after the dropped packet
+# leaves the same 1088.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-priming-gap
+fate-ffmpeg-trim-bsf-priming-gap: CMD = framecrc -copyts -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy 
-bsf:a 
"setts=pts=PTS+if(gte(N\,1)\,10000\,0),trim=start=1:start_type=pkt_index" 
-frames:a 2
+
+# Nor does the packet the skip lands on need a timestamp at all.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-priming-nopts
+fate-ffmpeg-trim-bsf-priming-nopts: CMD = framecrc -copyts -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy 
-bsf:a "setts=pts=if(gte(N\,1)\,NOPTS\,PTS),trim=start=1:start_type=pkt_index" 
-frames:a 2
+
+# The same gap with the duration stretched across it. A duration places the 
next
+# packet and does not count this one's samples.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-priming-gap-duration
+fate-ffmpeg-trim-bsf-priming-gap-duration: CMD = framecrc -copyts -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy 
-bsf:a 
"setts=duration=if(eq(N\,0)\,11024\,DURATION):pts=PTS+if(gte(N\,1)\,10000\,0),trim=start=1:start_type=pkt_index"
 -frames:a 1
+
+# The end is measured from the first sample the stream contributes, which the
+# priming pushes to 4160, leaving the last packet a 960 sample tail skip.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-priming-duration
+fate-ffmpeg-trim-bsf-priming-duration: CMD = framecrc -copyts -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy 
-bsf:a trim=start=512:end=2048:end_type=dur_ts
+
+# Untouched mode has no sample space, so a dropped packet takes its skip along.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-priming-untrimmed
+fate-ffmpeg-trim-bsf-priming-untrimmed: CMD = framecrc -copyts -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a -c:a copy 
-bsf:a trim=start=1:start_type=pkt_index:trim_packets=0 -frames:a 3
+
+# The composed skips cover 800 + 300 of the 1024 samples, leaving nothing.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, AAC, FRAMECRC, AAC_PARSER TRIM_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-skip-samples-empty
+fate-ffmpeg-trim-bsf-skip-samples-empty: CMD = framecrc -i 
$(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.adts -c:a copy 
-bsf:a trim=start=3217536,trim=end=3083472
+
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-video-pts fate-ffmpeg-trim-bsf-video-dts 
fate-ffmpeg-trim-bsf-video-dts-pts fate-ffmpeg-trim-bsf-video-pts-dts 
fate-ffmpeg-trim-bsf-video-dts-duration fate-ffmpeg-trim-bsf-video-pts-duration 
fate-ffmpeg-trim-bsf-video-pkt fate-ffmpeg-trim-bsf-video-samples 
fate-ffmpeg-trim-bsf-video-untrimmed
+fate-ffmpeg-trim-bsf-video-pts: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=60:end=600
+fate-ffmpeg-trim-bsf-video-dts: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=120:start_type=dts:end=360:end_type=dts
+fate-ffmpeg-trim-bsf-video-dts-pts: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=120:start_type=dts:end=600
+fate-ffmpeg-trim-bsf-video-pts-dts: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=60:end=360:end_type=dts
+fate-ffmpeg-trim-bsf-video-dts-duration: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=120:start_type=dts:end=100:end_type=dur_ts
+fate-ffmpeg-trim-bsf-video-pts-duration: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=60:end=100:end_type=dur_ts
+fate-ffmpeg-trim-bsf-video-pkt: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=5:start_type=pkt_index:end=15:end_type=pkt_index
+fate-ffmpeg-trim-bsf-video-samples: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=30:end=150
+fate-ffmpeg-trim-bsf-video-untrimmed: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
trim=start=30:end=150:trim_packets=0
+
+# A pts past the end with a dts before it drops its packet without ending the
+# stream, and three in-range packets follow.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-video-reordered
+fate-ffmpeg-trim-bsf-video-reordered: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 -map 0:v:0 -c:v 
copy -bsf:v trim=end=1600
+
+# The held packets carry the discard flag. B-frames placed before the bound 
after
+# it was crossed are held the same way.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-video-preroll fate-ffmpeg-trim-bsf-video-preroll-overflow
+fate-ffmpeg-trim-bsf-video-preroll: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 -map 0:v:0 -c:v 
copy -bsf:v trim=start=4096:preroll=1
+
+# A group that does not fit is dropped whole, leaving the output the one an
+# unset preroll gives.
+fate-ffmpeg-trim-bsf-video-preroll-overflow: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 -map 0:v:0 -c:v 
copy -bsf:v trim=start=4096:preroll=1:preroll_size=3
+
+# Decoding the held packets leaves the frames in range as the untrimmed stream
+# decodes them.
+FATE_SAMPLES_FFMPEG-$(call FRAMECRC, MOV, H264, TRIM_BSF) += 
fate-ffmpeg-trim-bsf-video-preroll-decoded
+fate-ffmpeg-trim-bsf-video-preroll-decoded: CMD = framecrc -bsf:v 
trim=start=4096:preroll=1 -i 
$(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 -map 0:v:0
+
+# Only the group the bound falls in is held, the keyframe at packet 11 starting
+# the window over.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MPEGPS, FRAMECRC, MPEG2VIDEO_DECODER 
MPEGVIDEO_DEMUXER MPEGVIDEO_PARSER EXTRACT_EXTRADATA_BSF TRIM_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-video-preroll-keyframe 
fate-ffmpeg-trim-bsf-video-preroll-on-keyframe
+fate-ffmpeg-trim-bsf-video-preroll-keyframe: CMD = framecrc -i 
$(TARGET_SAMPLES)/mpeg2/matrixbench_mpeg2.lq1.mpg -map 0:v:0 -c:v copy -bsf:v 
trim=start=15:start_type=pkt_index:preroll=1
+fate-ffmpeg-trim-bsf-video-preroll-on-keyframe: CMD = framecrc -i 
$(TARGET_SAMPLES)/mpeg2/matrixbench_mpeg2.lq1.mpg -map 0:v:0 -c:v copy -bsf:v 
trim=start=11:start_type=pkt_index:preroll=1
+
+# Input bsfs are flushed between loops, so each pass drops its own first 
packet.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-video-flush fate-ffmpeg-trim-bsf-video-flush-rel
+fate-ffmpeg-trim-bsf-video-flush: CMD = framecrc -stream_loop 1 -bsf:v 
trim=start=1:start_type=pkt_index -i $(TARGET_SAMPLES)/qtrle/aletrek-rle.mov 
-map 0:v:0 -c:v copy
+fate-ffmpeg-trim-bsf-video-flush-rel: CMD = framecrc -stream_loop 1 -bsf:v 
trim=start=120:start_rel=1 -i $(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 
0:v:0 -c:v copy
+
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-video-mixed-axes 
fate-ffmpeg-trim-bsf-video-mixed-axes-empty
+fate-ffmpeg-trim-bsf-video-mixed-axes: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
setts=pts=PTS+100,trim=start=10:start_type=dts:end=140:end_type=pts
+fate-ffmpeg-trim-bsf-video-mixed-axes-empty: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
setts=pts=PTS+100,trim=start=30:start_type=dts:end=120:end_type=pts
+
+# The first packet has no pts to be placed by, so both bounds are measured from
+# the second one.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-video-nopts-duration 
fate-ffmpeg-trim-bsf-video-nopts-rel fate-ffmpeg-trim-bsf-video-nopts-empty
+fate-ffmpeg-trim-bsf-video-nopts-duration: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
"setts=pts=if(eq(N\,0)\,NOPTS\,PTS),trim=end=100:end_type=dur_ts"
+fate-ffmpeg-trim-bsf-video-nopts-rel: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
"setts=pts=if(eq(N\,0)\,NOPTS\,PTS),trim=start=120:start_rel=1:end=600"
+fate-ffmpeg-trim-bsf-video-nopts-empty: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
"setts=pts=NOPTS,trim=end=100:end_type=dur_ts"
+
+# The dts start falls inside the first packet, and the duration runs from the
+# presentation time it is trimmed to.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-video-partial-dts-duration
+fate-ffmpeg-trim-bsf-video-partial-dts-duration: CMD = framecrc -i 
$(TARGET_SAMPLES)/qtrle/aletrek-rle.mov -map 0:v:0 -c:v copy -bsf:v 
setts=pts=PTS+100,trim=start=30:start_type=dts:end=100:end_type=dur_ts
+
+# Without a dts, nothing proves a later pts cannot come back into range, so an
+# out of range pts only drops its packet.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF SETTS_BSF 
PIPE_PROTOCOL) += fate-ffmpeg-trim-bsf-video-reordered-nodts
+fate-ffmpeg-trim-bsf-video-reordered-nodts: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 -map 0:v:0 -c:v 
copy -bsf:v "setts=pts=PTS:dts=NOPTS,trim=end=1600"
+
+# A relative packet count is measured on the exported packets, so a packet the
+# pts start drops does not count against it.
+FATE_SAMPLES_FFMPEG-$(call DEMMUX, MOV, FRAMECRC, TRIM_BSF PIPE_PROTOCOL) += 
fate-ffmpeg-trim-bsf-video-reordered-count
+fate-ffmpeg-trim-bsf-video-reordered-count: CMD = framecrc -i 
$(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 -map 0:v:0 -c:v 
copy -bsf:v trim=start=1100:end=3:end_type=pkt_index:end_rel=1
+
 FATE_TIME_BASE-$(call PARSERDEMDEC, MPEGVIDEO, MPEGPS, MPEG2VIDEO, 
MPEGVIDEO_DEMUXER MXF_MUXER) += fate-time_base
 fate-time_base: CMD = md5 -i $(TARGET_SAMPLES)/mpeg2/dvd_single_frame.vob -an 
-sn -c:v copy -r 25 -fflags +bitexact -f mxf
 
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-dts 
b/tests/ref/fate/ffmpeg-trim-bsf-dts
new file mode 100644
index 0000000000..2cae1141bd
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-dts
@@ -0,0 +1,9 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed
+0,    5419008,    5419008,  1806336,      101, 0xa57c2f3a
+0,    7225344,    7225344,  1806336,      321, 0xfb92953a
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-dts-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-dts-duration
new file mode 100644
index 0000000000..9da0bb88ef
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-dts-duration
@@ -0,0 +1,6 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed, S=1, Skip Samples,  
     10, 0x06090102
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-dts-pts 
b/tests/ref/fate/ffmpeg-trim-bsf-dts-pts
new file mode 100644
index 0000000000..454567e236
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-dts-pts
@@ -0,0 +1,13 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed
+0,    5419008,    5419008,  1806336,      101, 0xa57c2f3a
+0,    7225344,    7225344,  1806336,      321, 0xfb92953a
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
+0,   10838016,   10838016,  1806336,      126, 0x685c3988
+0,   12644352,   12644352,  1806336,      191, 0x83256440
+0,   14450688,   14450688,  1806336,      139, 0x90373f34
+0,   16257024,   16257024,  1806336,      159, 0xc36153dc
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-duration-zero 
b/tests/ref/fate/ffmpeg-trim-bsf-duration-zero
new file mode 100644
index 0000000000..aa85048ead
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-duration-zero
@@ -0,0 +1,5 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-gap-end 
b/tests/ref/fate/ffmpeg-trim-bsf-gap-end
new file mode 100644
index 0000000000..e56b95a5cf
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-gap-end
@@ -0,0 +1,6 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,          0,          0, 18063360,       11, 0x204d0430
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-gap-start 
b/tests/ref/fate/ffmpeg-trim-bsf-gap-start
new file mode 100644
index 0000000000..42ca835b01
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-gap-start
@@ -0,0 +1,6 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-msec 
b/tests/ref/fate/ffmpeg-trim-bsf-msec
new file mode 100644
index 0000000000..d3874ad7eb
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-msec
@@ -0,0 +1,24 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,   27095040,   27095040,  1806336,      160, 0x77e345fb, S=1, Skip Samples,  
     10, 0x05120082
+0,   28901376,   28901376,  1806336,      192, 0xb90452c3
+0,   30707712,   30707712,  1806336,      133, 0x443d404e
+0,   32514048,   32514048,  1806336,      253, 0xcb7f7ed0
+0,   34320384,   34320384,  1806336,      169, 0xb4b6508d
+0,   36126720,   36126720,  1806336,      142, 0x61393f69
+0,   37933056,   37933056,  1806336,      253, 0xe0c27aff
+0,   39739392,   39739392,  1806336,      269, 0x72ed7afa
+0,   41545728,   41545728,  1806336,       67, 0xd6281c15
+0,   43352064,   43352064,  1806336,      262, 0x61687cd4
+0,   45158400,   45158400,  1806336,      160, 0x27df47c7
+0,   46964736,   46964736,  1806336,      167, 0xb2d748dc
+0,   48771072,   48771072,  1806336,      222, 0x928864d7
+0,   50577408,   50577408,  1806336,      151, 0xef554327
+0,   52383744,   52383744,  1806336,      194, 0x77d05f2b
+0,   54190080,   54190080,  1806336,      184, 0xba7458a4
+0,   55996416,   55996416,  1806336,      163, 0x86965266
+0,   57802752,   57802752,  1806336,      208, 0xa9f162cb
+0,   59609088,   59609088,  1806336,      144, 0x1f633caa
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-opus-gap-end 
b/tests/ref/fate/ffmpeg-trim-bsf-opus-gap-end
new file mode 100644
index 0000000000..6e38634411
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-opus-gap-end
@@ -0,0 +1,7 @@
+#extradata 0:       19, 0x38100445
+#tb 0: 1/48000
+#media_type 0: audio
+#codec_id 0: opus
+#sample_rate 0: 48000
+#channel_layout_name 0: stereo
+0,       -312,       -312,    10000,      489, 0xb843f4b8, S=1, Skip Samples,  
     10, 0x02390039
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-opus-gap-start 
b/tests/ref/fate/ffmpeg-trim-bsf-opus-gap-start
new file mode 100644
index 0000000000..027bd4c7f4
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-opus-gap-start
@@ -0,0 +1,8 @@
+#extradata 0:       19, 0x38100445
+#tb 0: 1/48000
+#media_type 0: audio
+#codec_id 0: opus
+#sample_rate 0: 48000
+#channel_layout_name 0: stereo
+0,        648,        648,      960,      354, 0xa2a7b0c8
+0,       1608,       1608,      960,      366, 0xf507c0ab
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-pkt 
b/tests/ref/fate/ffmpeg-trim-bsf-pkt
new file mode 100644
index 0000000000..60fe07751f
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-pkt
@@ -0,0 +1,15 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
+0,   10838016,   10838016,  1806336,      126, 0x685c3988
+0,   12644352,   12644352,  1806336,      191, 0x83256440
+0,   14450688,   14450688,  1806336,      139, 0x90373f34
+0,   16257024,   16257024,  1806336,      159, 0xc36153dc
+0,   18063360,   18063360,  1806336,      234, 0xff6b6ed9
+0,   19869696,   19869696,  1806336,      129, 0x439b3859
+0,   21676032,   21676032,  1806336,      170, 0x5a275023
+0,   23482368,   23482368,  1806336,      154, 0xf2a846e2
+0,   25288704,   25288704,  1806336,      126, 0x40943574
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-pkt-rel 
b/tests/ref/fate/ffmpeg-trim-bsf-pkt-rel
new file mode 100644
index 0000000000..2262b8daab
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-pkt-rel
@@ -0,0 +1,10 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed
+0,    5419008,    5419008,  1806336,      101, 0xa57c2f3a
+0,    7225344,    7225344,  1806336,      321, 0xfb92953a
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-priming 
b/tests/ref/fate/ffmpeg-trim-bsf-priming
new file mode 100644
index 0000000000..39b13803f5
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-priming
@@ -0,0 +1,39 @@
+#extradata 0:        2, 0x0030001c
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1024,       1024,     1024,      163, 0xd5f85007, S=1, Skip Samples,  
     10, 0x02a40044
+0,       2048,       2048,     1024,      127, 0x66484065
+0,       3072,       3072,     1024,       94, 0x55222bd6
+0,       4096,       4096,     1024,      314, 0x3c7e923a
+0,       5120,       5120,     1024,      207, 0x1efc5d1b
+0,       6144,       6144,     1024,      119, 0xb2a13601
+0,       7168,       7168,     1024,      184, 0xcafc6091
+0,       8192,       8192,     1024,      132, 0xddd33c0b
+0,       9216,       9216,     1024,      152, 0x83935031
+0,      10240,      10240,     1024,      227, 0x32a86bc4
+0,      11264,      11264,     1024,      122, 0xd04e3571
+0,      12288,      12288,     1024,      163, 0x57d44d16
+0,      13312,      13312,     1024,      147, 0x226043d7
+0,      14336,      14336,     1024,      119, 0x8ad931ed
+0,      15360,      15360,     1024,      153, 0xbb6e432f
+0,      16384,      16384,     1024,      185, 0xa01f4ff3
+0,      17408,      17408,     1024,      126, 0x85503ce6
+0,      18432,      18432,     1024,      246, 0x652c7b59
+0,      19456,      19456,     1024,      162, 0xc9f04da0
+0,      20480,      20480,     1024,      135, 0x71fa3be0
+0,      21504,      21504,     1024,      246, 0x7a6f7788
+0,      22528,      22528,     1024,      262, 0xd3097781
+0,      23552,      23552,     1024,       60, 0x09a118f5
+0,      24576,      24576,     1024,      255, 0xbab5793c
+0,      25600,      25600,     1024,      153, 0x6b6a44fb
+0,      26624,      26624,     1024,      160, 0x550e4530
+0,      27648,      27648,     1024,      215, 0x7fe66144
+0,      28672,      28672,     1024,      144, 0xcd723f7d
+0,      29696,      29696,     1024,      187, 0x2a0b5c1b
+0,      30720,      30720,     1024,      177, 0xb8c355d5
+0,      31744,      31744,     1024,      156, 0x867d4f3a
+0,      32768,      32768,     1024,      201, 0x62745ff9
+0,      33792,      33792,     1024,      137, 0x90c639e0, S=1, Skip Samples,  
     10, 0x048a00c2
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-priming-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-priming-duration
new file mode 100644
index 0000000000..710dd0b7b6
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-priming-duration
@@ -0,0 +1,10 @@
+#extradata 0:        2, 0x0030001c
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1024,       1024,     1024,      163, 0xd5f85007, S=1, Skip Samples,  
     10, 0x02a40044
+0,       2048,       2048,     1024,      127, 0x66484065
+0,       3072,       3072,     1024,       94, 0x55222bd6
+0,       4096,       4096,     1024,      314, 0x3c7e923a, S=1, Skip Samples,  
     10, 0x048f00c3
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-priming-gap 
b/tests/ref/fate/ffmpeg-trim-bsf-priming-gap
new file mode 100644
index 0000000000..5792cf121f
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-priming-gap
@@ -0,0 +1,8 @@
+#extradata 0:        2, 0x0030001c
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1024,       1024,     1024,      163, 0xd5f85007, S=1, Skip Samples,  
     10, 0x02a40044
+0,       2048,       2048,     1024,      127, 0x66484065
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-priming-gap-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-priming-gap-duration
new file mode 100644
index 0000000000..ffc486a140
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-priming-gap-duration
@@ -0,0 +1,7 @@
+#extradata 0:        2, 0x0030001c
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1024,       1024,     1024,      163, 0xd5f85007, S=1, Skip Samples,  
     10, 0x02a40044
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-priming-nodur 
b/tests/ref/fate/ffmpeg-trim-bsf-priming-nodur
new file mode 100644
index 0000000000..9a032b4927
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-priming-nodur
@@ -0,0 +1,9 @@
+#extradata 0:        2, 0x0030001c
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1024,       1024,     1024,      163, 0xd5f85007, S=1, Skip Samples,  
     10, 0x02a40044
+0,       2048,       2048,     1024,      127, 0x66484065
+0,       3072,       3072,     1024,       94, 0x55222bd6
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-priming-nopts 
b/tests/ref/fate/ffmpeg-trim-bsf-priming-nopts
new file mode 100644
index 0000000000..5792cf121f
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-priming-nopts
@@ -0,0 +1,8 @@
+#extradata 0:        2, 0x0030001c
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1024,       1024,     1024,      163, 0xd5f85007, S=1, Skip Samples,  
     10, 0x02a40044
+0,       2048,       2048,     1024,      127, 0x66484065
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-priming-untrimmed 
b/tests/ref/fate/ffmpeg-trim-bsf-priming-untrimmed
new file mode 100644
index 0000000000..4d67b67ef2
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-priming-untrimmed
@@ -0,0 +1,9 @@
+#extradata 0:        2, 0x0030001c
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1024,       1024,     1024,      163, 0xd5f85007
+0,       2048,       2048,     1024,      127, 0x66484065
+0,       3072,       3072,     1024,       94, 0x55222bd6
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-pts 
b/tests/ref/fate/ffmpeg-trim-bsf-pts
new file mode 100644
index 0000000000..298cbdabde
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-pts
@@ -0,0 +1,14 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed
+0,    5419008,    5419008,  1806336,      101, 0xa57c2f3a
+0,    7225344,    7225344,  1806336,      321, 0xfb92953a
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
+0,   10838016,   10838016,  1806336,      126, 0x685c3988
+0,   12644352,   12644352,  1806336,      191, 0x83256440
+0,   14450688,   14450688,  1806336,      139, 0x90373f34
+0,   16257024,   16257024,  1806336,      159, 0xc36153dc
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-pts-dts 
b/tests/ref/fate/ffmpeg-trim-bsf-pts-dts
new file mode 100644
index 0000000000..2262b8daab
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-pts-dts
@@ -0,0 +1,10 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed
+0,    5419008,    5419008,  1806336,      101, 0xa57c2f3a
+0,    7225344,    7225344,  1806336,      321, 0xfb92953a
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-pts-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-pts-duration
new file mode 100644
index 0000000000..72f14ca017
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-pts-duration
@@ -0,0 +1,6 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314, S=1, Skip Samples,  
     10, 0x06090102
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-rel 
b/tests/ref/fate/ffmpeg-trim-bsf-rel
new file mode 100644
index 0000000000..72f14ca017
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-rel
@@ -0,0 +1,6 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314, S=1, Skip Samples,  
     10, 0x06090102
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-samples 
b/tests/ref/fate/ffmpeg-trim-bsf-samples
new file mode 100644
index 0000000000..57164ca656
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-samples
@@ -0,0 +1,15 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,          0,          0,  1806336,       11, 0x204d0430, S=1, Skip Samples,  
     10, 0x00120002
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed
+0,    5419008,    5419008,  1806336,      101, 0xa57c2f3a
+0,    7225344,    7225344,  1806336,      321, 0xfb92953a
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
+0,   10838016,   10838016,  1806336,      126, 0x685c3988
+0,   12644352,   12644352,  1806336,      191, 0x83256440
+0,   14450688,   14450688,  1806336,      139, 0x90373f34
+0,   16257024,   16257024,  1806336,      159, 0xc36153dc, S=1, Skip Samples,  
     10, 0x000a0002
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-skip-samples 
b/tests/ref/fate/ffmpeg-trim-bsf-skip-samples
new file mode 100644
index 0000000000..26cb7c2270
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-skip-samples
@@ -0,0 +1,6 @@
+#tb 0: 1/16000
+#media_type 0: audio
+#codec_id 0: pcm_s16le
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,       1280,       1280,      512,     1024, 0x00000000
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-skip-samples-empty 
b/tests/ref/fate/ffmpeg-trim-bsf-skip-samples-empty
new file mode 100644
index 0000000000..aa85048ead
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-skip-samples-empty
@@ -0,0 +1,5 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-untrimmed 
b/tests/ref/fate/ffmpeg-trim-bsf-untrimmed
new file mode 100644
index 0000000000..298cbdabde
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-untrimmed
@@ -0,0 +1,14 @@
+#tb 0: 1/28224000
+#media_type 0: audio
+#codec_id 0: aac
+#sample_rate 0: 16000
+#channel_layout_name 0: mono
+0,    1806336,    1806336,  1806336,      170, 0xd84b5314
+0,    3612672,    3612672,  1806336,      134, 0x38bd43ed
+0,    5419008,    5419008,  1806336,      101, 0xa57c2f3a
+0,    7225344,    7225344,  1806336,      321, 0xfb92953a
+0,    9031680,    9031680,  1806336,      214, 0x143460ad
+0,   10838016,   10838016,  1806336,      126, 0x685c3988
+0,   12644352,   12644352,  1806336,      191, 0x83256440
+0,   14450688,   14450688,  1806336,      139, 0x90373f34
+0,   16257024,   16257024,  1806336,      159, 0xc36153dc
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-dts 
b/tests/ref/fate/ffmpeg-trim-bsf-video-dts
new file mode 100644
index 0000000000..ddb1b29116
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-dts
@@ -0,0 +1,9 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,        120,        120,       60,     6899, 0x4441d2b9
+0,        180,        180,       60,     6900, 0x9c03e201
+0,        240,        240,       60,     6961, 0x4e9edbf7
+0,        300,        300,       60,     7011, 0xeb78f54b
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-dts-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-video-dts-duration
new file mode 100644
index 0000000000..496f3b9e85
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-dts-duration
@@ -0,0 +1,7 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,        120,        120,       60,     6899, 0x4441d2b9
+0,        180,        180,       40,     6900, 0x9c03e201
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-dts-pts 
b/tests/ref/fate/ffmpeg-trim-bsf-video-dts-pts
new file mode 100644
index 0000000000..08dc1f33e0
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-dts-pts
@@ -0,0 +1,13 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,        120,        120,       60,     6899, 0x4441d2b9
+0,        180,        180,       60,     6900, 0x9c03e201
+0,        240,        240,       60,     6961, 0x4e9edbf7
+0,        300,        300,       60,     7011, 0xeb78f54b
+0,        360,        360,       60,     6966, 0xeefcdc9a
+0,        420,        420,       60,     6981, 0xc773df6a
+0,        480,        480,       60,     6923, 0x66b7ebe7
+0,        540,        540,       60,     6784, 0x48cb9c99
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-flush 
b/tests/ref/fate/ffmpeg-trim-bsf-video-flush
new file mode 100644
index 0000000000..ea2516833b
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-flush
@@ -0,0 +1,71 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         60,         60,       60,     6885, 0xf83ed865
+0,        120,        120,       60,     6899, 0x4441d2b9
+0,        180,        180,       60,     6900, 0x9c03e201
+0,        240,        240,       60,     6961, 0x4e9edbf7
+0,        300,        300,       60,     7011, 0xeb78f54b
+0,        360,        360,       60,     6966, 0xeefcdc9a
+0,        420,        420,       60,     6981, 0xc773df6a
+0,        480,        480,       60,     6923, 0x66b7ebe7
+0,        540,        540,       60,     6784, 0x48cb9c99
+0,        600,        600,       60,     6856, 0x70f9cb69
+0,        660,        660,       60,     6861, 0xe2e1d5b0
+0,        720,        720,       60,     6952, 0x9b8fdd3a
+0,        780,        780,       60,     6973, 0x2a58ef94
+0,        840,        840,       60,     6855, 0xb8e7d149
+0,        900,        900,       60,     6964, 0x8139e2d6
+0,        960,        960,       60,     6955, 0xd482f11d
+0,       1020,       1020,       60,     6923, 0xb1a0c02a
+0,       1080,       1080,       60,     6954, 0xde96e53a
+0,       1140,       1140,       60,     6960, 0x612bdc68
+0,       1200,       1200,       60,     6844, 0x36c5d40f
+0,       1260,       1260,       60,     6965, 0x6c64dbde
+0,       1320,       1320,       60,     6955, 0x9f46e67c
+0,       1380,       1380,       60,     6931, 0xc305d602
+0,       1440,       1440,       60,     6988, 0x0ccfe04b
+0,       1500,       1500,       60,     6935, 0x295eeee3
+0,       1560,       1560,       60,     6796, 0xb82e9f95
+0,       1620,       1620,       60,     6923, 0xacabd648
+0,       1680,       1680,       60,     6993, 0x660df344
+0,       1740,       1740,       60,     6983, 0x85d4e394
+0,       1800,       1800,       60,     6995, 0x0a59f03b
+0,       1860,       1860,       60,     6813, 0xb48fc71b
+0,       1920,       1920,       60,     6938, 0x0cf3d962
+0,       1980,       1980,       20,     6942, 0x82a2eefe
+0,       2060,       2060,       60,     6885, 0xf83ed865
+0,       2120,       2120,       60,     6899, 0x4441d2b9
+0,       2180,       2180,       60,     6900, 0x9c03e201
+0,       2240,       2240,       60,     6961, 0x4e9edbf7
+0,       2300,       2300,       60,     7011, 0xeb78f54b
+0,       2360,       2360,       60,     6966, 0xeefcdc9a
+0,       2420,       2420,       60,     6981, 0xc773df6a
+0,       2480,       2480,       60,     6923, 0x66b7ebe7
+0,       2540,       2540,       60,     6784, 0x48cb9c99
+0,       2600,       2600,       60,     6856, 0x70f9cb69
+0,       2660,       2660,       60,     6861, 0xe2e1d5b0
+0,       2720,       2720,       60,     6952, 0x9b8fdd3a
+0,       2780,       2780,       60,     6973, 0x2a58ef94
+0,       2840,       2840,       60,     6855, 0xb8e7d149
+0,       2900,       2900,       60,     6964, 0x8139e2d6
+0,       2960,       2960,       60,     6955, 0xd482f11d
+0,       3020,       3020,       60,     6923, 0xb1a0c02a
+0,       3080,       3080,       60,     6954, 0xde96e53a
+0,       3140,       3140,       60,     6960, 0x612bdc68
+0,       3200,       3200,       60,     6844, 0x36c5d40f
+0,       3260,       3260,       60,     6965, 0x6c64dbde
+0,       3320,       3320,       60,     6955, 0x9f46e67c
+0,       3380,       3380,       60,     6931, 0xc305d602
+0,       3440,       3440,       60,     6988, 0x0ccfe04b
+0,       3500,       3500,       60,     6935, 0x295eeee3
+0,       3560,       3560,       60,     6796, 0xb82e9f95
+0,       3620,       3620,       60,     6923, 0xacabd648
+0,       3680,       3680,       60,     6993, 0x660df344
+0,       3740,       3740,       60,     6983, 0x85d4e394
+0,       3800,       3800,       60,     6995, 0x0a59f03b
+0,       3860,       3860,       60,     6813, 0xb48fc71b
+0,       3920,       3920,       60,     6938, 0x0cf3d962
+0,       3980,       3980,       20,     6942, 0x82a2eefe
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-flush-rel 
b/tests/ref/fate/ffmpeg-trim-bsf-video-flush-rel
new file mode 100644
index 0000000000..ba8ab00d63
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-flush-rel
@@ -0,0 +1,69 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,        120,        120,       60,     6899, 0x4441d2b9
+0,        180,        180,       60,     6900, 0x9c03e201
+0,        240,        240,       60,     6961, 0x4e9edbf7
+0,        300,        300,       60,     7011, 0xeb78f54b
+0,        360,        360,       60,     6966, 0xeefcdc9a
+0,        420,        420,       60,     6981, 0xc773df6a
+0,        480,        480,       60,     6923, 0x66b7ebe7
+0,        540,        540,       60,     6784, 0x48cb9c99
+0,        600,        600,       60,     6856, 0x70f9cb69
+0,        660,        660,       60,     6861, 0xe2e1d5b0
+0,        720,        720,       60,     6952, 0x9b8fdd3a
+0,        780,        780,       60,     6973, 0x2a58ef94
+0,        840,        840,       60,     6855, 0xb8e7d149
+0,        900,        900,       60,     6964, 0x8139e2d6
+0,        960,        960,       60,     6955, 0xd482f11d
+0,       1020,       1020,       60,     6923, 0xb1a0c02a
+0,       1080,       1080,       60,     6954, 0xde96e53a
+0,       1140,       1140,       60,     6960, 0x612bdc68
+0,       1200,       1200,       60,     6844, 0x36c5d40f
+0,       1260,       1260,       60,     6965, 0x6c64dbde
+0,       1320,       1320,       60,     6955, 0x9f46e67c
+0,       1380,       1380,       60,     6931, 0xc305d602
+0,       1440,       1440,       60,     6988, 0x0ccfe04b
+0,       1500,       1500,       60,     6935, 0x295eeee3
+0,       1560,       1560,       60,     6796, 0xb82e9f95
+0,       1620,       1620,       60,     6923, 0xacabd648
+0,       1680,       1680,       60,     6993, 0x660df344
+0,       1740,       1740,       60,     6983, 0x85d4e394
+0,       1800,       1800,       60,     6995, 0x0a59f03b
+0,       1860,       1860,       60,     6813, 0xb48fc71b
+0,       1920,       1920,       60,     6938, 0x0cf3d962
+0,       1980,       1980,       20,     6942, 0x82a2eefe
+0,       2120,       2120,       60,     6899, 0x4441d2b9
+0,       2180,       2180,       60,     6900, 0x9c03e201
+0,       2240,       2240,       60,     6961, 0x4e9edbf7
+0,       2300,       2300,       60,     7011, 0xeb78f54b
+0,       2360,       2360,       60,     6966, 0xeefcdc9a
+0,       2420,       2420,       60,     6981, 0xc773df6a
+0,       2480,       2480,       60,     6923, 0x66b7ebe7
+0,       2540,       2540,       60,     6784, 0x48cb9c99
+0,       2600,       2600,       60,     6856, 0x70f9cb69
+0,       2660,       2660,       60,     6861, 0xe2e1d5b0
+0,       2720,       2720,       60,     6952, 0x9b8fdd3a
+0,       2780,       2780,       60,     6973, 0x2a58ef94
+0,       2840,       2840,       60,     6855, 0xb8e7d149
+0,       2900,       2900,       60,     6964, 0x8139e2d6
+0,       2960,       2960,       60,     6955, 0xd482f11d
+0,       3020,       3020,       60,     6923, 0xb1a0c02a
+0,       3080,       3080,       60,     6954, 0xde96e53a
+0,       3140,       3140,       60,     6960, 0x612bdc68
+0,       3200,       3200,       60,     6844, 0x36c5d40f
+0,       3260,       3260,       60,     6965, 0x6c64dbde
+0,       3320,       3320,       60,     6955, 0x9f46e67c
+0,       3380,       3380,       60,     6931, 0xc305d602
+0,       3440,       3440,       60,     6988, 0x0ccfe04b
+0,       3500,       3500,       60,     6935, 0x295eeee3
+0,       3560,       3560,       60,     6796, 0xb82e9f95
+0,       3620,       3620,       60,     6923, 0xacabd648
+0,       3680,       3680,       60,     6993, 0x660df344
+0,       3740,       3740,       60,     6983, 0x85d4e394
+0,       3800,       3800,       60,     6995, 0x0a59f03b
+0,       3860,       3860,       60,     6813, 0xb48fc71b
+0,       3920,       3920,       60,     6938, 0x0cf3d962
+0,       3980,       3980,       20,     6942, 0x82a2eefe
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-mixed-axes 
b/tests/ref/fate/ffmpeg-trim-bsf-video-mixed-axes
new file mode 100644
index 0000000000..7c65ee4c7d
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-mixed-axes
@@ -0,0 +1,6 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         10,        110,       30,     6838, 0x2d59b149
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-mixed-axes-empty 
b/tests/ref/fate/ffmpeg-trim-bsf-video-mixed-axes-empty
new file mode 100644
index 0000000000..165f98c65e
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-mixed-axes-empty
@@ -0,0 +1,5 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-duration
new file mode 100644
index 0000000000..22f9216d1c
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-duration
@@ -0,0 +1,7 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         60,         60,       60,     6885, 0xf83ed865
+0,        120,        120,       40,     6899, 0x4441d2b9
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-empty 
b/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-empty
new file mode 100644
index 0000000000..165f98c65e
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-empty
@@ -0,0 +1,5 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-rel 
b/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-rel
new file mode 100644
index 0000000000..be24f86940
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-nopts-rel
@@ -0,0 +1,12 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,        180,        180,       60,     6900, 0x9c03e201
+0,        240,        240,       60,     6961, 0x4e9edbf7
+0,        300,        300,       60,     7011, 0xeb78f54b
+0,        360,        360,       60,     6966, 0xeefcdc9a
+0,        420,        420,       60,     6981, 0xc773df6a
+0,        480,        480,       60,     6923, 0x66b7ebe7
+0,        540,        540,       60,     6784, 0x48cb9c99
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-partial-dts-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-video-partial-dts-duration
new file mode 100644
index 0000000000..efd48725d4
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-partial-dts-duration
@@ -0,0 +1,8 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         30,        130,       30,     6838, 0x2d59b149
+0,         60,        160,       60,     6885, 0xf83ed865
+0,        120,        220,       10,     6899, 0x4441d2b9
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-pkt 
b/tests/ref/fate/ffmpeg-trim-bsf-video-pkt
new file mode 100644
index 0000000000..5186764a63
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-pkt
@@ -0,0 +1,15 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,        300,        300,       60,     7011, 0xeb78f54b
+0,        360,        360,       60,     6966, 0xeefcdc9a
+0,        420,        420,       60,     6981, 0xc773df6a
+0,        480,        480,       60,     6923, 0x66b7ebe7
+0,        540,        540,       60,     6784, 0x48cb9c99
+0,        600,        600,       60,     6856, 0x70f9cb69
+0,        660,        660,       60,     6861, 0xe2e1d5b0
+0,        720,        720,       60,     6952, 0x9b8fdd3a
+0,        780,        780,       60,     6973, 0x2a58ef94
+0,        840,        840,       60,     6855, 0xb8e7d149
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-preroll 
b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll
new file mode 100644
index 0000000000..2bf31a4d8b
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll
@@ -0,0 +1,31 @@
+#extradata 0:       38, 0xbe2e09b5
+#tb 0: 1/12800
+#media_type 0: video
+#codec_id 0: h264
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,       -512,          0,      512,     5670, 0x92b5edd6, F=0x5
+0,          0,       2048,      512,     3606, 0xfdf006a3, F=0x4
+0,        512,        512,      512,     1710, 0x338b58f6, F=0x4
+0,       1024,       1024,      512,     1852, 0xdeab9856, F=0x4
+0,       1536,       1536,      512,     1808, 0x2ea56967, F=0x4
+0,       2048,       4096,      512,     3214, 0x5542390e, F=0x0
+0,       2560,       2560,      512,     1686, 0xc7ca612f, F=0x4
+0,       3072,       3072,      512,     1702, 0x9bec5a5d, F=0x4
+0,       3584,       3584,      512,     1729, 0xd1e86623, F=0x4
+0,       4096,       6144,      512,     3033, 0x4f44e7ed, F=0x0
+0,       4608,       4608,      512,     1433, 0x6588c02f, F=0x0
+0,       5120,       5120,      512,     1658, 0x7f2c422d, F=0x0
+0,       5632,       5632,      512,     1755, 0xcc3f747e, F=0x0
+0,       6144,       8192,      512,     2615, 0xf99d0a04, F=0x0
+0,       6656,       6656,      512,     1489, 0x5af4e14d, F=0x0
+0,       7168,       7168,      512,     1899, 0x10eb978d, F=0x0
+0,       7680,       7680,      512,     1891, 0x237aa63d, F=0x0
+0,       8192,      10240,      512,     2750, 0x9e58380b, F=0x0
+0,       8704,       8704,      512,     1637, 0x2a9f2d9f, F=0x0
+0,       9216,       9216,      512,     1760, 0x0edb5ba8, F=0x0
+0,       9728,       9728,      512,     1716, 0x312f5526, F=0x0
+0,      10240,      12288,      512,     2759, 0x8f9b6043, F=0x0
+0,      10752,      10752,      512,     1836, 0x69308d30, F=0x0
+0,      11264,      11264,      512,     1946, 0x2af5c762, F=0x0
+0,      11776,      11776,      512,     2107, 0x11b723c1, F=0x0
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-decoded 
b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-decoded
new file mode 100644
index 0000000000..16bca1933a
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-decoded
@@ -0,0 +1,22 @@
+#tb 0: 1/25
+#media_type 0: video
+#codec_id 0: rawvideo
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,          8,          8,        1,   115200, 0xa2c0a850
+0,          9,          9,        1,   115200, 0x48a89f6e
+0,         10,         10,        1,   115200, 0x4f60a71e
+0,         11,         11,        1,   115200, 0x481a9d0e
+0,         12,         12,        1,   115200, 0xf3a29e28
+0,         13,         13,        1,   115200, 0x570aa640
+0,         14,         14,        1,   115200, 0xe75facac
+0,         15,         15,        1,   115200, 0x7ba9c067
+0,         16,         16,        1,   115200, 0x663cba45
+0,         17,         17,        1,   115200, 0x6c86bcc7
+0,         18,         18,        1,   115200, 0x3623be36
+0,         19,         19,        1,   115200, 0x1453b9e3
+0,         20,         20,        1,   115200, 0x9905cb44
+0,         21,         21,        1,   115200, 0x2e23b739
+0,         22,         22,        1,   115200, 0x60aeb2c3
+0,         23,         23,        1,   115200, 0x45be96ea
+0,         24,         24,        1,   115200, 0x23947e41
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-keyframe 
b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-keyframe
new file mode 100644
index 0000000000..7363e0909e
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-keyframe
@@ -0,0 +1,20 @@
+#extradata 0:       34, 0xb7420823
+#tb 0: 1/90000
+#media_type 0: video
+#codec_id 0: mpeg2video
+#dimensions 0: 716x236
+#sar 0: 1/1
+0,      36000,      43200,     3600,     8004, 0xf412f86e, F=0x5
+0,      39600,      39600,     3600,     3034, 0x3de5ee06, F=0x4
+0,      43200,      50400,     3600,     4567, 0x6bffffc5, F=0x4
+0,      46800,      46800,     3600,     2138, 0xdac10e2e, F=0x4
+0,      50400,      57600,     3600,     3464, 0xf6a5d069, F=0x0
+0,      54000,      54000,     3600,     1651, 0x802304b6, F=0x0
+0,      57600,      64800,     3600,     2749, 0xe9015e44, F=0x0
+0,      61200,      61200,     3600,     1508, 0xc11c9271, F=0x0
+0,      64800,      72000,     3600,     2149, 0x85e22e0d, F=0x0
+0,      68400,      68400,     3600,     1234, 0xfcc646b4, F=0x0
+0,      72000,      79200,     3600,     1962, 0x0cf0b59e, F=0x0
+0,      75600,      75600,     3600,     1159, 0x851d0fc4, F=0x0
+0,      79200, -9223372036854775808,     3600,     3894, 0xb6967928
+0,      82800,      82800,     3600,     1065, 0xf570d29c, F=0x0
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-on-keyframe 
b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-on-keyframe
new file mode 100644
index 0000000000..dbe28f5af6
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-on-keyframe
@@ -0,0 +1,20 @@
+#extradata 0:       34, 0xb7420823
+#tb 0: 1/90000
+#media_type 0: video
+#codec_id 0: mpeg2video
+#dimensions 0: 716x236
+#sar 0: 1/1
+0,      36000,      43200,     3600,     8004, 0xf412f86e
+0,      39600,      39600,     3600,     3034, 0x3de5ee06, F=0x0
+0,      43200,      50400,     3600,     4567, 0x6bffffc5, F=0x0
+0,      46800,      46800,     3600,     2138, 0xdac10e2e, F=0x0
+0,      50400,      57600,     3600,     3464, 0xf6a5d069, F=0x0
+0,      54000,      54000,     3600,     1651, 0x802304b6, F=0x0
+0,      57600,      64800,     3600,     2749, 0xe9015e44, F=0x0
+0,      61200,      61200,     3600,     1508, 0xc11c9271, F=0x0
+0,      64800,      72000,     3600,     2149, 0x85e22e0d, F=0x0
+0,      68400,      68400,     3600,     1234, 0xfcc646b4, F=0x0
+0,      72000,      79200,     3600,     1962, 0x0cf0b59e, F=0x0
+0,      75600,      75600,     3600,     1159, 0x851d0fc4, F=0x0
+0,      79200, -9223372036854775808,     3600,     3894, 0xb6967928
+0,      82800,      82800,     3600,     1065, 0xf570d29c, F=0x0
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-overflow 
b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-overflow
new file mode 100644
index 0000000000..370080fa91
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-preroll-overflow
@@ -0,0 +1,23 @@
+#extradata 0:       38, 0xbe2e09b5
+#tb 0: 1/12800
+#media_type 0: video
+#codec_id 0: h264
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,       2048,       4096,      512,     3214, 0x5542390e, F=0x0
+0,       4096,       6144,      512,     3033, 0x4f44e7ed, F=0x0
+0,       4608,       4608,      512,     1433, 0x6588c02f, F=0x0
+0,       5120,       5120,      512,     1658, 0x7f2c422d, F=0x0
+0,       5632,       5632,      512,     1755, 0xcc3f747e, F=0x0
+0,       6144,       8192,      512,     2615, 0xf99d0a04, F=0x0
+0,       6656,       6656,      512,     1489, 0x5af4e14d, F=0x0
+0,       7168,       7168,      512,     1899, 0x10eb978d, F=0x0
+0,       7680,       7680,      512,     1891, 0x237aa63d, F=0x0
+0,       8192,      10240,      512,     2750, 0x9e58380b, F=0x0
+0,       8704,       8704,      512,     1637, 0x2a9f2d9f, F=0x0
+0,       9216,       9216,      512,     1760, 0x0edb5ba8, F=0x0
+0,       9728,       9728,      512,     1716, 0x312f5526, F=0x0
+0,      10240,      12288,      512,     2759, 0x8f9b6043, F=0x0
+0,      10752,      10752,      512,     1836, 0x69308d30, F=0x0
+0,      11264,      11264,      512,     1946, 0x2af5c762, F=0x0
+0,      11776,      11776,      512,     2107, 0x11b723c1, F=0x0
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-pts 
b/tests/ref/fate/ffmpeg-trim-bsf-video-pts
new file mode 100644
index 0000000000..bfb800850b
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-pts
@@ -0,0 +1,14 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         60,         60,       60,     6885, 0xf83ed865
+0,        120,        120,       60,     6899, 0x4441d2b9
+0,        180,        180,       60,     6900, 0x9c03e201
+0,        240,        240,       60,     6961, 0x4e9edbf7
+0,        300,        300,       60,     7011, 0xeb78f54b
+0,        360,        360,       60,     6966, 0xeefcdc9a
+0,        420,        420,       60,     6981, 0xc773df6a
+0,        480,        480,       60,     6923, 0x66b7ebe7
+0,        540,        540,       60,     6784, 0x48cb9c99
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-pts-dts 
b/tests/ref/fate/ffmpeg-trim-bsf-video-pts-dts
new file mode 100644
index 0000000000..597042eb03
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-pts-dts
@@ -0,0 +1,10 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         60,         60,       60,     6885, 0xf83ed865
+0,        120,        120,       60,     6899, 0x4441d2b9
+0,        180,        180,       60,     6900, 0x9c03e201
+0,        240,        240,       60,     6961, 0x4e9edbf7
+0,        300,        300,       60,     7011, 0xeb78f54b
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-pts-duration 
b/tests/ref/fate/ffmpeg-trim-bsf-video-pts-duration
new file mode 100644
index 0000000000..22f9216d1c
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-pts-duration
@@ -0,0 +1,7 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         60,         60,       60,     6885, 0xf83ed865
+0,        120,        120,       40,     6899, 0x4441d2b9
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-reordered 
b/tests/ref/fate/ffmpeg-trim-bsf-video-reordered
new file mode 100644
index 0000000000..bbac9e91b3
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-reordered
@@ -0,0 +1,10 @@
+#extradata 0:       38, 0xbe2e09b5
+#tb 0: 1/12800
+#media_type 0: video
+#codec_id 0: h264
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,       -512,          0,      512,     5670, 0x92b5edd6
+0,        512,        512,      512,     1710, 0x338b58f6, F=0x0
+0,       1024,       1024,      512,     1852, 0xdeab9856, F=0x0
+0,       1536,       1536,       64,     1808, 0x2ea56967, F=0x0
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-reordered-count 
b/tests/ref/fate/ffmpeg-trim-bsf-video-reordered-count
new file mode 100644
index 0000000000..b882e384f3
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-reordered-count
@@ -0,0 +1,9 @@
+#extradata 0:       38, 0xbe2e09b5
+#tb 0: 1/12800
+#media_type 0: video
+#codec_id 0: h264
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,          0,       2048,      512,     3606, 0xfdf006a3, F=0x0
+0,       1100,       1100,      436,     1852, 0xdeab9856, F=0x0
+0,       1536,       1536,      512,     1808, 0x2ea56967, F=0x0
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-reordered-nodts 
b/tests/ref/fate/ffmpeg-trim-bsf-video-reordered-nodts
new file mode 100644
index 0000000000..1bbbfd0fbb
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-reordered-nodts
@@ -0,0 +1,10 @@
+#extradata 0:       38, 0xbe2e09b5
+#tb 0: 1/12800
+#media_type 0: video
+#codec_id 0: h264
+#dimensions 0: 320x240
+#sar 0: 1/1
+0,       -512,          0,      512,     5670, 0x92b5edd6
+0,          0,        512,      512,     1710, 0x338b58f6, F=0x0
+0,        512,       1024,      512,     1852, 0xdeab9856, F=0x0
+0,       1024,       1536,       64,     1808, 0x2ea56967, F=0x0
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-samples 
b/tests/ref/fate/ffmpeg-trim-bsf-video-samples
new file mode 100644
index 0000000000..44b28769f3
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-samples
@@ -0,0 +1,8 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         30,         30,       30,     6838, 0x2d59b149
+0,         60,         60,       60,     6885, 0xf83ed865
+0,        120,        120,       30,     6899, 0x4441d2b9
diff --git a/tests/ref/fate/ffmpeg-trim-bsf-video-untrimmed 
b/tests/ref/fate/ffmpeg-trim-bsf-video-untrimmed
new file mode 100644
index 0000000000..dbcef95d18
--- /dev/null
+++ b/tests/ref/fate/ffmpeg-trim-bsf-video-untrimmed
@@ -0,0 +1,7 @@
+#tb 0: 1/600
+#media_type 0: video
+#codec_id 0: qtrle
+#dimensions 0: 160x120
+#sar 0: 0/1
+0,         60,         60,       60,     6885, 0xf83ed865
+0,        120,        120,       60,     6899, 0x4441d2b9

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to