00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "libavresample/avresample.h"
00020 #include "libavutil/audio_fifo.h"
00021 #include "libavutil/common.h"
00022 #include "libavutil/mathematics.h"
00023 #include "libavutil/opt.h"
00024 #include "libavutil/samplefmt.h"
00025
00026 #include "audio.h"
00027 #include "avfilter.h"
00028 #include "internal.h"
00029
00030 typedef struct ASyncContext {
00031 const AVClass *class;
00032
00033 AVAudioResampleContext *avr;
00034 int64_t pts;
00035 int min_delta;
00036 int first_frame;
00037 int64_t first_pts;
00038
00039
00040 int resample;
00041 float min_delta_sec;
00042 int max_comp;
00043
00044
00045 int got_output;
00046 } ASyncContext;
00047
00048 #define OFFSET(x) offsetof(ASyncContext, x)
00049 #define A AV_OPT_FLAG_AUDIO_PARAM
00050 #define F AV_OPT_FLAG_FILTERING_PARAM
00051 static const AVOption asyncts_options[] = {
00052 { "compensate", "Stretch/squeeze the data to make it match the timestamps", OFFSET(resample), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, A|F },
00053 { "min_delta", "Minimum difference between timestamps and audio data "
00054 "(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A|F },
00055 { "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, A|F },
00056 { "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 },
00057 { NULL },
00058 };
00059
00060 AVFILTER_DEFINE_CLASS(asyncts);
00061
00062 static int init(AVFilterContext *ctx, const char *args)
00063 {
00064 ASyncContext *s = ctx->priv;
00065 int ret;
00066
00067 s->class = &asyncts_class;
00068 av_opt_set_defaults(s);
00069
00070 if ((ret = av_set_options_string(s, args, "=", ":")) < 0)
00071 return ret;
00072 av_opt_free(s);
00073
00074 s->pts = AV_NOPTS_VALUE;
00075 s->first_frame = 1;
00076
00077 return 0;
00078 }
00079
00080 static void uninit(AVFilterContext *ctx)
00081 {
00082 ASyncContext *s = ctx->priv;
00083
00084 if (s->avr) {
00085 avresample_close(s->avr);
00086 avresample_free(&s->avr);
00087 }
00088 }
00089
00090 static int config_props(AVFilterLink *link)
00091 {
00092 ASyncContext *s = link->src->priv;
00093 int ret;
00094
00095 s->min_delta = s->min_delta_sec * link->sample_rate;
00096 link->time_base = (AVRational){1, link->sample_rate};
00097
00098 s->avr = avresample_alloc_context();
00099 if (!s->avr)
00100 return AVERROR(ENOMEM);
00101
00102 av_opt_set_int(s->avr, "in_channel_layout", link->channel_layout, 0);
00103 av_opt_set_int(s->avr, "out_channel_layout", link->channel_layout, 0);
00104 av_opt_set_int(s->avr, "in_sample_fmt", link->format, 0);
00105 av_opt_set_int(s->avr, "out_sample_fmt", link->format, 0);
00106 av_opt_set_int(s->avr, "in_sample_rate", link->sample_rate, 0);
00107 av_opt_set_int(s->avr, "out_sample_rate", link->sample_rate, 0);
00108
00109 if (s->resample)
00110 av_opt_set_int(s->avr, "force_resampling", 1, 0);
00111
00112 if ((ret = avresample_open(s->avr)) < 0)
00113 return ret;
00114
00115 return 0;
00116 }
00117
00118
00119 static int64_t get_delay(ASyncContext *s)
00120 {
00121 return avresample_available(s->avr) + avresample_get_delay(s->avr);
00122 }
00123
00124 static void handle_trimming(AVFilterContext *ctx)
00125 {
00126 ASyncContext *s = ctx->priv;
00127
00128 if (s->pts < s->first_pts) {
00129 int delta = FFMIN(s->first_pts - s->pts, avresample_available(s->avr));
00130 av_log(ctx, AV_LOG_VERBOSE, "Trimming %d samples from start\n",
00131 delta);
00132 avresample_read(s->avr, NULL, delta);
00133 s->pts += delta;
00134 } else if (s->first_frame)
00135 s->pts = s->first_pts;
00136 }
00137
00138 static int request_frame(AVFilterLink *link)
00139 {
00140 AVFilterContext *ctx = link->src;
00141 ASyncContext *s = ctx->priv;
00142 int ret = 0;
00143 int nb_samples;
00144
00145 s->got_output = 0;
00146 while (ret >= 0 && !s->got_output)
00147 ret = ff_request_frame(ctx->inputs[0]);
00148
00149
00150 if (ret == AVERROR_EOF) {
00151 if (s->first_pts != AV_NOPTS_VALUE)
00152 handle_trimming(ctx);
00153
00154 if (nb_samples = get_delay(s)) {
00155 AVFilterBufferRef *buf = ff_get_audio_buffer(link, AV_PERM_WRITE,
00156 nb_samples);
00157 if (!buf)
00158 return AVERROR(ENOMEM);
00159 ret = avresample_convert(s->avr, buf->extended_data,
00160 buf->linesize[0], nb_samples, NULL, 0, 0);
00161 if (ret <= 0) {
00162 avfilter_unref_bufferp(&buf);
00163 return (ret < 0) ? ret : AVERROR_EOF;
00164 }
00165
00166 buf->pts = s->pts;
00167 return ff_filter_frame(link, buf);
00168 }
00169 }
00170
00171 return ret;
00172 }
00173
00174 static int write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf)
00175 {
00176 int ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
00177 buf->linesize[0], buf->audio->nb_samples);
00178 avfilter_unref_buffer(buf);
00179 return ret;
00180 }
00181
00182 static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
00183 {
00184 AVFilterContext *ctx = inlink->dst;
00185 ASyncContext *s = ctx->priv;
00186 AVFilterLink *outlink = ctx->outputs[0];
00187 int nb_channels = av_get_channel_layout_nb_channels(buf->audio->channel_layout);
00188 int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts :
00189 av_rescale_q(buf->pts, inlink->time_base, outlink->time_base);
00190 int out_size, ret;
00191 int64_t delta;
00192
00193
00194 if (s->pts == AV_NOPTS_VALUE || pts == AV_NOPTS_VALUE) {
00195 if (pts != AV_NOPTS_VALUE) {
00196 s->pts = pts - get_delay(s);
00197 }
00198 return write_to_fifo(s, buf);
00199 }
00200
00201 if (s->first_pts != AV_NOPTS_VALUE) {
00202 handle_trimming(ctx);
00203 if (!avresample_available(s->avr))
00204 return write_to_fifo(s, buf);
00205 }
00206
00207
00208
00209 delta = pts - s->pts - get_delay(s);
00210 out_size = avresample_available(s->avr);
00211
00212 if (labs(delta) > s->min_delta ||
00213 (s->first_frame && delta && s->first_pts != AV_NOPTS_VALUE)) {
00214 av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta);
00215 out_size = av_clipl_int32((int64_t)out_size + delta);
00216 } else {
00217 if (s->resample) {
00218 int comp = av_clip(delta, -s->max_comp, s->max_comp);
00219 av_log(ctx, AV_LOG_VERBOSE, "Compensating %d samples per second.\n", comp);
00220 avresample_set_compensation(s->avr, comp, inlink->sample_rate);
00221 }
00222 delta = 0;
00223 }
00224
00225 if (out_size > 0) {
00226 AVFilterBufferRef *buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE,
00227 out_size);
00228 if (!buf_out) {
00229 ret = AVERROR(ENOMEM);
00230 goto fail;
00231 }
00232
00233 if (s->first_frame && delta > 0) {
00234 int ch;
00235
00236 av_samples_set_silence(buf_out->extended_data, 0, delta,
00237 nb_channels, buf->format);
00238
00239 for (ch = 0; ch < nb_channels; ch++)
00240 buf_out->extended_data[ch] += delta;
00241
00242 avresample_read(s->avr, buf_out->extended_data, out_size);
00243
00244 for (ch = 0; ch < nb_channels; ch++)
00245 buf_out->extended_data[ch] -= delta;
00246 } else {
00247 avresample_read(s->avr, buf_out->extended_data, out_size);
00248
00249 if (delta > 0) {
00250 av_samples_set_silence(buf_out->extended_data, out_size - delta,
00251 delta, nb_channels, buf->format);
00252 }
00253 }
00254 buf_out->pts = s->pts;
00255 ret = ff_filter_frame(outlink, buf_out);
00256 if (ret < 0)
00257 goto fail;
00258 s->got_output = 1;
00259 } else if (avresample_available(s->avr)) {
00260 av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
00261 "whole buffer.\n");
00262 }
00263
00264
00265 avresample_read(s->avr, NULL, avresample_available(s->avr));
00266
00267 s->pts = pts - avresample_get_delay(s->avr);
00268 ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
00269 buf->linesize[0], buf->audio->nb_samples);
00270
00271 s->first_frame = 0;
00272 fail:
00273 avfilter_unref_buffer(buf);
00274
00275 return ret;
00276 }
00277
00278 static const AVFilterPad avfilter_af_asyncts_inputs[] = {
00279 {
00280 .name = "default",
00281 .type = AVMEDIA_TYPE_AUDIO,
00282 .filter_frame = filter_frame
00283 },
00284 { NULL }
00285 };
00286
00287 static const AVFilterPad avfilter_af_asyncts_outputs[] = {
00288 {
00289 .name = "default",
00290 .type = AVMEDIA_TYPE_AUDIO,
00291 .config_props = config_props,
00292 .request_frame = request_frame
00293 },
00294 { NULL }
00295 };
00296
00297 AVFilter avfilter_af_asyncts = {
00298 .name = "asyncts",
00299 .description = NULL_IF_CONFIG_SMALL("Sync audio data to timestamps"),
00300
00301 .init = init,
00302 .uninit = uninit,
00303
00304 .priv_size = sizeof(ASyncContext),
00305
00306 .inputs = avfilter_af_asyncts_inputs,
00307 .outputs = avfilter_af_asyncts_outputs,
00308 .priv_class = &asyncts_class,
00309 };