Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added PCM remapping to all DVD audio renderers

Removed deprecated asound.conf hardcoded codec mappings
Added PulseAudio remapping support
Added ALSA remapping support
Added Win32 Remapping Support - Thanks ArtVandelae

git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@27266 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
  • Loading branch information...
commit 9a13b1427036f7d67615ee9cc8b264ef1c40b610 1 parent aa03045
gnif2 authored
Showing with 828 additions and 664 deletions.
  1. +2 −2 project/VS2008Express/XBMC.vcproj
  2. +16 −130 system/asound.conf
  3. +83 −59 xbmc/cores/AudioRenderers/ALSADirectSound.cpp
  4. +2 −1  xbmc/cores/AudioRenderers/ALSADirectSound.h
  5. +4 −4 xbmc/cores/AudioRenderers/AudioRendererFactory.cpp
  6. +1 −1  xbmc/cores/AudioRenderers/AudioRendererFactory.h
  7. +5 −1 xbmc/cores/AudioRenderers/IAudioRenderer.h
  8. +1 −1  xbmc/cores/AudioRenderers/NullDirectSound.cpp
  9. +1 −1  xbmc/cores/AudioRenderers/NullDirectSound.h
  10. +27 −7 xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp
  11. +1 −1  xbmc/cores/AudioRenderers/PulseAudioDirectSound.h
  12. +0 −148 xbmc/cores/AudioRenderers/Win32ChannelRemap.cpp
  13. +0 −54 xbmc/cores/AudioRenderers/Win32ChannelRemap.h
  14. +103 −10 xbmc/cores/AudioRenderers/Win32DirectSound.cpp
  15. +6 −4 xbmc/cores/AudioRenderers/Win32DirectSound.h
  16. +93 −6 xbmc/cores/AudioRenderers/Win32WASAPI.cpp
  17. +5 −3 xbmc/cores/AudioRenderers/Win32WASAPI.h
  18. +2 −2 xbmc/cores/dvdplayer/DVDAudio.cpp
  19. +6 −0 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
  20. +48 −0 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
  21. +1 −0  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
  22. +75 −128 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.cpp
  23. +7 −6 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h
  24. +21 −1 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp
  25. +7 −5 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h
  26. +6 −5 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h
  27. +53 −77 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.cpp
  28. +7 −6 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h
  29. +1 −0  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h
  30. +1 −0  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
  31. +18 −0 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp
  32. +1 −0  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h
  33. +1 −0  xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
  34. +1 −0  xbmc/cores/dvdplayer/DVDPlayerAudio.h
  35. +3 −1 xbmc/cores/paplayer/PAPlayer.cpp
  36. +1 −0  xbmc/cores/paplayer/PAPlayer.h
  37. +1 −0  xbmc/utils/Makefile
  38. +147 −0 xbmc/utils/PCMRemap.cpp
  39. +70 −0 xbmc/utils/PCMRemap.h
View
4 project/VS2008Express/XBMC.vcproj
@@ -2114,11 +2114,11 @@
>
</File>
<File
- RelativePath="..\..\xbmc\cores\AudioRenderers\Win32ChannelRemap.cpp"
+ RelativePath="..\..\xbmc\utils\PCMRemap.cpp"
>
</File>
<File
- RelativePath="..\..\xbmc\cores\AudioRenderers\Win32ChannelRemap.h"
+ RelativePath="..\..\xbmc\utils\PCMRemap.h"
>
</File>
<File
View
146 system/asound.conf
@@ -1,138 +1,24 @@
-
-# Linux has channel order
-# FL, FR, SL, SR, C, LFE
-# so we remap all channelorders to this
-
-# Windows - FL, FR, C, LFE, BL, BR, (FLC, FRC, BC, SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR)
-pcm.xbmc_win51 {
- @args.0 SLAVE
- @args.SLAVE {
- type string
- default "default"
- }
- type route
- slave {
- pcm $SLAVE
- channels 6
- }
- ttable {
- 0.0= 1
- 1.1= 1
- 2.4= 1
- 3.5= 1
- 4.2= 1
- 5.3= 1
- }
-}
-
-pcm.xbmc_win50 {
- @args.0 SLAVE
- @args.SLAVE {
- type string
- default "default"
- }
- type route
- slave {
- pcm $SLAVE
- channels 5
- }
- ttable {
- 0.0= 1
- 1.1= 1
- 2.4= 1
- 3.2= 1
- 4.3= 1
- }
-}
-
-# FL, C, FR, SL, SR, LFE
-pcm.xbmc_ogg51 {
- @args.0 SLAVE
- @args.SLAVE {
- type string
- default "default"
- }
- type route
- slave {
- pcm $SLAVE
- channels 6
- }
- ttable {
- 0.0= 1
- 1.4= 1
- 2.1= 1
- 3.2= 1
- 4.3= 1
- 5.5= 1
- }
-}
-
-pcm.xbmc_ogg50 {
- @args.0 SLAVE
- @args.SLAVE {
- type string
- default "default"
- }
- type route
- slave {
- pcm $SLAVE
- channels 5
- }
- ttable {
- 0.0= 1
- 1.4= 1
- 2.1= 1
- 3.2= 1
- 4.3= 1
- }
-}
-
-# C, FL, FR, SL, SR, LFE
-pcm.xbmc_aac51 {
- @args.0 SLAVE
- @args.SLAVE {
- type string
- default "default"
- }
- type route
- slave {
- pcm $SLAVE
- channels 6
- }
- ttable {
- 0.4= 1
- 1.0= 1
- 2.1= 1
- 3.2= 1
- 4.3= 1
- 5.5= 1
- }
-}
-
-pcm.xbmc_aac50 {
+# downmixing to 2 channels
+pcm.xbmc_71to2 {
@args.0 SLAVE
@args.SLAVE {
type string
default "default"
}
- type route
- slave {
- pcm $SLAVE
- channels 6
- }
- ttable {
- 0.4= 1
- 1.0= 1
- 2.1= 1
- 3.2= 1
- 4.3= 1
- }
-}
-
-# this could potentially be used to encode multichannels
-# to ac3 for passthrough out an spdif
-pcm.xbmc_a52encode {
- type a52
+ type plug
+ slave.pcm $SLAVE
+ slave.channels 2
+ route_policy duplicate
+ ttable.0.0 1 # front left speaker
+ ttable.1.1 1 # front right speaker
+ ttable.2.0 0.7 # rear left speaker
+ ttable.3.1 0.7 # rear right speaker
+ ttable.4.0 0.7 # center to left mapping
+ ttable.4.1 0.7 # center to right mapping
+ ttable.5.0 0.5 # LFE (base) to left mapping
+ ttable.5.1 0.5 # LFE to right mapping
+ ttable.6.0 0.6 # SL to left mapping
+ ttable.7.0 0.6 # SR to right mapping
}
# downmixing to 2 channels
View
142 xbmc/cores/AudioRenderers/ALSADirectSound.cpp
@@ -47,14 +47,44 @@ CALSADirectSound::CALSADirectSound()
m_bIsAllocated = false;
}
-bool CALSADirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+bool CALSADirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
{
+ static int8_t ALSAChannelMap[8] =
+ {
+ PCM_FRONT_LEFT , PCM_FRONT_RIGHT ,
+ PCM_BACK_LEFT , PCM_BACK_RIGHT ,
+ PCM_FRONT_CENTER, PCM_LOW_FREQUENCY,
+ PCM_SIDE_LEFT , PCM_SIDE_RIGHT
+ };
+
CStdString deviceuse;
- CLog::Log(LOGDEBUG,"CALSADirectSound::CALSADirectSound - Channels: %i - SampleRate: %i - SampleBit: %i - Resample %s - Codec %s - IsMusic %s - IsPassthrough %s - audioDevice: %s", iChannels, uiSamplesPerSec, uiBitsPerSample, bResample ? "true" : "false", strAudioCodec, bIsMusic ? "true" : "false", bPassthrough ? "true" : "false", device.c_str());
+ /* setup the channel mapping */
+ m_uiDataChannels = iChannels;
+ m_remap.SetInputFormat (iChannels, channelMap, uiBitsPerSample / 8);
- if (iChannels == 0)
- iChannels = 2;
+ if (channelMap)
+ {
+ unsigned int outChannels = 0;
+ for(unsigned int ch = 0; ch < m_uiDataChannels; ++ch)
+ for(unsigned int map = 0; map < 8; ++map)
+ if (channelMap[ch] == ALSAChannelMap[map])
+ {
+ if (map > outChannels)
+ outChannels = map;
+ break;
+ }
+
+ m_remap.SetOutputFormat(++outChannels, ALSAChannelMap);
+ if (m_remap.CanRemap())
+ {
+ iChannels = outChannels;
+ if (m_uiDataChannels != (unsigned int)iChannels)
+ CLog::Log(LOGDEBUG, "CALSADirectSound::CALSADirectSound - Requested channels changed from %i to %i", m_uiDataChannels, iChannels);
+ }
+ }
+
+ CLog::Log(LOGDEBUG,"CALSADirectSound::CALSADirectSound - Channels: %i - SampleRate: %i - SampleBit: %i - Resample %s - Codec %s - IsMusic %s - IsPassthrough %s - audioDevice: %s", iChannels, uiSamplesPerSec, uiBitsPerSample, bResample ? "true" : "false", strAudioCodec, bIsMusic ? "true" : "false", bPassthrough ? "true" : "false", device.c_str());
bool bAudioOnAllSpeakers(false);
g_audioContext.SetupSpeakerConfig(iChannels, bAudioOnAllSpeakers, bIsMusic);
@@ -126,48 +156,25 @@ bool CALSADirectSound::Initialize(IAudioCallback* pCallback, const CStdString& d
if(g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
{
- if(iChannels == 6)
- deviceuse = "xbmc_51to2:'" + EscapeDevice(deviceuse) + "'";
- else if(iChannels == 5)
- deviceuse = "xbmc_50to2:'" + EscapeDevice(deviceuse) + "'";
- }
- else
- {
- if(deviceuse == "default")
+ switch(iChannels)
{
- if(iChannels == 6)
- deviceuse = "surround51";
- else if(iChannels == 5)
- deviceuse = "surround50";
- else if(iChannels == 4)
- deviceuse = "surround40";
+ case 8: deviceuse = "xbmc_71to2:'" + EscapeDevice(deviceuse) + "'"; break;
+ case 6: deviceuse = "xbmc_51to2:'" + EscapeDevice(deviceuse) + "'"; break;
+ case 5: deviceuse = "xbmc_50to2:'" + EscapeDevice(deviceuse) + "'"; break;
}
}
-
- // setup channel mapping to linux default
- if (strstr(strAudioCodec, "AAC"))
- {
- if(iChannels == 6)
- deviceuse = "xbmc_aac51:'" + EscapeDevice(deviceuse) + "'";
- else if(iChannels == 5)
- deviceuse = "xbmc_aac50:'" + EscapeDevice(deviceuse) + "'";
- }
- else if (strstr(strAudioCodec, "DMO") || strstr(strAudioCodec, "FLAC") || strstr(strAudioCodec, "PCM"))
- {
- if(iChannels == 6)
- deviceuse = "xbmc_win51:'" + EscapeDevice(deviceuse) + "'";
- else if(iChannels == 5)
- deviceuse = "xbmc_win50:'" + EscapeDevice(deviceuse) + "'";
- }
- else if (strstr(strAudioCodec, "OggVorbis"))
+ else
{
- if(iChannels == 6)
- deviceuse = "xbmc_ogg51:'" + EscapeDevice(deviceuse) + "'";
- else if(iChannels == 5)
- deviceuse = "xbmc_ogg50:'" + EscapeDevice(deviceuse) + "'";
+ if(deviceuse == "default")
+ switch(iChannels)
+ {
+ case 8: deviceuse = "surround71"; break;
+ case 6: deviceuse = "surround51"; break;
+ case 5: deviceuse = "surround50"; break;
+ case 4: deviceuse = "surround40"; break;
+ }
}
-
if(deviceuse != device)
{
snd_input_t* input;
@@ -320,7 +327,8 @@ bool CALSADirectSound::Deinitialize()
return true;
}
-void CALSADirectSound::Flush() {
+void CALSADirectSound::Flush()
+{
if (!m_bIsAllocated)
return;
@@ -427,7 +435,8 @@ unsigned int CALSADirectSound::GetSpace()
Flush();
}
}
- if (nSpace < 0) {
+ if (nSpace < 0)
+ {
CLog::Log(LOGWARNING,"CALSADirectSound::GetSpace - get space failed. err: %d (%s)", nSpace, snd_strerror(nSpace));
nSpace = 0;
Flush();
@@ -438,7 +447,8 @@ unsigned int CALSADirectSound::GetSpace()
//***********************************************************************************************
unsigned int CALSADirectSound::AddPackets(const void* data, unsigned int len)
{
- if (!m_bIsAllocated) {
+ if (!m_bIsAllocated)
+ {
CLog::Log(LOGERROR,"CALSADirectSound::AddPackets - sanity failed. no valid play handle!");
return len;
}
@@ -447,21 +457,21 @@ unsigned int CALSADirectSound::AddPackets(const void* data, unsigned int len)
if(m_bPause)
return 0;
- const unsigned char *pcmPtr = (const unsigned char *)data;
int framesToWrite;
- framesToWrite = std::min(GetSpace(), len);
- framesToWrite /= m_dwPacketSize;
- framesToWrite *= m_dwPacketSize;
- int bytesToWrite = framesToWrite;
- framesToWrite = snd_pcm_bytes_to_frames(m_pPlayHandle, framesToWrite);
+ framesToWrite = std::min(GetSpace(), (len / m_uiDataChannels) * m_uiChannels);
+ framesToWrite /= m_dwPacketSize;
+ framesToWrite *= m_dwPacketSize;
+ int bytesToWrite = framesToWrite;
+ int inputSamples = ((framesToWrite / m_uiChannels) * m_uiDataChannels) / 2;
+ framesToWrite = snd_pcm_bytes_to_frames(m_pPlayHandle, framesToWrite);
if(framesToWrite == 0)
return 0;
// handle volume de-amp
if (!m_bPassthrough)
- m_amp.DeAmplify((short *)pcmPtr, framesToWrite * m_uiChannels);
+ m_amp.DeAmplify((short *)data, inputSamples);
int writeResult;
if (m_bPassthrough && m_nCurrentVolume == VOLUME_MINIMUM)
@@ -471,24 +481,36 @@ unsigned int CALSADirectSound::AddPackets(const void* data, unsigned int len)
writeResult = snd_pcm_writei(m_pPlayHandle, dummy, framesToWrite);
}
else
- writeResult = snd_pcm_writei(m_pPlayHandle, pcmPtr, framesToWrite);
- if ( writeResult == -EPIPE ) {
+ {
+ if (m_remap.CanRemap())
+ {
+ /* remap the data to the correct channels */
+ uint8_t outData[bytesToWrite];
+ m_remap.Remap((void *)data, outData, framesToWrite);
+ writeResult = snd_pcm_writei(m_pPlayHandle, outData, framesToWrite);
+ }
+ else
+ writeResult = snd_pcm_writei(m_pPlayHandle, data, framesToWrite);
+ }
+ if ( writeResult == -EPIPE )
+ {
CLog::Log(LOGDEBUG, "CALSADirectSound::AddPackets - buffer underun (tried to write %d frames)",
framesToWrite);
Flush();
return 0;
}
- else if (writeResult != framesToWrite) {
+ else if (writeResult != framesToWrite)
+ {
CLog::Log(LOGERROR, "CALSADirectSound::AddPackets - failed to write %d frames. "
"bad write (err: %d) - %s",
framesToWrite, writeResult, snd_strerror(writeResult));
Flush();
}
- if (writeResult>0)
- pcmPtr += snd_pcm_frames_to_bytes(m_pPlayHandle, writeResult);
+ if (writeResult > 0)
+ return writeResult * (m_uiBitsPerSample / 8) * m_uiDataChannels;
- return writeResult * (m_uiBitsPerSample / 8) * m_uiChannels;
+ return 0;
}
//***********************************************************************************************
@@ -501,12 +523,14 @@ float CALSADirectSound::GetDelay()
int nErr = snd_pcm_delay(m_pPlayHandle, &frames);
CHECK_ALSA(LOGERROR,"snd_pcm_delay",nErr);
- if (nErr < 0) {
+ if (nErr < 0)
+ {
frames = 0;
Flush();
}
- if (frames < 0) {
+ if (frames < 0)
+ {
#if SND_LIB_VERSION >= 0x000901 /* snd_pcm_forward() exists since 0.9.0rc8 */
snd_pcm_forward(m_pPlayHandle, -frames);
#endif
@@ -529,7 +553,7 @@ float CALSADirectSound::GetCacheTotal()
//***********************************************************************************************
unsigned int CALSADirectSound::GetChunkLen()
{
- return m_dwPacketSize;
+ return (m_dwPacketSize / m_uiChannels) * m_uiDataChannels;
}
//***********************************************************************************************
int CALSADirectSound::SetPlaySpeed(int iSpeed)
View
3  xbmc/cores/AudioRenderers/ALSADirectSound.h
@@ -51,7 +51,7 @@ class CALSADirectSound : public IAudioRenderer
virtual float GetCacheTime();
virtual float GetCacheTotal();
CALSADirectSound();
- virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+ virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
virtual ~CALSADirectSound();
virtual unsigned int AddPackets(const void* data, unsigned int len);
@@ -88,6 +88,7 @@ class CALSADirectSound : public IAudioRenderer
unsigned int m_uiBufferSize;
unsigned int m_uiSamplesPerSec;
unsigned int m_uiBitsPerSample;
+ unsigned int m_uiDataChannels;
unsigned int m_uiChannels;
bool m_bPassthrough;
View
8 xbmc/cores/AudioRenderers/AudioRendererFactory.cpp
@@ -41,7 +41,7 @@
#define ReturnOnValidInitialize() \
{ \
- if (audioSink->Initialize(pCallback, device, iChannels, uiSamplesPerSec, uiBitsPerSample, bResample, strAudioCodec, bIsMusic, bPassthrough)) \
+ if (audioSink->Initialize(pCallback, device, iChannels, channelMap, uiSamplesPerSec, uiBitsPerSample, bResample, strAudioCodec, bIsMusic, bPassthrough)) \
return audioSink; \
else \
{ \
@@ -51,7 +51,7 @@
} \
}\
-IAudioRenderer* CAudioRendererFactory::Create(IAudioCallback* pCallback, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+IAudioRenderer* CAudioRendererFactory::Create(IAudioCallback* pCallback, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
{
IAudioRenderer* audioSink = NULL;
@@ -91,7 +91,7 @@ IAudioRenderer* CAudioRendererFactory::Create(IAudioCallback* pCallback, int iCh
#endif
audioSink = new CNullDirectSound();
- audioSink->Initialize(pCallback, device, iChannels, uiSamplesPerSec, uiBitsPerSample, bResample, strAudioCodec, bIsMusic, bPassthrough);
+ audioSink->Initialize(pCallback, device, iChannels, channelMap, uiSamplesPerSec, uiBitsPerSample, bResample, strAudioCodec, bIsMusic, bPassthrough);
return audioSink;
}
}
@@ -119,7 +119,7 @@ IAudioRenderer* CAudioRendererFactory::Create(IAudioCallback* pCallback, int iCh
#endif
audioSink = new CNullDirectSound();
- audioSink->Initialize(pCallback, device, iChannels, uiSamplesPerSec, uiBitsPerSample, bResample, strAudioCodec, bIsMusic, bPassthrough);
+ audioSink->Initialize(pCallback, device, iChannels, channelMap, uiSamplesPerSec, uiBitsPerSample, bResample, strAudioCodec, bIsMusic, bPassthrough);
return audioSink;
}
View
2  xbmc/cores/AudioRenderers/AudioRendererFactory.h
@@ -31,7 +31,7 @@
class CAudioRendererFactory
{
public:
- static IAudioRenderer *Create(IAudioCallback* pCallback, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough);
+ static IAudioRenderer *Create(IAudioCallback* pCallback, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough);
static void EnumerateAudioSinks(AudioSinkList& vAudioSinks, bool passthrough);
private:
static IAudioRenderer *CreateFromUri(const CStdString &soundsystem);
View
6 xbmc/cores/AudioRenderers/IAudioRenderer.h
@@ -31,6 +31,7 @@
#include "StdString.h"
#include "IAudioCallback.h"
+#include "PCMRemap.h"
extern void RegisterAudioCallback(IAudioCallback* pCallback);
extern void UnRegisterAudioCallback();
@@ -42,7 +43,7 @@ class IAudioRenderer
public:
IAudioRenderer() {};
virtual ~IAudioRenderer() {};
- virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false) = 0;
+ virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false) = 0;
virtual void UnRegisterAudioCallback() = 0;
virtual void RegisterAudioCallback(IAudioCallback* pCallback) = 0;
virtual float GetDelay() = 0;
@@ -66,6 +67,9 @@ class IAudioRenderer
virtual void WaitCompletion() = 0;
virtual void SwitchChannels(int iAudioStream, bool bAudioOnAllSpeakers) = 0;
+protected:
+ CPCMRemap m_remap;
+
private:
};
View
2  xbmc/cores/AudioRenderers/NullDirectSound.cpp
@@ -41,7 +41,7 @@ void CNullDirectSound::DoWork()
CNullDirectSound::CNullDirectSound()
{
}
-bool CNullDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+bool CNullDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
{
CLog::Log(LOGERROR,"Creating a Null Audio Renderer, Check your audio settings as this should not happen");
if (iChannels == 0)
View
2  xbmc/cores/AudioRenderers/NullDirectSound.h
@@ -41,7 +41,7 @@ class CNullDirectSound : public IAudioRenderer
virtual float GetDelay();
virtual float GetCacheTime();
CNullDirectSound();
- virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+ virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
virtual ~CNullDirectSound();
virtual unsigned int AddPackets(const void* data, unsigned int len);
View
34 xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp
@@ -143,11 +143,9 @@ CPulseAudioDirectSound::CPulseAudioDirectSound()
{
}
-bool CPulseAudioDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
+bool CPulseAudioDirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
{
CLog::Log(LOGDEBUG,"PulseAudio: Opening Channels: %i - SampleRate: %i - SampleBit: %i - Resample %s - Codec %s - IsMusic %s - IsPassthrough %s - device: %s", iChannels, uiSamplesPerSec, uiBitsPerSample, bResample ? "true" : "false", strAudioCodec, bIsMusic ? "true" : "false", bPassthrough ? "true" : "false", device.c_str());
- if (iChannels == 0)
- iChannels = 2;
bool bAudioOnAllSpeakers(false);
g_audioContext.SetupSpeakerConfig(iChannels, bAudioOnAllSpeakers, bIsMusic);
@@ -205,10 +203,32 @@ bool CPulseAudioDirectSound::Initialize(IAudioCallback* pCallback, const CStdStr
return false;
}
- if (strstr(strAudioCodec, "DMO") || strstr(strAudioCodec, "FLAC") || strstr(strAudioCodec, "PCM"))
- pa_channel_map_init_auto(&map, m_SampleSpec.channels, PA_CHANNEL_MAP_WAVEEX);
- else
- pa_channel_map_init_auto(&map, m_SampleSpec.channels, PA_CHANNEL_MAP_ALSA);
+ // Build the channel map, we dont need to use PCMRemap, pulse does it for us :)
+ map.channels = iChannels;
+ for(int ch = 0; ch < iChannels; ++ch)
+ {
+ switch(channelMap[ch])
+ {
+ case PCM_FRONT_LEFT : map.map[ch] = PA_CHANNEL_POSITION_FRONT_LEFT ; break;
+ case PCM_FRONT_RIGHT : map.map[ch] = PA_CHANNEL_POSITION_FRONT_RIGHT ; break;
+ case PCM_FRONT_CENTER : map.map[ch] = PA_CHANNEL_POSITION_FRONT_CENTER ; break;
+ case PCM_BACK_CENTER : map.map[ch] = PA_CHANNEL_POSITION_REAR_CENTER ; break;
+ case PCM_BACK_LEFT : map.map[ch] = PA_CHANNEL_POSITION_REAR_LEFT ; break;
+ case PCM_BACK_RIGHT : map.map[ch] = PA_CHANNEL_POSITION_REAR_RIGHT ; break;
+ case PCM_LOW_FREQUENCY : map.map[ch] = PA_CHANNEL_POSITION_LFE ; break;
+ case PCM_FRONT_LEFT_OF_CENTER : map.map[ch] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ; break;
+ case PCM_FRONT_RIGHT_OF_CENTER: map.map[ch] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; break;
+ case PCM_SIDE_LEFT : map.map[ch] = PA_CHANNEL_POSITION_SIDE_LEFT ; break;
+ case PCM_SIDE_RIGHT : map.map[ch] = PA_CHANNEL_POSITION_SIDE_RIGHT ; break;
+ case PCM_TOP_CENTER : map.map[ch] = PA_CHANNEL_POSITION_TOP_CENTER ; break;
+ case PCM_TOP_FRONT_LEFT : map.map[ch] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT ; break;
+ case PCM_TOP_FRONT_RIGHT : map.map[ch] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ; break;
+ case PCM_TOP_FRONT_CENTER : map.map[ch] = PA_CHANNEL_POSITION_TOP_CENTER ; break;
+ case PCM_TOP_BACK_LEFT : map.map[ch] = PA_CHANNEL_POSITION_TOP_REAR_LEFT ; break;
+ case PCM_TOP_BACK_RIGHT : map.map[ch] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT ; break;
+ case PCM_TOP_BACK_CENTER : map.map[ch] = PA_CHANNEL_POSITION_TOP_REAR_CENTER ; break;
+ }
+ }
pa_cvolume_reset(&m_Volume, m_SampleSpec.channels);
View
2  xbmc/cores/AudioRenderers/PulseAudioDirectSound.h
@@ -47,7 +47,7 @@ class CPulseAudioDirectSound : public IAudioRenderer
virtual float GetCacheTime();
virtual float GetCacheTotal();
CPulseAudioDirectSound();
- virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+ virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
virtual ~CPulseAudioDirectSound();
virtual unsigned int AddPackets(const void* data, unsigned int len);
View
148 xbmc/cores/AudioRenderers/Win32ChannelRemap.cpp
@@ -1,148 +0,0 @@
-#include "Win32ChannelRemap.h"
-#include "Log.h"
-
-CWin32ChannelRemap::CWin32ChannelRemap() :
- m_pChannelMap(NULL),
- m_uiChannels(0),
- m_uiBitsPerSample(0),
- m_bPassthrough(false)
-{
-}
-
-CWin32ChannelRemap::~CWin32ChannelRemap()
-{
-}
-
-// Channel maps
-// Our output order is FL, FR, C, LFE, SL, SR, SC, FLC, FRC
-const unsigned char ac3_51_Map[] = {0,1,4,5,2,3}; // Sent as FL, FR, SL, SR, C, LFE
-const unsigned char ac3_50_Map[] = {0,1,4,2,3}; // Sent as FL, FR, SL, SR, C
-const unsigned char eac3_51_Map[] = {0,2,1,4,5,3}; // Sent as FL, C, FR, SL, SR, LFE
-const unsigned char eac3_50_Map[] = {0,2,1,4,5}; // Sent as FL, C, FR, SL, SR, LFE
-const unsigned char aac_51_Map[] = {2,0,1,4,5,3}; // Sent as C, FL, FR, SL, SR, LFE
-const unsigned char aac_50_Map[] = {2,0,1,4,5}; // Sent as C, FL, FR, SL, SR
-const unsigned char vorbis_51_Map[] = {0,2,1,4,5,3}; // Sent as FL, C, FR, SL, SR, LFE
-const unsigned char vorbis_50_Map[] = {0,2,1,4,5}; // Sent as FL, C, FR, SL, SR
-
-void CWin32ChannelRemap::SetChannelMap(unsigned int channels, unsigned int bitsPerSample, bool passthrough, const char* strAudioCodec)
-{
- if (!strcmp(strAudioCodec, "AC3") || !strcmp(strAudioCodec, "DTS"))
- {
- if (channels == 6)
- m_pChannelMap = (unsigned char*)ac3_51_Map;
- else if (channels == 5)
- m_pChannelMap = (unsigned char*)ac3_50_Map;
- }
- else if (!strcmp(strAudioCodec, "AAC"))
- {
- if (channels == 6)
- m_pChannelMap = (unsigned char*)aac_51_Map;
- else if (channels == 5)
- m_pChannelMap = (unsigned char*)aac_50_Map;
- }
- else if (!strcmp(strAudioCodec, "Vorbis"))
- {
- if (channels == 6)
- m_pChannelMap = (unsigned char*)vorbis_51_Map;
- else if (channels == 5)
- m_pChannelMap = (unsigned char*)vorbis_50_Map;
- }
- else if (!strcmp(strAudioCodec, "EAC3"))
- {
- if (channels == 6)
- m_pChannelMap = (unsigned char*)eac3_51_Map;
- else if (channels == 5)
- m_pChannelMap = (unsigned char*)eac3_50_Map;
- }
- else
- {
- m_pChannelMap = NULL;
- }
-
- m_uiChannels = channels;
- m_uiBitsPerSample = bitsPerSample;
- m_bPassthrough = passthrough;
-}
-
-void CWin32ChannelRemap::MapDataIntoBuffer(unsigned char* pData, unsigned int len, unsigned char* pOut)
-{
- if(pData == NULL || pOut == NULL || len == 0)
- {
- CLog::Log(LOGERROR, __FUNCTION__": Null data pointer or 0 length parameter passed.");
- return;
- }
-
- if (m_pChannelMap && !m_bPassthrough)
- {
- switch(m_uiBitsPerSample)
- {
- case 8:
- MapData8(pData, len, pOut);
- break;
- case 16:
- MapData16(pData, len, pOut);
- break;
- case 24:
- MapData24(pData, len, pOut);
- break;
- case 32:
- MapData32(pData, len, pOut);
- break;
- default:
- CLog::Log(LOGERROR, __FUNCTION__": Invalid bits per sample applied to channel mapping");
- break;
- }
- }
- else
- {
- memcpy(pOut, pData, len); // If no mapping required, just copy the data.
- }
-}
-
-void CWin32ChannelRemap::MapData8(unsigned char* pData, unsigned int len, unsigned char* pOut)
-{
- unsigned char* pOutFrame = pOut;
- for (unsigned char* pInFrame = pData; pInFrame < pData + (len / sizeof(unsigned char)); pInFrame += m_uiChannels, pOutFrame += m_uiChannels)
- {
- // Remap a single frame
- for (unsigned int chan = 0; chan < m_uiChannels; chan++)
- pOutFrame[m_pChannelMap[chan]] = pInFrame[chan]; // Copy sample into correct position in the output buffer
- }
-}
-
-void CWin32ChannelRemap::MapData16(unsigned char* pData, unsigned int len, unsigned char* pOut)
-{
- short* pOutFrame = (short*)pOut;
- for (short* pInFrame = (short*)pData; pInFrame < (short*)pData + (len / sizeof(short)); pInFrame += m_uiChannels, pOutFrame += m_uiChannels)
- {
- // Remap a single frame
- for (unsigned int chan = 0; chan < m_uiChannels; chan++)
- pOutFrame[m_pChannelMap[chan]] = pInFrame[chan]; // Copy sample into correct position in the output buffer
- }
-}
-
-void CWin32ChannelRemap::MapData24(unsigned char* pData, unsigned int len, unsigned char* pOut)
-{
- unsigned char* pOutFrame = pOut;
- for (unsigned char* pInFrame = pData; pInFrame < pData + (len / sizeof(unsigned char)); pInFrame += m_uiChannels*3, pOutFrame += m_uiChannels*3)
- {
- // Remap a single frame
- for (unsigned int chan = 0; chan < m_uiChannels; chan++)
- {
- pOutFrame[m_pChannelMap[chan]*3] = pInFrame[chan*3]; // Copy sample into correct position in the output buffer
- pOutFrame[(m_pChannelMap[chan]*3)+1] = pInFrame[(chan*3)+1];
- pOutFrame[(m_pChannelMap[chan]*3)+2] = pInFrame[(chan*3)+2];
- }
- }
-}
-
-void CWin32ChannelRemap::MapData32(unsigned char* pData, unsigned int len, unsigned char* pOut)
-{
- int* pOutFrame = (int*)pOut;
- for (int* pInFrame = (int*)pData; pInFrame < (int*)pData + (len / sizeof(int)); pInFrame += m_uiChannels, pOutFrame += m_uiChannels)
- {
- // Remap a single frame
- for (unsigned int chan = 0; chan < m_uiChannels; chan++)
- pOutFrame[m_pChannelMap[chan]] = pInFrame[chan]; // Copy sample into correct position in the output buffer
- }
-}
View
54 xbmc/cores/AudioRenderers/Win32ChannelRemap.h
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2005-2009 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#ifndef __WIN32CHANNELREMAP_H__
-#define __WIN32CHANNELREMAP_H__
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-class CWin32ChannelRemap
-{
-public:
-
- CWin32ChannelRemap();
- ~CWin32ChannelRemap();
-
-protected:
-
- void SetChannelMap(unsigned int channels, unsigned int bitsPerSample, bool passthrough, const char* strAudioCodec);
- void MapDataIntoBuffer(unsigned char* pData, unsigned int len, unsigned char* pOut);
-
-private:
-
- void MapData8(unsigned char* pData, unsigned int len, unsigned char* pOut);
- void MapData16(unsigned char* pData, unsigned int len, unsigned char* pOut);
- void MapData24(unsigned char* pData, unsigned int len, unsigned char* pOut);
- void MapData32(unsigned char* pData, unsigned int len, unsigned char* pOut);
-
- const unsigned char* m_pChannelMap;
- unsigned int m_uiChannels;
- unsigned int m_uiBitsPerSample;
- bool m_bPassthrough;
-};
-
-#endif // __WIN32CHANNELREMAP_H__
View
113 xbmc/cores/AudioRenderers/Win32DirectSound.cpp
@@ -47,7 +47,11 @@ const int dsound_channel_mask[] =
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY
};
+const int dsound_channel_order[] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_FRONT_LEFT_OF_CENTER, PCM_FRONT_RIGHT_OF_CENTER, PCM_BACK_CENTER, PC
+M_SIDE_LEFT, PCM_SIDE_RIGHT};
+
#define DSOUND_CHANNEL_MASK_COUNT 8
+#define DSOUND_TOTAL_CHANNELS 11
static BOOL CALLBACK DSEnumCallback(LPGUID lpGuid, LPCTSTR lpcstrDescription, LPCTSTR lpcstrModule, LPVOID lpContext)
{
@@ -72,12 +76,11 @@ CWin32DirectSound::CWin32DirectSound() :
m_dwChunkSize(0),
m_dwBufferLen(0),
m_PreCacheSize(0),
- m_LastCacheCheck(0),
- m_pChannelMap(NULL)
+ m_LastCacheCheck(0)
{
}
-bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bAudioPassthrough)
+bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bAudioPassthrough)
{
if(iChannels > DSOUND_CHANNEL_MASK_COUNT)
{
@@ -85,6 +88,16 @@ bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString&
return false;
}
+ //If there is a listing of required channels, build the speaker mask and mapping from that.
+ //Otherwise, use the default.
+ if(channelMap)
+ BuildChannelMapping(iChannels, channelMap);
+ else
+ m_uiSpeakerMask = dsound_channel_mask[iChannels - 1];
+
+ m_remap.SetInputFormat (iChannels, channelMap, uiBitsPerSample / 8);
+ m_remap.SetOutputFormat(iChannels, m_SpeakerOrder);
+
bool bAudioOnAllSpeakers(false);
g_audioContext.SetupSpeakerConfig(iChannels, bAudioOnAllSpeakers, bIsMusic);
if(bAudioPassthrough)
@@ -120,7 +133,7 @@ bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString&
}
else
{
- wfxex.dwChannelMask = dsound_channel_mask[iChannels - 1];
+ wfxex.dwChannelMask = m_uiSpeakerMask;
if (iChannels > 2)
wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
@@ -137,6 +150,8 @@ bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString&
m_AvgBytesPerSec = wfxex.Format.nAvgBytesPerSec;
+ m_uiBytesPerFrame = wfxex.Format.nBlockAlign;
+
// unsure if these are the right values
m_dwChunkSize = wfxex.Format.nBlockAlign * 3096;
m_PreCacheSize = m_dwChunkSize;
@@ -185,9 +200,6 @@ bool CWin32DirectSound::Initialize(IAudioCallback* pCallback, const CStdString&
}
CLog::Log(LOGDEBUG, __FUNCTION__": secondary buffer created");
- // Set up channel mapping
- SetChannelMap(iChannels, uiBitsPerSample, bAudioPassthrough, strAudioCodec);
-
m_pBuffer->Stop();
if (DSERR_CONTROLUNAVAIL == m_pBuffer->SetVolume(g_settings.m_nVolumeLevel))
@@ -327,12 +339,20 @@ unsigned int CWin32DirectSound::AddPackets(const void* data, unsigned int len)
break;
}
- // Write data into the buffer
- MapDataIntoBuffer(pBuffer, size, (unsigned char*)start);
+ // Remap the data to the correct channels into the buffer
+ if (m_remap.CanRemap())
+ m_remap.Remap((void*)pBuffer, start, size / m_uiBytesPerFrame);
+ else
+ memcpy(start, pBuffer, size);
+
m_BufferOffset += size;
if (startWrap) // Write-region wraps to beginning of buffer
{
- MapDataIntoBuffer(pBuffer + size, sizeWrap, (unsigned char*)startWrap);
+ // Remap the data to the correct channels into the buffer
+ if (m_remap.CanRemap())
+ m_remap.Remap((void*)(pBuffer + size), startWrap, sizeWrap / m_uiBytesPerFrame);
+ else
+ memcpy(startWrap, pBuffer + size, sizeWrap);
m_BufferOffset = sizeWrap;
}
@@ -563,3 +583,76 @@ char * CWin32DirectSound::dserr2str(int err)
default: return "unknown";
}
}
+
+//***********************************************************************************************
+void CWin32DirectSound::BuildChannelMapping(int channels, int8_t* map)
+{
+ bool usedChannels[DSOUND_TOTAL_CHANNELS];
+
+ memset(usedChannels, false, sizeof(usedChannels));
+
+ m_uiSpeakerMask = 0;
+
+ //Build the speaker mask and note which are used.
+ for(int i = 0; i < channels; i++)
+ {
+ switch(map[i])
+ {
+ case PCM_FRONT_LEFT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_LEFT;
+ break;
+ case PCM_FRONT_RIGHT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_RIGHT;
+ break;
+ case PCM_FRONT_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_CENTER;
+ break;
+ case PCM_LOW_FREQUENCY:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_LOW_FREQUENCY;
+ break;
+ case PCM_BACK_LEFT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_BACK_LEFT;
+ break;
+ case PCM_BACK_RIGHT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_BACK_RIGHT;
+ break;
+ case PCM_FRONT_LEFT_OF_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_LEFT_OF_CENTER;
+ break;
+ case PCM_FRONT_RIGHT_OF_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_RIGHT_OF_CENTER;
+ break;
+ case PCM_BACK_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_BACK_CENTER;
+ break;
+ case PCM_SIDE_LEFT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_SIDE_LEFT;
+ break;
+ case PCM_SIDE_RIGHT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_SIDE_RIGHT;
+ break;
+ }
+ }
+
+ //Assemble a compacted channel set.
+ for(int i = 0, j = 0; i < DSOUND_TOTAL_CHANNELS; i++)
+ {
+ if(usedChannels[i])
+ {
+ m_SpeakerOrder[j] = dsound_channel_order[i];
+ j++;
+ }
+ }
+}
+
View
10 xbmc/cores/AudioRenderers/Win32DirectSound.h
@@ -30,13 +30,12 @@
#endif // _MSC_VER > 1000
#include "IAudioRenderer.h"
-#include "Win32ChannelRemap.h"
#include "utils/CriticalSection.h"
extern void RegisterAudioCallback(IAudioCallback* pCallback);
extern void UnRegisterAudioCallback();
-class CWin32DirectSound : private CWin32ChannelRemap, public IAudioRenderer
+class CWin32DirectSound : public IAudioRenderer
{
public:
virtual void UnRegisterAudioCallback();
@@ -46,7 +45,7 @@ class CWin32DirectSound : private CWin32ChannelRemap, public IAudioRenderer
virtual float GetCacheTime();
virtual float GetCacheTotal();
CWin32DirectSound();
- virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
+ virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, int8_t* channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bPassthrough = false);
virtual ~CWin32DirectSound();
virtual unsigned int AddPackets(const void* data, unsigned int len);
@@ -68,6 +67,7 @@ class CWin32DirectSound : private CWin32ChannelRemap, public IAudioRenderer
private:
void UpdateCacheStatus();
void CheckPlayStatus();
+ void BuildChannelMapping(int channels, int8_t* map);
LPDIRECTSOUNDBUFFER m_pBuffer;
LPDIRECTSOUND8 m_pDSound;
@@ -85,6 +85,9 @@ class CWin32DirectSound : private CWin32ChannelRemap, public IAudioRenderer
unsigned int m_uiBitsPerSample;
unsigned int m_uiChannels;
unsigned int m_AvgBytesPerSec;
+ unsigned int m_uiBytesPerFrame;
+ unsigned int m_uiSpeakerMask;
+ int8_t m_SpeakerOrder[8];
char * dserr2str(int err);
@@ -94,7 +97,6 @@ class CWin32DirectSound : private CWin32ChannelRemap, public IAudioRenderer
unsigned int m_LastCacheCheck;
size_t m_PreCacheSize;
- unsigned char* m_pChannelMap;
CCriticalSection m_critSection;
};
View
99 xbmc/cores/AudioRenderers/Win32WASAPI.cpp
@@ -57,7 +57,10 @@ const int wasapi_channel_mask[] =
SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT | SPEAKER_LOW_FREQUENCY
};
+const int wasapi_channel_order[] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_FRONT_LEFT_OF_CENTER, PCM_FRONT_RIGHT_OF_CENTER, PCM_BACK_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT};
+
#define WASAPI_CHANNEL_MASK_COUNT 8
+#define WASAPI_TOTAL_CHANNELS 11
#define EXIT_ON_FAILURE(hr, reason, ...) if(FAILED(hr)) {CLog::Log(LOGERROR, reason, __VA_ARGS__); goto failed;}
@@ -82,7 +85,7 @@ CWin32WASAPI::CWin32WASAPI() :
{
}
-bool CWin32WASAPI::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bAudioPassthrough)
+bool CWin32WASAPI::Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, uint8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bAudioPassthrough)
{
//First check if the version of Windows we are running on even supports WASAPI.
OSVERSIONINFO winVersion;
@@ -96,6 +99,16 @@ bool CWin32WASAPI::Initialize(IAudioCallback* pCallback, const CStdString& devic
return false;
}
+ //If there is a listing of required channels, build the speaker mask and mapping from that.
+ //Otherwise, use the default.
+ if(channelMap)
+ BuildChannelMapping(iChannels, channelMap);
+ else
+ m_uiSpeakerMask = wasapi_channel_mask[iChannels-1];
+
+ m_remap.SetInputFormat (iChannels, channelMap, uiBitsPerSample / 8);
+ m_remap.SetOutputFormat(iChannels, m_SpeakerOrder);
+
//Only one exclusive stream may be initialized at one time.
if(m_bIsAllocated)
{
@@ -137,7 +150,7 @@ bool CWin32WASAPI::Initialize(IAudioCallback* pCallback, const CStdString& devic
}
else
{
- wfxex.dwChannelMask = wasapi_channel_mask[iChannels - 1];
+ wfxex.dwChannelMask = m_uiSpeakerMask;
wfxex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
wfxex.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
wfxex.Format.wBitsPerSample = uiBitsPerSample == 24 ? 32 : uiBitsPerSample;
@@ -251,9 +264,6 @@ bool CWin32WASAPI::Initialize(IAudioCallback* pCallback, const CStdString& devic
hr = m_pAudioClient->GetService(IID_IAudioRenderClient, (void**)&m_pRenderClient);
EXIT_ON_FAILURE(hr, __FUNCTION__": Could not initialize the WASAPI render client interface.")
- // Set up channel mapping
- SetChannelMap(iChannels, uiBitsPerSample, bAudioPassthrough, strAudioCodec);
-
m_bIsAllocated = true;
m_CacheLen = 0;
m_LastCacheCheck = CTimeUtils::GetTimeMS();
@@ -657,7 +667,11 @@ void CWin32WASAPI::AddDataToBuffer(unsigned char* pData, unsigned int len, unsig
}
}
- MapDataIntoBuffer(pData, len, pOut);
+ // Remap the data to the correct channels
+ if (m_remap.CanRemap())
+ m_remap.Remap((void*)pData, pOut, len / m_uiBytesPerFrame);
+ else
+ memcpy(pOut, pData, len);
}
//***********************************************************************************************
@@ -665,3 +679,76 @@ void CWin32WASAPI::SwitchChannels(int iAudioStream, bool bAudioOnAllSpeakers)
{
return;
}
+
+//***********************************************************************************************
+void CWin32WASAPI::BuildChannelMapping(int channels, uint8_t* map)
+{
+ bool usedChannels[WASAPI_TOTAL_CHANNELS];
+
+ memset(usedChannels, false, sizeof(usedChannels));
+
+ m_uiSpeakerMask = 0;
+
+ //Build the speaker mask and note which are used.
+ for(int i = 0; i < channels; i++)
+ {
+ switch(map[i])
+ {
+ case PCM_FRONT_LEFT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_LEFT;
+ break;
+ case PCM_FRONT_RIGHT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_RIGHT;
+ break;
+ case PCM_FRONT_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_CENTER;
+ break;
+ case PCM_LOW_FREQUENCY:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_LOW_FREQUENCY;
+ break;
+ case PCM_BACK_LEFT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_BACK_LEFT;
+ break;
+ case PCM_BACK_RIGHT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_BACK_RIGHT;
+ break;
+ case PCM_FRONT_LEFT_OF_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_LEFT_OF_CENTER;
+ break;
+ case PCM_FRONT_RIGHT_OF_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_FRONT_RIGHT_OF_CENTER;
+ break;
+ case PCM_BACK_CENTER:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_BACK_CENTER;
+ break;
+ case PCM_SIDE_LEFT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_SIDE_LEFT;
+ break;
+ case PCM_SIDE_RIGHT:
+ usedChannels[map[i]] = true;
+ m_uiSpeakerMask |= SPEAKER_SIDE_RIGHT;
+ break;
+ }
+ }
+
+ //Assemble a compacted channel set.
+ for(int i = 0, j = 0; i < WASAPI_TOTAL_CHANNELS; i++)
+ {
+ if(usedChannels[i])
+ {
+ m_SpeakerOrder[j] = wasapi_channel_order[i];
+ j++;
+ }
+ }
+}
+
View
8 xbmc/cores/AudioRenderers/Win32WASAPI.h
@@ -29,14 +29,13 @@
#include "IAudioRenderer.h"
#include "utils/CriticalSection.h"
-#include "Win32ChannelRemap.h"
#include <mmdeviceapi.h>
#include <Audioclient.h>
extern void RegisterAudioCallback(IAudioCallback* pCallback);
extern void UnRegisterAudioCallback();
-class CWin32WASAPI : private CWin32ChannelRemap, public IAudioRenderer
+class CWin32WASAPI : public IAudioRenderer
{
public:
CWin32WASAPI();
@@ -47,7 +46,7 @@ class CWin32WASAPI : private CWin32ChannelRemap, public IAudioRenderer
virtual float GetDelay();
virtual float GetCacheTime();
virtual float GetCacheTotal();
- virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bAudioPassthrough=false);
+ virtual bool Initialize(IAudioCallback* pCallback, const CStdString& device, int iChannels, uint8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec = "", bool bIsMusic=false, bool bAudioPassthrough=false);
virtual unsigned int AddPackets(const void* data, unsigned int len);
virtual unsigned int GetSpace();
@@ -69,6 +68,7 @@ class CWin32WASAPI : private CWin32ChannelRemap, public IAudioRenderer
void AddDataToBuffer(unsigned char* pData, unsigned int len, unsigned char* pOut);
void UpdateCacheStatus();
void CheckPlayStatus();
+ void BuildChannelMapping(int channels, uint8_t* map);
IMMDevice* m_pDevice;
IAudioClient* m_pAudioClient;
@@ -85,6 +85,8 @@ class CWin32WASAPI : private CWin32ChannelRemap, public IAudioRenderer
unsigned int m_uiBitsPerSample;
unsigned int m_uiChannels;
unsigned int m_uiAvgBytesPerSec;
+ unsigned int m_uiSpeakerMask;
+ uint8_t m_SpeakerOrder[8];
static bool m_bIsAllocated;
bool m_bPlaying;
View
4 xbmc/cores/dvdplayer/DVDAudio.cpp
@@ -92,7 +92,7 @@ bool CDVDAudio::Create(const DVDAudioFrame &audioframe, CodecID codec)
else
codecstring = "PCM";
- m_pAudioDecoder = CAudioRendererFactory::Create(m_pCallback, audioframe.channels, audioframe.sample_rate, audioframe.bits_per_sample, false, codecstring, false, audioframe.passthrough);
+ m_pAudioDecoder = CAudioRendererFactory::Create(m_pCallback, audioframe.channels, audioframe.channel_map, audioframe.sample_rate, audioframe.bits_per_sample, false, codecstring, false, audioframe.passthrough);
if (!m_pAudioDecoder) return false;
@@ -345,4 +345,4 @@ double CDVDAudio::GetCacheTotal()
if(!m_pAudioDecoder)
return 0.0;
return m_pAudioDecoder->GetCacheTotal();
-}
+}
View
6 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
@@ -22,6 +22,7 @@
*/
#include "system.h"
+#include "../../../../utils/PCMRemap.h"
#if (defined HAVE_CONFIG_H) && (!defined WIN32)
#include "config.h"
@@ -90,6 +91,11 @@ class CDVDAudioCodec
virtual int GetChannels() = 0;
/*
+ * returns the channel mapping
+ */
+ virtual int8_t* GetChannelMap() = 0;
+
+ /*
* returns the samplerate for the decoded audio stream
*/
virtual int GetSampleRate() = 0;
View
48 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
@@ -90,6 +90,12 @@ bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options
m_pCodecContext->request_channels = 2;
}
+ if(g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
+ {
+ m_pCodecContext->request_channel_layout = CH_LAYOUT_STEREO;
+ m_pCodecContext->channels = 2;
+ }
+
if( hints.extradata && hints.extrasize > 0 )
{
m_pCodecContext->extradata_size = hints.extrasize;
@@ -246,3 +252,45 @@ int CDVDAudioCodecFFmpeg::GetBitsPerSample()
{
return 16;
}
+
+int8_t* CDVDAudioCodecFFmpeg::GetChannelMap()
+{
+ static int8_t map[14][8] =
+ {
+ {/* MONO */ PCM_FRONT_CENTER },
+ {/* STEREO */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT },
+ {/* 2_1 */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_CENTER },
+ {/* SURROUND */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER },
+ {/* 4POINT0 */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_CENTER },
+ {/* 2_2 */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* QUAD */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT , PCM_BACK_RIGHT },
+ {/* 5POINT0 */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* 5POINT1 */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* 5POINT0_BACK */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT , PCM_BACK_RIGHT },
+ {/* 5POINT1_BACK */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT , PCM_BACK_RIGHT },
+ {/* 7POINT0 */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT , PCM_BACK_RIGHT, PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* 7POINT1 */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT , PCM_BACK_RIGHT, PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* 7POINT1_WIDE */ PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_BACK_LEFT , PCM_BACK_RIGHT, PCM_FRONT_LEFT_OF_CENTER , PCM_FRONT_RIGHT_OF_CENTER}
+ };
+
+ switch(m_pCodecContext->channel_layout &~ CH_LAYOUT_STEREO_DOWNMIX)
+ {
+ case CH_LAYOUT_MONO : return map[ 0];
+ case CH_LAYOUT_STEREO : return map[ 1];
+ case CH_LAYOUT_2_1 : return map[ 2];
+ case CH_LAYOUT_SURROUND : return map[ 3];
+ case CH_LAYOUT_4POINT0 : return map[ 4];
+ case CH_LAYOUT_2_2 : return map[ 5];
+ case CH_LAYOUT_QUAD : return map[ 6];
+ case CH_LAYOUT_5POINT0 : return map[ 7];
+ case CH_LAYOUT_5POINT1 : return map[ 8];
+ case CH_LAYOUT_5POINT0_BACK: return map[ 9];
+ case CH_LAYOUT_5POINT1_BACK: return map[10];
+ case CH_LAYOUT_7POINT0 : return map[11];
+ case CH_LAYOUT_7POINT1 : return map[12];
+ case CH_LAYOUT_7POINT1_WIDE: return map[13];
+ default:
+ return NULL;
+ }
+}
+
View
1  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
@@ -36,6 +36,7 @@ class CDVDAudioCodecFFmpeg : public CDVDAudioCodec
virtual int GetData(BYTE** dst);
virtual void Reset();
virtual int GetChannels();
+ virtual int8_t *GetChannelMap();
virtual int GetSampleRate();
virtual int GetBitsPerSample();
virtual const char* GetName() { return "FFmpeg"; }
View
203 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.cpp
@@ -39,112 +39,26 @@ static inline int16_t convert(int32_t i)
return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i);
}
-void CDVDAudioCodecLibDts::convert2s16_multi(convert_t * _f, int16_t * s16, int flags)
+/**
+ * \brief Function to convert the "planar" float format used by libdts
+ * into the interleaved int16 format used by us.
+ * \param in the input buffer containing the planar samples.
+ * \param out the output buffer where the interleaved result is stored.
+ * \param channels the total number of channels in the decoded data
+ */
+static int resample_int16(sample_t * in, int16_t *out, unsigned int channels)
{
- register int i;
- register int32_t * f = (int32_t *) _f;
-
- switch (flags)
- {
- case DTS_MONO:
- for (i = 0; i < 256; i++)
- {
- s16[2*i ] = convert (f[i]);
- s16[2*i+1] = convert (f[i]);
- }
- break;
- case DTS_CHANNEL:
- case DTS_STEREO:
- case DTS_DOLBY:
- for (i = 0; i < 256; i++)
- {
- s16[2*i ] = convert (f[i]);
- s16[2*i+1] = convert (f[i+256]);
- }
- break;
- case DTS_3F:
- for (i = 0; i < 256; i++)
- {
- s16[6*i ] = convert (f[i+256]);
- s16[6*i+1] = convert (f[i+512]);
- s16[6*i+2] = 0;
- s16[6*i+3] = 0;
- s16[6*i+4] = convert (f[i]);
- s16[6*i+4] = 0;
- }
- break;
- case DTS_2F2R:
- for (i = 0; i < 256; i++)
- {
- s16[4*i ] = convert (f[i]);
- s16[4*i+1] = convert (f[i+256]);
- s16[4*i+2] = convert (f[i+512]);
- s16[4*i+3] = convert (f[i+768]);
- }
- break;
- case DTS_3F2R:
- for (i = 0; i < 256; i++)
- {
- s16[6*i ] = convert (f[i]);
- s16[6*i+1] = convert (f[i+256]);
- s16[6*i+2] = convert (f[i+512]);
- s16[6*i+3] = convert (f[i+768]);
- s16[6*i+4] = convert (f[i+1024]);
- s16[6*i+5] = 0;
- }
- break;
- case DTS_MONO | DTS_LFE:
- for (i = 0; i < 256; i++)
- {
- s16[6*i ] = s16[6*i+1] = s16[6*i+2] = s16[6*i+3] = 0;
- s16[6*i+4] = convert (f[i]);
- s16[6*i+5] = convert (f[i+256]);
- }
- break;
- case DTS_CHANNEL | DTS_LFE:
- case DTS_STEREO | DTS_LFE:
- case DTS_DOLBY | DTS_LFE:
- for (i = 0; i < 256; i++)
- {
- s16[6*i ] = convert (f[i]);
- s16[6*i+1] = convert (f[i+256]);
- s16[6*i+2] = s16[6*i+3] = s16[6*i+4] = 0;
- s16[6*i+5] = convert (f[i+512]);
- }
- break;
- case DTS_3F | DTS_LFE:
- for (i = 0; i < 256; i++)
- {
- s16[6*i ] = convert (f[i+256]);
- s16[6*i+1] = convert (f[i+512]);
- s16[6*i+2] = s16[6*i+3] = 0;
- s16[6*i+4] = convert (f[i]);
- s16[6*i+5] = convert (f[i+768]);
- }
- break;
- case DTS_2F2R | DTS_LFE:
- for (i = 0; i < 256; i++)
- {
- s16[6*i ] = convert (f[i]);
- s16[6*i+1] = convert (f[i+256]);
- s16[6*i+2] = convert (f[i+512]);
- s16[6*i+3] = convert (f[i+768]);
- s16[6*i+4] = 0;
- s16[6*i+5] = convert (f[i+1024]);
- }
- break;
- case DTS_3F2R | DTS_LFE:
- for (i = 0; i < 256; i++)
+ unsigned int i, ch;
+ int16_t *p = out;
+ for(i = 0; i < 256; ++i)
+ {
+ for(ch = 0; ch < channels; ++ch)
{
- s16[6*i ] = convert (f[i+256]);
- s16[6*i+1] = convert (f[i+512]);
- s16[6*i+2] = convert (f[i+768]);
- s16[6*i+3] = convert (f[i+1024]);
- s16[6*i+4] = convert (f[i]);
- s16[6*i+5] = convert (f[i+1280]);
+ *p = convert( ((int32_t*)in)[i + (ch << 8)] );
+ ++p;
}
- break;
- }
+ }
+ return p - out;
}
CDVDAudioCodecLibDts::CDVDAudioCodecLibDts() : CDVDAudioCodec()
@@ -186,34 +100,68 @@ void CDVDAudioCodecLibDts::Dispose()
m_pState = NULL;
}
-int CDVDAudioCodecLibDts::GetNrOfChannels(int iFlags)
-{
- if(iFlags & DTS_LFE)
- return 6;
- if(iFlags & DTS_CHANNEL)
- return 6;
- else if ((iFlags & DTS_CHANNEL_MASK) == DTS_2F2R)
- return 4;
- else
- return 2;
-}
-
void CDVDAudioCodecLibDts::SetupChannels(int flags)
{
- m_iSourceFlags = flags;
- m_iSourceChannels = GetNrOfChannels(flags);
+ /* These are channel mappings that libdts outputs */
+ static int8_t channelMaps[14][6] =
+ {
+ /* Without LFE */
+ {/* DTS_MONO */ PCM_FRONT_CENTER },
+ {/* DTS_STEREO */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT },
+ {/* DTS_3F */ PCM_FRONT_CENTER, PCM_FRONT_LEFT , PCM_FRONT_RIGHT },
+ {/* DTS_2F1R */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_BACK_CENTER },
+ {/* DTS_3F1R */ PCM_FRONT_CENTER, PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_BACK_CENTER },
+ {/* DTS_2F2R */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* DTS_3F2R */ PCM_FRONT_CENTER, PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ /* With LFE */
+ {/* DTS_MONO */ PCM_FRONT_CENTER, PCM_LOW_FREQUENCY },
+ {/* DTS_STEREO */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_LOW_FREQUENCY },
+ {/* DTS_3F */ PCM_FRONT_CENTER, PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_LOW_FREQUENCY },
+ {/* DTS_2F1R */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_BACK_CENTER },
+ {/* DTS_3F1R */ PCM_FRONT_CENTER, PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_BACK_CENTER, PCM_LOW_FREQUENCY },
+ {/* DTS_2F2R */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_SIDE_LEFT , PCM_SIDE_RIGHT , PCM_LOW_FREQUENCY },
+ {/* DTS_3F2R */ PCM_FRONT_CENTER, PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_SIDE_LEFT , PCM_SIDE_RIGHT , PCM_LOW_FREQUENCY},
+ };
+
+ m_iSourceFlags = flags;
+
+ // setup channel map
+ int channels = 0;
+ int chOffset = (flags & DTS_LFE) ? 7 : 0;
+ switch (m_iSourceFlags &~ DTS_LFE)
+ {
+ case DTS_MONO : m_pChannelMap = channelMaps[chOffset + 0]; channels = 1; break;
+ case DTS_CHANNEL:
+ case DTS_DOLBY :
+ case DTS_STEREO : m_pChannelMap = channelMaps[chOffset + 1]; channels = 2; break;
+ case DTS_3F : m_pChannelMap = channelMaps[chOffset + 2]; channels = 3; break;
+ case DTS_2F1R : m_pChannelMap = channelMaps[chOffset + 3]; channels = 3; break;
+ case DTS_3F1R : m_pChannelMap = channelMaps[chOffset + 4]; channels = 4; break;
+ case DTS_2F2R : m_pChannelMap = channelMaps[chOffset + 5]; channels = 4; break;
+ case DTS_3F2R : m_pChannelMap = channelMaps[chOffset + 6]; channels = 5; break;
+ default : m_pChannelMap = NULL; break;
+ }
+
+ if(m_pChannelMap == NULL)
+ CLog::Log(LOGERROR, "CDVDAudioCodecLibDts::SetupChannels - Invalid channel mapping");
+
+ if(m_iSourceChannels > 0 && m_iSourceChannels != channels)
+ CLog::Log(LOGINFO, "%s - Number of channels changed in stream from %d to %d, data might be truncated", __FUNCTION__, m_iOutputChannels, channels);
+
+ m_iSourceChannels = channels;
+ m_iOutputChannels = m_iSourceChannels;
+ m_iOutputFlags = m_iSourceFlags;
+
+ // If we can't support multichannel output downmix
if (g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
+ {
m_iOutputChannels = 2;
- else
- m_iOutputChannels = m_iSourceChannels;
-
- if (m_iOutputChannels == 1)
- m_iOutputFlags = DTS_MONO;
- else if (m_iOutputChannels == 2)
- m_iOutputFlags = DTS_STEREO;
- else
- m_iOutputFlags = m_iSourceFlags;
+ m_pChannelMap = channelMaps[1];
+ m_iOutputFlags = DTS_STEREO;
+ }
+ /* adjust level should always be set, to keep samples in proper range */
+ /* after any downmixing has been done */
m_iOutputFlags |= DTS_ADJUST_LEVEL;
}
@@ -332,8 +280,7 @@ int CDVDAudioCodecLibDts::Decode(BYTE* pData, int iSize)
CLog::Log(LOGERROR, "CDVDAudioCodecLibDts::Decode : dts_block != 0");
break;
}
- convert2s16_multi(m_fSamples, (int16_t*)(m_decodedData + m_decodedSize), flags & (DTS_CHANNEL_MASK | DTS_LFE));
- m_decodedSize += 2 * 256 * m_iOutputChannels;
+ m_decodedSize += 2*resample_int16(m_fSamples, (int16_t*)(m_decodedData + m_decodedSize), m_iOutputChannels);
}
return len;
View
13 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h
@@ -37,15 +37,15 @@ class CDVDAudioCodecLibDts : public CDVDAudioCodec
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iOutputChannels; }
- virtual int GetSampleRate() { return m_iSourceSampleRate; }
- virtual int GetBufferSize() { return m_inputSize; }
- virtual int GetBitsPerSample() { return 16; }
- virtual const char* GetName() { return "libdts"; }
+ virtual int GetChannels() { return m_iOutputChannels; }
+ virtual int8_t *GetChannelMap() { return m_pChannelMap; }
+ virtual int GetSampleRate() { return m_iSourceSampleRate; }
+ virtual int GetBufferSize() { return m_inputSize; }
+ virtual int GetBitsPerSample() { return 16; }
+ virtual const char* GetName() { return "libdts"; }
protected:
void SetDefault();
- int GetNrOfChannels(int flags);
void SetupChannels(int flags);
int ParseFrame(BYTE* data, int size, BYTE** frame, int* framesize);
@@ -64,6 +64,7 @@ class CDVDAudioCodecLibDts : public CDVDAudioCodec
int m_iOutputFlags;
int m_iOutputChannels;
+ uint8_t *m_pChannelMap;
DllLibDts m_dll;
View
22 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp
@@ -103,6 +103,26 @@ bool CDVDAudioCodecLibFaad::SyncStream()
return false;
}
+int8_t* CDVDAudioCodecLibFaad::GetChannelMap()
+{
+ for(int i = 0; i < m_iSourceChannels; ++i)
+ {
+ switch(m_frameInfo.channel_position[i])
+ {
+ case FRONT_CHANNEL_CENTER: m_pChannelMap[i] = PCM_FRONT_CENTER ; break;
+ case FRONT_CHANNEL_LEFT : m_pChannelMap[i] = PCM_FRONT_LEFT ; break;
+ case FRONT_CHANNEL_RIGHT : m_pChannelMap[i] = PCM_FRONT_RIGHT ; break;
+ case SIDE_CHANNEL_LEFT : m_pChannelMap[i] = PCM_SIDE_LEFT ; break;
+ case SIDE_CHANNEL_RIGHT : m_pChannelMap[i] = PCM_SIDE_RIGHT ; break;
+ case BACK_CHANNEL_LEFT : m_pChannelMap[i] = PCM_BACK_LEFT ; break;
+ case BACK_CHANNEL_RIGHT : m_pChannelMap[i] = PCM_BACK_RIGHT ; break;
+ case BACK_CHANNEL_CENTER : m_pChannelMap[i] = PCM_BACK_CENTER ; break;
+ case LFE_CHANNEL : m_pChannelMap[i] = PCM_LOW_FREQUENCY; break;
+ }
+ }
+ return m_pChannelMap;
+}
+
int CDVDAudioCodecLibFaad::Decode(BYTE* pData, int iSize)
{
m_DecodedDataSize = 0;
@@ -227,7 +247,7 @@ bool CDVDAudioCodecLibFaad::OpenDecoder()
// modify some stuff here
pConfiguration->outputFormat = FAAD_FMT_16BIT; // already default
- pConfiguration->downMatrix = g_guiSettings.GetBool("audiooutput.downmixmultichannel") ? 1 : 0;
+ pConfiguration->downMatrix = g_guiSettings.GetBool("audiooutput.downmixmultichannel") ? 1 : 0;
m_dll.faacDecSetConfiguration(m_pHandle, pConfiguration);
View
12 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h
@@ -37,11 +37,12 @@ class CDVDAudioCodecLibFaad : public CDVDAudioCodec
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iSourceChannels; }
- virtual int GetSampleRate() { return m_iSourceSampleRate; }
- virtual int GetBitsPerSample() { return 16; }
- virtual const char* GetName() { return "libfaad"; }
- virtual int GetBufferSize() { return m_InputBufferSize; }
+ virtual int GetChannels() { return m_iSourceChannels; }
+ virtual int8_t* GetChannelMap();
+ virtual int GetSampleRate() { return m_iSourceSampleRate; }
+ virtual int GetBitsPerSample() { return 16; }
+ virtual const char* GetName() { return "libfaad"; }
+ virtual int GetBufferSize() { return m_InputBufferSize; }
private:
@@ -52,6 +53,7 @@ class CDVDAudioCodecLibFaad : public CDVDAudioCodec
int m_iSourceSampleRate;
int m_iSourceChannels;
+ int8_t m_pChannelMap[64];
int m_iSourceBitrate;
bool m_bInitializedDecoder;
View
11 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h
@@ -37,11 +37,12 @@ class CDVDAudioCodecLibMad : public CDVDAudioCodec
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iSourceChannels; }
- virtual int GetSampleRate() { return m_iSourceSampleRate; }
- virtual int GetBitsPerSample() { return 16; }
- virtual const char* GetName() { return "libmad"; }
- virtual int GetBufferSize() { return m_iInputBufferSize; }
+ virtual int GetChannels() { return m_iSourceChannels; }
+ virtual int8_t* GetChannelMap() { static int8_t map[2] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT}; return map; }
+ virtual int GetSampleRate() { return m_iSourceSampleRate; }
+ virtual int GetBitsPerSample() { return 16; }
+ virtual const char* GetName() { return "libmad"; }
+ virtual int GetBufferSize() { return m_iInputBufferSize; }
private:
View
130 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.cpp
@@ -49,23 +49,21 @@ static inline int16_t convert(int32_t i)
* into the interleaved int16 format used by us.
* \param in the input buffer containing the planar samples.
* \param out the output buffer where the interleaved result is stored.
+ * \param channels the total number of channels in the decoded data
*/
-static int resample_int16(sample_t * in, int16_t *out, int32_t channel_map)
+static int resample_int16(sample_t * in, int16_t *out, unsigned int channels)
{
- unsigned long i;
+ unsigned int i, ch;
int16_t *p = out;
- for (i = 0; i != 256; i++) {
- unsigned long map = channel_map;
- do {
- unsigned long ch = map & 15;
- if (ch == 15)
- *p = 0;
- else
- *p = convert( ((int32_t*)in)[i + ((ch-1)<<8)] );
- p++;
- } while ((map >>= 4));
+ for(i = 0; i < 256; ++i)
+ {
+ for(ch = 0; ch < channels; ++ch)
+ {
+ *p = convert( ((int32_t*)in)[i + (ch << 8)] );
+ ++p;
+ }
}
- return (int16_t*) p - out;
+ return p - out;
}
@@ -111,77 +109,55 @@ void CDVDAudioCodecLiba52::Dispose()
void CDVDAudioCodecLiba52::SetupChannels(int flags)
{
-/* Internal AC3 ordering for different configs
- * A52_CHANNEL: 1+1 2 Ch1, Ch2
- * A52_MONO : 1/0 1 C
- * A52_STEREO : 2/0 2 L, R
- * A52_3F : 3/0 3 L, C, R
- * A52_2F1R : 2/1 3 L, R, S
- * A52_3F1R : 3/1 4 L, C, R, S
- * A52_2F2R : 2/2 4 L, R, SL, SR
- * A52_3F2R : 3/2 5 L, C, R, SL, SR
-*/
+ /* These are channel mappings that liba52 outputs */
+ static int8_t channelMaps[14][6] =
+ {
+ /* Without LFE */
+ {/* A52_MONO */ PCM_FRONT_CENTER },
+ {/* A52_STEREO */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT },
+ {/* A52_3F */ PCM_FRONT_LEFT , PCM_FRONT_CENTER , PCM_FRONT_RIGHT },
+ {/* A52_2F1R */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_BACK_CENTER },
+ {/* A52_3F1R */ PCM_FRONT_LEFT , PCM_FRONT_CENTER , PCM_FRONT_RIGHT, PCM_BACK_CENTER },
+ {/* A52_2F2R */ PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* A52_3F2R */ PCM_FRONT_LEFT , PCM_FRONT_CENTER , PCM_FRONT_RIGHT, PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ /* With LFE */
+ {/* A52_MONO */ PCM_LOW_FREQUENCY, PCM_FRONT_CENTER },
+ {/* A52_STEREO */ PCM_LOW_FREQUENCY, PCM_FRONT_LEFT , PCM_FRONT_RIGHT },
+ {/* A52_3F */ PCM_LOW_FREQUENCY, PCM_FRONT_LEFT , PCM_FRONT_CENTER , PCM_FRONT_RIGHT },
+ {/* A52_2F1R */ PCM_LOW_FREQUENCY, PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_BACK_CENTER },
+ {/* A52_3F1R */ PCM_LOW_FREQUENCY, PCM_FRONT_LEFT , PCM_FRONT_CENTER , PCM_FRONT_RIGHT, PCM_BACK_CENTER },
+ {/* A52_2F2R */ PCM_LOW_FREQUENCY, PCM_FRONT_LEFT , PCM_FRONT_RIGHT , PCM_SIDE_LEFT , PCM_SIDE_RIGHT },
+ {/* A52_3F2R */ PCM_LOW_FREQUENCY, PCM_FRONT_LEFT , PCM_FRONT_CENTER , PCM_FRONT_RIGHT, PCM_SIDE_LEFT , PCM_SIDE_RIGHT }
+ };
m_iSourceFlags = flags;
- // setup channel map for how to translate to linear format
- // standard windows format
- if(m_iSourceFlags & A52_LFE)
- {
- switch (m_iSourceFlags&~A52_LFE) {
- case A52_MONO : m_iOutputMapping = 0x12ffff; break;
- case A52_CHANNEL:
- case A52_STEREO :
- case A52_DOLBY : m_iOutputMapping = 0x1fff32; break;
- case A52_2F1R : m_iOutputMapping = 0x1f5542; break;
- case A52_2F2R : m_iOutputMapping = 0x1f5432; break;
- case A52_3F : m_iOutputMapping = 0x13ff42; break;
- case A52_3F1R : m_iOutputMapping = 0x135542; break;
- case A52_3F2R : m_iOutputMapping = 0x136542; break;
- default : m_iOutputMapping = 0x000000; break;
- }
- }
- else
+
+ // setup channel map
+ int channels = 0;
+ int chOffset = (flags & A52_LFE) ? 7 : 0;
+ switch (m_iSourceFlags &~ A52_LFE)
{
- switch (m_iSourceFlags) {
- case A52_MONO : m_iOutputMapping = 0x1; break;
- case A52_CHANNEL:
- case A52_STEREO :
- case A52_DOLBY : m_iOutputMapping = 0x21; break;
- case A52_2F1R : m_iOutputMapping = 0x2231; break;
- case A52_2F2R : m_iOutputMapping = 0x4321; break;
- case A52_3F : m_iOutputMapping = 0x2ff31; break;
- case A52_3F1R : m_iOutputMapping = 0x24431; break;
- case A52_3F2R : m_iOutputMapping = 0x25431; break;
- default : m_iOutputMapping = 0x0; break;
- }
+ case A52_MONO : m_pChannelMap = channelMaps[chOffset + 0]; channels = 1; break;
+ case A52_CHANNEL:
+ case A52_DOLBY :
+ case A52_STEREO : m_pChannelMap = channelMaps[chOffset + 1]; channels = 2; break;
+ case A52_3F : m_pChannelMap = channelMaps[chOffset + 2]; channels = 3; break;
+ case A52_2F1R : m_pChannelMap = channelMaps[chOffset + 3]; channels = 3; break;
+ case A52_3F1R : m_pChannelMap = channelMaps[chOffset + 4]; channels = 4; break;
+ case A52_2F2R : m_pChannelMap = channelMaps[chOffset + 5]; channels = 4; break;
+ case A52_3F2R : m_pChannelMap = channelMaps[chOffset + 6]; channels = 5; break;
+ default : m_pChannelMap = NULL; break;
}
- if(m_iOutputMapping == 0x0)
- CLog::Log(LOGERROR, "CDVDAudioCodecLiba52::SetupChannels - Invalid channel mapping");
-
- int channels = 0;
- unsigned int m = m_iOutputMapping<<4;
- while(m>>=4) channels++;
+ if(flags & A52_LFE) ++channels;
- // xbox can't handle these
- if(channels == 5 || channels == 3)
- channels = 6;
+ if(m_pChannelMap == NULL)
+ CLog::Log(LOGERROR, "CDVDAudioCodecLiba52::SetupChannels - Invalid channel mapping");
if(m_iSourceChannels > 0 && m_iSourceChannels != channels)
CLog::Log(LOGINFO, "%s - Number of channels changed in stream from %d to %d, data might be truncated", __FUNCTION__, m_iOutputChannels, channels);
m_iSourceChannels = channels;
-
- // make sure map contains enough channels
- for(int i=0;i<m_iSourceChannels;i++)
- {
- if((m_iOutputMapping & (0xf<<(i*4))) == 0)
- m_iOutputMapping |= 0xf<<(i*4);
- }
- // and nothing more
- m_iOutputMapping &= ~(0xffffffff<<(m_iSourceChannels*4));
-
-
m_iOutputChannels = m_iSourceChannels;
m_iOutputFlags = m_iSourceFlags;
@@ -189,10 +165,10 @@ void CDVDAudioCodecLiba52::SetupChannels(int flags)
if (g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
{
m_iOutputChannels = 2;
- m_iOutputMapping = 0x21;
- m_iOutputFlags = A52_STEREO;
+ m_pChannelMap = channelMaps[1];
+ m_iOutputFlags = A52_STEREO;
if (m_iSourceChannels > 2)
- m_Gain = pow(2.0f, g_advancedSettings.m_ac3Gain/6.0f); // Hack for downmix attenuation
+ m_Gain = pow(2.0f, g_advancedSettings.m_ac3Gain / 6.0f); // Hack for downmix attenuation
}
/* adjust level should always be set, to keep samples in proper range */
@@ -320,7 +296,7 @@ int CDVDAudioCodecLiba52::Decode(BYTE* pData, int iSize)
CLog::Log(LOGERROR, "CDVDAudioCodecLiba52::Decode - a52_block failed");
break;
}
- m_decodedSize += 2*resample_int16(m_fSamples, (int16_t*)(m_decodedData + m_decodedSize), m_iOutputMapping);
+ m_decodedSize += 2*resample_int16(m_fSamples, (int16_t*)(m_decodedData + m_decodedSize), m_iOutputChannels);
}
return len;
}
View
13 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h
@@ -43,11 +43,12 @@ class CDVDAudioCodecLiba52 : public CDVDAudioCodec
virtual int Decode(BYTE* pData, int iSize);
virtual int GetData(BYTE** dst);
virtual void Reset();
- virtual int GetChannels() { return m_iOutputChannels; }
- virtual int GetSampleRate() { return m_iSourceSampleRate; }
- virtual int GetBufferSize() { return m_inputSize; }
- virtual int GetBitsPerSample() { return 16; }
- virtual const char* GetName() { return "liba52"; }
+ virtual int GetChannels() { return m_iOutputChannels; }
+ virtual int8_t *GetChannelMap() { return m_pChannelMap; }
+ virtual int GetSampleRate() { return m_iSourceSampleRate; }
+ virtual int GetBufferSize() { return m_inputSize; }
+ virtual int GetBitsPerSample() { return 16; }
+ virtual const char* GetName() { return "liba52"; }
protected:
void SetDefault();
@@ -67,7 +68,7 @@ class CDVDAudioCodecLiba52 : public CDVDAudioCodec
int m_iOutputFlags;
int m_iOutputChannels;
- unsigned int m_iOutputMapping;
+ uint8_t *m_pChannelMap;
DllLiba52 m_dll;
View
1  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h
@@ -44,6 +44,7 @@ class CDVDAudioCodecPassthrough : public CDVDAudioCodec
virtual int GetData(BYTE** dst);
virtual void Reset();
virtual int GetChannels();
+ virtual int8_t *GetChannelMap() { static uint8_t map[2] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT}; return map; }
virtual int GetSampleRate();
virtual int GetBitsPerSample();
virtual bool NeedPassthrough() { return true; }
View
1  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
@@ -39,6 +39,7 @@ class CDVDAudioCodecPassthroughFFmpeg : public CDVDAudioCodec
virtual int GetData(BYTE** dst);
virtual void Reset();
virtual int GetChannels();
+ virtual int8_t *GetChannelMap() { static int8_t map[2] = {PCM_FRONT_LEFT, PCM_FRONT_RIGHT}; return map; }
virtual int GetSampleRate();
virtual int GetBitsPerSample();
virtual bool NeedPassthrough() { return true; }
View
18 xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp
@@ -293,6 +293,24 @@ int CDVDAudioCodecPcm::GetChannels()
return m_iOutputChannels;
}
+int8_t* CDVDAudioCodecPcm::GetChannelMap()
+{
+ /* ? = probarbly wrong, just a guess */
+ static int8_t map[8][8] =
+ {
+ /* MONO */ {PCM_FRONT_CENTER },
+ /* STEREO */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT },
+ /* 3.0 ? */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER },
+ /* 4.0 ? */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT , PCM_BACK_RIGHT },
+ /* 5.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT },
+ /* 5.1 ? */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY },
+ /* 7.0 ? */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_FRONT_LEFT_OF_CENTER, PCM_FRONT_RIGHT_OF_CENTER },
+ /* 7.1 ? */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY , PCM_FRONT_LEFT_OF_CENTER , PCM_FRONT_RIGHT_OF_CENTER}
+ };
+
+ return map[m_iOutputChannels - 1];
+}
+
int CDVDAudioCodecPcm::GetSampleRate()
{
return m_iSourceSampleRate;
View
1  xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h
@@ -34,6 +34,7 @@ class CDVDAudioCodecPcm : public CDVDAudioCodec
virtual int GetData(BYTE** dst);
virtual void Reset();
virtual int GetChannels();
+ virtual int8_t* GetChannelMap();
virtual int GetSampleRate();
virtual int GetBitsPerSample();
virtual const char* GetName() { return "pcm"; }
View
1  xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
@@ -316,6 +316,7 @@ int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket)
audioframe.size = m_pAudioCodec->GetData(&audioframe.data);
audioframe.pts = m_audioClock;
audioframe.channels = m_pAudioCodec->GetChannels();
+ audioframe.channel_map = m_pAudioCodec->GetChannelMap();
audioframe.bits_per_sample = m_pAudioCodec->GetBitsPerSample();
audioframe.sample_rate = m_pAudioCodec->GetSampleRate();
audioframe.passthrough = m_pAudioCodec->NeedPassthrough();
View
1  xbmc/cores/dvdplayer/DVDPlayerAudio.h
@@ -54,6 +54,7 @@ typedef struct stDVDAudioFrame
unsigned int size;
int channels;
+ int8_t *channel_map;
int bits_per_sample;
int sample_rate;
bool passthrough;
View
4 xbmc/cores/paplayer/PAPlayer.cpp
@@ -71,6 +71,7 @@ PAPlayer::PAPlayer(IPlayerCallback& callback) : IPlayer(callback)
for (int i=0; i<2; i++)
{
m_channelCount[i] = 0;
+ m_channelMap[i] = NULL;
m_sampleRate[i] = 0;
m_bitsPerSample[i] = 0;
@@ -370,10 +371,11 @@ bool PAPlayer::CreateStream(int num, unsigned int channels, unsigned int sampler
m_bitsPerSample[num] = 16;
m_sampleRate[num] = outputSampleRate;
m_channelCount[num] = channels;
+ m_channelMap[num] = NULL;
m_BytesPerSecond = (m_bitsPerSample[num] / 8)* outputSampleRate * channels;
/* Open the device */
- m_pAudioDecoder[num] = CAudioRendererFactory::Create(m_pCallback, m_channelCount[num], m_sampleRate[num], m_bitsPerSample[num], false, codec.c_str(), true, false);
+ m_pAudioDecoder[num] = CAudioRendererFactory::Create(m_pCallback, m_channelCount[num], m_channelMap[num], m_sampleRate[num], m_bitsPerSample[num], false, codec.c_str(), true, false);
if (!m_pAudioDecoder[num]) return false;
View
1  xbmc/cores/paplayer/PAPlayer.h
@@ -179,6 +179,7 @@ class PAPlayer : public IPlayer, public CThread
// format (this should be stored/retrieved from the audio device object probably)
unsigned int m_channelCount[2];
+ int8_t* m_channelMap[2];
unsigned int m_sampleRate[2];
unsigned int m_bitsPerSample[2];
unsigned int m_BytesPerSecond;
View
1  xbmc/utils/Makefile
@@ -32,6 +32,7 @@ SRCS=AlarmClock.cpp \
Win32Exception.cpp \
CPUInfo.cpp \
PCMAmplifier.cpp \
+ PCMRemap.cpp \
LabelFormatter.cpp \
Network.cpp \
BitstreamStats.cpp \
View
147 xbmc/utils/PCMRemap.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2005-2010 Team XBMC
+ * http://www.xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <cstdlib>
+#include <string.h>
+#include <stdio.h>
+
+#include "PCMRemap.h"
+#include "utils/log.h"
+
+CPCMRemap::CPCMRemap() :
+ m_inSet (false),
+ m_outSet (false),
+ m_chLookup(NULL )
+{
+}
+
+CPCMRemap::~CPCMRemap()
+{
+ Dispose();
+}
+
+void CPCMRemap::Dispose()
+{
+ if (m_chLookup != NULL)
+ {
+ delete m_chLookup;
+ m_chLookup = NULL;
+ }
+}
+
+/*
+ builds a lookup table to convert from the input mapping to the output
+ mapping, this decreases the amount of work per sample to remap it.
+*/
+void CPCMRemap::BuildMap()
+{
+ unsigned int in_ch, out_ch;
+
+ if (!m_inSet || !m_outSet) return;