2012-05-08 16:33:50 +02:00
|
|
|
/*
|
|
|
|
* This file is part of Libav.
|
|
|
|
*
|
|
|
|
* Libav is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* Libav is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with Libav; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "libavresample/avresample.h"
|
2013-04-30 18:30:02 +02:00
|
|
|
#include "libavutil/attributes.h"
|
2012-05-08 16:33:50 +02:00
|
|
|
#include "libavutil/audio_fifo.h"
|
2012-08-06 15:49:32 +02:00
|
|
|
#include "libavutil/common.h"
|
2012-05-08 16:33:50 +02:00
|
|
|
#include "libavutil/mathematics.h"
|
|
|
|
#include "libavutil/opt.h"
|
|
|
|
#include "libavutil/samplefmt.h"
|
|
|
|
|
|
|
|
#include "audio.h"
|
|
|
|
#include "avfilter.h"
|
2012-05-30 11:20:32 +02:00
|
|
|
#include "internal.h"
|
2012-05-08 16:33:50 +02:00
|
|
|
|
|
|
|
typedef struct ASyncContext {
|
|
|
|
const AVClass *class;
|
|
|
|
|
|
|
|
AVAudioResampleContext *avr;
|
|
|
|
int64_t pts; ///< timestamp in samples of the first sample in fifo
|
|
|
|
int min_delta; ///< pad/trim min threshold in samples
|
2012-12-11 23:36:09 +01:00
|
|
|
int first_frame; ///< 1 until filter_frame() has processed at least 1 frame with a pts != AV_NOPTS_VALUE
|
|
|
|
int64_t first_pts; ///< user-specified first expected pts, in samples
|
af_asyncts: fix compensation and PTS monotonicity
This patch improves af_asyncts behavior on streams with bogus PTS, which
are either non-monotonic, or contain PTS jitter, and trigger the
non-monotonicity error. With this patch, af_asyncts is able to correct
these streams and avoid the error.
Firstly, it fixes resample compensation calculation by supplying proper
units to avresample_set_compensation (sample count per second instead
of sample count per some arbitrary frame size). Also, the calculation of
the compensation itself is fixed - delta is proportional to an adjustment
of the compensation, not the compensation itself. Ideally, the compensation
should converge to a value that keeps delta at zero.
To be able to deal with sources with PTS jitter even without resampling,
small PTS errors are adjusted, so the output frames do not overlap.
Finally, one more monotonicity check is added.
The FATE reference changes because now there is 8 less samples of
silence because of the pts jitter.
Signed-off-by: Jindřich Makovička <makovick@gmail.com>
2013-03-09 10:08:09 +01:00
|
|
|
int comp; ///< current resample compensation
|
2012-05-08 16:33:50 +02:00
|
|
|
|
|
|
|
/* options */
|
|
|
|
int resample;
|
|
|
|
float min_delta_sec;
|
|
|
|
int max_comp;
|
2012-07-04 16:46:17 +02:00
|
|
|
|
2012-11-27 07:49:45 +01:00
|
|
|
/* set by filter_frame() to signal an output frame to request_frame() */
|
2012-07-04 16:46:17 +02:00
|
|
|
int got_output;
|
2012-05-08 16:33:50 +02:00
|
|
|
} ASyncContext;
|
|
|
|
|
|
|
|
#define OFFSET(x) offsetof(ASyncContext, x)
|
|
|
|
#define A AV_OPT_FLAG_AUDIO_PARAM
|
|
|
|
static const AVOption options[] = {
|
2012-08-31 12:22:31 +02:00
|
|
|
{ "compensate", "Stretch/squeeze the data to make it match the timestamps", OFFSET(resample), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, A },
|
2012-05-08 16:33:50 +02:00
|
|
|
{ "min_delta", "Minimum difference between timestamps and audio data "
|
2012-08-31 12:34:23 +02:00
|
|
|
"(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A },
|
2012-08-31 12:22:31 +02:00
|
|
|
{ "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, A },
|
2012-12-11 23:36:09 +01:00
|
|
|
{ "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 },
|
2012-05-08 16:33:50 +02:00
|
|
|
{ NULL },
|
|
|
|
};
|
|
|
|
|
|
|
|
static const AVClass async_class = {
|
|
|
|
.class_name = "asyncts filter",
|
|
|
|
.item_name = av_default_item_name,
|
|
|
|
.option = options,
|
|
|
|
.version = LIBAVUTIL_VERSION_INT,
|
|
|
|
};
|
|
|
|
|
2013-04-30 18:30:02 +02:00
|
|
|
static av_cold int init(AVFilterContext *ctx)
|
2012-05-08 16:33:50 +02:00
|
|
|
{
|
|
|
|
ASyncContext *s = ctx->priv;
|
|
|
|
|
2012-12-11 23:36:09 +01:00
|
|
|
s->pts = AV_NOPTS_VALUE;
|
|
|
|
s->first_frame = 1;
|
|
|
|
|
2012-05-08 16:33:50 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-04-30 18:30:02 +02:00
|
|
|
static av_cold void uninit(AVFilterContext *ctx)
|
2012-05-08 16:33:50 +02:00
|
|
|
{
|
|
|
|
ASyncContext *s = ctx->priv;
|
|
|
|
|
|
|
|
if (s->avr) {
|
|
|
|
avresample_close(s->avr);
|
|
|
|
avresample_free(&s->avr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int config_props(AVFilterLink *link)
|
|
|
|
{
|
|
|
|
ASyncContext *s = link->src->priv;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
s->min_delta = s->min_delta_sec * link->sample_rate;
|
|
|
|
link->time_base = (AVRational){1, link->sample_rate};
|
|
|
|
|
|
|
|
s->avr = avresample_alloc_context();
|
|
|
|
if (!s->avr)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
|
|
|
|
av_opt_set_int(s->avr, "in_channel_layout", link->channel_layout, 0);
|
|
|
|
av_opt_set_int(s->avr, "out_channel_layout", link->channel_layout, 0);
|
|
|
|
av_opt_set_int(s->avr, "in_sample_fmt", link->format, 0);
|
|
|
|
av_opt_set_int(s->avr, "out_sample_fmt", link->format, 0);
|
|
|
|
av_opt_set_int(s->avr, "in_sample_rate", link->sample_rate, 0);
|
|
|
|
av_opt_set_int(s->avr, "out_sample_rate", link->sample_rate, 0);
|
|
|
|
|
|
|
|
if (s->resample)
|
|
|
|
av_opt_set_int(s->avr, "force_resampling", 1, 0);
|
|
|
|
|
|
|
|
if ((ret = avresample_open(s->avr)) < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-12-12 19:10:13 +01:00
|
|
|
/* get amount of data currently buffered, in samples */
|
|
|
|
static int64_t get_delay(ASyncContext *s)
|
|
|
|
{
|
|
|
|
return avresample_available(s->avr) + avresample_get_delay(s->avr);
|
|
|
|
}
|
|
|
|
|
2012-12-11 23:36:09 +01:00
|
|
|
static void handle_trimming(AVFilterContext *ctx)
|
|
|
|
{
|
|
|
|
ASyncContext *s = ctx->priv;
|
|
|
|
|
|
|
|
if (s->pts < s->first_pts) {
|
|
|
|
int delta = FFMIN(s->first_pts - s->pts, avresample_available(s->avr));
|
|
|
|
av_log(ctx, AV_LOG_VERBOSE, "Trimming %d samples from start\n",
|
|
|
|
delta);
|
|
|
|
avresample_read(s->avr, NULL, delta);
|
|
|
|
s->pts += delta;
|
|
|
|
} else if (s->first_frame)
|
|
|
|
s->pts = s->first_pts;
|
|
|
|
}
|
|
|
|
|
2012-05-08 16:33:50 +02:00
|
|
|
static int request_frame(AVFilterLink *link)
|
|
|
|
{
|
|
|
|
AVFilterContext *ctx = link->src;
|
|
|
|
ASyncContext *s = ctx->priv;
|
2012-07-04 16:46:17 +02:00
|
|
|
int ret = 0;
|
2012-05-08 16:33:50 +02:00
|
|
|
int nb_samples;
|
|
|
|
|
2012-07-04 16:46:17 +02:00
|
|
|
s->got_output = 0;
|
|
|
|
while (ret >= 0 && !s->got_output)
|
|
|
|
ret = ff_request_frame(ctx->inputs[0]);
|
|
|
|
|
2012-05-08 16:33:50 +02:00
|
|
|
/* flush the fifo */
|
2012-12-11 23:36:09 +01:00
|
|
|
if (ret == AVERROR_EOF) {
|
|
|
|
if (s->first_pts != AV_NOPTS_VALUE)
|
|
|
|
handle_trimming(ctx);
|
|
|
|
|
|
|
|
if (nb_samples = get_delay(s)) {
|
2012-11-28 08:41:07 +01:00
|
|
|
AVFrame *buf = ff_get_audio_buffer(link, nb_samples);
|
2012-12-13 17:55:40 +01:00
|
|
|
if (!buf)
|
|
|
|
return AVERROR(ENOMEM);
|
|
|
|
ret = avresample_convert(s->avr, buf->extended_data,
|
|
|
|
buf->linesize[0], nb_samples, NULL, 0, 0);
|
|
|
|
if (ret <= 0) {
|
2012-11-28 08:41:07 +01:00
|
|
|
av_frame_free(&buf);
|
2012-12-13 17:55:40 +01:00
|
|
|
return (ret < 0) ? ret : AVERROR_EOF;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf->pts = s->pts;
|
|
|
|
return ff_filter_frame(link, buf);
|
2012-12-11 23:36:09 +01:00
|
|
|
}
|
2012-05-08 16:33:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-11-28 08:41:07 +01:00
|
|
|
static int write_to_fifo(ASyncContext *s, AVFrame *buf)
|
2012-05-08 16:33:50 +02:00
|
|
|
{
|
2012-10-05 06:56:00 +02:00
|
|
|
int ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
|
2012-11-28 08:41:07 +01:00
|
|
|
buf->linesize[0], buf->nb_samples);
|
|
|
|
av_frame_free(&buf);
|
2012-07-02 20:13:40 +02:00
|
|
|
return ret;
|
2012-05-08 16:33:50 +02:00
|
|
|
}
|
|
|
|
|
2012-11-28 08:41:07 +01:00
|
|
|
static int filter_frame(AVFilterLink *inlink, AVFrame *buf)
|
2012-05-08 16:33:50 +02:00
|
|
|
{
|
|
|
|
AVFilterContext *ctx = inlink->dst;
|
|
|
|
ASyncContext *s = ctx->priv;
|
|
|
|
AVFilterLink *outlink = ctx->outputs[0];
|
2012-11-28 08:41:07 +01:00
|
|
|
int nb_channels = av_get_channel_layout_nb_channels(buf->channel_layout);
|
2012-05-08 16:33:50 +02:00
|
|
|
int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts :
|
|
|
|
av_rescale_q(buf->pts, inlink->time_base, outlink->time_base);
|
2012-07-02 20:13:40 +02:00
|
|
|
int out_size, ret;
|
2012-05-08 16:33:50 +02:00
|
|
|
int64_t delta;
|
af_asyncts: fix compensation and PTS monotonicity
This patch improves af_asyncts behavior on streams with bogus PTS, which
are either non-monotonic, or contain PTS jitter, and trigger the
non-monotonicity error. With this patch, af_asyncts is able to correct
these streams and avoid the error.
Firstly, it fixes resample compensation calculation by supplying proper
units to avresample_set_compensation (sample count per second instead
of sample count per some arbitrary frame size). Also, the calculation of
the compensation itself is fixed - delta is proportional to an adjustment
of the compensation, not the compensation itself. Ideally, the compensation
should converge to a value that keeps delta at zero.
To be able to deal with sources with PTS jitter even without resampling,
small PTS errors are adjusted, so the output frames do not overlap.
Finally, one more monotonicity check is added.
The FATE reference changes because now there is 8 less samples of
silence because of the pts jitter.
Signed-off-by: Jindřich Makovička <makovick@gmail.com>
2013-03-09 10:08:09 +01:00
|
|
|
int64_t new_pts;
|
2012-05-08 16:33:50 +02:00
|
|
|
|
2012-12-13 19:20:51 +01:00
|
|
|
/* buffer data until we get the next timestamp */
|
|
|
|
if (s->pts == AV_NOPTS_VALUE || pts == AV_NOPTS_VALUE) {
|
2012-05-08 16:33:50 +02:00
|
|
|
if (pts != AV_NOPTS_VALUE) {
|
|
|
|
s->pts = pts - get_delay(s);
|
|
|
|
}
|
2012-07-02 20:13:40 +02:00
|
|
|
return write_to_fifo(s, buf);
|
2012-05-08 16:33:50 +02:00
|
|
|
}
|
|
|
|
|
2012-12-11 23:36:09 +01:00
|
|
|
if (s->first_pts != AV_NOPTS_VALUE) {
|
|
|
|
handle_trimming(ctx);
|
|
|
|
if (!avresample_available(s->avr))
|
|
|
|
return write_to_fifo(s, buf);
|
|
|
|
}
|
|
|
|
|
2012-05-08 16:33:50 +02:00
|
|
|
/* when we have two timestamps, compute how many samples would we have
|
|
|
|
* to add/remove to get proper sync between data and timestamps */
|
|
|
|
delta = pts - s->pts - get_delay(s);
|
|
|
|
out_size = avresample_available(s->avr);
|
|
|
|
|
2012-12-14 00:30:20 +01:00
|
|
|
if (labs(delta) > s->min_delta ||
|
|
|
|
(s->first_frame && delta && s->first_pts != AV_NOPTS_VALUE)) {
|
2012-05-08 16:33:50 +02:00
|
|
|
av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta);
|
2012-07-28 19:12:38 +02:00
|
|
|
out_size = av_clipl_int32((int64_t)out_size + delta);
|
2012-05-22 20:44:07 +02:00
|
|
|
} else {
|
|
|
|
if (s->resample) {
|
af_asyncts: fix compensation and PTS monotonicity
This patch improves af_asyncts behavior on streams with bogus PTS, which
are either non-monotonic, or contain PTS jitter, and trigger the
non-monotonicity error. With this patch, af_asyncts is able to correct
these streams and avoid the error.
Firstly, it fixes resample compensation calculation by supplying proper
units to avresample_set_compensation (sample count per second instead
of sample count per some arbitrary frame size). Also, the calculation of
the compensation itself is fixed - delta is proportional to an adjustment
of the compensation, not the compensation itself. Ideally, the compensation
should converge to a value that keeps delta at zero.
To be able to deal with sources with PTS jitter even without resampling,
small PTS errors are adjusted, so the output frames do not overlap.
Finally, one more monotonicity check is added.
The FATE reference changes because now there is 8 less samples of
silence because of the pts jitter.
Signed-off-by: Jindřich Makovička <makovick@gmail.com>
2013-03-09 10:08:09 +01:00
|
|
|
// adjust the compensation if delta is non-zero
|
|
|
|
int delay = get_delay(s);
|
|
|
|
int comp = s->comp + av_clip(delta * inlink->sample_rate / delay,
|
|
|
|
-s->max_comp, s->max_comp);
|
|
|
|
if (comp != s->comp) {
|
|
|
|
av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp);
|
|
|
|
if (avresample_set_compensation(s->avr, comp, inlink->sample_rate) == 0) {
|
|
|
|
s->comp = comp;
|
|
|
|
}
|
|
|
|
}
|
2012-05-22 20:44:07 +02:00
|
|
|
}
|
af_asyncts: fix compensation and PTS monotonicity
This patch improves af_asyncts behavior on streams with bogus PTS, which
are either non-monotonic, or contain PTS jitter, and trigger the
non-monotonicity error. With this patch, af_asyncts is able to correct
these streams and avoid the error.
Firstly, it fixes resample compensation calculation by supplying proper
units to avresample_set_compensation (sample count per second instead
of sample count per some arbitrary frame size). Also, the calculation of
the compensation itself is fixed - delta is proportional to an adjustment
of the compensation, not the compensation itself. Ideally, the compensation
should converge to a value that keeps delta at zero.
To be able to deal with sources with PTS jitter even without resampling,
small PTS errors are adjusted, so the output frames do not overlap.
Finally, one more monotonicity check is added.
The FATE reference changes because now there is 8 less samples of
silence because of the pts jitter.
Signed-off-by: Jindřich Makovička <makovick@gmail.com>
2013-03-09 10:08:09 +01:00
|
|
|
// adjust PTS to avoid monotonicity errors with input PTS jitter
|
|
|
|
pts -= delta;
|
2012-05-22 20:44:07 +02:00
|
|
|
delta = 0;
|
2012-05-08 16:33:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (out_size > 0) {
|
2012-11-28 08:41:07 +01:00
|
|
|
AVFrame *buf_out = ff_get_audio_buffer(outlink, out_size);
|
2012-07-02 20:13:40 +02:00
|
|
|
if (!buf_out) {
|
|
|
|
ret = AVERROR(ENOMEM);
|
|
|
|
goto fail;
|
|
|
|
}
|
2012-05-08 16:33:50 +02:00
|
|
|
|
2012-12-11 23:36:09 +01:00
|
|
|
if (s->first_frame && delta > 0) {
|
|
|
|
int ch;
|
|
|
|
|
|
|
|
av_samples_set_silence(buf_out->extended_data, 0, delta,
|
|
|
|
nb_channels, buf->format);
|
|
|
|
|
|
|
|
for (ch = 0; ch < nb_channels; ch++)
|
|
|
|
buf_out->extended_data[ch] += delta;
|
2012-05-08 16:33:50 +02:00
|
|
|
|
2012-12-11 23:36:09 +01:00
|
|
|
avresample_read(s->avr, buf_out->extended_data, out_size);
|
|
|
|
|
|
|
|
for (ch = 0; ch < nb_channels; ch++)
|
|
|
|
buf_out->extended_data[ch] -= delta;
|
|
|
|
} else {
|
|
|
|
avresample_read(s->avr, buf_out->extended_data, out_size);
|
|
|
|
|
|
|
|
if (delta > 0) {
|
|
|
|
av_samples_set_silence(buf_out->extended_data, out_size - delta,
|
|
|
|
delta, nb_channels, buf->format);
|
|
|
|
}
|
2012-05-08 16:33:50 +02:00
|
|
|
}
|
2012-12-11 23:36:09 +01:00
|
|
|
buf_out->pts = s->pts;
|
2012-11-27 07:49:45 +01:00
|
|
|
ret = ff_filter_frame(outlink, buf_out);
|
2012-07-02 20:13:40 +02:00
|
|
|
if (ret < 0)
|
|
|
|
goto fail;
|
2012-07-04 16:46:17 +02:00
|
|
|
s->got_output = 1;
|
2012-12-11 23:36:09 +01:00
|
|
|
} else if (avresample_available(s->avr)) {
|
2012-05-08 16:33:50 +02:00
|
|
|
av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
|
|
|
|
"whole buffer.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* drain any remaining buffered data */
|
|
|
|
avresample_read(s->avr, NULL, avresample_available(s->avr));
|
|
|
|
|
af_asyncts: fix compensation and PTS monotonicity
This patch improves af_asyncts behavior on streams with bogus PTS, which
are either non-monotonic, or contain PTS jitter, and trigger the
non-monotonicity error. With this patch, af_asyncts is able to correct
these streams and avoid the error.
Firstly, it fixes resample compensation calculation by supplying proper
units to avresample_set_compensation (sample count per second instead
of sample count per some arbitrary frame size). Also, the calculation of
the compensation itself is fixed - delta is proportional to an adjustment
of the compensation, not the compensation itself. Ideally, the compensation
should converge to a value that keeps delta at zero.
To be able to deal with sources with PTS jitter even without resampling,
small PTS errors are adjusted, so the output frames do not overlap.
Finally, one more monotonicity check is added.
The FATE reference changes because now there is 8 less samples of
silence because of the pts jitter.
Signed-off-by: Jindřich Makovička <makovick@gmail.com>
2013-03-09 10:08:09 +01:00
|
|
|
new_pts = pts - avresample_get_delay(s->avr);
|
|
|
|
/* check for s->pts monotonicity */
|
|
|
|
if (new_pts > s->pts) {
|
|
|
|
s->pts = new_pts;
|
|
|
|
ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
|
|
|
|
buf->linesize[0], buf->nb_samples);
|
|
|
|
} else {
|
|
|
|
av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
|
|
|
|
"whole buffer.\n");
|
|
|
|
ret = 0;
|
|
|
|
}
|
2012-07-02 20:13:40 +02:00
|
|
|
|
2012-12-11 23:36:09 +01:00
|
|
|
s->first_frame = 0;
|
2012-07-02 20:13:40 +02:00
|
|
|
fail:
|
2012-11-28 08:41:07 +01:00
|
|
|
av_frame_free(&buf);
|
2012-07-02 20:13:40 +02:00
|
|
|
|
|
|
|
return ret;
|
2012-05-08 16:33:50 +02:00
|
|
|
}
|
|
|
|
|
2012-07-24 15:14:01 +02:00
|
|
|
static const AVFilterPad avfilter_af_asyncts_inputs[] = {
|
|
|
|
{
|
|
|
|
.name = "default",
|
|
|
|
.type = AVMEDIA_TYPE_AUDIO,
|
2012-11-27 07:49:45 +01:00
|
|
|
.filter_frame = filter_frame,
|
2012-07-24 15:14:01 +02:00
|
|
|
},
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
|
|
|
static const AVFilterPad avfilter_af_asyncts_outputs[] = {
|
|
|
|
{
|
|
|
|
.name = "default",
|
|
|
|
.type = AVMEDIA_TYPE_AUDIO,
|
|
|
|
.config_props = config_props,
|
|
|
|
.request_frame = request_frame
|
|
|
|
},
|
|
|
|
{ NULL }
|
|
|
|
};
|
|
|
|
|
2012-05-08 16:33:50 +02:00
|
|
|
AVFilter avfilter_af_asyncts = {
|
|
|
|
.name = "asyncts",
|
|
|
|
.description = NULL_IF_CONFIG_SMALL("Sync audio data to timestamps"),
|
|
|
|
|
|
|
|
.init = init,
|
|
|
|
.uninit = uninit,
|
|
|
|
|
|
|
|
.priv_size = sizeof(ASyncContext),
|
2013-02-25 21:21:29 +01:00
|
|
|
.priv_class = &async_class,
|
2012-05-08 16:33:50 +02:00
|
|
|
|
2012-07-24 15:14:01 +02:00
|
|
|
.inputs = avfilter_af_asyncts_inputs,
|
|
|
|
.outputs = avfilter_af_asyncts_outputs,
|
2012-05-08 16:33:50 +02:00
|
|
|
};
|