From 7e1a42f7ed28d77888f7a9eba541f729697ad5f6 Mon Sep 17 00:00:00 2001 From: Johns Date: Sat, 3 Mar 2012 16:45:59 +0100 Subject: [PATCH] Experimental ac3 audio drift correction support. --- ChangeLog | 1 + codec.c | 92 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5f1ef18..c70dde8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ User johns Date: + Experimental ac3 audio drift correction support. Removes LPCM detection from TS parser. Rewrote video/audio start code. Add support for attach/detach plugin. diff --git a/codec.c b/codec.c index 9d497c6..400dd64 100644 --- a/codec.c +++ b/codec.c @@ -352,7 +352,7 @@ void CodecVideoOpen(VideoDecoder * decoder, const char *name, int codec_id) { 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) { 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))) { Debug(3, "codec: vdpau decoder found\n"); } 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 } decoder->VideoCodec = video_codec; @@ -615,6 +615,7 @@ struct _audio_decoder_ int Drift; ///< accumulated audio drift int DriftCorr; ///< audio drift correction value + int DriftFrac; ///< audio drift fraction for ac3 struct AVResampleContext *AvResample; ///< second audio resample context #define MAX_CHANNELS 8 ///< max number of channels supported @@ -675,10 +676,12 @@ void CodecAudioOpen(AudioDecoder * audio_decoder, const char *name, { 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))) { Debug(3, "codec: audio decoder '%s' found\n", name); } 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 } audio_decoder->AudioCodec = audio_codec; @@ -846,6 +849,7 @@ static void CodecReorderAudioFrame(int16_t * buf, int size, int channels) ** Set/update audio pts clock. ** ** @param audio_decoder audio decoder data +** @param pts presentation timestamp */ 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->LastDelay = delay; audio_decoder->Drift = 0; + audio_decoder->DriftFrac = 0; Debug(3, "codec/audio: inital delay %zd ms\n", delay / 90); return; } @@ -885,46 +890,52 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts) (tim_diff * 90) / (1000 * 1000) - pts_diff + delay - audio_decoder->LastDelay; + // adjust rounding error + nowtime.tv_nsec -= nowtime.tv_nsec % (1000 * 1000 / 90); audio_decoder->LastTime = nowtime; audio_decoder->LastPTS = pts; audio_decoder->LastDelay = delay; - if (1) { + if (0) { 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, audio_decoder->DriftCorr); } - - if (abs(drift) > 5 * 90) { + // underruns and av_resample have the same time :((( + if (abs(drift) > 10 * 90) { // drift too big, pts changed? - Debug(3, "codec/audio: drift(%5d) %3dms reset\n", - audio_decoder->DriftCorr, drift); + Debug(3, "codec/audio: drift(%6d) %3dms reset\n", + audio_decoder->DriftCorr, drift / 90); audio_decoder->LastDelay = 0; - return; - } + } else { - drift += audio_decoder->Drift; - audio_decoder->Drift = drift; - corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000); -#ifdef USE_PASSTHROUGH - // SPDIF/HDMI passthrough - if (!CodecPassthroughAC3 - || audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3) + drift += audio_decoder->Drift; + audio_decoder->Drift = drift; + corr = (10 * audio_decoder->HwSampleRate * drift) / (90 * 1000); +#if defined(USE_PASSTHROUGH) && !defined(USE_AC3_DRIFT_CORRECTION) + // SPDIF/HDMI passthrough + if (!CodecPassthroughAC3 + || audio_decoder->AudioCtx->codec_id != CODEC_ID_AC3) #endif - { - audio_decoder->DriftCorr -= corr; - } + { + audio_decoder->DriftCorr = -corr; + } - if (audio_decoder->DriftCorr < -20000) { // limit correction - audio_decoder->DriftCorr = -20000; - } else if (audio_decoder->DriftCorr > 20000) { - audio_decoder->DriftCorr = 20000; + if (audio_decoder->DriftCorr < -20000) { // limit correction + audio_decoder->DriftCorr = -20000; + } else if (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) { + int distance; + + distance = (pts_diff * audio_decoder->HwSampleRate) / (90 * 1000); 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); } @@ -996,7 +1007,11 @@ static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder) } } // prepare audio drift resample +#ifdef USE_AUDIO_DRIFT_CORRECTION if (!isAC3) { + if (audio_decoder->AvResample) { + Error(_("codec/audio: overwrite resample\n")); + } audio_decoder->AvResample = av_resample_init(audio_decoder->HwSampleRate, audio_decoder->HwSampleRate, 16, 10, 0, 0.8); @@ -1005,11 +1020,13 @@ static void CodecAudioUpdateFormat(AudioDecoder * audio_decoder) } else { // reset drift to some default value audio_decoder->DriftCorr /= 2; + audio_decoder->DriftFrac = 0; av_resample_compensate(audio_decoder->AvResample, audio_decoder->DriftCorr / 10, 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], audio_decoder->Buffer[ch], &consumed, bytes_n / 2, 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 if (bytes_n - consumed * 2 > audio_decoder->RemainSize) { 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 // avpkt is the original data 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) { Error(_ ("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); // don't play with the ac-3 samples AudioEnqueue(buf, buf_sz); - // FIXME: handle drift. return; } #if 0