Add support for ac3 audio pass through.

This commit is contained in:
Johns 2012-01-07 03:05:43 +01:00
parent 92ffd978b0
commit 45a34a3381
4 changed files with 132 additions and 85 deletions

View File

@ -1,6 +1,8 @@
User johns User johns
Data: Data:
Add support for ac3 audio pass through.
Add workaround for alsa not playing hdmi sound.
Fix bug: broken device plugin stop and exit. Fix bug: broken device plugin stop and exit.
Show transparent cursor to hide cursor. Show transparent cursor to hide cursor.
VDPAU: Add color standard support. VDPAU: Add color standard support.

View File

@ -115,6 +115,10 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioDelay = 0 softhddevice.AudioDelay = 0
+n or -n ms +n or -n ms
softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3
Commandline: Commandline:
------------ ------------

196
codec.c
View File

@ -35,8 +35,12 @@
*/ */
#define USE_AVPARSER #define USE_AVPARSER
/// compile with passthrough support (experimental)
#define USE_PASSTHROUGH
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <endian.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -585,8 +589,17 @@ struct _audio_decoder_
int HwChannels; ///< hw channels int HwChannels; ///< hw channels
ReSampleContext *ReSample; ///< audio resampling context ReSampleContext *ReSample; ///< audio resampling context
}; };
#ifdef USE_PASSTHROUGH
//static char CodecPassthroughPCM; ///< pass pcm through (unsupported)
static char CodecPassthroughAC3; ///< pass ac3 through
//static char CodecPassthroughDTS; ///< pass dts through (unsupported)
//static char CodecPassthroughMPA; ///< pass mpa through (unsupported)
#endif
/** /**
** Allocate a new audio decoder context. ** Allocate a new audio decoder context.
** **
@ -683,6 +696,18 @@ void CodecAudioClose(AudioDecoder * audio_decoder)
} }
} }
/**
** Set audio pass-through.
*/
void CodecSetAudioPassthrough(int mask)
{
#ifdef USE_PASSTHROUGH
CodecPassthroughAC3 = mask & 1 ? 1 : 0;
#endif
// FIXME: must update audio decoder (nr. of channels wrong)
(void)mask;
}
#ifdef USE_AVPARSER #ifdef USE_AVPARSER
/** /**
@ -730,6 +755,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
!index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE, !index ? (uint64_t) spkt->pts : AV_NOPTS_VALUE,
!index ? (uint64_t) spkt->dts : AV_NOPTS_VALUE, -1); !index ? (uint64_t) spkt->dts : AV_NOPTS_VALUE, -1);
// FIXME: make this a function for both #ifdef cases
if (dpkt->size) { if (dpkt->size) {
int buf_sz; int buf_sz;
@ -765,7 +791,15 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
audio_decoder->SampleRate = audio_ctx->sample_rate; audio_decoder->SampleRate = audio_ctx->sample_rate;
audio_decoder->HwSampleRate = audio_ctx->sample_rate; audio_decoder->HwSampleRate = audio_ctx->sample_rate;
audio_decoder->Channels = audio_ctx->channels; audio_decoder->Channels = audio_ctx->channels;
audio_decoder->HwChannels = audio_ctx->channels; #ifdef USE_PASSTHROUGH
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
} else
#endif
{
audio_decoder->HwChannels = audio_ctx->channels;
}
// channels not support? // channels not support?
if ((err = if ((err =
@ -826,6 +860,81 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
AudioEnqueue(outbuf, outlen); AudioEnqueue(outbuf, outlen);
} }
} else { } else {
#ifdef USE_PASSTHROUGH
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3
&& audio_ctx->codec_id == CODEC_ID_AC3) {
// build SPDIF header and append A52 audio to it
// dpkt is the original data
buf_sz = 6144;
if (buf_sz < dpkt->size + 8) {
Error(_
("codec/audio: decoded data smaller than encoded\n"));
break;
}
// copy original data for output
// FIXME: not 100% sure, if endian is correct
buf[0] = htole16(0xF872); // iec 61937 sync word
buf[1] = htole16(0x4E1F);
buf[2] = htole16(0x01 | (dpkt->data[5] & 0x07) << 8);
buf[3] = htole16(dpkt->size * 8);
swab(dpkt->data, buf + 4, dpkt->size);
memset(buf + 4 + dpkt->size / 2, 0,
buf_sz - 8 - dpkt->size);
}
#if 0
//
// old experimental code
//
if (1) {
// FIXME: need to detect dts
// copy original data for output
// FIXME: buf is sint
buf[0] = 0x72;
buf[1] = 0xF8;
buf[2] = 0x1F;
buf[3] = 0x4E;
buf[4] = 0x00;
switch (dpkt->size) {
case 512:
buf[5] = 0x0B;
break;
case 1024:
buf[5] = 0x0C;
break;
case 2048:
buf[5] = 0x0D;
break;
default:
Debug(3,
"codec/audio: dts sample burst not supported\n");
buf[5] = 0x00;
break;
}
buf[6] = (dpkt->size * 8);
buf[7] = (dpkt->size * 8) >> 8;
//buf[8] = 0x0B;
//buf[9] = 0x77;
//printf("%x %x\n", dpkt->data[0],dpkt->data[1]);
// swab?
memcpy(buf + 8, dpkt->data, dpkt->size);
memset(buf + 8 + dpkt->size, 0,
buf_sz - 8 - dpkt->size);
} else if (1) {
// FIXME: need to detect mp2
// FIXME: mp2 passthrough
// see softhddev.c version/layer
// 0x04 mpeg1 layer1
// 0x05 mpeg1 layer23
// 0x06 mpeg2 ext
// 0x07 mpeg2.5 layer 1
// 0x08 mpeg2.5 layer 2
// 0x09 mpeg2.5 layer 3
}
// DTS HD?
// True HD?
#endif
#endif
AudioEnqueue(buf, buf_sz); AudioEnqueue(buf, buf_sz);
} }
} }
@ -904,90 +1013,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt); avcodec_decode_audio4(audio_ctx, frame, &got_frame, dpkt);
#else #else
#endif #endif
if (buf_sz > 0) { // something decoded // FIXME: see above, old code removed
// Update audio clock
if ((uint64_t) spkt->pts != AV_NOPTS_VALUE) {
AudioSetClock(spkt->pts);
spkt->pts = AV_NOPTS_VALUE;
}
// FIXME: must first play remainings bytes, than change and play new.
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) {
int err;
if (audio_decoder->ReSample) {
audio_resample_close(audio_decoder->ReSample);
audio_decoder->ReSample = NULL;
}
audio_decoder->SampleRate = audio_ctx->sample_rate;
audio_decoder->HwSampleRate = audio_ctx->sample_rate;
audio_decoder->Channels = audio_ctx->channels;
audio_decoder->HwChannels = audio_ctx->channels;
// channels not support?
if ((err =
AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels))) {
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
audio_ctx->sample_rate, audio_ctx->channels,
audio_decoder->HwSampleRate,
audio_decoder->HwChannels);
if (err == 1) {
audio_decoder->ReSample =
av_audio_resample_init(audio_decoder->HwChannels,
audio_ctx->channels, audio_decoder->HwSampleRate,
audio_ctx->sample_rate, audio_ctx->sample_fmt,
audio_ctx->sample_fmt, 16, 10, 0, 0.8);
// libav-0.8_pre didn't support 6 -> 2 channels
if (!audio_decoder->ReSample) {
Error(_("codec/audio: resample setup error\n"));
audio_decoder->HwChannels = 0;
audio_decoder->HwSampleRate = 0;
}
} else {
// FIXME: handle errors
Debug(3, "codec/audio: audio setup error\n");
audio_decoder->HwChannels = 0;
audio_decoder->HwSampleRate = 0;
break;
}
}
}
if (audio_decoder->HwSampleRate && audio_decoder->HwChannels) {
// need to resample audio
if (audio_decoder->ReSample) {
int16_t outbuf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 4 +
FF_INPUT_BUFFER_PADDING_SIZE]
__attribute__ ((aligned(16)));
int outlen;
// FIXME: libav-0.7.2 crash here
outlen =
audio_resample(audio_decoder->ReSample, outbuf, buf,
buf_sz);
#ifdef DEBUG
if (outlen != buf_sz) {
Debug(3, "codec/audio: possible fixed ffmpeg\n");
}
#endif
if (outlen) {
// outlen seems to be wrong in ffmpeg-0.9
outlen /= audio_ctx->channels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
outlen *=
audio_decoder->HwChannels *
av_get_bytes_per_sample(audio_ctx->sample_fmt);
Debug(4, "codec/audio: %d -> %d\n", buf_sz, outlen);
AudioEnqueue(outbuf, outlen);
}
} else {
AudioEnqueue(buf, buf_sz);
}
}
}
index += n; index += n;
} }

View File

@ -37,6 +37,7 @@ extern "C"
{ {
#include "video.h" #include "video.h"
extern void AudioPoller(void); extern void AudioPoller(void);
extern void CodecSetAudioPassthrough(int);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -57,6 +58,7 @@ static int ConfigVideoDenoise; ///< config denoise
static int ConfigVideoSharpen; ///< config sharpen static int ConfigVideoSharpen; ///< config sharpen
static char ConfigVideoScaling; ///< config scaling static char ConfigVideoScaling; ///< config scaling
static int ConfigVideoAudioDelay; ///< config audio delay static int ConfigVideoAudioDelay; ///< config audio delay
static int ConfigAudioPassthrough; ///< config audio pass-through
static volatile char DoMakePrimary; ///< flag switch primary static volatile char DoMakePrimary; ///< flag switch primary
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -273,6 +275,7 @@ class cMenuSetupSoft:public cMenuSetupPage
int Sharpen; int Sharpen;
int Scaling; int Scaling;
int AudioDelay; int AudioDelay;
int AudioPassthrough;
protected: protected:
virtual void Store(void); virtual void Store(void);
public: public:
@ -290,6 +293,9 @@ cMenuSetupSoft::cMenuSetupSoft(void)
static const char *const scaling[] = { static const char *const scaling[] = {
"Normal", "Fast", "HQ", "Anamorphic" "Normal", "Fast", "HQ", "Anamorphic"
}; };
static const char *const passthrough[] = {
"None", "AC-3"
};
// cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem // cMenuEditBoolItem cMenuEditBitItem cMenuEditNumItem
// cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem // cMenuEditStrItem cMenuEditStraItem cMenuEditIntItem
@ -313,6 +319,9 @@ cMenuSetupSoft::cMenuSetupSoft(void)
AudioDelay = ConfigVideoAudioDelay; AudioDelay = ConfigVideoAudioDelay;
Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000, Add(new cMenuEditIntItem(tr("Audio delay (ms)"), &AudioDelay, -1000,
1000)); 1000));
AudioPassthrough = ConfigAudioPassthrough;
Add(new cMenuEditStraItem(tr("Audio pass-through"), &AudioPassthrough, 2,
passthrough));
} }
/** /**
@ -334,6 +343,8 @@ void cMenuSetupSoft::Store(void)
VideoSetScaling(ConfigVideoScaling); VideoSetScaling(ConfigVideoScaling);
SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay); SetupStore("AudioDelay", ConfigVideoAudioDelay = AudioDelay);
VideoSetAudioDelay(ConfigVideoAudioDelay); VideoSetAudioDelay(ConfigVideoAudioDelay);
SetupStore("AudioPassthrough", ConfigAudioPassthrough = AudioPassthrough);
CodecSetAudioPassthrough(ConfigAudioPassthrough);
} }
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@ -837,6 +848,10 @@ bool cPluginSoftHdDevice::SetupParse(const char *name, const char *value)
VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value)); VideoSetAudioDelay(ConfigVideoAudioDelay = atoi(value));
return true; return true;
} }
if (!strcmp(name, "AudioPassthrough")) {
CodecSetAudioPassthrough(ConfigAudioPassthrough = atoi(value));
return true;
}
return false; return false;
} }