Created
December 11, 2012 22:38
-
-
Save justinruggles/4262989 to your computer and use it in GitHub Desktop.
asyncts first_pts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From a0bfc6fd8e28d0d378c537f38ea48bbbd5aea96a Mon Sep 17 00:00:00 2001 | |
From: Justin Ruggles <[email protected]> | |
Date: Tue, 11 Dec 2012 17:36:09 -0500 | |
Subject: [PATCH] WIP: fix the asyncts first_pts option | |
--- | |
libavfilter/af_asyncts.c | 79 ++++++++++++++++++++++++++++++++++----------- | |
libavfilter/buffersrc.c | 7 ++++ | |
2 files changed, 66 insertions(+), 20 deletions(-) | |
diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c | |
index 5d009f0..3630a12 100644 | |
--- a/libavfilter/af_asyncts.c | |
+++ b/libavfilter/af_asyncts.c | |
@@ -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; ///< 0 if filter_frame() got at least 1 frame with a pts != AV_NOPTS_VALUE | |
+ int drop_samples; | |
/* options */ | |
int resample; | |
@@ -75,6 +77,8 @@ static int init(AVFilterContext *ctx, const char *args) | |
} | |
av_opt_free(s); | |
+ s->first_frame = 1; | |
+ | |
return 0; | |
} | |
@@ -116,6 +120,12 @@ static int config_props(AVFilterLink *link) | |
return 0; | |
} | |
+/* 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); | |
+} | |
+ | |
static int request_frame(AVFilterLink *link) | |
{ | |
AVFilterContext *ctx = link->src; | |
@@ -128,7 +138,7 @@ static int request_frame(AVFilterLink *link) | |
ret = ff_request_frame(ctx->inputs[0]); | |
/* flush the fifo */ | |
- if (ret == AVERROR_EOF && (nb_samples = avresample_get_delay(s->avr))) { | |
+ if (ret == AVERROR_EOF && (nb_samples = get_delay(s))) { | |
AVFilterBufferRef *buf = ff_get_audio_buffer(link, AV_PERM_WRITE, | |
nb_samples); | |
if (!buf) | |
@@ -140,6 +150,7 @@ static int request_frame(AVFilterLink *link) | |
return (ret < 0) ? ret : AVERROR_EOF; | |
} | |
+ av_log(0,0,"filter_frame: %d samples\n", nb_samples); | |
buf->pts = s->pts; | |
return ff_filter_frame(link, buf); | |
} | |
@@ -155,12 +166,6 @@ static int write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf) | |
return ret; | |
} | |
-/* 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); | |
-} | |
- | |
static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |
{ | |
AVFilterContext *ctx = inlink->dst; | |
@@ -173,12 +178,8 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |
int64_t delta; | |
/* buffer data until we get the first timestamp */ | |
- if (s->pts == AV_NOPTS_VALUE) { | |
- if (pts != AV_NOPTS_VALUE) { | |
- s->pts = pts - get_delay(s); | |
- } | |
- return write_to_fifo(s, buf); | |
- } | |
+ if (s->pts == AV_NOPTS_VALUE && pts != AV_NOPTS_VALUE) | |
+ s->pts = pts - get_delay(s); | |
/* now wait for the next timestamp */ | |
if (pts == AV_NOPTS_VALUE) { | |
@@ -187,10 +188,20 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *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); | |
+ delta = pts - s->pts - get_delay(s); | |
+ if (s->first_frame && delta < 0) { | |
+ int buffered_samples = avresample_available(s->avr); | |
+ s->drop_samples = -delta; | |
+ if (buffered_samples) { | |
+ int drain = FFMIN(s->drop_samples, buffered_samples); | |
+ avresample_read(s->avr, NULL, drain); | |
+ s->drop_samples -= drain; | |
+ delta += drain; | |
+ } | |
+ } | |
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 { | |
@@ -202,6 +213,10 @@ static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) | |
delta = 0; | |
} | |
+ if (s->first_frame) | |
+ av_log(0,0,"first_pts=%ld pts=%ld delta=%ld avail=%d out_size=%d\n", | |
+ s->pts, pts, delta, avresample_available(s->avr), out_size); | |
+ | |
if (out_size > 0) { | |
AVFilterBufferRef *buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, | |
out_size); | |
@@ -210,13 +225,30 @@ 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; | |
+ uint8_t **data0 = av_mallocz(nb_channels * sizeof(*data0)); | |
+ if (!data0) | |
+ return AVERROR(ENOMEM); | |
- if (delta > 0) { | |
- av_samples_set_silence(buf_out->extended_data, out_size - delta, | |
- delta, nb_channels, buf->format); | |
+ av_samples_set_silence(buf_out->extended_data, 0, delta, | |
+ nb_channels, buf->format); | |
+ | |
+ for (ch = 0; ch < nb_channels; ch++) | |
+ data0[ch] = buf_out->extended_data[ch] + delta; | |
+ avresample_read(s->avr, data0, out_size); | |
+ | |
+ free(data0); | |
+ } 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); | |
+ } | |
} | |
+ av_log(0,0,"filter_frame: %d samples\n", out_size); | |
+ buf_out->pts = s->pts; | |
ret = ff_filter_frame(outlink, buf_out); | |
if (ret < 0) | |
goto fail; | |
@@ -233,6 +265,13 @@ 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); | |
+ if (s->drop_samples > 0) { | |
+ int drain = FFMIN(s->drop_samples, avresample_available(s->avr)); | |
+ avresample_read(s->avr, NULL, drain); | |
+ s->drop_samples -= drain; | |
+ } | |
+ | |
+ s->first_frame = 0; | |
fail: | |
avfilter_unref_buffer(buf); | |
diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c | |
index 3cee68d..dc5e08e 100644 | |
--- a/libavfilter/buffersrc.c | |
+++ b/libavfilter/buffersrc.c | |
@@ -54,6 +54,7 @@ typedef struct { | |
char *channel_layout_str; | |
int eof; | |
+ int first; | |
} BufferSourceContext; | |
#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\ | |
@@ -246,6 +247,7 @@ static av_cold int init_audio(AVFilterContext *ctx, const char *args) | |
"ch layout:%s\n", s->time_base.num, s->time_base.den, s->sample_fmt_str, | |
s->sample_rate, s->channel_layout_str); | |
+ s->first = 2; | |
fail: | |
av_opt_free(s); | |
return ret; | |
@@ -327,6 +329,11 @@ static int request_frame(AVFilterLink *link) | |
} | |
av_fifo_generic_read(c->fifo, &buf, sizeof(buf), NULL); | |
+ if (c->first) { | |
+ buf->pts = AV_NOPTS_VALUE; | |
+ c->first--; | |
+ } | |
+ | |
ff_filter_frame(link, buf); | |
return ret; | |
-- | |
1.7.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment