FFmpeg
Loading...
Searching...
No Matches
trim.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <stdint.h>
20
21#include "config.h"
22#include "config_components.h"
23
25#include "libavutil/common.h"
26#include "libavutil/log.h"
28#include "libavutil/opt.h"
29#include "libavutil/samplefmt.h"
30
31#include "audio.h"
32#include "avfilter.h"
33#include "filters.h"
34#include "video.h"
35
36typedef struct TrimContext {
37 const AVClass *class;
38
39 /*
40 * AVOptions
41 */
45 /*
46 * in the link timebase for video,
47 * in 1/samplerate for audio
48 */
51
52 /*
53 * number of video frames that arrived on this filter so far
54 */
56 /*
57 * number of audio samples that arrived on this filter so far
58 */
60 /*
61 * timestamp of the first frame in the output, in the timebase units
62 */
64 /*
65 * duration in the timebase units
66 */
68
70
71 int eof;
72
75
77{
78 TrimContext *s = ctx->priv;
79
80 s->first_pts = AV_NOPTS_VALUE;
81
82 return 0;
83}
84
85#if CONFIG_TRIM_FILTER
86static int trim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
87{
88 AVFilterContext *ctx = inlink->dst;
89 TrimContext *s = ctx->priv;
90 int drop;
91
92 /* drop everything if EOF has already been returned */
93 if (s->eof)
94 return 0;
95
96 if (s->start_frame >= 0 || s->start_pts != AV_NOPTS_VALUE) {
97 drop = 1;
98 if (s->start_frame >= 0 && s->nb_frames >= s->start_frame)
99 drop = 0;
100 if (s->start_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE &&
101 frame->pts >= s->start_pts)
102 drop = 0;
103 if (drop)
104 goto drop;
105 }
106
107 if (s->first_pts == AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE)
108 s->first_pts = frame->pts;
109
110 if (s->end_frame != INT64_MAX || s->end_pts != AV_NOPTS_VALUE || s->duration_tb) {
111 drop = 1;
112
113 if (s->end_frame != INT64_MAX && s->nb_frames < s->end_frame)
114 drop = 0;
115 if (s->end_pts != AV_NOPTS_VALUE && frame->pts != AV_NOPTS_VALUE &&
116 frame->pts < s->end_pts)
117 drop = 0;
118 if (s->duration_tb && frame->pts != AV_NOPTS_VALUE &&
119 frame->pts - s->first_pts < s->duration_tb)
120 drop = 0;
121
122 if (drop) {
123 s->eof = 1;
125 ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, frame->pts);
126 goto drop;
127 }
128 }
129
130 s->nb_frames++;
131
132 return 1;
133
134drop:
135 s->nb_frames++;
136 return 0;
137}
138#endif // CONFIG_TRIM_FILTER
139
140#if CONFIG_ATRIM_FILTER
141static int atrim_filter_frame(AVFilterLink *inlink, AVFrame *frame)
142{
143 AVFilterContext *ctx = inlink->dst;
144 TrimContext *s = ctx->priv;
145 int64_t start_sample, end_sample;
146 int64_t pts;
147 int drop;
148
149 /* drop everything if EOF has already been returned */
150 if (s->eof)
151 return 0;
152
153 if (frame->pts != AV_NOPTS_VALUE)
154 pts = av_rescale_q(frame->pts, inlink->time_base,
155 (AVRational){ 1, inlink->sample_rate });
156 else
157 pts = s->next_pts;
158 s->next_pts = pts + frame->nb_samples;
159
160 /* check if at least a part of the frame is after the start time */
161 if (s->start_sample < 0 && s->start_pts == AV_NOPTS_VALUE) {
162 start_sample = 0;
163 } else {
164 drop = 1;
165 start_sample = frame->nb_samples;
166
167 if (s->start_sample >= 0 &&
168 s->nb_samples + frame->nb_samples > s->start_sample) {
169 drop = 0;
170 start_sample = FFMIN(start_sample, s->start_sample - s->nb_samples);
171 }
172
173 if (s->start_pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE &&
174 pts + frame->nb_samples > s->start_pts) {
175 drop = 0;
176 start_sample = FFMIN(start_sample, s->start_pts - pts);
177 }
178
179 if (drop)
180 goto drop;
181 }
182
183 if (s->first_pts == AV_NOPTS_VALUE)
184 s->first_pts = pts + start_sample;
185
186 /* check if at least a part of the frame is before the end time */
187 if (s->end_sample == INT64_MAX && s->end_pts == AV_NOPTS_VALUE && !s->duration_tb) {
188 end_sample = frame->nb_samples;
189 } else {
190 drop = 1;
191 end_sample = 0;
192
193 if (s->end_sample != INT64_MAX &&
194 s->nb_samples < s->end_sample) {
195 drop = 0;
196 end_sample = FFMAX(end_sample, s->end_sample - s->nb_samples);
197 }
198
199 if (s->end_pts != AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE &&
200 pts < s->end_pts) {
201 drop = 0;
202 end_sample = FFMAX(end_sample, s->end_pts - pts);
203 }
204
205 if (s->duration_tb && pts - s->first_pts < s->duration_tb) {
206 drop = 0;
207 end_sample = FFMAX(end_sample, s->first_pts + s->duration_tb - pts);
208 }
209
210 if (drop) {
211 s->eof = 1;
213 ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, frame->pts);
214 goto drop;
215 }
216 }
217
218 s->nb_samples += frame->nb_samples;
219 start_sample = FFMAX(0, start_sample);
220 end_sample = FFMIN(frame->nb_samples, end_sample);
221 if (start_sample >= end_sample || !frame->nb_samples)
222 goto drop;
223
224 if (start_sample) {
225 AVFrame *out = ff_get_audio_buffer(ctx->outputs[0], end_sample - start_sample);
226 if (!out)
227 return AVERROR(ENOMEM);
228
230 av_samples_copy(out->extended_data, frame->extended_data, 0, start_sample,
231 out->nb_samples, inlink->ch_layout.nb_channels,
232 frame->format);
233 if (out->pts != AV_NOPTS_VALUE)
234 out->pts += av_rescale_q(start_sample, (AVRational){ 1, out->sample_rate },
235 inlink->time_base);
236
240 } else
241 frame->nb_samples = end_sample;
242
243 return 1;
244
245drop:
246 s->nb_samples += frame->nb_samples;
247 return 0;
248}
249#endif // CONFIG_ATRIM_FILTER
250
251static int config_input(AVFilterLink *inlink)
252{
253 AVFilterContext *ctx = inlink->dst;
254 TrimContext *s = ctx->priv;
255 AVRational tb = (inlink->type == AVMEDIA_TYPE_VIDEO) ?
256 inlink->time_base : (AVRational){ 1, inlink->sample_rate };
257
258#if CONFIG_TRIM_FILTER
259 if (inlink->type == AVMEDIA_TYPE_VIDEO)
260 s->filter_frame = trim_filter_frame;
261#endif
262#if CONFIG_ATRIM_FILTER
263 if (inlink->type == AVMEDIA_TYPE_AUDIO)
264 s->filter_frame = atrim_filter_frame;
265#endif
266 if (s->start_time != INT64_MAX) {
267 int64_t start_pts = av_rescale_q(s->start_time, AV_TIME_BASE_Q, tb);
268 if (s->start_pts == AV_NOPTS_VALUE || start_pts < s->start_pts)
269 s->start_pts = start_pts;
270 }
271 if (s->end_time != INT64_MAX) {
272 int64_t end_pts = av_rescale_q(s->end_time, AV_TIME_BASE_Q, tb);
273 if (s->end_pts == AV_NOPTS_VALUE || end_pts > s->end_pts)
274 s->end_pts = end_pts;
275 }
276 if (s->duration)
277 s->duration_tb = av_rescale_q(s->duration, AV_TIME_BASE_Q, tb);
278
279 return 0;
280}
281
283{
284 TrimContext *s = ctx->priv;
285 AVFilterLink *inlink = ctx->inputs[0];
286 AVFilterLink *outlink = ctx->outputs[0];
287 AVFrame *frame = NULL;
288 int ret;
289
290 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
291
292 while ((ret = ff_inlink_consume_frame(inlink, &frame))) {
293 if (ret < 0)
294 return ret;
295
296 ret = s->filter_frame(inlink, frame);
297 if (ret > 0)
298 return ff_filter_frame(outlink, frame);
300 if (ret < 0)
301 return ret;
302 }
303
304 FF_FILTER_FORWARD_STATUS(inlink, outlink);
305 FF_FILTER_FORWARD_WANTED(outlink, inlink);
306
307 return FFERROR_NOT_READY;
308}
309
310#define OFFSET(x) offsetof(TrimContext, x)
311#define COMMON_OPTS \
312 { "start", "Timestamp of the first frame that " \
313 "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \
314 { "starti", "Timestamp of the first frame that " \
315 "should be passed", OFFSET(start_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \
316 { "end", "Timestamp of the first frame that " \
317 "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \
318 { "endi", "Timestamp of the first frame that " \
319 "should be dropped again", OFFSET(end_time), AV_OPT_TYPE_DURATION, { .i64 = INT64_MAX }, INT64_MIN, INT64_MAX, FLAGS }, \
320 { "start_pts", "Timestamp of the first frame that should be " \
321 " passed", OFFSET(start_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \
322 { "end_pts", "Timestamp of the first frame that should be " \
323 "dropped again", OFFSET(end_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, FLAGS }, \
324 { "duration", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, \
325 { "durationi", "Maximum duration of the output", OFFSET(duration), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS },
326
327
328#if CONFIG_TRIM_FILTER
329
330#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
331static const AVOption trim_options[] = {
333 { "start_frame", "Number of the first frame that should be passed "
334 "to the output", OFFSET(start_frame), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS },
335 { "end_frame", "Number of the first frame that should be dropped "
336 "again", OFFSET(end_frame), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS },
337 { NULL }
338};
339#undef FLAGS
340
342
343static const AVFilterPad trim_inputs[] = {
344 {
345 .name = "default",
346 .type = AVMEDIA_TYPE_VIDEO,
347 .config_props = config_input,
348 },
349};
350
351const FFFilter ff_vf_trim = {
352 .p.name = "trim",
353 .p.description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."),
354 .p.priv_class = &trim_class,
356 .init = init,
357 .activate = activate,
358 .priv_size = sizeof(TrimContext),
359 FILTER_INPUTS(trim_inputs),
361};
362#endif // CONFIG_TRIM_FILTER
363
364#if CONFIG_ATRIM_FILTER
365
366#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
367static const AVOption atrim_options[] = {
369 { "start_sample", "Number of the first audio sample that should be "
370 "passed to the output", OFFSET(start_sample), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, FLAGS },
371 { "end_sample", "Number of the first audio sample that should be "
372 "dropped again", OFFSET(end_sample), AV_OPT_TYPE_INT64, { .i64 = INT64_MAX }, 0, INT64_MAX, FLAGS },
373 { NULL }
374};
375#undef FLAGS
376
378
379static const AVFilterPad atrim_inputs[] = {
380 {
381 .name = "default",
382 .type = AVMEDIA_TYPE_AUDIO,
383 .config_props = config_input,
384 },
385};
386
387const FFFilter ff_af_atrim = {
388 .p.name = "atrim",
389 .p.description = NULL_IF_CONFIG_SMALL("Pick one continuous section from the input, drop the rest."),
390 .p.priv_class = &atrim_class,
392 .init = init,
393 .activate = activate,
394 .priv_size = sizeof(TrimContext),
395 FILTER_INPUTS(atrim_inputs),
397};
398#endif // CONFIG_ATRIM_FILTER
static int config_input(AVFilterLink *inlink)
const FFFilter ff_af_atrim
const FFFilter ff_vf_trim
const AVFilterPad ff_audio_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_AUDIO.
Definition audio.c:34
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition audio.c:74
void ff_inlink_set_status(AVFilterLink *link, int status)
Set the status on an input link.
Definition avfilter.c:1632
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link's FIFO and update the link's stats.
Definition avfilter.c:1520
Main libavfilter public API header.
#define s(width, name)
Definition cbs_vp9.c:198
Public libavutil channel layout APIs header.
#define FLAGS
Definition cmdutils.c:598
common internal and external API header
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
static AVFrame * frame
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
#define COMMON_OPTS
Definition f_segment.c:264
@ AV_OPT_TYPE_INT64
Underlying C type is int64_t.
Definition opt.h:262
#define AVFILTER_FLAG_METADATA_ONLY
The filter is a "metadata" filter - it does not modify the frame data in any way.
Definition avfilter.h:182
#define AVERROR_EOF
End of file.
Definition error.h:57
#define AVERROR(e)
Definition error.h:45
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition frame.c:496
void av_frame_move_ref(AVFrame *dst, AVFrame *src)
Move everything contained in src to dst and reset src.
Definition frame.c:523
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition frame.c:64
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition frame.c:599
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_AUDIO
Definition avutil.h:201
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
int av_samples_copy(uint8_t *const *dst, uint8_t *const *src, int dst_offset, int src_offset, int nb_samples, int nb_channels, enum AVSampleFormat sample_fmt)
Copy samples from src to dst.
Definition samplefmt.c:222
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
static int activate(AVBitStreamFilterContext *ctx)
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
Definition filters.h:694
#define FF_FILTER_FORWARD_STATUS(inlink, outlink)
Acknowledge the status on an input link and forward it to an output link.
Definition filters.h:666
static void ff_outlink_set_status(AVFilterLink *link, int status, int64_t pts)
Set the status field of a link from the source filter.
Definition filters.h:629
#define FFERROR_NOT_READY
Filters implementation helper functions and internal structures.
Definition filters.h:34
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition filters.h:639
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
#define FFMIN(a, b)
Definition macros.h:49
#define FFMAX(a, b)
Definition macros.h:47
AVOptions.
int nb_channels
Number of channels in this layout.
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
Rational number (pair of numerator and denominator).
Definition rational.h:58
int64_t start_frame
Definition trim.c:44
int64_t start_sample
Definition trim.c:50
int64_t nb_samples
Definition trim.c:59
int eof
Definition trim.c:71
int64_t first_pts
Definition trim.c:63
int64_t start_time
Definition trim.c:43
int64_t nb_frames
Definition trim.c:55
int64_t end_time
Definition trim.c:43
int64_t next_pts
Definition trim.c:69
int64_t start_pts
Definition trim.c:49
int64_t end_frame
Definition trim.c:44
int(* filter_frame)(AVFilterLink *inlink, AVFrame *frame)
Definition trim.c:73
int64_t end_sample
Definition trim.c:50
int64_t duration_tb
Definition trim.c:67
int64_t duration
Definition trim.c:42
int64_t end_pts
Definition trim.c:49
static FILE * out
Definition movenc.c:55
static AVFormatContext * ctx
Definition movenc.c:49
static int64_t pts
static int config_input(AVFilterLink *inlink)
Definition trim.c:251
static int activate(AVFilterContext *ctx)
Definition trim.c:282
#define OFFSET(x)
Definition trim.c:310
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition video.c:37