Skip to content

Commit

Permalink
Merge commit 'b35e5d985dd12acf9a0aaa52334134edcf35d68e'
Browse files Browse the repository at this point in the history
* commit 'b35e5d985dd12acf9a0aaa52334134edcf35d68e':
  doc: improve documentation for the asyncts filter first_pts option
  asyncts: fix the asyncts behavior when using the first_pts option

Conflicts:
	libavfilter/af_asyncts.c

Merged-by: Michael Niedermayer <[email protected]>
  • Loading branch information
michaelni committed Dec 14, 2012
2 parents 593f5c0 + b35e5d9 commit b6e7041
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 11 deletions.
5 changes: 3 additions & 2 deletions doc/filters.texi
Original file line number Diff line number Diff line change
Expand Up @@ -782,11 +782,12 @@ Maximum compensation in samples per second. Relevant only with compensate=1.
Default value 500.

@item first_pts
Assume the first pts should be this value.
Assume the first pts should be this value. The time base is 1 / sample rate.
This allows for padding/trimming at the start of stream. By default, no
assumption is made about the first frame's expected pts, so no padding or
trimming is done. For example, this could be set to 0 to pad the beginning with
silence if an audio stream starts after the video stream.
silence if an audio stream starts after the video stream or to trim any samples
with a negative pts due to encoder delay.

@end table

Expand Down
64 changes: 55 additions & 9 deletions libavfilter/af_asyncts.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ typedef struct ASyncContext {
AVAudioResampleContext *avr;
int64_t pts; ///< timestamp in samples of the first sample in fifo
int min_delta; ///< pad/trim min threshold in samples
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

/* options */
int resample;
Expand All @@ -51,7 +53,7 @@ static const AVOption asyncts_options[] = {
{ "min_delta", "Minimum difference between timestamps and audio data "
"(in seconds) to trigger padding/trimmin the data.", OFFSET(min_delta_sec), AV_OPT_TYPE_FLOAT, { .dbl = 0.1 }, 0, INT_MAX, A|F },
{ "max_comp", "Maximum compensation in samples per second.", OFFSET(max_comp), AV_OPT_TYPE_INT, { .i64 = 500 }, 0, INT_MAX, A|F },
{ "first_pts", "Assume the first pts should be this value.", OFFSET(pts), AV_OPT_TYPE_INT64, { .i64 = AV_NOPTS_VALUE }, INT64_MIN, INT64_MAX, A|F },
{ "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 },
{ NULL },
};

Expand All @@ -69,6 +71,9 @@ static int init(AVFilterContext *ctx, const char *args)
return ret;
av_opt_free(s);

s->pts = AV_NOPTS_VALUE;
s->first_frame = 1;

return 0;
}

Expand Down Expand Up @@ -116,6 +121,20 @@ static int64_t get_delay(ASyncContext *s)
return avresample_available(s->avr) + avresample_get_delay(s->avr);
}

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;
}

static int request_frame(AVFilterLink *link)
{
AVFilterContext *ctx = link->src;
Expand All @@ -128,7 +147,11 @@ static int request_frame(AVFilterLink *link)
ret = ff_request_frame(ctx->inputs[0]);

/* flush the fifo */
if (ret == AVERROR_EOF && (nb_samples = get_delay(s))) {
if (ret == AVERROR_EOF) {
if (s->first_pts != AV_NOPTS_VALUE)
handle_trimming(ctx);

if (nb_samples = get_delay(s)) {
AVFilterBufferRef *buf = ff_get_audio_buffer(link, AV_PERM_WRITE,
nb_samples);
if (!buf)
Expand All @@ -142,6 +165,7 @@ static int request_frame(AVFilterLink *link)

buf->pts = s->pts;
return ff_filter_frame(link, buf);
}
}

return ret;
Expand Down Expand Up @@ -179,12 +203,18 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
return write_to_fifo(s, buf);
}

if (s->first_pts != AV_NOPTS_VALUE) {
handle_trimming(ctx);
if (!avresample_available(s->avr))
return write_to_fifo(s, buf);
}

/* 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);

if (labs(delta) > s->min_delta) {
if (labs(delta) > s->min_delta || (s->first_frame && delta)) {
av_log(ctx, AV_LOG_VERBOSE, "Discontinuity - %"PRId64" samples.\n", delta);
out_size = av_clipl_int32((int64_t)out_size + delta);
} else {
Expand All @@ -204,18 +234,33 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
goto fail;
}

avresample_read(s->avr, buf_out->extended_data, out_size);
buf_out->pts = s->pts;
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;

if (delta > 0) {
av_samples_set_silence(buf_out->extended_data, out_size - delta,
delta, nb_channels, buf->format);
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);
}
}
buf_out->pts = s->pts;
ret = ff_filter_frame(outlink, buf_out);
if (ret < 0)
goto fail;
s->got_output = 1;
} else {
} else if (avresample_available(s->avr)) {
av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping "
"whole buffer.\n");
}
Expand All @@ -227,6 +272,7 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
ret = avresample_convert(s->avr, NULL, 0, 0, buf->extended_data,
buf->linesize[0], buf->audio->nb_samples);

s->first_frame = 0;
fail:
avfilter_unref_buffer(buf);

Expand Down

0 comments on commit b6e7041

Please sign in to comment.