mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Experimental ac3 audio drift correction support.
This commit is contained in:
parent
dda9011abc
commit
7e1a42f7ed
@ -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.
|
||||||
|
72
codec.c
72
codec.c
@ -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,34 +890,35 @@ 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
|
||||||
@ -920,11 +926,16 @@ static void CodecAudioSetClock(AudioDecoder * audio_decoder, int64_t pts)
|
|||||||
} else if (audio_decoder->DriftCorr > 20000) {
|
} else if (audio_decoder->DriftCorr > 20000) {
|
||||||
audio_decoder->DriftCorr = 20000;
|
audio_decoder->DriftCorr = 20000;
|
||||||
}
|
}
|
||||||
if (audio_decoder->AvResample && audio_decoder->DriftCorr) {
|
|
||||||
av_resample_compensate(audio_decoder->AvResample,
|
|
||||||
audio_decoder->DriftCorr / 10, 10 * audio_decoder->HwSampleRate);
|
|
||||||
}
|
}
|
||||||
printf("codec/audio: drift(%5d) %8dus %4d\n", audio_decoder->DriftCorr,
|
// 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, distance);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user