Browse code

Merge commit 'a1e05b0487a1939334c2920fc7f9936bc9efe876'

* commit 'a1e05b0487a1939334c2920fc7f9936bc9efe876':
lavfi: add trim and atrim filters.

Conflicts:
Changelog
doc/filters.texi
libavfilter/Makefile
libavfilter/allfilters.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>

Michael Niedermayer authored on 2013/05/01 18:26:53
Showing 15 changed files
... ...
@@ -34,6 +34,7 @@ version <next>:
34 34
 - vidstabdetect and vidstabtransform filters for video stabilization using
35 35
   the vid.stab library
36 36
 - astats filter
37
+- trim and atrim filters
37 38
 
38 39
 
39 40
 version 1.2:
... ...
@@ -1335,6 +1335,70 @@ with a negative pts due to encoder delay.
1335 1335
 
1336 1336
 @end table
1337 1337
 
1338
+@section atrim
1339
+Trim the input so that the output contains one continuous subpart of the input.
1340
+
1341
+This filter accepts the following options:
1342
+@table @option
1343
+@item start
1344
+Timestamp (in seconds) of the start of the kept section. I.e. the audio sample
1345
+with the timestamp @var{start} will be the first sample in the output.
1346
+
1347
+@item end
1348
+Timestamp (in seconds) of the first audio sample that will be dropped. I.e. the
1349
+audio sample immediately preceding the one with the timestamp @var{end} will be
1350
+the last sample in the output.
1351
+
1352
+@item start_pts
1353
+Same as @var{start}, except this option sets the start timestamp in samples
1354
+instead of seconds.
1355
+
1356
+@item end_pts
1357
+Same as @var{end}, except this option sets the end timestamp in samples instead
1358
+of seconds.
1359
+
1360
+@item duration
1361
+Maximum duration of the output in seconds.
1362
+
1363
+@item start_sample
1364
+Number of the first sample that should be passed to output.
1365
+
1366
+@item end_sample
1367
+Number of the first sample that should be dropped.
1368
+@end table
1369
+
1370
+Note that the first two sets of the start/end options and the @option{duration}
1371
+option look at the frame timestamp, while the _sample options simply count the
1372
+samples that pass through the filter. So start/end_pts and start/end_sample will
1373
+give different results when the timestamps are wrong, inexact or do not start at
1374
+zero. Also note that this filter does not modify the timestamps. If you wish
1375
+that the output timestamps start at zero, insert the asetpts filter after the
1376
+atrim filter.
1377
+
1378
+If multiple start or end options are set, this filter tries to be greedy and
1379
+keep all samples that match at least one of the specified constraints. To keep
1380
+only the part that matches all the constraints at once, chain multiple atrim
1381
+filters.
1382
+
1383
+The defaults are such that all the input is kept. So it is possible to set e.g.
1384
+just the end values to keep everything before the specified time.
1385
+
1386
+Examples:
1387
+@itemize
1388
+@item
1389
+drop everything except the second minute of input
1390
+@example
1391
+ffmpeg -i INPUT -af atrim=60:120
1392
+@end example
1393
+
1394
+@item
1395
+keep only the first 1000 samples
1396
+@example
1397
+ffmpeg -i INPUT -af atrim=end_sample=1000
1398
+@end example
1399
+
1400
+@end itemize
1401
+
1338 1402
 @section channelsplit
1339 1403
 Split each channel in input audio stream into a separate output stream.
1340 1404
 
... ...
@@ -6278,6 +6342,69 @@ The command above can also be specified as:
6278 6278
 transpose=1:portrait
6279 6279
 @end example
6280 6280
 
6281
+@section trim
6282
+Trim the input so that the output contains one continuous subpart of the input.
6283
+
6284
+This filter accepts the following options:
6285
+@table @option
6286
+@item start
6287
+Timestamp (in seconds) of the start of the kept section. I.e. the frame with the
6288
+timestamp @var{start} will be the first frame in the output.
6289
+
6290
+@item end
6291
+Timestamp (in seconds) of the first frame that will be dropped. I.e. the frame
6292
+immediately preceding the one with the timestamp @var{end} will be the last
6293
+frame in the output.
6294
+
6295
+@item start_pts
6296
+Same as @var{start}, except this option sets the start timestamp in timebase
6297
+units instead of seconds.
6298
+
6299
+@item end_pts
6300
+Same as @var{end}, except this option sets the end timestamp in timebase units
6301
+instead of seconds.
6302
+
6303
+@item duration
6304
+Maximum duration of the output in seconds.
6305
+
6306
+@item start_frame
6307
+Number of the first frame that should be passed to output.
6308
+
6309
+@item end_frame
6310
+Number of the first frame that should be dropped.
6311
+@end table
6312
+
6313
+Note that the first two sets of the start/end options and the @option{duration}
6314
+option look at the frame timestamp, while the _frame variants simply count the
6315
+frames that pass through the filter. Also note that this filter does not modify
6316
+the timestamps. If you wish that the output timestamps start at zero, insert a
6317
+setpts filter after the trim filter.
6318
+
6319
+If multiple start or end options are set, this filter tries to be greedy and
6320
+keep all the frames that match at least one of the specified constraints. To keep
6321
+only the part that matches all the constraints at once, chain multiple trim
6322
+filters.
6323
+
6324
+The defaults are such that all the input is kept. So it is possible to set e.g.
6325
+just the end values to keep everything before the specified time.
6326
+
6327
+Examples:
6328
+@itemize
6329
+@item
6330
+drop everything except the second minute of input
6331
+@example
6332
+ffmpeg -i INPUT -vf trim=60:120
6333
+@end example
6334
+
6335
+@item
6336
+keep only the first second
6337
+@example
6338
+ffmpeg -i INPUT -vf trim=duration=1
6339
+@end example
6340
+
6341
+@end itemize
6342
+
6343
+
6281 6344
 @section unsharp
6282 6345
 
6283 6346
 Sharpen or blur the input video.
... ...
@@ -73,6 +73,7 @@ OBJS-$(CONFIG_ASTATS_FILTER)                 += af_astats.o
73 73
 OBJS-$(CONFIG_ASTREAMSYNC_FILTER)            += af_astreamsync.o
74 74
 OBJS-$(CONFIG_ASYNCTS_FILTER)                += af_asyncts.o
75 75
 OBJS-$(CONFIG_ATEMPO_FILTER)                 += af_atempo.o
76
+OBJS-$(CONFIG_ATRIM_FILTER)                  += trim.o
76 77
 OBJS-$(CONFIG_BANDPASS_FILTER)               += af_biquads.o
77 78
 OBJS-$(CONFIG_BANDREJECT_FILTER)             += af_biquads.o
78 79
 OBJS-$(CONFIG_BASS_FILTER)                   += af_biquads.o
... ...
@@ -178,6 +179,7 @@ OBJS-$(CONFIG_THUMBNAIL_FILTER)              += vf_thumbnail.o
178 178
 OBJS-$(CONFIG_TILE_FILTER)                   += vf_tile.o
179 179
 OBJS-$(CONFIG_TINTERLACE_FILTER)             += vf_tinterlace.o
180 180
 OBJS-$(CONFIG_TRANSPOSE_FILTER)              += vf_transpose.o
181
+OBJS-$(CONFIG_TRIM_FILTER)                   += trim.o
181 182
 OBJS-$(CONFIG_UNSHARP_FILTER)                += vf_unsharp.o
182 183
 OBJS-$(CONFIG_VFLIP_FILTER)                  += vf_vflip.o
183 184
 OBJS-$(CONFIG_VIDSTABDETECT_FILTER)          += vidstabutils.o vf_vidstabdetect.o
... ...
@@ -71,6 +71,7 @@ void avfilter_register_all(void)
71 71
     REGISTER_FILTER(ASTREAMSYNC,    astreamsync,    af);
72 72
     REGISTER_FILTER(ASYNCTS,        asyncts,        af);
73 73
     REGISTER_FILTER(ATEMPO,         atempo,         af);
74
+    REGISTER_FILTER(ATRIM,          atrim,          af);
74 75
     REGISTER_FILTER(BANDPASS,       bandpass,       af);
75 76
     REGISTER_FILTER(BANDREJECT,     bandreject,     af);
76 77
     REGISTER_FILTER(BASS,           bass,           af);
... ...
@@ -175,6 +176,7 @@ void avfilter_register_all(void)
175 175
     REGISTER_FILTER(TILE,           tile,           vf);
176 176
     REGISTER_FILTER(TINTERLACE,     tinterlace,     vf);
177 177
     REGISTER_FILTER(TRANSPOSE,      transpose,      vf);
178
+    REGISTER_FILTER(TRIM,           trim,           vf);
178 179
     REGISTER_FILTER(UNSHARP,        unsharp,        vf);
179 180
     REGISTER_FILTER(VFLIP,          vflip,          vf);
180 181
     REGISTER_FILTER(VIDSTABDETECT,  vidstabdetect,  vf);
181 182
new file mode 100644
... ...
@@ -0,0 +1,407 @@
0
+/*
1
+ * This file is part of FFmpeg.
2
+ *
3
+ * FFmpeg is free software; you can redistribute it and/or
4
+ * modify it under the terms of the GNU Lesser General Public
5
+ * License as published by the Free Software Foundation; either
6
+ * version 2.1 of the License, or (at your option) any later version.
7
+ *
8
+ * FFmpeg is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with FFmpeg; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
+ */
17
+
18
+#include <float.h>
19
+#include <math.h>
20
+
21
+#include "config.h"
22
+
23
+#include "libavutil/avassert.h"
24
+#include "libavutil/channel_layout.h"
25
+#include "libavutil/common.h"
26
+#include "libavutil/log.h"
27
+#include "libavutil/mathematics.h"
28
+#include "libavutil/opt.h"
29
+#include "libavutil/samplefmt.h"
30
+
31
+#include "audio.h"
32
+#include "avfilter.h"
33
+#include "internal.h"
34
+
35
+typedef struct TrimContext {
36
+    const AVClass *class;
37
+
38
+    /*
39
+     * AVOptions
40
+     */
41
+    double duration;
42
+    double start_time, end_time;
43
+    int64_t start_frame, end_frame;
44
+    /*
45
+     * in the link timebase for video,
46
+     * in 1/samplerate for audio
47
+     */
48
+    int64_t start_pts, end_pts;
49
+    int64_t start_sample, end_sample;
50
+
51
+    /*
52
+     * number of video frames that arrived on this filter so far
53
+     */
54
+    int64_t nb_frames;
55
+    /*
56
+     * number of audio samples that arrived on this filter so far
57
+     */
58
+    int64_t nb_samples;
59
+    /*
60
+     * timestamp of the first frame in the output, in the timebase units
61
+     */
62
+    int64_t first_pts;
63
+    /*
64
+     * duration in the timebase units
65
+     */
66
+    int64_t duration_tb;
67
+
68
+    int64_t next_pts;
69
+
70
+    int eof;
71
+    int got_output;
72
+} TrimContext;
73
+
74
+static int init(AVFilterContext *ctx)
75
+{
76
+    TrimContext *s = ctx->priv;
77
+
78
+    s->first_pts = AV_NOPTS_VALUE;
79
+
80
+    return 0;
81
+}
82
+
83
+static int config_input(AVFilterLink *inlink)
84
+{
85
+    AVFilterContext *ctx = inlink->dst;
86
+    TrimContext       *s = ctx->priv;
87
+    AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ?
88
+                     inlink->time_base : (AVRational){ 1, inlink->sample_rate };
89
+
90
+    if (s->start_time != DBL_MAX) {
91
+        int64_t start_pts = lrintf(s->start_time / av_q2d(tb));
92
+        if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts)
93
+            s->start_pts = start_pts;
94
+    }
95
+    if (s->end_time != DBL_MAX) {
96
+        int64_t end_pts = lrintf(s->end_time / av_q2d(tb));
97
+        if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts)
98
+            s->end_pts = end_pts;
99
+    }
100
+    if (s->duration)
101
+        s->duration_tb = lrintf(s->duration / av_q2d(tb));
102
+
103
+    return 0;
104
+}
105
+
106
+static int request_frame(AVFilterLink *outlink)
107
+{
108
+    AVFilterContext *ctx = outlink->src;
109
+    TrimContext       *s = ctx->priv;
110
+    int ret;
111
+
112
+    s->got_output = 0;
113
+    while (!s->got_output) {
114
+        if (s->eof)
115
+            return AVERROR_EOF;
116
+
117
+        ret = ff_request_frame(ctx->inputs[0]);
118
+        if (ret < 0)
119
+            return ret;
120
+    }
121
+
122
+    return 0;
123
+}
124
+
125
+#define OFFSET(x) offsetof(TrimContext, x)
126
+#define COMMON_OPTS                                                                                                                                                         \
127
+    { "start",       "Timestamp in seconds of the first frame that "                                                                                                        \
128
+        "should be passed",                                              OFFSET(start_time),  AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX },       -DBL_MAX, DBL_MAX,     FLAGS }, \
129
+    { "end",         "Timestamp in seconds of the first frame that "                                                                                                        \
130
+        "should be dropped again",                                       OFFSET(end_time),    AV_OPT_TYPE_DOUBLE, { .dbl = DBL_MAX },       -DBL_MAX, DBL_MAX,     FLAGS }, \
131
+    { "start_pts",   "Timestamp of the first frame that should be "                                                                                                         \
132
+       " passed",                                                        OFFSET(start_pts),   AV_OPT_TYPE_INT64,  { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \
133
+    { "end_pts",     "Timestamp of the first frame that should be "                                                                                                         \
134
+        "dropped again",                                                 OFFSET(end_pts),     AV_OPT_TYPE_INT64,  { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \
135
+    { "duration",    "Maximum duration of the output in seconds",        OFFSET(duration),    AV_OPT_TYPE_DOUBLE, { .dbl = 0 },                      0,   DBL_MAX, FLAGS },
136
+
137
+
138
+#if CONFIG_TRIM_FILTER
139
+static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
140
+{
141
+    AVFilterContext *ctx = inlink->dst;
142
+    TrimContext       *s = ctx->priv;
143
+    int drop;
144
+
145
+    /* drop everything if EOF has already been returned */
146
+    if (s->eof) {
147
+        av_frame_free(&frame);
148
+        return 0;
149
+    }
150
+
151
+    if (s->start_frame >= 0 || s->start_pts != AV_NOPTS_VALUE) {
152
+        drop = 1;
153
+        if (s->start_frame >= 0 && s->nb_frames >= s->start_frame)
154
+            drop = 0;
155
+        if (s->start_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE &&
156
+            frame->pts >= s->start_pts)
157
+            drop = 0;
158
+        if (drop)
159
+            goto drop;
160
+    }
161
+
162
+    if (s->first_pts == AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE)
163
+        s->first_pts = frame->pts;
164
+
165
+    if (s->end_frame != INT64_MAX || s->end_pts != AV_NOPTS_VALUE || s->duration_tb) {
166
+        drop = 1;
167
+
168
+        if (s->end_frame != INT64_MAX && s->nb_frames < s->end_frame)
169
+            drop = 0;
170
+        if (s->end_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE &&
171
+            frame->pts < s->end_pts)
172
+            drop = 0;
173
+        if (s->duration_tb && frame->pts != AV_NOPTS_VALUE &&
174
+            frame->pts - s->first_pts < s->duration_tb)
175
+            drop = 0;
176
+
177
+        if (drop) {
178
+            s->eof = 1;
179
+            goto drop;
180
+        }
181
+    }
182
+
183
+    s->nb_frames++;
184
+    s->got_output = 1;
185
+
186
+    return ff_filter_frame(ctx->outputs[0], frame);
187
+
188
+drop:
189
+    s->nb_frames++;
190
+    av_frame_free(&frame);
191
+    return 0;
192
+}
193
+
194
+#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
195
+static const AVOption trim_options[] = {
196
+    COMMON_OPTS
197
+    { "start_frame", "Number of the first frame that should be passed "
198
+        "to the output",                                                 OFFSET(start_frame), AV_OPT_TYPE_INT64,  { .i64 = -1 },       -1, INT64_MAX, FLAGS },
199
+    { "end_frame",   "Number of the first frame that should be dropped "
200
+        "again",                                                         OFFSET(end_frame),   AV_OPT_TYPE_INT64,  { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS },
201
+    { NULL },
202
+};
203
+#undef FLAGS
204
+
205
+static const AVClass trim_class = {
206
+    .class_name = "trim",
207
+    .item_name  = av_default_item_name,
208
+    .option     = trim_options,
209
+    .version    = LIBAVUTIL_VERSION_INT,
210
+};
211
+
212
+static const AVFilterPad trim_inputs[] = {
213
+    {
214
+        .name         = "default",
215
+        .type         = AVMEDIA_TYPE_VIDEO,
216
+        .filter_frame = trim_filter_frame,
217
+        .config_props = config_input,
218
+    },
219
+    { NULL }
220
+};
221
+
222
+static const AVFilterPad trim_outputs[] = {
223
+    {
224
+        .name          = "default",
225
+        .type          = AVMEDIA_TYPE_VIDEO,
226
+        .request_frame = request_frame,
227
+    },
228
+    { NULL }
229
+};
230
+
231
+AVFilter avfilter_vf_trim = {
232
+    .name        = "trim",
233
+    .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."),
234
+
235
+    .init        = init,
236
+
237
+    .priv_size   = sizeof(TrimContext),
238
+    .priv_class  = &trim_class,
239
+
240
+    .inputs      = trim_inputs,
241
+    .outputs     = trim_outputs,
242
+};
243
+#endif // CONFIG_TRIM_FILTER
244
+
245
+#if CONFIG_ATRIM_FILTER
246
+static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
247
+{
248
+    AVFilterContext *ctx = inlink->dst;
249
+    TrimContext       *s = ctx->priv;
250
+    int64_t start_sample, end_sample = frame->nb_samples;
251
+    int64_t pts;
252
+    int drop;
253
+
254
+    /* drop everything if EOF has already been returned */
255
+    if (s->eof) {
256
+        av_frame_free(&frame);
257
+        return 0;
258
+    }
259
+
260
+    if (frame->pts != AV_NOPTS_VALUE)
261
+        pts = av_rescale_q(frame->pts, inlink->time_base,
262
+                           (AVRational){ 1, inlink->sample_rate });
263
+    else
264
+        pts = s->next_pts;
265
+    s->next_pts = pts + frame->nb_samples;
266
+
267
+    /* check if at least a part of the frame is after the start time */
268
+    if (s->start_sample < 0 && s->start_pts == AV_NOPTS_VALUE) {
269
+        start_sample = 0;
270
+    } else {
271
+        drop = 1;
272
+        start_sample = frame->nb_samples;
273
+
274
+        if (s->start_sample >= 0 &&
275
+            s->nb_samples + frame->nb_samples > s->start_sample) {
276
+            drop         = 0;
277
+            start_sample = FFMIN(start_sample, s->start_sample - s->nb_samples);
278
+        }
279
+
280
+        if (s->start_pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE &&
281
+            pts + frame->nb_samples > s->start_pts) {
282
+            drop = 0;
283
+            start_sample = FFMIN(start_sample, s->start_pts - pts);
284
+        }
285
+
286
+        if (drop)
287
+            goto drop;
288
+    }
289
+
290
+    if (s->first_pts == AV_NOPTS_VALUE)
291
+        s->first_pts = pts + start_sample;
292
+
293
+    /* check if at least a part of the frame is before the end time */
294
+    if (s->end_sample == INT64_MAX && s->end_pts == AV_NOPTS_VALUE && !s->duration_tb) {
295
+        end_sample = frame->nb_samples;
296
+    } else {
297
+        drop       = 1;
298
+        end_sample = 0;
299
+
300
+        if (s->end_sample != INT64_MAX &&
301
+            s->nb_samples < s->end_sample) {
302
+            drop       = 0;
303
+            end_sample = FFMAX(end_sample, s->end_sample - s->nb_samples);
304
+        }
305
+
306
+        if (s->end_pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE &&
307
+            pts < s->end_pts) {
308
+            drop       = 0;
309
+            end_sample = FFMAX(end_sample, s->end_pts - pts);
310
+        }
311
+
312
+        if (s->duration_tb && pts - s->first_pts < s->duration_tb) {
313
+            drop       = 0;
314
+            end_sample = FFMAX(end_sample, s->first_pts + s->duration_tb - pts);
315
+        }
316
+
317
+        if (drop) {
318
+            s->eof = 1;
319
+            goto drop;
320
+        }
321
+    }
322
+
323
+    s->nb_samples += frame->nb_samples;
324
+    start_sample   = FFMAX(0, start_sample);
325
+    end_sample     = FFMIN(frame->nb_samples, end_sample);
326
+    av_assert0(start_sample < end_sample);
327
+
328
+    if (start_sample) {
329
+        AVFrame *out = ff_get_audio_buffer(ctx->outputs[0], end_sample - start_sample);
330
+        if (!out) {
331
+            av_frame_free(&frame);
332
+            return AVERROR(ENOMEM);
333
+        }
334
+
335
+        av_frame_copy_props(out, frame);
336
+        av_samples_copy(out->extended_data, frame->extended_data, 0, start_sample,
337
+                        out->nb_samples, av_get_channel_layout_nb_channels(frame->channel_layout),
338
+                        frame->format);
339
+        if (out->pts != AV_NOPTS_VALUE)
340
+            out->pts += av_rescale_q(start_sample, (AVRational){ 1, out->sample_rate },
341
+                                     inlink->time_base);
342
+
343
+        av_frame_free(&frame);
344
+        frame = out;
345
+    } else
346
+        frame->nb_samples = end_sample;
347
+
348
+    s->got_output = 1;
349
+    return ff_filter_frame(ctx->outputs[0], frame);
350
+
351
+drop:
352
+    s->nb_samples += frame->nb_samples;
353
+    av_frame_free(&frame);
354
+    return 0;
355
+}
356
+
357
+#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
358
+static const AVOption atrim_options[] = {
359
+    COMMON_OPTS
360
+    { "start_sample", "Number of the first audio sample that should be "
361
+        "passed to the output",                                          OFFSET(start_sample), AV_OPT_TYPE_INT64,  { .i64 = -1 },       -1, INT64_MAX, FLAGS },
362
+    { "end_sample",   "Number of the first audio sample that should be "
363
+        "dropped again",                                                 OFFSET(end_sample),   AV_OPT_TYPE_INT64,  { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS },
364
+    { NULL },
365
+};
366
+#undef FLAGS
367
+
368
+static const AVClass atrim_class = {
369
+    .class_name = "atrim",
370
+    .item_name  = av_default_item_name,
371
+    .option     = atrim_options,
372
+    .version    = LIBAVUTIL_VERSION_INT,
373
+};
374
+
375
+static const AVFilterPad atrim_inputs[] = {
376
+    {
377
+        .name         = "default",
378
+        .type         = AVMEDIA_TYPE_AUDIO,
379
+        .filter_frame = atrim_filter_frame,
380
+        .config_props = config_input,
381
+    },
382
+    { NULL }
383
+};
384
+
385
+static const AVFilterPad atrim_outputs[] = {
386
+    {
387
+        .name          = "default",
388
+        .type          = AVMEDIA_TYPE_AUDIO,
389
+        .request_frame = request_frame,
390
+    },
391
+    { NULL }
392
+};
393
+
394
+AVFilter avfilter_af_atrim = {
395
+    .name        = "atrim",
396
+    .description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."),
397
+
398
+    .init        = init,
399
+
400
+    .priv_size   = sizeof(TrimContext),
401
+    .priv_class  = &atrim_class,
402
+
403
+    .inputs      = atrim_inputs,
404
+    .outputs     = atrim_outputs,
405
+};
406
+#endif // CONFIG_ATRIM_FILTER
... ...
@@ -31,6 +31,22 @@ fate-filter-aresample: CMD = pcm -i $(SRC) -af aresample=min_comp=0.001:min_hard
31 31
 fate-filter-aresample: CMP = oneoff
32 32
 fate-filter-aresample: REF = $(SAMPLES)/nellymoser/nellymoser-discont.pcm
33 33
 
34
+FATE_ATRIM += fate-filter-atrim-duration
35
+fate-filter-atrim-duration: CMD = framecrc -i $(SRC) -af atrim=start=0.1:duration=0.01
36
+FATE_ATRIM += fate-filter-atrim-mixed
37
+fate-filter-atrim-mixed: CMD = framecrc -i $(SRC) -af atrim=start=0.05:start_sample=1025:end=0.1:end_sample=4411
38
+
39
+FATE_ATRIM += fate-filter-atrim-samples
40
+fate-filter-atrim-samples: CMD = framecrc -i $(SRC) -af atrim=start_sample=26:end_sample=80
41
+
42
+FATE_ATRIM += fate-filter-atrim-time
43
+fate-filter-atrim-time: CMD = framecrc -i $(SRC) -af atrim=0.1:0.2
44
+
45
+$(FATE_ATRIM): tests/data/asynth-44100-2.wav
46
+$(FATE_ATRIM): SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav
47
+
48
+FATE_FILTER-$(call FILTERDEMDECENCMUX, ATRIM, WAV, PCM_S16LE, PCM_S16LE, WAV) += $(FATE_ATRIM)
49
+
34 50
 FATE_AFILTER-$(call FILTERDEMDECENCMUX, CHANNELMAP, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-channelmap
35 51
 fate-filter-channelmap: SRC = $(TARGET_PATH)/tests/data/asynth-44100-6.wav
36 52
 fate-filter-channelmap: tests/data/asynth-44100-6.wav
... ...
@@ -73,6 +73,20 @@ fate-filter-telecine: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf telecine
73 73
 FATE_FILTER_VSYNTH-$(CONFIG_TRANSPOSE_FILTER) += fate-filter-transpose
74 74
 fate-filter-transpose: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf transpose
75 75
 
76
+FATE_TRIM += fate-filter-trim-duration
77
+fate-filter-trim-duration: CMD = framecrc -i $(SRC) -vf trim=start=0.4:duration=0.05
78
+
79
+FATE_TRIM += fate-filter-trim-frame
80
+fate-filter-trim-frame: CMD = framecrc -i $(SRC) -vf trim=start_frame=3:end_frame=10
81
+
82
+FATE_TRIM += fate-filter-trim-mixed
83
+fate-filter-trim-mixed: CMD = framecrc -i $(SRC) -vf trim=start=0.2:end=0.4:start_frame=1:end_frame=3
84
+
85
+FATE_TRIM += fate-filter-trim-time
86
+fate-filter-trim-time: CMD = framecrc -i $(SRC) -vf trim=0:0.1
87
+
88
+FATE_FILTER_VSYNTH-$(CONFIG_TRIM_FILTER) += $(FATE_TRIM)
89
+
76 90
 FATE_FILTER_VSYNTH-$(CONFIG_UNSHARP_FILTER) += fate-filter-unsharp
77 91
 fate-filter-unsharp: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf unsharp=11:11:-1.5:11:11:-1.5
78 92
 
79 93
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+#tb 0: 1/44100
1
+0,       4410,       4410,      441,     1764, 0x61e374f7
0 2
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+#tb 0: 1/44100
1
+0,       1025,       1025,     1023,     4092, 0x78560a4c
2
+0,       2048,       2048,     1024,     4096, 0xc477fa99
3
+0,       3072,       3072,     1024,     4096, 0x3bc0f14f
4
+0,       4096,       4096,      315,     1260, 0xe4b26b50
0 5
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+#tb 0: 1/44100
1
+0,         26,         26,       54,      216, 0x6b376c6c
0 2
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+#tb 0: 1/44100
1
+0,       4410,       4410,      710,     2840, 0x658982a3
2
+0,       5120,       5120,     1024,     4096, 0xfd6a0070
3
+0,       6144,       6144,     1024,     4096, 0x0b01f4cf
4
+0,       7168,       7168,     1024,     4096, 0x6716fd93
5
+0,       8192,       8192,      628,     2512, 0xda5ddff8
0 6
new file mode 100644
... ...
@@ -0,0 +1,2 @@
0
+#tb 0: 1/25
1
+0,         10,         10,        1,   152064, 0xb45c4760
0 2
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+#tb 0: 1/25
1
+0,          3,          3,        1,   152064, 0xceb080b0
2
+0,          4,          4,        1,   152064, 0x473db652
3
+0,          5,          5,        1,   152064, 0x287da8e6
4
+0,          6,          6,        1,   152064, 0x68b47c23
5
+0,          7,          7,        1,   152064, 0xe9028bac
6
+0,          8,          8,        1,   152064, 0x28ff8026
7
+0,          9,          9,        1,   152064, 0x2d7c3915
0 8
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+#tb 0: 1/25
1
+0,          1,          1,        1,   152064, 0x7f5f6551
2
+0,          2,          2,        1,   152064, 0xc566f64a
3
+0,          3,          3,        1,   152064, 0xceb080b0
4
+0,          4,          4,        1,   152064, 0x473db652
5
+0,          5,          5,        1,   152064, 0x287da8e6
6
+0,          6,          6,        1,   152064, 0x68b47c23
7
+0,          7,          7,        1,   152064, 0xe9028bac
8
+0,          8,          8,        1,   152064, 0x28ff8026
9
+0,          9,          9,        1,   152064, 0x2d7c3915
0 10
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+#tb 0: 1/25
1
+0,          0,          0,        1,   152064, 0x6e4f89ef
2
+0,          1,          1,        1,   152064, 0x7f5f6551