1 /*
2 * Copyright (c) 2016 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config_components.h"
22
23 #include "libavutil/audio_fifo.h"
24 #include "libavutil/fifo.h"
25 #include "libavutil/internal.h"
26 #include "libavutil/opt.h"
27 #include "avfilter.h"
28 #include "audio.h"
29 #include "filters.h"
30 #include "formats.h"
31 #include "internal.h"
32 #include "video.h"
33
34 typedef struct LoopContext {
35 const AVClass *class;
36
37 AVAudioFifo *fifo;
38 AVAudioFifo *left;
39 AVFrame **frames;
40 int nb_frames;
41 int current_frame;
42 int64_t start_pts;
43 int64_t duration;
44 int64_t current_sample;
45 int64_t nb_samples;
46 int64_t ignored_samples;
47
48 int loop;
49 int eof;
50 int64_t size;
51 int64_t start;
52 int64_t pts;
53 } LoopContext;
54
55 #define AFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
56 #define VFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
57 #define OFFSET(x) offsetof(LoopContext, x)
58
check_size(AVFilterContext * ctx)59 static void check_size(AVFilterContext *ctx)
60 {
61 LoopContext *s = ctx->priv;
62
63 if (!s->size)
64 av_log(ctx, AV_LOG_WARNING, "Number of %s to loop is not set!\n",
65 ctx->input_pads[0].type == AVMEDIA_TYPE_VIDEO ? "frames" : "samples");
66 }
67
68 #if CONFIG_ALOOP_FILTER
69
aconfig_input(AVFilterLink * inlink)70 static int aconfig_input(AVFilterLink *inlink)
71 {
72 AVFilterContext *ctx = inlink->dst;
73 LoopContext *s = ctx->priv;
74
75 s->fifo = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, 8192);
76 s->left = av_audio_fifo_alloc(inlink->format, inlink->ch_layout.nb_channels, 8192);
77 if (!s->fifo || !s->left)
78 return AVERROR(ENOMEM);
79
80 check_size(ctx);
81
82 return 0;
83 }
84
auninit(AVFilterContext * ctx)85 static av_cold void auninit(AVFilterContext *ctx)
86 {
87 LoopContext *s = ctx->priv;
88
89 av_audio_fifo_free(s->fifo);
90 av_audio_fifo_free(s->left);
91 }
92
push_samples(AVFilterContext * ctx,int nb_samples)93 static int push_samples(AVFilterContext *ctx, int nb_samples)
94 {
95 AVFilterLink *outlink = ctx->outputs[0];
96 LoopContext *s = ctx->priv;
97 AVFrame *out;
98 int ret = 0, i = 0;
99
100 while (s->loop != 0 && i < nb_samples) {
101 out = ff_get_audio_buffer(outlink, FFMIN(nb_samples, s->nb_samples - s->current_sample));
102 if (!out)
103 return AVERROR(ENOMEM);
104 ret = av_audio_fifo_peek_at(s->fifo, (void **)out->extended_data, out->nb_samples, s->current_sample);
105 if (ret < 0) {
106 av_frame_free(&out);
107 return ret;
108 }
109 out->pts = s->pts;
110 out->nb_samples = ret;
111 s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
112 i += out->nb_samples;
113 s->current_sample += out->nb_samples;
114
115 ret = ff_filter_frame(outlink, out);
116 if (ret < 0)
117 return ret;
118
119 if (s->current_sample >= s->nb_samples) {
120 s->duration = s->pts;
121 s->current_sample = 0;
122
123 if (s->loop > 0)
124 s->loop--;
125 }
126 }
127
128 return ret;
129 }
130
afilter_frame(AVFilterLink * inlink,AVFrame * frame)131 static int afilter_frame(AVFilterLink *inlink, AVFrame *frame)
132 {
133 AVFilterContext *ctx = inlink->dst;
134 AVFilterLink *outlink = ctx->outputs[0];
135 LoopContext *s = ctx->priv;
136 int ret = 0;
137
138 if (s->ignored_samples + frame->nb_samples > s->start && s->size > 0 && s->loop != 0) {
139 if (s->nb_samples < s->size) {
140 int written = FFMIN(frame->nb_samples, s->size - s->nb_samples);
141 int drain = 0;
142
143 ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, written);
144 if (ret < 0)
145 return ret;
146 if (!s->nb_samples) {
147 drain = FFMAX(0, s->start - s->ignored_samples);
148 s->pts = frame->pts;
149 av_audio_fifo_drain(s->fifo, drain);
150 s->pts += av_rescale_q(s->start - s->ignored_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
151 }
152 s->nb_samples += ret - drain;
153 drain = frame->nb_samples - written;
154 if (s->nb_samples == s->size && drain > 0) {
155 int ret2;
156
157 ret2 = av_audio_fifo_write(s->left, (void **)frame->extended_data, frame->nb_samples);
158 if (ret2 < 0)
159 return ret2;
160 av_audio_fifo_drain(s->left, drain);
161 }
162 frame->nb_samples = ret;
163 s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, outlink->time_base);
164 ret = ff_filter_frame(outlink, frame);
165 } else {
166 int nb_samples = frame->nb_samples;
167
168 av_frame_free(&frame);
169 ret = push_samples(ctx, nb_samples);
170 }
171 } else {
172 s->ignored_samples += frame->nb_samples;
173 frame->pts = s->pts;
174 s->pts += av_rescale_q(frame->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
175 ret = ff_filter_frame(outlink, frame);
176 }
177
178 return ret;
179 }
180
arequest_frame(AVFilterLink * outlink)181 static int arequest_frame(AVFilterLink *outlink)
182 {
183 AVFilterContext *ctx = outlink->src;
184 LoopContext *s = ctx->priv;
185 int ret = 0;
186
187 if ((!s->size) ||
188 (s->nb_samples < s->size) ||
189 (s->nb_samples >= s->size && s->loop == 0)) {
190 int nb_samples = av_audio_fifo_size(s->left);
191
192 if (s->loop == 0 && nb_samples > 0) {
193 AVFrame *out;
194
195 out = ff_get_audio_buffer(outlink, nb_samples);
196 if (!out)
197 return AVERROR(ENOMEM);
198 av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples);
199 out->pts = s->pts;
200 s->pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
201 ret = ff_filter_frame(outlink, out);
202 if (ret < 0)
203 return ret;
204 }
205 ret = ff_request_frame(ctx->inputs[0]);
206 } else {
207 ret = push_samples(ctx, 1024);
208 }
209
210 if (s->eof && s->nb_samples > 0 && s->loop != 0) {
211 ret = push_samples(ctx, 1024);
212 }
213
214 return ret;
215 }
216
aactivate(AVFilterContext * ctx)217 static int aactivate(AVFilterContext *ctx)
218 {
219 AVFilterLink *inlink = ctx->inputs[0];
220 AVFilterLink *outlink = ctx->outputs[0];
221 LoopContext *s = ctx->priv;
222 AVFrame *frame = NULL;
223 int ret, status;
224 int64_t pts;
225
226 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
227
228 if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) {
229 ret = ff_inlink_consume_frame(inlink, &frame);
230 if (ret < 0)
231 return ret;
232 if (ret > 0)
233 return afilter_frame(inlink, frame);
234 }
235
236 if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
237 if (status == AVERROR_EOF) {
238 s->size = s->nb_samples;
239 s->eof = 1;
240 }
241 }
242
243 if (s->eof && (!s->loop || !s->size)) {
244 ff_outlink_set_status(outlink, AVERROR_EOF, s->duration);
245 return 0;
246 }
247
248 if (!s->eof && (!s->size ||
249 (s->nb_samples < s->size) ||
250 (s->nb_samples >= s->size && s->loop == 0))) {
251 FF_FILTER_FORWARD_WANTED(outlink, inlink);
252 } else if (s->loop && s->nb_samples == s->size) {
253 return arequest_frame(outlink);
254 }
255
256 return FFERROR_NOT_READY;
257 }
258
259 static const AVOption aloop_options[] = {
260 { "loop", "number of loops", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, INT_MAX, AFLAGS },
261 { "size", "max number of samples to loop", OFFSET(size), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT32_MAX, AFLAGS },
262 { "start", "set the loop start sample", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, AFLAGS },
263 { NULL }
264 };
265
266 AVFILTER_DEFINE_CLASS(aloop);
267
268 static const AVFilterPad ainputs[] = {
269 {
270 .name = "default",
271 .type = AVMEDIA_TYPE_AUDIO,
272 .config_props = aconfig_input,
273 },
274 };
275
276 static const AVFilterPad aoutputs[] = {
277 {
278 .name = "default",
279 .type = AVMEDIA_TYPE_AUDIO,
280 },
281 };
282
283 const AVFilter ff_af_aloop = {
284 .name = "aloop",
285 .description = NULL_IF_CONFIG_SMALL("Loop audio samples."),
286 .priv_size = sizeof(LoopContext),
287 .priv_class = &aloop_class,
288 .activate = aactivate,
289 .uninit = auninit,
290 FILTER_INPUTS(ainputs),
291 FILTER_OUTPUTS(aoutputs),
292 };
293 #endif /* CONFIG_ALOOP_FILTER */
294
295 #if CONFIG_LOOP_FILTER
296
init(AVFilterContext * ctx)297 static av_cold int init(AVFilterContext *ctx)
298 {
299 LoopContext *s = ctx->priv;
300
301 s->frames = av_calloc(s->size, sizeof(*s->frames));
302 if (!s->frames)
303 return AVERROR(ENOMEM);
304
305 check_size(ctx);
306
307 return 0;
308 }
309
uninit(AVFilterContext * ctx)310 static av_cold void uninit(AVFilterContext *ctx)
311 {
312 LoopContext *s = ctx->priv;
313 int i;
314
315 for (i = 0; i < s->nb_frames; i++)
316 av_frame_free(&s->frames[i]);
317
318 av_freep(&s->frames);
319 s->nb_frames = 0;
320 }
321
push_frame(AVFilterContext * ctx)322 static int push_frame(AVFilterContext *ctx)
323 {
324 AVFilterLink *outlink = ctx->outputs[0];
325 LoopContext *s = ctx->priv;
326 int64_t pts, duration;
327 int ret;
328
329 AVFrame *out = av_frame_clone(s->frames[s->current_frame]);
330
331 if (!out)
332 return AVERROR(ENOMEM);
333 out->pts += s->duration - s->start_pts;
334 if (out->pkt_duration)
335 duration = out->pkt_duration;
336 else
337 duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
338 pts = out->pts + duration;
339 ret = ff_filter_frame(outlink, out);
340 s->current_frame++;
341
342 if (s->current_frame >= s->nb_frames) {
343 s->duration = pts;
344 s->current_frame = 0;
345
346 if (s->loop > 0)
347 s->loop--;
348 }
349
350 return ret;
351 }
352
filter_frame(AVFilterLink * inlink,AVFrame * frame)353 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
354 {
355 AVFilterContext *ctx = inlink->dst;
356 AVFilterLink *outlink = ctx->outputs[0];
357 LoopContext *s = ctx->priv;
358 int64_t duration;
359 int ret = 0;
360
361 if (inlink->frame_count_out >= s->start && s->size > 0 && s->loop != 0) {
362 if (s->nb_frames < s->size) {
363 if (!s->nb_frames)
364 s->start_pts = frame->pts;
365 s->frames[s->nb_frames] = av_frame_clone(frame);
366 if (!s->frames[s->nb_frames]) {
367 av_frame_free(&frame);
368 return AVERROR(ENOMEM);
369 }
370 s->nb_frames++;
371 if (frame->pkt_duration)
372 duration = frame->pkt_duration;
373 else
374 duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
375 s->duration = frame->pts + duration;
376 ret = ff_filter_frame(outlink, frame);
377 } else {
378 av_frame_free(&frame);
379 ret = push_frame(ctx);
380 }
381 } else {
382 frame->pts += s->duration;
383 ret = ff_filter_frame(outlink, frame);
384 }
385
386 return ret;
387 }
388
activate(AVFilterContext * ctx)389 static int activate(AVFilterContext *ctx)
390 {
391 AVFilterLink *inlink = ctx->inputs[0];
392 AVFilterLink *outlink = ctx->outputs[0];
393 LoopContext *s = ctx->priv;
394 AVFrame *frame = NULL;
395 int ret, status;
396 int64_t pts;
397
398 FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
399
400 if (!s->eof && (s->nb_frames < s->size || !s->loop || !s->size)) {
401 ret = ff_inlink_consume_frame(inlink, &frame);
402 if (ret < 0)
403 return ret;
404 if (ret > 0)
405 return filter_frame(inlink, frame);
406 }
407
408 if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
409 if (status == AVERROR_EOF) {
410 s->size = s->nb_frames;
411 s->eof = 1;
412 }
413 }
414
415 if (s->eof && (!s->loop || !s->size)) {
416 ff_outlink_set_status(outlink, AVERROR_EOF, s->duration);
417 return 0;
418 }
419
420 if (!s->eof && (!s->size ||
421 (s->nb_frames < s->size) ||
422 (s->nb_frames >= s->size && s->loop == 0))) {
423 FF_FILTER_FORWARD_WANTED(outlink, inlink);
424 } else if (s->loop && s->nb_frames == s->size) {
425 return push_frame(ctx);
426 }
427
428 return FFERROR_NOT_READY;
429 }
430
431 static const AVOption loop_options[] = {
432 { "loop", "number of loops", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, INT_MAX, VFLAGS },
433 { "size", "max number of frames to loop", OFFSET(size), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT16_MAX, VFLAGS },
434 { "start", "set the loop start frame", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, VFLAGS },
435 { NULL }
436 };
437
438 AVFILTER_DEFINE_CLASS(loop);
439
440 static const AVFilterPad inputs[] = {
441 {
442 .name = "default",
443 .type = AVMEDIA_TYPE_VIDEO,
444 },
445 };
446
447 static const AVFilterPad outputs[] = {
448 {
449 .name = "default",
450 .type = AVMEDIA_TYPE_VIDEO,
451 },
452 };
453
454 const AVFilter ff_vf_loop = {
455 .name = "loop",
456 .description = NULL_IF_CONFIG_SMALL("Loop video frames."),
457 .priv_size = sizeof(LoopContext),
458 .priv_class = &loop_class,
459 .init = init,
460 .uninit = uninit,
461 .activate = activate,
462 FILTER_INPUTS(inputs),
463 FILTER_OUTPUTS(outputs),
464 };
465 #endif /* CONFIG_LOOP_FILTER */
466