[FFmpeg-devel] Incorrect usage of timefilter by alsa-audio-dec?
Andreas U. Trottmann
andreas.trottmann at werft22.com
Thu Dec 22 19:31:59 CET 2011
I recently upgraded a live encoder from ffmpeg-0.8.4 to
The immediate symptom I found was that "-async stopped working".
More specifically, when using audio input via alsa together with
"-async [any-number-larger-than-zero]", the encoding process
would "hang" after a couple seconds.
I did some debugging, and found that shortly after launch, the
pts values of the audio stream would jump around like crazy, even
getting negative. The synchronisation algorithm would then flip
between throwing away lage amounts of samples and inserting large
amounts of silence.
Apparently the jumpy pts values came from the usage of the
timefilter in libavdevice/alsa-audio-dec.c
The dts calculation done here (alsa-audio-dec.c, line 130ff) gave
dts = av_gettime();
dts -= av_rescale(delay + res, 1000000, s->sample_rate);
Up to here, everything looked ok. However, after the following
line, things started to be off:
pkt->pts = ff_timefilter_update(s->timefilter, dts, res);
So I looked at the timefilter implementation in
libavdevice/timefilter.c, specifically ff_timefilter_update. I
don't pretend to fully understand it, but I saw that up to line
72, everything was fine:
self->cycle_time += self->clock_period * period;
/// calculate loop error
loop_error = system_time - self->cycle_time;
While in the next line, things went wrong:
/// update loop
self->cycle_time += FFMAX(self->feedback2_factor, 1.0/(self->count)) * loop_error;
Apparently self->feedback2_factor was greater than 1, so
FFMAX(...) went greater than 1, so cycle_time was corrected by
more than the loop error, which then would cause the following
errors to always increase instead of decrease and the newly
determined cycle time to be more unstable with every iteration.
Now, the "obviously wrong" feedback2_factor is set using
ff_timefilter_new in line 90 of libavdevice/alsa-audio-dec.c,
in the function audio_read_header:
o = 2 * M_PI * s->period_size / s->sample_rate * 1.5; // bandwidth: 1.5Hz
s->timefilter = ff_timefilter_new(1000000.0 / s->sample_rate,
sqrt(2 * o), o * o);
In my case, s->period_size is 8192, s->sample_rate is 48000,
giving an o of approximately 1.6 and sqrt(2*o) of about 1.8,
which then becomes feedback2_factor in the timefilter.
This is what I have found out so far.
In order to get a working system, I blindly changed "sqrt(2 * o)"
to "1.0/sqrt(2 * o)" which gives a feedback2_factor < 1, and
causes the timefilter correction algorithm to converge rather
than diverge. This, in turn, appears to have made me an
ffmpeg which can encode using "-async" again. Very obviouly I
have no idea whether that "fix" will work for everyone, or just
for my situation.
I would be extremely happy if someone with more insight in the
algorithm and the parameters of timefilter could take a look at
this, and find out how the calculation of o and the
initialisation of the timefilter parameters in alsa-audio-dec.c
can be properly fixed.
Thank you very much!
More information about the ffmpeg-devel