FFmpeg  4.2.2
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;
41  int64_t start_pts;
42  int64_t duration;
43  int64_t current_sample;
44  int64_t nb_samples;
45  int64_t ignored_samples;
46 
47  int loop;
48  int eof;
49  int64_t size;
50  int64_t start;
51  int64_t pts;
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 += out->nb_samples;
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->current_sample = 0;
120 
121  if (s->loop > 0)
122  s->loop--;
123  }
124  }
125 
126  return ret;
127 }
128 
129 static int afilter_frame(AVFilterLink *inlink, AVFrame *frame)
130 {
131  AVFilterContext *ctx = inlink->dst;
132  AVFilterLink *outlink = ctx->outputs[0];
133  LoopContext *s = ctx->priv;
134  int ret = 0;
135 
136  if (s->ignored_samples + frame->nb_samples > s->start && s->size > 0 && s->loop != 0) {
137  if (s->nb_samples < s->size) {
138  int written = FFMIN(frame->nb_samples, s->size - s->nb_samples);
139  int drain = 0;
140 
141  ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, written);
142  if (ret < 0)
143  return ret;
144  if (!s->nb_samples) {
145  drain = FFMAX(0, s->start - s->ignored_samples);
146  s->pts = frame->pts;
147  av_audio_fifo_drain(s->fifo, drain);
148  s->pts += s->start - s->ignored_samples;
149  }
150  s->nb_samples += ret - drain;
151  drain = frame->nb_samples - written;
152  if (s->nb_samples == s->size && drain > 0) {
153  int ret2;
154 
155  ret2 = av_audio_fifo_write(s->left, (void **)frame->extended_data, frame->nb_samples);
156  if (ret2 < 0)
157  return ret2;
158  av_audio_fifo_drain(s->left, drain);
159  }
160  frame->nb_samples = ret;
161  s->pts += ret;
162  ret = ff_filter_frame(outlink, frame);
163  } else {
164  int nb_samples = frame->nb_samples;
165 
166  av_frame_free(&frame);
167  ret = push_samples(ctx, nb_samples);
168  }
169  } else {
170  s->ignored_samples += frame->nb_samples;
171  frame->pts = s->pts;
172  s->pts += frame->nb_samples;
173  ret = ff_filter_frame(outlink, frame);
174  }
175 
176  return ret;
177 }
178 
179 static int arequest_frame(AVFilterLink *outlink)
180 {
181  AVFilterContext *ctx = outlink->src;
182  LoopContext *s = ctx->priv;
183  int ret = 0;
184 
185  if ((!s->size) ||
186  (s->nb_samples < s->size) ||
187  (s->nb_samples >= s->size && s->loop == 0)) {
189 
190  if (s->loop == 0 && nb_samples > 0) {
191  AVFrame *out;
192 
193  out = ff_get_audio_buffer(outlink, nb_samples);
194  if (!out)
195  return AVERROR(ENOMEM);
196  av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples);
197  out->pts = s->pts;
198  s->pts += nb_samples;
199  ret = ff_filter_frame(outlink, out);
200  if (ret < 0)
201  return ret;
202  }
203  ret = ff_request_frame(ctx->inputs[0]);
204  } else {
205  ret = push_samples(ctx, 1024);
206  }
207 
208  if (ret == AVERROR_EOF && s->nb_samples > 0 && s->loop != 0) {
209  ret = push_samples(ctx, outlink->sample_rate);
210  }
211 
212  return ret;
213 }
214 
215 static const AVOption aloop_options[] = {
216  { "loop", "number of loops", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, INT_MAX, AFLAGS },
217  { "size", "max number of samples to loop", OFFSET(size), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT32_MAX, AFLAGS },
218  { "start", "set the loop start sample", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, AFLAGS },
219  { NULL }
220 };
221 
222 AVFILTER_DEFINE_CLASS(aloop);
223 
224 static const AVFilterPad ainputs[] = {
225  {
226  .name = "default",
227  .type = AVMEDIA_TYPE_AUDIO,
228  .filter_frame = afilter_frame,
229  .config_props = aconfig_input,
230  },
231  { NULL }
232 };
233 
234 static const AVFilterPad aoutputs[] = {
235  {
236  .name = "default",
237  .type = AVMEDIA_TYPE_AUDIO,
238  .request_frame = arequest_frame,
239  },
240  { NULL }
241 };
242 
244  .name = "aloop",
245  .description = NULL_IF_CONFIG_SMALL("Loop audio samples."),
246  .priv_size = sizeof(LoopContext),
247  .priv_class = &aloop_class,
248  .uninit = auninit,
249  .inputs = ainputs,
250  .outputs = aoutputs,
251 };
252 #endif /* CONFIG_ALOOP_FILTER */
253 
254 #if CONFIG_LOOP_FILTER
255 
256 static av_cold int init(AVFilterContext *ctx)
257 {
258  LoopContext *s = ctx->priv;
259 
260  s->frames = av_calloc(s->size, sizeof(*s->frames));
261  if (!s->frames)
262  return AVERROR(ENOMEM);
263 
264  check_size(ctx);
265 
266  return 0;
267 }
268 
269 static av_cold void uninit(AVFilterContext *ctx)
270 {
271  LoopContext *s = ctx->priv;
272  int i;
273 
274  for (i = 0; i < s->nb_frames; i++)
275  av_frame_free(&s->frames[i]);
276 
277  av_freep(&s->frames);
278  s->nb_frames = 0;
279 }
280 
281 static int push_frame(AVFilterContext *ctx)
282 {
283  AVFilterLink *outlink = ctx->outputs[0];
284  LoopContext *s = ctx->priv;
285  int64_t pts, duration;
286  int ret;
287 
289 
290  if (!out)
291  return AVERROR(ENOMEM);
292  out->pts += s->duration - s->start_pts;
293  if (out->pkt_duration)
294  duration = out->pkt_duration;
295  else
296  duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
297  pts = out->pts + duration;
298  ret = ff_filter_frame(outlink, out);
299  s->current_frame++;
300 
301  if (s->current_frame >= s->nb_frames) {
302  s->duration = pts;
303  s->current_frame = 0;
304 
305  if (s->loop > 0)
306  s->loop--;
307  }
308 
309  return ret;
310 }
311 
312 static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
313 {
314  AVFilterContext *ctx = inlink->dst;
315  AVFilterLink *outlink = ctx->outputs[0];
316  LoopContext *s = ctx->priv;
317  int64_t duration;
318  int ret = 0;
319 
320  if (inlink->frame_count_out >= s->start && s->size > 0 && s->loop != 0) {
321  if (s->nb_frames < s->size) {
322  if (!s->nb_frames)
323  s->start_pts = frame->pts;
324  s->frames[s->nb_frames] = av_frame_clone(frame);
325  if (!s->frames[s->nb_frames]) {
326  av_frame_free(&frame);
327  return AVERROR(ENOMEM);
328  }
329  s->nb_frames++;
330  if (frame->pkt_duration)
331  duration = frame->pkt_duration;
332  else
333  duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base);
334  s->duration = frame->pts + duration;
335  ret = ff_filter_frame(outlink, frame);
336  } else {
337  av_frame_free(&frame);
338  ret = push_frame(ctx);
339  }
340  } else {
341  frame->pts += s->duration;
342  ret = ff_filter_frame(outlink, frame);
343  }
344 
345  return ret;
346 }
347 
348 static int activate(AVFilterContext *ctx)
349 {
350  AVFilterLink *inlink = ctx->inputs[0];
351  AVFilterLink *outlink = ctx->outputs[0];
352  LoopContext *s = ctx->priv;
353  AVFrame *frame = NULL;
354  int ret, status;
355  int64_t pts;
356 
357  FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink);
358 
359  if (!s->eof && (s->nb_frames < s->size || !s->loop || !s->size)) {
360  ret = ff_inlink_consume_frame(inlink, &frame);
361  if (ret < 0)
362  return ret;
363  if (ret > 0)
364  return filter_frame(inlink, frame);
365  }
366 
367  if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) {
368  if (status == AVERROR_EOF) {
369  s->size = s->nb_frames;
370  s->eof = 1;
371  }
372  }
373 
374  if (s->eof && (!s->loop || !s->size)) {
376  return 0;
377  }
378 
379  if (!s->eof && (!s->size ||
380  (s->nb_frames < s->size) ||
381  (s->nb_frames >= s->size && s->loop == 0))) {
382  FF_FILTER_FORWARD_WANTED(outlink, inlink);
383  } else if (s->loop && s->nb_frames == s->size) {
384  return push_frame(ctx);
385  }
386 
387  return FFERROR_NOT_READY;
388 }
389 
390 static const AVOption loop_options[] = {
391  { "loop", "number of loops", OFFSET(loop), AV_OPT_TYPE_INT, {.i64 = 0 }, -1, INT_MAX, VFLAGS },
392  { "size", "max number of frames to loop", OFFSET(size), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT16_MAX, VFLAGS },
393  { "start", "set the loop start frame", OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, VFLAGS },
394  { NULL }
395 };
396 
398 
399 static const AVFilterPad inputs[] = {
400  {
401  .name = "default",
402  .type = AVMEDIA_TYPE_VIDEO,
403  },
404  { NULL }
405 };
406 
407 static const AVFilterPad outputs[] = {
408  {
409  .name = "default",
410  .type = AVMEDIA_TYPE_VIDEO,
411  },
412  { NULL }
413 };
414 
416  .name = "loop",
417  .description = NULL_IF_CONFIG_SMALL("Loop video frames."),
418  .priv_size = sizeof(LoopContext),
419  .priv_class = &loop_class,
420  .init = init,
421  .uninit = uninit,
422  .activate = activate,
423  .inputs = inputs,
424  .outputs = outputs,
425 };
426 #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:1481
#define NULL
Definition: coverity.c:32
static int push_samples(ATempoContext *atempo, AVFilterLink *outlink, int n_out)
Definition: af_atempo.c:1065
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:295
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:244
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:1080
#define av_cold
Definition: attributes.h:82
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:388
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:161
#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:1436
AVFilterPad * input_pads
array of input pads
Definition: avfilter.h:345
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:259
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:202
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
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:609
#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:540
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:574
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
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:334
#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:342
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:361
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