Skip audio to sync with video.

This commit is contained in:
Johns 2012-04-28 12:24:03 +02:00
parent 5456164dce
commit 8d5ff6f6fb

86
audio.c
View File

@ -145,6 +145,7 @@ static char AudioDoingInit; ///> flag in init, reduce error
static volatile char AudioRunning; ///< thread running / stopped static volatile char AudioRunning; ///< thread running / stopped
static volatile char AudioPaused; ///< audio paused static volatile char AudioPaused; ///< audio paused
static volatile char AudioVideoIsReady; ///< video ready start early static volatile char AudioVideoIsReady; ///< video ready start early
static int AudioSkip; ///< skip audio to sync to video
#ifndef USE_AUDIORING #ifndef USE_AUDIORING
static unsigned AudioSampleRate; ///< audio sample rate in Hz static unsigned AudioSampleRate; ///< audio sample rate in Hz
@ -1120,6 +1121,7 @@ static void AlsaFlushBuffers(void)
} }
AudioRunning = 0; AudioRunning = 0;
AudioVideoIsReady = 0; AudioVideoIsReady = 0;
AudioSkip = 0;
AudioPTS = INT64_C(0x8000000000000000); AudioPTS = INT64_C(0x8000000000000000);
} }
@ -2453,6 +2455,7 @@ static void OssFlushBuffers(void)
} }
AudioRunning = 0; AudioRunning = 0;
AudioVideoIsReady = 0; AudioVideoIsReady = 0;
AudioSkip = 0;
AudioPTS = INT64_C(0x8000000000000000); AudioPTS = INT64_C(0x8000000000000000);
} }
@ -3626,16 +3629,25 @@ void AudioEnqueue(const void *samples, int count)
} }
if (!AudioRunning) { // check, if we can start the thread if (!AudioRunning) { // check, if we can start the thread
//int64_t video_pts; int skip;
//video_pts = VideoGetClock();
n = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer); n = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer);
skip = AudioSkip;
if (skip) {
if (n < (unsigned)skip) {
skip = n;
}
AudioSkip -= skip;
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer, skip);
n = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer);
}
Debug(3, "audio: start? %4zdms\n", (n * 1000) Debug(3, "audio: start? %4zdms\n", (n * 1000)
/ (AudioRing[AudioRingWrite].HwSampleRate * / (AudioRing[AudioRingWrite].HwSampleRate *
AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample)); AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample));
// forced start or enough video + audio buffered // forced start or enough video + audio buffered
if (AudioStartThreshold * 2 < n || (AudioVideoIsReady if (AudioStartThreshold * 4 < n || (AudioVideoIsReady
&& AudioStartThreshold < n)) { && AudioStartThreshold < n)) {
// restart play-back // restart play-back
// no lock needed, can wakeup next time // no lock needed, can wakeup next time
@ -3687,6 +3699,65 @@ void AudioEnqueue(const void *samples, int count)
void AudioVideoReady(int64_t pts) void AudioVideoReady(int64_t pts)
{ {
#ifdef USE_AUDIORING #ifdef USE_AUDIORING
int64_t audio_pts;
size_t used;
if (pts == (int64_t) INT64_C(0x8000000000000000)) {
return;
}
// no valid audio known
if (!AudioRing[AudioRingWrite].HwSampleRate
|| !AudioRing[AudioRingWrite].HwChannels
|| AudioRing[AudioRingWrite].PTS ==
(int64_t) INT64_C(0x8000000000000000)) {
Debug(3, "audio: a/v start, no valid audio\n");
AudioVideoIsReady = 1;
return;
}
// Audio.PTS = next written sample time stamp
used = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer);
audio_pts =
AudioRing[AudioRingWrite].PTS -
(used * 90 * 1000) / (AudioRing[AudioRingWrite].HwSampleRate *
AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample);
Debug(3, "audio: a/v buf:%4zdms %s|%s = %dms video ready\n",
(used * 1000) / (AudioRing[AudioRingWrite].HwSampleRate *
AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample),
Timestamp2String(pts), Timestamp2String(audio_pts),
(int)(pts - audio_pts) / 90);
if (!AudioRunning) {
int skip;
// keep ~5 frames
skip = pts - 5 * 20 - audio_pts;
if (skip > 0) {
skip = (((int64_t) skip * AudioRing[AudioRingWrite].HwSampleRate)
/ (1000 * 90))
* AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample;
if ((unsigned)skip > used) {
AudioSkip = skip - used;
skip = used;
}
Debug(3, "audio: advance %dms %d/%zd\n",
(skip * 1000) / (AudioRing[AudioRingWrite].HwSampleRate *
AudioRing[AudioRingWrite].HwChannels *
AudioBytesProSample), skip, used);
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer, skip);
used = RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer);
// enough video + audio buffered
if (AudioStartThreshold < used) {
AudioRunning = 1;
pthread_cond_signal(&AudioStartCond);
}
}
}
AudioVideoIsReady = 1;
#if 0
if (AudioRing[AudioRingWrite].HwSampleRate if (AudioRing[AudioRingWrite].HwSampleRate
&& AudioRing[AudioRingWrite].HwChannels) { && AudioRing[AudioRingWrite].HwChannels) {
if (pts != (int64_t) INT64_C(0x8000000000000000) if (pts != (int64_t) INT64_C(0x8000000000000000)
@ -3702,6 +3773,7 @@ void AudioVideoReady(int64_t pts)
AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample), AudioRing[AudioRingWrite].HwChannels * AudioBytesProSample),
Timestamp2String(pts), Timestamp2String(pts),
Timestamp2String(AudioRing[AudioRingWrite].PTS)); Timestamp2String(AudioRing[AudioRingWrite].PTS));
if (!AudioRunning) { if (!AudioRunning) {
size_t used; size_t used;
@ -3709,14 +3781,14 @@ void AudioVideoReady(int64_t pts)
// enough video + audio buffered // enough video + audio buffered
if (AudioStartThreshold < used) { if (AudioStartThreshold < used) {
// too much audio buffered, skip it // too much audio buffered, skip it
if (AudioStartThreshold * 2 < used) { if (AudioStartThreshold < used) {
Debug(3, "audio: start %4zdms skip video ready\n", Debug(3, "audio: start %4zdms skip video ready\n",
((used - AudioStartThreshold * 2) * 1000) ((used - AudioStartThreshold) * 1000)
/ (AudioRing[AudioRingWrite].HwSampleRate * / (AudioRing[AudioRingWrite].HwSampleRate *
AudioRing[AudioRingWrite].HwChannels * AudioRing[AudioRingWrite].HwChannels *
AudioBytesProSample)); AudioBytesProSample));
RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer, RingBufferReadAdvance(AudioRing[AudioRingWrite].RingBuffer,
used - AudioStartThreshold * 2); used - AudioStartThreshold);
} }
AudioRunning = 1; AudioRunning = 1;
pthread_cond_signal(&AudioStartCond); pthread_cond_signal(&AudioStartCond);
@ -3724,6 +3796,7 @@ void AudioVideoReady(int64_t pts)
} }
} }
AudioVideoIsReady = 1; AudioVideoIsReady = 1;
#endif
#else #else
(void)pts; (void)pts;
AudioVideoIsReady = 1; AudioVideoIsReady = 1;
@ -3752,6 +3825,7 @@ void AudioFlushBuffers(void)
RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer)); RingBufferUsedBytes(AudioRing[AudioRingWrite].RingBuffer));
Debug(3, "audio: reset video ready\n"); Debug(3, "audio: reset video ready\n");
AudioVideoIsReady = 0; AudioVideoIsReady = 0;
AudioSkip = 0;
atomic_inc(&AudioRingFilled); atomic_inc(&AudioRingFilled);