Experimental ac3 audio drift correction support.

This commit is contained in:
Johns 2012-03-03 16:45:59 +01:00
parent dda9011abc
commit 7e1a42f7ed
2 changed files with 65 additions and 28 deletions

View File

@ -1,6 +1,7 @@
User johns User johns
Date: Date:
Experimental ac3 audio drift correction support.
Removes LPCM detection from TS parser. Removes LPCM detection from TS parser.
Rewrote video/audio start code. Rewrote video/audio start code.
Add support for attach/detach plugin. Add support for attach/detach plugin.

92
codec.c
View File

@ -352,7 +352,7 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
{ {
AVCodec *video_codec; AVCodec *video_codec;
Debug(3, "codec: using codec %s or ID %#04x\n", name, codec_id); Debug(3, "codec: using video codec %s or ID %#06x\n", name, codec_id);
if (decoder->VideoCtx) { if (decoder->VideoCtx) {
Error(_("codec: missing close\n")); Error(_("codec: missing close\n"));
@ -377,7 +377,7 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id)
if (name && (video_codec = avcodec_find_decoder_by_name(name))) { if (name && (video_codec = avcodec_find_decoder_by_name(name))) {
Debug(3, "codec: vdpau decoder found\n"); Debug(3, "codec: vdpau decoder found\n");
} else if (!(video_codec = avcodec_find_decoder(codec_id))) { } else if (!(video_codec = avcodec_find_decoder(codec_id))) {
Fatal(_("codec: codec ID %#04x not found\n"), codec_id); Fatal(_("codec: codec ID %#06x not found\n"), codec_id);
// FIXME: none fatal // FIXME: none fatal
} }
decoder->VideoCodec = video_codec; decoder->VideoCodec = video_codec;
@ -615,6 +615,7 @@ struct _audio_decoder_
int Drift; ///< accumulated audio drift int Drift; ///< accumulated audio drift
int DriftCorr; ///< audio drift correction value int DriftCorr; ///< audio drift correction value
int DriftFrac; ///< audio drift fraction for ac3
struct AVResampleContext *AvResample; ///< second audio resample context struct AVResampleContext *AvResample; ///< second audio resample context
#define MAX_CHANNELS 8 ///< max number of channels supported #define MAX_CHANNELS 8 ///< max number of channels supported
@ -675,10 +676,12 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name,
{ {
AVCodec *audio_codec; AVCodec *audio_codec;
Debug(3, "codec: using audio codec %s or ID %#06x\n", name, codec_id);
if (name && (audio_codec = avcodec_find_decoder_by_name(name))) { if (name && (audio_codec = avcodec_find_decoder_by_name(name))) {
Debug(3, "codec: audio decoder '%s' found\n", name); Debug(3, "codec: audio decoder '%s' found\n", name);
} else if (!(audio_codec = avcodec_find_decoder(codec_id))) { } else if (!(audio_codec = avcodec_find_decoder(codec_id))) {
Fatal(_("codec: codec ID %#04x not found\n"), codec_id); Fatal(_("codec: codec ID %#06x not found\n"), codec_id);
// FIXME: errors aren't fatal // FIXME: errors aren't fatal
} }
audio_decoder->AudioCodec = audio_codec; audio_decoder->AudioCodec = audio_codec;
@ -846,6 +849,7 @@ static void CodecReorderAudioFrame(int16_t * buf, int size, int channels)
** Set/update audio pts clock. ** Set/update audio pts clock.
** **
** @param audio_decoder audio decoder data ** @param audio_decoder audio decoder data
** @param pts presentation timestamp
*/ */
static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts) static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
{ {
@ -868,6 +872,7 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
audio_decoder->LastPTS = pts; audio_decoder->LastPTS = pts;
audio_decoder->LastDelay = delay; audio_decoder->LastDelay = delay;
audio_decoder->Drift = 0; audio_decoder->Drift = 0;
audio_decoder->DriftFrac = 0;
Debug(3, "codec/audio: inital delay %zd ms\n", delay / 90); Debug(3, "codec/audio: inital delay %zd ms\n", delay / 90);
return; return;
} }
@ -885,46 +890,52 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
(tim_diff * 90) / (1000 * 1000) - pts_diff + delay - (tim_diff * 90) / (1000 * 1000) - pts_diff + delay -
audio_decoder->LastDelay; audio_decoder->LastDelay;
// adjust rounding error
nowtime.tv_nsec -= nowtime.tv_nsec % (1000 * 1000 / 90);
audio_decoder->LastTime = nowtime; audio_decoder->LastTime = nowtime;
audio_decoder->LastPTS = pts; audio_decoder->LastPTS = pts;
audio_decoder->LastDelay = delay; audio_decoder->LastDelay = delay;
if (1) { if (0) {
Debug(3, "codec/audio: interval P:%5zdms T:%5zdms D:%4zdms %f %d\n", Debug(3, "codec/audio: interval P:%5zdms T:%5zdms D:%4zdms %f %d\n",
pts_diff / 90, tim_diff / (1000 * 1000), delay / 90, drift / 90.0, pts_diff / 90, tim_diff / (1000 * 1000), delay / 90, drift / 90.0,
audio_decoder->DriftCorr); audio_decoder->DriftCorr);
} }
// underruns and av_resample have the same time :(((
if (abs(drift) > 5 * 90) { if (abs(drift) > 10 * 90) {
// drift too big, pts changed? // drift too big, pts changed?
Debug(3, "codec/audio: drift(%5d) %3dms reset\n", Debug(3, "codec/audio: drift(%6d) %3dms reset\n",
audio_decoder->DriftCorr, drift); audio_decoder->DriftCorr, drift / 90);
audio_decoder->LastDelay = 0; audio_decoder->LastDelay = 0;
return; } else {
}
drift += audio_decoder->Drift; drift += audio_decoder->Drift;
audio_decoder->Drift = drift; audio_decoder->Drift = drift;
corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000); corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000);
#ifdef USE_PASSTHROUGH #if defined(USE_PASSTHROUGH) && !defined(USE_AC3_DRIFT_CORRECTION)
// SPDIF/HDMI passthrough // SPDIF/HDMI passthrough
if (!CodecPassthroughAC3 if (!CodecPassthroughAC3
|| audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3) || audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3)
#endif #endif
{ {
audio_decoder->DriftCorr -= corr; audio_decoder->DriftCorr = -corr;
} }
if (audio_decoder->DriftCorr < -20000) { // limit correction if (audio_decoder->DriftCorr < -20000) { // limit correction
audio_decoder->DriftCorr = -20000; audio_decoder->DriftCorr = -20000;
} else if (audio_decoder->DriftCorr > 20000) { } else if (audio_decoder->DriftCorr > 20000) {
audio_decoder->DriftCorr = 20000; audio_decoder->DriftCorr = 20000;
}
} }
// FIXME: this works with libav 0.8, and only with >10ms with ffmpeg 0.10
if (audio_decoder->AvResample && audio_decoder->DriftCorr) { if (audio_decoder->AvResample && audio_decoder->DriftCorr) {
int distance;
distance = (pts_diff * audio_decoder->HwSampleRate) / (90 * 1000);
av_resample_compensate(audio_decoder->AvResample, av_resample_compensate(audio_decoder->AvResample,
audio_decoder->DriftCorr / 10, 10 * audio_decoder->HwSampleRate); audio_decoder->DriftCorr / 10, distance);
} }
printf("codec/audio: drift(%5d) %8dus %4d\n", audio_decoder->DriftCorr, Debug(3, "codec/audio: drift(%6d) %8dus %5d\n", audio_decoder->DriftCorr,
drift * 1000 / 90, corr); drift * 1000 / 90, corr);
} }
@ -996,7 +1007,11 @@ static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
} }
} }
// prepare audio drift resample // prepare audio drift resample
#ifdef USE_AUDIO_DRIFT_CORRECTION
if (!isAC3) { if (!isAC3) {
if (audio_decoder->AvResample) {
Error(_("codec/audio: overwrite resample\n"));
}
audio_decoder->AvResample = audio_decoder->AvResample =
av_resample_init(audio_decoder->HwSampleRate, av_resample_init(audio_decoder->HwSampleRate,
audio_decoder->HwSampleRate, 16, 10, 0, 0.8); audio_decoder->HwSampleRate, 16, 10, 0, 0.8);
@ -1005,11 +1020,13 @@ static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder)
} else { } else {
// reset drift to some default value // reset drift to some default value
audio_decoder->DriftCorr /= 2; audio_decoder->DriftCorr /= 2;
audio_decoder->DriftFrac = 0;
av_resample_compensate(audio_decoder->AvResample, av_resample_compensate(audio_decoder->AvResample,
audio_decoder->DriftCorr / 10, audio_decoder->DriftCorr / 10,
10 * audio_decoder->HwSampleRate); 10 * audio_decoder->HwSampleRate);
} }
} }
#endif
} }
/** /**
@ -1063,7 +1080,6 @@ void CodecAudioEnqueue(AudioDecoder * audio_decoder, int16_t * data, int count)
n = av_resample(audio_decoder->AvResample, buftmp[ch], n = av_resample(audio_decoder->AvResample, buftmp[ch],
audio_decoder->Buffer[ch], &consumed, bytes_n / 2, audio_decoder->Buffer[ch], &consumed, bytes_n / 2,
sizeof(buftmp[ch]) / 2, ch == audio_decoder->HwChannels - 1); sizeof(buftmp[ch]) / 2, ch == audio_decoder->HwChannels - 1);
//printf("remain%d: %d = %d/%d\n", ch, n, consumed, bytes_n /2);
// fixme remaining channels // fixme remaining channels
if (bytes_n - consumed * 2 > audio_decoder->RemainSize) { if (bytes_n - consumed * 2 > audio_decoder->RemainSize) {
audio_decoder->RemainSize = bytes_n - consumed * 2; audio_decoder->RemainSize = bytes_n - consumed * 2;
@ -1178,6 +1194,27 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
// build SPDIF header and append A52 audio to it // build SPDIF header and append A52 audio to it
// avpkt is the original data // avpkt is the original data
buf_sz = 6144; buf_sz = 6144;
#ifdef USE_AC3_DRIFT_CORRECTION
if (1) {
int x;
x = (audio_decoder->DriftFrac +
(audio_decoder->DriftCorr * buf_sz)) / (10 *
audio_decoder->HwSampleRate * 100);
audio_decoder->DriftFrac =
(audio_decoder->DriftFrac +
(audio_decoder->DriftCorr * buf_sz)) % (10 *
audio_decoder->HwSampleRate * 100);
x *= audio_decoder->HwChannels * 4;
if (x < -64) { // limit correction
x = -64;
} else if (x > 64) {
x = 64;
}
buf_sz += x;
}
#endif
if (buf_sz < avpkt->size + 8) { if (buf_sz < avpkt->size + 8) {
Error(_ Error(_
("codec/audio: decoded data smaller than encoded\n")); ("codec/audio: decoded data smaller than encoded\n"));
@ -1193,7 +1230,6 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
memset(buf + 4 + avpkt->size / 2, 0, buf_sz - 8 - avpkt->size); memset(buf + 4 + avpkt->size / 2, 0, buf_sz - 8 - avpkt->size);
// don't play with the ac-3 samples // don't play with the ac-3 samples
AudioEnqueue(buf, buf_sz); AudioEnqueue(buf, buf_sz);
// FIXME: handle drift.
return; return;
} }
#if 0 #if 0