* 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>
... | ... |
@@ -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 |
|
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 |