FFmpeg  4.3.8
f_loop.c
Go to the documentation of this file.
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 "libavutil/audio_fifo.h"
22 #include "libavutil/avassert.h"
23 #include "libavutil/fifo.h"
24 #include "libavutil/internal.h"
25 #include "libavutil/opt.h"
26 #include "avfilter.h"
27 #include "audio.h"
28 #include "filters.h"
29 #include "formats.h"
30 #include "internal.h"
31 #include "video.h"
32 
33 typedef struct LoopContext {
34  const AVClass *class;
35 
39  int nb_frames;
46 
47  int loop;
48  int eof;
52 } LoopContext;
53 
54 #define AFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
55 #define VFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
56 #define OFFSET(x) offsetof(LoopContext, x)
57 
59 {
60  LoopContext *s = ctx->priv;
61 
62  if (!s->size)
63  av_log(ctx, AV_LOG_WARNING, "Number of %s to loop is not set!\n",
64  ctx->input_pads[0].type == AVMEDIA_TYPE_VIDEO ? "frames" : "samples");
65 }
66 
67 #if CONFIG_ALOOP_FILTER
68 
69 static int aconfig_input(AVFilterLink *inlink)
70 {
71  AVFilterContext *ctx = inlink->dst;
72  LoopContext *s = ctx->priv;
73 
74  s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, 8192);
75  s->left = av_audio_fifo_alloc(inlink->format, inlink->channels, 8192);
76  if (!s->fifo || !s->left)
77  return AVERROR(ENOMEM);
78 
79  check_size(ctx);
80 
81  return 0;
82 }
83 
84 static av_cold void auninit(AVFilterContext *ctx)
85 {
86  LoopContext *s = ctx->priv;
87 
90 }
91 
92 static int push_samples(AVFilterContext *ctx, int nb_samples)
93 {
94  AVFilterLink *outlink = ctx->outputs[0];
95  LoopContext *s = ctx->priv;
96  AVFrame *out;
97  int ret, i = 0;
98 
99  while (s->loop != 0 && i < nb_samples) {
100  out = ff_get_audio_buffer(outlink, FFMIN(nb_samples, s->nb_samples - s->current_sample));
101  if (!out)
102  return AVERROR(ENOMEM);
103  ret = av_audio_fifo_peek_at(s->fifo, (void **)out->extended_data, out->nb_samples, s->current_sample);
104  if (ret < 0) {
105  av_frame_free(&out);
106  return ret;
107  }
108  out->pts = s->pts;
109  out->nb_samples = ret;
110  s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
111  i += out->nb_samples;
112  s->current_sample += out->nb_samples;
113 
114  ret = ff_filter_frame(outlink, out);
115  if (ret < 0)
116  return ret;
117 
118  if (s->current_sample >= s->nb_samples) {
119  s->duration = s->pts;
120  s->current_sample = 0;
121 
122  if (s->loop > 0)
123  s->loop--;
124  }
125  }
126 
127  return ret;
128 }
129 
130 static int afilter_frame(AVFilterLink *inlink, AVFrame *frame)
131 {
132  AVFilterContext *ctx = inlink->dst;
133  AVFilterLink *outlink = ctx->outputs[0];
134  LoopContext *s = ctx->priv;
135  int ret = 0;
136 
137  if (s->ignored_samples + frame->nb_samples > s->start && s->size > 0 && s->loop != 0) {
138  if (s->nb_samples < s->size) {
139  int written = FFMIN(frame->nb_samples, s->size - s->nb_samples);
140  int drain = 0;
141 
142  ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, written);
143  if (ret < 0)
144  return ret;
145  if (!s->nb_samples) {
146  drain = FFMAX(0, s->start - s->ignored_samples);
147  s->pts = frame->pts;
148  av_audio_fifo_drain(s->fifo, drain);
149  s->pts += av_rescale_q(s->start - s->ignored_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
150  }
151  s->nb_samples += ret - drain;
152  drain = frame->nb_samples - written;
153  if (s->nb_samples == s->size && drain > 0) {
154  int ret2;
155 
156  ret2 = av_audio_fifo_write(s->left, (void **)frame->extended_data, frame->nb_samples);
157  if (ret2 < 0)
158  return ret2;
159  av_audio_fifo_drain(s->left, drain);
160  }
161  frame->nb_samples = ret;
162  s->pts += av_rescale_q(ret, (AVRational){1, outlink->sample_rate}, outlink->time_base);
163  ret = ff_filter_frame(outlink, frame);
164  } else {
165  int nb_samples = frame->nb_samples;
166 
167  av_frame_free(&frame);
168  ret = push_samples(ctx, nb_samples);
169  }
170  } else {
171  s->ignored_samples += frame->nb_samples;
172  frame->pts = s->pts;
173  s->pts += av_rescale_q(frame->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
174  ret = ff_filter_frame(outlink, frame);
175  }
176 
177  return ret;
178 }
179 
180 static int arequest_frame(AVFilterLink *outlink)
181 {
182  AVFilterContext *ctx = outlink->src;
183  LoopContext *s = ctx->priv;
184  int ret = 0;
185 
186  if ((!s->size) ||
187  (s->nb_samples < s->size) ||
188  (s->nb_samples >= s->size && s->loop == 0)) {
190 
191  if (s->loop == 0 && nb_samples > 0) {
192  AVFrame *out;
193 
194  out = ff_get_audio_buffer(outlink, nb_samples);
195  if (!out)
196  return AVERROR(ENOMEM);
197  av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples);
198  out->pts = s->pts;
199  s->pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base);
200  ret = ff_filter_frame(outlink, out);
201  if (ret < 0)
202  return ret;
203  }
204  ret = ff_request_frame(ctx->inputs[0]);
205  } else {
206  ret = push_samples(ctx, 1024);
207  }
208 
209  if (s->eof && s->nb_samples > 0 && s->loop != 0) {
210  ret = push_samples(ctx, 1024);
211  }
212 
213  return ret;
214 }
215 
216 static int aactivate(AVFilterContext *ctx)
217 {
218  AVFilterLink *inlink = ctx->inputs[0];
219  AVFilterLink *outlink = ctx->outputs[0];
220  LoopContext *s = ctx->priv;
221  AVFrame *frame = NULL;
222  int ret, status;
223  int64_t pts;
224 
225  FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
226 
227  if (!s->eof && (s->nb_samples < s->size || !s->loop || !s->size)) {
228  ret = ff_inlink_consume_frame(inlink, &frame);
229  if (ret < 0)
230  return ret;
231  if (ret > 0)
232  return afilter_frame(inlink, frame);
233  }
234 
235  if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
236  if (status == AVERROR_EOF) {
237  s->size = s->nb_samples;
238  s->eof = 1;
239  }
240  }
241 
242  if (s->eof && (!s->loop || !s->size)) {
244  return 0;
245  }
246 
247  if (!s->eof && (!s->size ||
248  (s->nb_samples < s->size) ||
249  (s->nb_samples >= s->size && s->loop == 0))) {
250  FF_FILTER_FORWARD_WANTED(outlink, inlink);
251  } else if (s->loop && s->nb_samples == s->size) {
252  return arequest_frame(outlink);
253  }
254 
255  return FFERROR_NOT_READY;
256 }
257 
258 static const AVOption aloop_options[] = {
259  { "loop", "number of loops", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, INT_MAX, AFLAGS },
260  { "size", "max number of samples to loop", OFFSET(size), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT32_MAX, AFLAGS },
261  { "start", "set the loop start sample", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, AFLAGS },
262  { NULL }
263 };
264 
265 AVFILTER_DEFINE_CLASS(aloop);
266 
267 static const AVFilterPad ainputs[] = {
268  {
269  .name = "default",
270  .type = AVMEDIA_TYPE_AUDIO,
271  .config_props = aconfig_input,
272  },
273  { NULL }
274 };
275 
276 static const AVFilterPad aoutputs[] = {
277  {
278  .name = "default",
279  .type = AVMEDIA_TYPE_AUDIO,
280  },
281  { NULL }
282 };
283 
285  .name = "aloop",
286  .description = NULL_IF_CONFIG_SMALL("Loop audio samples."),
287  .priv_size = sizeof(LoopContext),
288  .priv_class = &aloop_class,
289  .activate = aactivate,
290  .uninit = auninit,
291  .inputs = ainputs,
292  .outputs = aoutputs,
293 };
294 #endif /* CONFIG_ALOOP_FILTER */
295 
296 #if CONFIG_LOOP_FILTER
297 
298 static av_cold int init(AVFilterContext *ctx)
299 {
300  LoopContext *s = ctx->priv;
301 
302  s->frames = av_calloc(s->size, sizeof(*s->frames));
303  if (!s->frames)
304  return AVERROR(ENOMEM);
305 
306  check_size(ctx);
307 
308  return 0;
309 }
310 
311 static av_cold void uninit(AVFilterContext *ctx)
312 {
313  LoopContext *s = ctx->priv;
314  int i;
315 
316  for (i = 0; i < s->nb_frames; i++)
317  av_frame_free(&s->frames[i]);
318 
319  av_freep(&s->frames);
320  s->nb_frames = 0;
321 }
322 
323 static int push_frame(AVFilterContext *ctx)
324 {
325  AVFilterLink *outlink = ctx->outputs[0];
326  LoopContext *s = ctx->priv;
328  int ret;
329 
331 
332  if (!out)
333  return AVERROR(ENOMEM);
334  out->pts += s->duration - s->start_pts;
335  if (out->pkt_duration)
336  duration = out->pkt_duration;
337  else
338  duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
339  pts = out->pts + duration;
340  ret = ff_filter_frame(outlink, out);
341  s->current_frame++;
342 
343  if (s->current_frame >= s->nb_frames) {
344  s->duration = pts;
345  s->current_frame = 0;
346 
347  if (s->loop > 0)
348  s->loop--;
349  }
350 
351  return ret;
352 }
353 
354 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
355 {
356  AVFilterContext *ctx = inlink->dst;
357  AVFilterLink *outlink = ctx->outputs[0];
358  LoopContext *s = ctx->priv;
360  int ret = 0;
361 
362  if (inlink->frame_count_out >= s->start && s->size > 0 && s->loop != 0) {
363  if (s->nb_frames < s->size) {
364  if (!s->nb_frames)
365  s->start_pts = frame->pts;
366  s->frames[s->nb_frames] = av_frame_clone(frame);
367  if (!s->frames[s->nb_frames]) {
368  av_frame_free(&frame);
369  return AVERROR(ENOMEM);
370  }
371  s->nb_frames++;
372  if (frame->pkt_duration)
373  duration = frame->pkt_duration;
374  else
375  duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
376  s->duration = frame->pts + duration;
377  ret = ff_filter_frame(outlink, frame);
378  } else {
379  av_frame_free(&frame);
380  ret = push_frame(ctx);
381  }
382  } else {
383  frame->pts += s->duration;
384  ret = ff_filter_frame(outlink, frame);
385  }
386 
387  return ret;
388 }
389 
390 static int activate(AVFilterContext *ctx)
391 {
392  AVFilterLink *inlink = ctx->inputs[0];
393  AVFilterLink *outlink = ctx->outputs[0];
394  LoopContext *s = ctx->priv;
395  AVFrame *frame = NULL;
396  int ret, status;
397  int64_t pts;
398 
399  FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
400 
401  if (!s->eof && (s->nb_frames < s->size || !s->loop || !s->size)) {
402  ret = ff_inlink_consume_frame(inlink, &frame);
403  if (ret < 0)
404  return ret;
405  if (ret > 0)
406  return filter_frame(inlink, frame);
407  }
408 
409  if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
410  if (status == AVERROR_EOF) {
411  s->size = s->nb_frames;
412  s->eof = 1;
413  }
414  }
415 
416  if (s->eof && (!s->loop || !s->size)) {
418  return 0;
419  }
420 
421  if (!s->eof && (!s->size ||
422  (s->nb_frames < s->size) ||
423  (s->nb_frames >= s->size && s->loop == 0))) {
424  FF_FILTER_FORWARD_WANTED(outlink, inlink);
425  } else if (s->loop && s->nb_frames == s->size) {
426  return push_frame(ctx);
427  }
428 
429  return FFERROR_NOT_READY;
430 }
431 
432 static const AVOption loop_options[] = {
433  { "loop", "number of loops", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, INT_MAX, VFLAGS },
434  { "size", "max number of frames to loop", OFFSET(size), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT16_MAX, VFLAGS },
435  { "start", "set the loop start frame", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, VFLAGS },
436  { NULL }
437 };
438 
440 
441 static const AVFilterPad inputs[] = {
442  {
443  .name = "default",
444  .type = AVMEDIA_TYPE_VIDEO,
445  },
446  { NULL }
447 };
448 
449 static const AVFilterPad outputs[] = {
450  {
451  .name = "default",
452  .type = AVMEDIA_TYPE_VIDEO,
453  },
454  { NULL }
455 };
456 
458  .name = "loop",
459  .description = NULL_IF_CONFIG_SMALL("Loop video frames."),
460  .priv_size = sizeof(LoopContext),
461  .priv_class = &loop_class,
462  .init = init,
463  .uninit = uninit,
464  .activate = activate,
465  .inputs = inputs,
466  .outputs = outputs,
467 };
468 #endif /* CONFIG_LOOP_FILTER */
int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe)
Take a frame from the link&#39;s FIFO and update the link&#39;s stats.
Definition: avfilter.c:1476
#define NULL
Definition: coverity.c:32
static int push_samples(ATempoContext *atempo, AVFilterLink *outlink, int n_out)
Definition: af_atempo.c:1051
static void check_size(AVFilterContext *ctx)
Definition: f_loop.c:58
AVAudioFifo * av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, int nb_samples)
Allocate an AVAudioFifo.
Definition: audio_fifo.c:59
int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples)
Read data from an AVAudioFifo.
Definition: audio_fifo.c:181
This structure describes decoded (raw) audio or video data.
Definition: frame.h:300
AVOption.
Definition: opt.h:246
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
Main libavfilter public API header.
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
void av_audio_fifo_free(AVAudioFifo *af)
Free an AVAudioFifo.
Definition: audio_fifo.c:45
#define FFERROR_NOT_READY
Filters implementation helper functions.
Definition: filters.h:34
int64_t pts
Definition: f_loop.c:51
enum AVMediaType type
AVFilterPad type.
Definition: internal.h:65
int loop
Definition: f_loop.c:47
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:189
AVFrame ** frames
Definition: f_loop.c:38
void * av_calloc(size_t nmemb, size_t size)
Non-inlined equivalent of av_mallocz_array().
Definition: mem.c:245
const char * name
Pad name.
Definition: internal.h:60
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:346
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition: avfilter.c:1075
#define av_cold
Definition: attributes.h:88
static av_cold int uninit(AVCodecContext *avctx)
Definition: crystalhd.c:279
AVOptions.
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:393
int eof
Definition: f_loop.c:48
static AVFrame * frame
int current_frame
Definition: f_loop.c:40
static int push_frame(AVFilterContext *ctx, unsigned in_no, AVFrame *buf)
Definition: avf_concat.c:174
#define AVERROR_EOF
End of file.
Definition: error.h:55
#define av_log(a,...)
#define FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink)
Forward the status on an output link to an input link.
Definition: filters.h:199
int64_t current_sample
Definition: f_loop.c:43
A filter pad used for either input or output.
Definition: internal.h:54
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts)
Test and acknowledge the change of status on the link.
Definition: avfilter.c:1431
AVFilterPad * input_pads
array of input pads
Definition: avfilter.h:345
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:86
#define AVERROR(e)
Definition: error.h:43
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:203
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:188
int64_t start
Definition: f_loop.c:50
void * priv
private data for use by the filter
Definition: avfilter.h:353
int nb_frames
Definition: f_loop.c:39
simple assert() macros that are a bit more flexible than ISO C assert().
#define FFMAX(a, b)
Definition: common.h:94
Context for an Audio FIFO Buffer.
Definition: audio_fifo.c:34
common internal API header
int av_audio_fifo_size(AVAudioFifo *af)
Get the current number of samples in the AVAudioFifo available for reading.
Definition: audio_fifo.c:228
#define FF_FILTER_FORWARD_WANTED(outlink, inlink)
Forward the frame_wanted_out flag from an output link to an input link.
Definition: filters.h:254
#define FFMIN(a, b)
Definition: common.h:96
int64_t duration
Definition: f_loop.c:42
int64_t start_pts
Definition: f_loop.c:41
AVFormatContext * ctx
Definition: movenc.c:48
static int activate(AVFilterContext *ctx)
Definition: af_adeclick.c:622
#define s(width, name)
Definition: cbs_vp9.c:257
#define AFLAGS
Definition: f_loop.c:54
int64_t size
Definition: f_loop.c:49
static const AVFilterPad inputs[]
Definition: af_acontrast.c:193
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:541
static const AVFilterPad outputs[]
Definition: af_acontrast.c:203
int64_t pkt_duration
duration of the corresponding packet, expressed in AVStream->time_base units, 0 if unknown...
Definition: frame.h:579
long long int64_t
Definition: coverity.c:34
a very simple circular buffer FIFO implementation
AVAudioFifo * left
Definition: f_loop.c:37
Describe the class of an AVClass context structure.
Definition: log.h:67
Filter definition.
Definition: avfilter.h:144
Rational number (pair of numerator and denominator).
Definition: rational.h:58
const char * name
Filter name.
Definition: avfilter.h:148
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:350
int64_t nb_samples
Definition: f_loop.c:44
static int filter_frame(DBEContext *s, AVFrame *frame)
Definition: dolby_e.c:565
int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples)
Write data to an AVAudioFifo.
Definition: audio_fifo.c:112
int64_t ignored_samples
Definition: f_loop.c:45
int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples)
Drain data from an AVAudioFifo.
Definition: audio_fifo.c:201
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
AVFilter ff_vf_loop
Audio FIFO Buffer.
#define AVFILTER_DEFINE_CLASS(fname)
Definition: internal.h:314
#define OFFSET(x)
Definition: f_loop.c:56
AVAudioFifo * fifo
Definition: f_loop.c:36
An instance of a filter.
Definition: avfilter.h:338
#define VFLAGS
Definition: f_loop.c:55
FILE * out
Definition: movenc.c:54
AVFilter ff_af_aloop
#define av_freep(p)
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:407
internal API functions
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: frame.h:347
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:366
int av_audio_fifo_peek_at(AVAudioFifo *af, void **data, int nb_samples, int offset)
Peek data from an AVAudioFifo.
Definition: audio_fifo.c:157