mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Add support for ac3 audio pass through.
This commit is contained in:
parent
92ffd978b0
commit
45a34a3381
@ -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.
|
||||||
|
@ -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
196
codec.c
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user