af_asyncts.c
Go to the documentation of this file.
1 /*
2  * This file is part of Libav.
3  *
4  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
20 #include "libavutil/audio_fifo.h"
21 #include "libavutil/common.h"
22 #include "libavutil/mathematics.h"
23 #include "libavutil/opt.h"
24 #include "libavutil/samplefmt.h"
25 
26 #include "audio.h"
27 #include "avfilter.h"
28 #include "internal.h"
29 
30 typedef struct ASyncContext {
31  const AVClass *class;
32 
34  int64_t pts; ///< timestamp in samples of the first sample in fifo
35  int min_delta; ///< pad/trim min threshold in samples
36  int first_frame; ///< 1 until filter_frame() has processed at least 1 frame with a pts != AV_NOPTS_VALUE
37  int64_t first_pts; ///< user-specified first expected pts, in samples
38  int comp; ///< current resample compensation
39 
40  /* options */
41  int resample;
43  int max_comp;
44 
45  /* set by filter_frame() to signal an output frame to request_frame() */
47 } ASyncContext;
48 
49 #define OFFSET(x) offsetof(ASyncContext, x)
50 #define A AV_OPT_FLAG_AUDIO_PARAM
51 #define F AV_OPT_FLAG_FILTERING_PARAM
52 static const AVOption asyncts_options[] = {
53  { "compensate", "Stretch/squeeze the data to make it match the timestamps", OFFSET(resample), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, A|F },
54  { "min_delta", "Minimum difference between timestamps and audio data "
55  "(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A|F },
56  { "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, A|F },
57  { "first_pts", "Assume the first pts should be this value.", OFFSET(first_pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, A|F },
58  { NULL },
59 };
60 
61 AVFILTER_DEFINE_CLASS(asyncts);
62 
63 static int init(AVFilterContext *ctx)
64 {
65  ASyncContext *s = ctx->priv;
66 
67  s->pts = AV_NOPTS_VALUE;
68  s->first_frame = 1;
69 
70  return 0;
71 }
72 
73 static void uninit(AVFilterContext *ctx)
74 {
75  ASyncContext *s = ctx->priv;
76 
77  if (s->avr) {
79  avresample_free(&s->avr);
80  }
81 }
82 
84 {
85  ASyncContext *s = link->src->priv;
86  int ret;
87 
88  s->min_delta = s->min_delta_sec * link->sample_rate;
89  link->time_base = (AVRational){1, link->sample_rate};
90 
92  if (!s->avr)
93  return AVERROR(ENOMEM);
94 
95  av_opt_set_int(s->avr, "in_channel_layout", link->channel_layout, 0);
96  av_opt_set_int(s->avr, "out_channel_layout", link->channel_layout, 0);
97  av_opt_set_int(s->avr, "in_sample_fmt", link->format, 0);
98  av_opt_set_int(s->avr, "out_sample_fmt", link->format, 0);
99  av_opt_set_int(s->avr, "in_sample_rate", link->sample_rate, 0);
100  av_opt_set_int(s->avr, "out_sample_rate", link->sample_rate, 0);
101 
102  if (s->resample)
103  av_opt_set_int(s->avr, "force_resampling", 1, 0);
104 
105  if ((ret = avresample_open(s->avr)) < 0)
106  return ret;
107 
108  return 0;
109 }
110 
111 /* get amount of data currently buffered, in samples */
112 static int64_t get_delay(ASyncContext *s)
113 {
115 }
116 
118 {
119  ASyncContext *s = ctx->priv;
120 
121  if (s->pts < s->first_pts) {
122  int delta = FFMIN(s->first_pts - s->pts, avresample_available(s->avr));
123  av_log(ctx, AV_LOG_VERBOSE, "Trimming %d samples from start\n",
124  delta);
125  avresample_read(s->avr, NULL, delta);
126  s->pts += delta;
127  } else if (s->first_frame)
128  s->pts = s->first_pts;
129 }
130 
132 {
133  AVFilterContext *ctx = link->src;
134  ASyncContext *s = ctx->priv;
135  int ret = 0;
136  int nb_samples;
137 
138  s->got_output = 0;
139  while (ret >= 0 && !s->got_output)
140  ret = ff_request_frame(ctx->inputs[0]);
141 
142  /* flush the fifo */
143  if (ret == AVERROR_EOF) {
144  if (s->first_pts != AV_NOPTS_VALUE)
145  handle_trimming(ctx);
146 
147  if (nb_samples = get_delay(s)) {
148  AVFrame *buf = ff_get_audio_buffer(link, nb_samples);
149  if (!buf)
150  return AVERROR(ENOMEM);
151  ret = avresample_convert(s->avr, buf->extended_data,
152  buf->linesize[0], nb_samples, NULL, 0, 0);
153  if (ret <= 0) {
154  av_frame_free(&buf);
155  return (ret < 0) ? ret : AVERROR_EOF;
156  }
157 
158  buf->pts = s->pts;
159  return ff_filter_frame(link, buf);
160  }
161  }
162 
163  return ret;
164 }
165 
167 {
168  int ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
169  buf->linesize[0], buf->nb_samples);
170  av_frame_free(&buf);
171  return ret;
172 }
173 
174 static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
175 {
176  AVFilterContext *ctx = inlink->dst;
177  ASyncContext *s = ctx->priv;
178  AVFilterLink *outlink = ctx->outputs[0];
180  int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts :
181  av_rescale_q(buf->pts, inlink->time_base, outlink->time_base);
182  int out_size, ret;
183  int64_t delta;
184  int64_t new_pts;
185 
186  /* buffer data until we get the next timestamp */
187  if (s->pts == AV_NOPTS_VALUE || pts == AV_NOPTS_VALUE) {
188  if (pts != AV_NOPTS_VALUE) {
189  s->pts = pts - get_delay(s);
190  }
191  return write_to_fifo(s, buf);
192  }
193 
194  if (s->first_pts != AV_NOPTS_VALUE) {
195  handle_trimming(ctx);
196  if (!avresample_available(s->avr))
197  return write_to_fifo(s, buf);
198  }
199 
200  /* when we have two timestamps, compute how many samples would we have
201  * to add/remove to get proper sync between data and timestamps */
202  delta = pts - s->pts - get_delay(s);
203  out_size = avresample_available(s->avr);
204 
205  if (labs(delta) > s->min_delta ||
206  (s->first_frame && delta && s->first_pts != AV_NOPTS_VALUE)) {
207  av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta);
208  out_size = av_clipl_int32((int64_t)out_size + delta);
209  } else {
210  if (s->resample) {
211  // adjust the compensation if delta is non-zero
212  int delay = get_delay(s);
213  int comp = s->comp + av_clip(delta * inlink->sample_rate / delay,
214  -s->max_comp, s->max_comp);
215  if (comp != s->comp) {
216  av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp);
217  if (avresample_set_compensation(s->avr, comp, inlink->sample_rate) == 0) {
218  s->comp = comp;
219  }
220  }
221  }
222  // adjust PTS to avoid monotonicity errors with input PTS jitter
223  pts -= delta;
224  delta = 0;
225  }
226 
227  if (out_size > 0) {
228  AVFrame *buf_out = ff_get_audio_buffer(outlink, out_size);
229  if (!buf_out) {
230  ret = AVERROR(ENOMEM);
231  goto fail;
232  }
233 
234  if (s->first_frame && delta > 0) {
235  int ch;
236 
237  av_samples_set_silence(buf_out->extended_data, 0, delta,
238  nb_channels, buf->format);
239 
240  for (ch = 0; ch < nb_channels; ch++)
241  buf_out->extended_data[ch] += delta;
242 
243  avresample_read(s->avr, buf_out->extended_data, out_size);
244 
245  for (ch = 0; ch < nb_channels; ch++)
246  buf_out->extended_data[ch] -= delta;
247  } else {
248  avresample_read(s->avr, buf_out->extended_data, out_size);
249 
250  if (delta > 0) {
251  av_samples_set_silence(buf_out->extended_data, out_size - delta,
252  delta, nb_channels, buf->format);
253  }
254  }
255  buf_out->pts = s->pts;
256  ret = ff_filter_frame(outlink, buf_out);
257  if (ret < 0)
258  goto fail;
259  s->got_output = 1;
260  } else if (avresample_available(s->avr)) {
261  av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
262  "whole buffer.\n");
263  }
264 
265  /* drain any remaining buffered data */
267 
268  new_pts = pts - avresample_get_delay(s->avr);
269  /* check for s->pts monotonicity */
270  if (new_pts > s->pts) {
271  s->pts = new_pts;
272  ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
273  buf->linesize[0], buf->nb_samples);
274  } else {
275  av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
276  "whole buffer.\n");
277  ret = 0;
278  }
279 
280  s->first_frame = 0;
281 fail:
282  av_frame_free(&buf);
283 
284  return ret;
285 }
286 
288  {
289  .name = "default",
290  .type = AVMEDIA_TYPE_AUDIO,
291  .filter_frame = filter_frame
292  },
293  { NULL }
294 };
295 
297  {
298  .name = "default",
299  .type = AVMEDIA_TYPE_AUDIO,
300  .config_props = config_props,
301  .request_frame = request_frame
302  },
303  { NULL }
304 };
305 
307  .name = "asyncts",
308  .description = NULL_IF_CONFIG_SMALL("Sync audio data to timestamps"),
309 
310  .init = init,
311  .uninit = uninit,
312 
313  .priv_size = sizeof(ASyncContext),
314  .priv_class = &asyncts_class,
315 
316  .inputs = avfilter_af_asyncts_inputs,
317  .outputs = avfilter_af_asyncts_outputs,
318 };
const char * s
Definition: avisynth_c.h:668
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
static const AVFilterPad avfilter_af_asyncts_inputs[]
Definition: af_asyncts.c:287
AVOption.
Definition: opt.h:251
float min_delta_sec
Definition: af_asyncts.c:42
int min_delta
pad/trim min threshold in samples
Definition: af_asyncts.c:35
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:117
external API header
int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples)
Read samples from the output FIFO.
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
Definition: af_asyncts.c:174
int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, int compensation_distance)
Set compensation for resampling.
void avresample_free(AVAudioResampleContext **avr)
Free AVAudioResampleContext and associated AVOption values.
struct ASyncContext ASyncContext
const char * name
Pad name.
AVFilterLink ** inputs
array of pointers to input links
Definition: avfilter.h:532
static int init(AVFilterContext *ctx)
Definition: af_asyncts.c:63
it can be given away to ff_start_frame *A reference passed to ff_filter_frame(or the deprecated ff_start_frame) is given away and must no longer be used.*A reference created with avfilter_ref_buffer belongs to the code that created it.*A reference obtained with ff_get_video_buffer or ff_get_audio_buffer belongs to the code that requested it.*A reference given as return value by the get_video_buffer or get_audio_buffer method is given away and must no longer be used.Link reference fields---------------------The AVFilterLink structure has a few AVFilterBufferRef fields.The cur_buf and out_buf were used with the deprecated start_frame/draw_slice/end_frame API and should no longer be used.src_buf
float delta
AVOptions.
#define OFFSET(x)
Definition: af_asyncts.c:49
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:159
#define AVERROR_EOF
End of file.
Definition: error.h:55
static void uninit(AVFilterContext *ctx)
Definition: af_asyncts.c:73
void avresample_close(AVAudioResampleContext *avr)
Close AVAudioResampleContext.
static int request_frame(AVFilterLink *link)
Definition: af_asyncts.c:131
A filter pad used for either input or output.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:130
AVFrame * ff_get_audio_buffer(AVFilterLink *link, int nb_samples)
Request an audio samples buffer with a specific set of permissions.
Definition: audio.c:84
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
int comp
current resample compensation
Definition: af_asyncts.c:38
void * priv
private data for use by the filter
Definition: avfilter.h:545
int64_t pts
timestamp in samples of the first sample in fifo
Definition: af_asyncts.c:34
int av_get_channel_layout_nb_channels(uint64_t channel_layout)
Return the number of channels in the channel layout.
int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
Definition: opt.c:394
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
AVFilter avfilter_af_asyncts
Definition: af_asyncts.c:306
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a link
uint64_t channel_layout
Channel layout of the audio data.
Definition: frame.h:331
static int config_props(AVFilterLink *link)
Definition: af_asyncts.c:83
#define AV_LOG_VERBOSE
Definition: log.h:157
struct AVRational AVRational
rational number numerator/denominator
external API header
#define FFMIN(a, b)
Definition: common.h:58
int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, int nb_channels, enum AVSampleFormat sample_fmt)
Fill an audio buffer with silence.
Definition: samplefmt.c:249
static const AVOption asyncts_options[]
Definition: af_asyncts.c:52
ret
Definition: avfilter.c:821
AVAudioResampleContext * avr
Definition: af_asyncts.c:33
int first_frame
1 until filter_frame() has processed at least 1 frame with a pts != AV_NOPTS_VALUE ...
Definition: af_asyncts.c:36
AVFILTER_DEFINE_CLASS(asyncts)
int64_t first_pts
user-specified first expected pts, in samples
Definition: af_asyncts.c:37
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:134
int avresample_get_delay(AVAudioResampleContext *avr)
Return the number of samples currently in the resampling delay buffer.
NULL
Definition: eval.c:55
int avresample_available(AVAudioResampleContext *avr)
Return the number of available samples in the output FIFO.
#define F
Definition: af_asyncts.c:51
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
#define A
Definition: af_asyncts.c:50
void * buf
Definition: avisynth_c.h:594
static int write_to_fifo(ASyncContext *s, AVFrame *buf)
Definition: af_asyncts.c:166
Describe the class of an AVClass context structure.
Definition: log.h:50
Filter definition.
Definition: avfilter.h:436
int avresample_convert(AVAudioResampleContext *avr, uint8_t **output, int out_plane_size, int out_samples, uint8_t **input, int in_plane_size, int in_samples)
Convert input samples and write them to the output FIFO.
const char * name
filter name
Definition: avfilter.h:437
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:539
static int64_t get_delay(ASyncContext *s)
Definition: af_asyncts.c:112
AVAudioResampleContext * avresample_alloc_context(void)
Allocate AVAudioResampleContext and set options.
common internal and external API header
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
static void handle_trimming(AVFilterContext *ctx)
Definition: af_asyncts.c:117
int got_output
Definition: af_asyncts.c:46
Audio FIFO Buffer.
An instance of a filter.
Definition: avfilter.h:524
static const AVFilterPad avfilter_af_asyncts_outputs[]
Definition: af_asyncts.c:296
int ff_request_frame(AVFilterLink *link)
Request an input frame from the filter at the other end of the link.
Definition: avfilter.c:319
int nb_channels
internal API functions
uint8_t ** extended_data
pointers to the data planes/channels.
Definition: frame.h:117
int avresample_open(AVAudioResampleContext *avr)
Initialize AVAudioResampleContext.
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
int nb_samples
number of audio samples (per channel) described by this frame
Definition: frame.h:127
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition: avutil.h:190