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]