2 * Copyright (c) 2016 Paul B Mahol
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "config_components.h"
23 #include "libavutil/audio_fifo.h"
24 #include "libavutil/avassert.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/mem.h"
27 #include "libavutil/opt.h"
33 typedef struct LoopContext
{
43 int64_t current_sample
;
45 int64_t ignored_samples
;
57 #define AFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
58 #define VFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
59 #define OFFSET(x) offsetof(LoopContext, x)
61 static void check_size(AVFilterContext
*ctx
)
63 LoopContext
*s
= ctx
->priv
;
66 av_log(ctx
, AV_LOG_WARNING
, "Number of %s to loop is not set!\n",
67 ctx
->input_pads
[0].type
== AVMEDIA_TYPE_VIDEO
? "frames" : "samples");
70 static void update_time(AVFilterContext
*ctx
, AVRational tb
)
72 LoopContext
*s
= ctx
->priv
;
74 if (s
->time
!= INT64_MAX
) {
75 int64_t time_pts
= av_rescale_q(s
->time
, AV_TIME_BASE_Q
, tb
);
76 if (s
->time_pts
== AV_NOPTS_VALUE
|| time_pts
< s
->time_pts
)
77 s
->time_pts
= time_pts
;
81 #if CONFIG_ALOOP_FILTER
83 static int aconfig_input(AVFilterLink
*inlink
)
85 AVFilterContext
*ctx
= inlink
->dst
;
86 LoopContext
*s
= ctx
->priv
;
88 s
->time_pts
= AV_NOPTS_VALUE
;
90 s
->fifo
= av_audio_fifo_alloc(inlink
->format
, inlink
->ch_layout
.nb_channels
, 8192);
91 s
->left
= av_audio_fifo_alloc(inlink
->format
, inlink
->ch_layout
.nb_channels
, 8192);
92 if (!s
->fifo
|| !s
->left
)
93 return AVERROR(ENOMEM
);
100 static av_cold
void auninit(AVFilterContext
*ctx
)
102 LoopContext
*s
= ctx
->priv
;
104 av_audio_fifo_free(s
->fifo
);
105 av_audio_fifo_free(s
->left
);
108 static int push_samples(AVFilterContext
*ctx
, int nb_samples
, AVFrame
**frame
)
110 AVFilterLink
*outlink
= ctx
->outputs
[0];
111 LoopContext
*s
= ctx
->priv
;
115 while (s
->loop
!= 0 && i
< nb_samples
) {
116 out
= ff_get_audio_buffer(outlink
, FFMIN(nb_samples
, s
->nb_samples
- s
->current_sample
));
118 return AVERROR(ENOMEM
);
119 ret
= av_audio_fifo_peek_at(s
->fifo
, (void **)out
->extended_data
, out
->nb_samples
, s
->current_sample
);
125 out
->nb_samples
= ret
;
126 s
->pts
+= av_rescale_q(out
->nb_samples
, (AVRational
){1, outlink
->sample_rate
}, outlink
->time_base
);
127 i
+= out
->nb_samples
;
128 s
->current_sample
+= out
->nb_samples
;
132 if (s
->current_sample
>= s
->nb_samples
) {
133 s
->current_sample
= 0;
145 static int afilter_frame(AVFilterLink
*inlink
, AVFrame
*frame
)
147 FilterLink
*inl
= ff_filter_link(inlink
);
148 AVFilterContext
*ctx
= inlink
->dst
;
149 AVFilterLink
*outlink
= ctx
->outputs
[0];
150 LoopContext
*s
= ctx
->priv
;
153 if (((s
->start
>= 0 && s
->ignored_samples
+ frame
->nb_samples
> s
->start
) ||
154 (s
->time_pts
!= AV_NOPTS_VALUE
&&
155 frame
->pts
>= s
->time_pts
)) &&
156 s
->size
> 0 && s
->loop
!= 0) {
157 if (s
->nb_samples
< s
->size
) {
158 int written
= FFMIN(frame
->nb_samples
, s
->size
- s
->nb_samples
);
162 s
->start
= inl
->sample_count_out
- written
;
164 ret
= av_audio_fifo_write(s
->fifo
, (void **)frame
->extended_data
, written
);
167 if (!s
->nb_samples
) {
168 drain
= FFMAX(0, s
->start
- s
->ignored_samples
);
170 av_audio_fifo_drain(s
->fifo
, drain
);
171 s
->pts
+= av_rescale_q(s
->start
- s
->ignored_samples
, (AVRational
){1, outlink
->sample_rate
}, outlink
->time_base
);
173 s
->nb_samples
+= ret
- drain
;
174 if (s
->nb_samples
== s
->size
&& frame
->nb_samples
> written
) {
177 ret2
= av_audio_fifo_write(s
->left
, (void **)frame
->extended_data
, frame
->nb_samples
);
180 av_audio_fifo_drain(s
->left
, written
);
182 frame
->nb_samples
= ret
;
183 s
->pts
+= av_rescale_q(ret
, (AVRational
){1, outlink
->sample_rate
}, outlink
->time_base
);
184 ret
= ff_filter_frame(outlink
, frame
);
189 s
->ignored_samples
+= frame
->nb_samples
;
191 s
->pts
+= av_rescale_q(frame
->nb_samples
, (AVRational
){1, outlink
->sample_rate
}, outlink
->time_base
);
192 ret
= ff_filter_frame(outlink
, frame
);
198 static int arequest_frame(AVFilterLink
*outlink
, AVFrame
**frame
)
200 AVFilterContext
*ctx
= outlink
->src
;
201 LoopContext
*s
= ctx
->priv
;
205 (s
->nb_samples
< s
->size
) ||
206 (s
->nb_samples
>= s
->size
&& s
->loop
== 0)) {
207 int nb_samples
= av_audio_fifo_size(s
->left
);
209 if (s
->loop
== 0 && nb_samples
> 0) {
212 out
= ff_get_audio_buffer(outlink
, nb_samples
);
214 return AVERROR(ENOMEM
);
215 av_audio_fifo_read(s
->left
, (void **)out
->extended_data
, nb_samples
);
217 s
->pts
+= av_rescale_q(nb_samples
, (AVRational
){1, outlink
->sample_rate
}, outlink
->time_base
);
222 ret
= push_samples(ctx
, 1024, frame
);
228 static int aactivate(AVFilterContext
*ctx
)
230 AVFilterLink
*inlink
= ctx
->inputs
[0];
231 AVFilterLink
*outlink
= ctx
->outputs
[0];
232 LoopContext
*s
= ctx
->priv
;
233 AVFrame
*frame
= NULL
;
236 FF_FILTER_FORWARD_STATUS_BACK(outlink
, inlink
);
238 update_time(ctx
, inlink
->time_base
);
241 ret
= arequest_frame(outlink
, &frame
);
245 return ff_filter_frame(outlink
, frame
);
247 ret
= ff_inlink_consume_frame(inlink
, &frame
);
251 return afilter_frame(inlink
, frame
);
253 ret
= ff_inlink_acknowledge_status(inlink
, &status
, &s
->eof_pts
);
255 if (status
== AVERROR_EOF
&& !s
->eof
) {
256 s
->size
= s
->nb_samples
;
260 ff_outlink_set_status(outlink
, status
, s
->eof_pts
);
264 FF_FILTER_FORWARD_WANTED(outlink
, inlink
);
266 return FFERROR_NOT_READY
;
269 static const AVOption aloop_options
[] = {
270 { "loop", "number of loops", OFFSET(loop
), AV_OPT_TYPE_INT
, {.i64
= 0 }, -1, INT_MAX
, AFLAGS
},
271 { "size", "max number of samples to loop", OFFSET(size
), AV_OPT_TYPE_INT64
, {.i64
= 0 }, 0, INT32_MAX
, AFLAGS
},
272 { "start", "set the loop start sample", OFFSET(start
), AV_OPT_TYPE_INT64
, {.i64
= 0 }, -1, INT64_MAX
, AFLAGS
},
273 { "time", "set the loop start time", OFFSET(time
), AV_OPT_TYPE_DURATION
, {.i64
=INT64_MAX
}, INT64_MIN
, INT64_MAX
, AFLAGS
},
277 AVFILTER_DEFINE_CLASS(aloop
);
279 static const AVFilterPad ainputs
[] = {
282 .type
= AVMEDIA_TYPE_AUDIO
,
283 .config_props
= aconfig_input
,
287 const FFFilter ff_af_aloop
= {
289 .p
.description
= NULL_IF_CONFIG_SMALL("Loop audio samples."),
290 .p
.priv_class
= &aloop_class
,
291 .priv_size
= sizeof(LoopContext
),
292 .activate
= aactivate
,
294 FILTER_INPUTS(ainputs
),
295 FILTER_OUTPUTS(ff_audio_default_filterpad
),
297 #endif /* CONFIG_ALOOP_FILTER */
299 #if CONFIG_LOOP_FILTER
301 static av_cold
int init(AVFilterContext
*ctx
)
303 LoopContext
*s
= ctx
->priv
;
305 s
->time_pts
= AV_NOPTS_VALUE
;
307 s
->frames
= av_calloc(s
->size
, sizeof(*s
->frames
));
309 return AVERROR(ENOMEM
);
316 static void free_frames(AVFilterContext
*ctx
)
318 LoopContext
*s
= ctx
->priv
;
320 for (int i
= 0; i
< s
->nb_frames
; i
++)
321 av_frame_free(&s
->frames
[i
]);
324 static av_cold
void uninit(AVFilterContext
*ctx
)
326 LoopContext
*s
= ctx
->priv
;
329 av_freep(&s
->frames
);
333 static int push_frame(AVFilterContext
*ctx
)
335 AVFilterLink
*outlink
= ctx
->outputs
[0];
336 LoopContext
*s
= ctx
->priv
;
340 out
= av_frame_clone(s
->frames
[s
->current_frame
]);
342 return AVERROR(ENOMEM
);
343 out
->pts
+= s
->pts_offset
;
344 ret
= ff_filter_frame(outlink
, out
);
347 if (s
->current_frame
>= s
->nb_frames
) {
348 s
->current_frame
= 0;
350 s
->pts_offset
+= s
->duration
;
360 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*frame
)
362 FilterLink
*inl
= ff_filter_link(inlink
);
363 AVFilterContext
*ctx
= inlink
->dst
;
364 AVFilterLink
*outlink
= ctx
->outputs
[0];
365 FilterLink
*outl
= ff_filter_link(outlink
);
366 LoopContext
*s
= ctx
->priv
;
370 if (((s
->start
>= 0 && inl
->frame_count_out
>= s
->start
) ||
371 (s
->time_pts
!= AV_NOPTS_VALUE
&&
372 frame
->pts
>= s
->time_pts
)) &&
373 s
->size
> 0 && s
->loop
!= 0) {
374 if (s
->nb_frames
< s
->size
) {
375 s
->frames
[s
->nb_frames
] = av_frame_clone(frame
);
376 if (!s
->frames
[s
->nb_frames
]) {
377 av_frame_free(&frame
);
378 return AVERROR(ENOMEM
);
382 duration
= frame
->duration
;
384 duration
= av_rescale_q(1, av_inv_q(outl
->frame_rate
), outlink
->time_base
);
385 s
->duration
+= duration
;
386 s
->pts_offset
= s
->duration
;
387 ret
= ff_filter_frame(outlink
, frame
);
389 av_frame_free(&frame
);
390 ret
= push_frame(ctx
);
393 frame
->pts
+= s
->pts_offset
- s
->duration
;
394 ret
= ff_filter_frame(outlink
, frame
);
400 static int activate(AVFilterContext
*ctx
)
402 AVFilterLink
*inlink
= ctx
->inputs
[0];
403 AVFilterLink
*outlink
= ctx
->outputs
[0];
404 LoopContext
*s
= ctx
->priv
;
405 AVFrame
*frame
= NULL
;
408 ret
= ff_outlink_get_status(outlink
);
410 ff_inlink_set_status(inlink
, ret
);
415 update_time(ctx
, inlink
->time_base
);
417 if (!s
->eof
&& (s
->nb_frames
< s
->size
|| !s
->loop
|| !s
->size
)) {
418 ret
= ff_inlink_consume_frame(inlink
, &frame
);
422 return filter_frame(inlink
, frame
);
425 if (!s
->eof
&& ff_inlink_acknowledge_status(inlink
, &status
, &s
->eof_pts
)) {
426 if (status
== AVERROR_EOF
) {
427 s
->size
= s
->nb_frames
;
432 if (s
->eof
&& (!s
->loop
|| !s
->size
)) {
433 ff_outlink_set_status(outlink
, AVERROR_EOF
, s
->eof_pts
+ s
->pts_offset
);
438 if (!s
->eof
&& (!s
->size
||
439 (s
->nb_frames
< s
->size
) ||
440 (s
->nb_frames
>= s
->size
&& s
->loop
== 0))) {
441 FF_FILTER_FORWARD_WANTED(outlink
, inlink
);
442 } else if (s
->loop
&& s
->nb_frames
== s
->size
) {
443 return push_frame(ctx
);
446 return FFERROR_NOT_READY
;
449 static const AVOption loop_options
[] = {
450 { "loop", "number of loops", OFFSET(loop
), AV_OPT_TYPE_INT
, {.i64
= 0 }, -1, INT_MAX
, VFLAGS
},
451 { "size", "max number of frames to loop", OFFSET(size
), AV_OPT_TYPE_INT64
, {.i64
= 0 }, 0, INT16_MAX
, VFLAGS
},
452 { "start", "set the loop start frame", OFFSET(start
), AV_OPT_TYPE_INT64
, {.i64
= 0 }, -1, INT64_MAX
, VFLAGS
},
453 { "time", "set the loop start time", OFFSET(time
), AV_OPT_TYPE_DURATION
, {.i64
=INT64_MAX
}, INT64_MIN
, INT64_MAX
, VFLAGS
},
457 AVFILTER_DEFINE_CLASS(loop
);
459 const FFFilter ff_vf_loop
= {
461 .p
.description
= NULL_IF_CONFIG_SMALL("Loop video frames."),
462 .p
.priv_class
= &loop_class
,
463 .priv_size
= sizeof(LoopContext
),
466 .activate
= activate
,
467 FILTER_INPUTS(ff_video_default_filterpad
),
468 FILTER_OUTPUTS(ff_video_default_filterpad
),
470 #endif /* CONFIG_LOOP_FILTER */