All pastes #1748217 Raw Edit

Untitled

public text v1 · immutable
#1748217 ·published 2010-01-12 12:58 UTC
rendered paste body
Index: xbmc/cores/dvdplayer/DVDAudio.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDAudio.cpp	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDAudio.cpp	(working copy)
@@ -92,7 +92,7 @@
   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 @@
   if(!m_pAudioDecoder)
     return 0.0;
   return m_pAudioDecoder->GetCacheTotal();
-}
\ No newline at end of file
+}
Index: xbmc/cores/dvdplayer/DVDPlayerAudio.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayerAudio.cpp	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDPlayerAudio.cpp	(working copy)
@@ -316,6 +316,7 @@
       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();
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.cpp	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.cpp	(working copy)
@@ -37,112 +37,24 @@
     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]);
+    unsigned int i, ch;
+    int16_t *p = out;
+    for(i = 0; i < 256; ++i) {
+      for(ch = 0; ch < channels; ++ch) {
+        *p = convert( ((int32_t*)in)[i + (ch << 8)] );
+        ++p;
       }
-      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++)
-      {
-        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]);
-      }
-      break;
-  }
+    }
+    return p - out; 
 }
 
 CDVDAudioCodecLibDts::CDVDAudioCodecLibDts() : CDVDAudioCodec()
@@ -184,34 +96,60 @@
   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);
-  if (g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
-    m_iOutputChannels = 2;
-  else
-    m_iOutputChannels = m_iSourceChannels;
+  /* These are channel mappings that libdts outputs */
+  static uint8_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_BACK_LEFT    , PCM_BACK_RIGHT                                       },
+    {/* DTS_3F2R    */ PCM_FRONT_CENTER, PCM_FRONT_LEFT   , PCM_FRONT_RIGHT  , PCM_BACK_LEFT  , PCM_BACK_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_BACK_LEFT    , PCM_BACK_RIGHT , PCM_LOW_FREQUENCY                   },
+    {/* DTS_3F2R    */ PCM_FRONT_CENTER, PCM_FRONT_LEFT   , PCM_FRONT_RIGHT  , PCM_BACK_LEFT  , PCM_BACK_RIGHT   , PCM_LOW_FREQUENCY},
+  };
 
-  if (m_iOutputChannels == 1)
-    m_iOutputFlags = DTS_MONO;
-  else if (m_iOutputChannels == 2)
-    m_iOutputFlags = DTS_STEREO;
-  else
-    m_iOutputFlags = m_iSourceFlags;
+  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;
+
+  /* adjust level should always be set, to keep samples in proper range */
+  /* after any downmixing has been done */
   m_iOutputFlags |= DTS_ADJUST_LEVEL;
 }
 
@@ -330,8 +268,7 @@
       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_iSourceChannels);
   }
 
   return len;
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.cpp	(working copy)
@@ -103,6 +103,24 @@
   return false;
 }
 
+uint8_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;
@@ -217,7 +235,7 @@
 
     // modify some stuff here
     pConfiguration->outputFormat = FAAD_FMT_16BIT; // already default
-    pConfiguration->downMatrix = g_guiSettings.GetBool("audiooutput.downmixmultichannel") ? 1 : 0;
+    pConfiguration->downMatrix = 0; //g_guiSettings.GetBool("audiooutput.downmixmultichannel") ? 1 : 0;
 
     m_dll.faacDecSetConfiguration(m_pHandle, pConfiguration);
 
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.h	(working copy)
@@ -40,11 +40,12 @@
   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 uint8_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();
@@ -64,7 +65,7 @@
 
   int m_iOutputFlags;
   int m_iOutputChannels;
-  unsigned int m_iOutputMapping;
+  uint8_t *m_pChannelMap;
 
   DllLiba52 m_dll;
 
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodec.h	(working copy)
@@ -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 @@
   virtual int GetChannels() = 0;
 
   /*
+   * returns the channel mapping
+   */
+  virtual uint8_t* GetChannelMap() = 0;
+
+  /*
    * returns the samplerate for the decoded audio stream
    */
   virtual int GetSampleRate() = 0;
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.h	(working copy)
@@ -34,6 +34,7 @@
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels();
+  virtual uint8_t* GetChannelMap();
   virtual int GetSampleRate();
   virtual int GetBitsPerSample();
   virtual const char* GetName()  { return "pcm"; }
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibDts.h	(working copy)
@@ -34,15 +34,15 @@
   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 uint8_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);
 
@@ -61,6 +61,7 @@
 
   int m_iOutputFlags;
   int m_iOutputChannels;
+  uint8_t *m_pChannelMap;
 
   DllLibDts m_dll;
 
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibFaad.h	(working copy)
@@ -37,11 +37,12 @@
   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 uint8_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 @@
 
   int m_iSourceSampleRate;
   int m_iSourceChannels;
+  uint8_t m_pChannelMap[64];
   int m_iSourceBitrate;
 
   bool m_bInitializedDecoder;
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLibMad.h	(working copy)
@@ -37,11 +37,12 @@
   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 uint8_t* GetChannelMap() { static uint8_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:
 
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.cpp	(working copy)
@@ -218,6 +218,46 @@
   return 0;
 }
 
+uint8_t* CDVDAudioCodecFFmpeg::GetChannelMap()
+{
+  static uint8_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;
+  }
+}
+
 int CDVDAudioCodecFFmpeg::GetSampleRate()
 {
   if (m_pCodecContext) return m_pCodecContext->sample_rate;
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecFFmpeg.h	(working copy)
@@ -36,6 +36,7 @@
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels();
+  virtual uint8_t *GetChannelMap();
   virtual int GetSampleRate();
   virtual int GetBitsPerSample();
   virtual const char* GetName() { return "FFmpeg"; }
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthrough.h	(working copy)
@@ -37,6 +37,7 @@
   virtual int GetData(BYTE** dst);
   virtual void Reset();
   virtual int GetChannels();
+  virtual uint8_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; }
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.cpp	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecLiba52.cpp	(working copy)
@@ -47,23 +47,19 @@
  * 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; 
 }
 
 
@@ -109,90 +105,58 @@
 
 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 uint8_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_BACK_LEFT  , PCM_BACK_RIGHT                                      },
+    {/* A52_3F2R    */ PCM_FRONT_LEFT  , PCM_FRONT_CENTER , PCM_FRONT_RIGHT, PCM_BACK_LEFT  , PCM_BACK_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_BACK_LEFT  , PCM_BACK_RIGHT                   },
+    {/* A52_3F2R    */ PCM_LOW_FREQUENCY, PCM_FRONT_LEFT  , PCM_FRONT_CENTER , PCM_FRONT_RIGHT, PCM_BACK_LEFT  , PCM_BACK_RIGHT  }
+  };
 
   m_iSourceFlags = flags;
-  // setup channel map for how to translate to linear format
-  // standard windows format
-  if(m_iSourceFlags & A52_LFE)
+
+  // setup channel map
+  int channels = 0;
+  int chOffset = (flags & A52_LFE) ? 7 : 0;
+  switch (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;
-    }
+    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;
   }
-  else
-  {
-    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;
-    }
-  }
 
-  if(m_iOutputMapping == 0x0)
+  if(flags & A52_LFE) ++channels;
+
+  if(m_pChannelMap == NULL)
     CLog::Log(LOGERROR, "CDVDAudioCodecLiba52::SetupChannels - Invalid channel mapping");
 
-  int channels = 0;
-  unsigned int m = m_iOutputMapping<<4;
-  while(m>>=4) channels++;
-
-  // xbox can't handle these
-  if(channels == 5 || channels == 3)
-    channels = 6;
-
   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;
 
-  // If we can't support multichannel output downmix
-  if (g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
-  {
-    m_iOutputChannels = 2;
-    m_iOutputMapping = 0x21;
-    m_iOutputFlags = A52_STEREO;
-    if (m_iSourceChannels > 2)
-      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 */
   /* after any downmixing has been done */
   m_iOutputFlags |= A52_ADJUST_LEVEL;
@@ -318,7 +282,7 @@
       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_iSourceChannels);
   }
   return len;
 }
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPcm.cpp	(working copy)
@@ -293,6 +293,24 @@
   return m_iOutputChannels;
 }
 
+uint8_t* CDVDAudioCodecPcm::GetChannelMap()
+{
+  /* ? = probarbly wrong, just a guess */
+  static uint8_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;
Index: xbmc/cores/dvdplayer/DVDPlayerAudio.h
===================================================================
--- xbmc/cores/dvdplayer/DVDPlayerAudio.h	(revision 26715)
+++ xbmc/cores/dvdplayer/DVDPlayerAudio.h	(working copy)
@@ -54,6 +54,7 @@
   unsigned int size;
 
   int channels;
+  uint8_t *channel_map;
   int bits_per_sample;
   int sample_rate;
   bool passthrough;
Index: xbmc/cores/AudioRenderers/IAudioRenderer.h
===================================================================
--- xbmc/cores/AudioRenderers/IAudioRenderer.h	(revision 26715)
+++ xbmc/cores/AudioRenderers/IAudioRenderer.h	(working copy)
@@ -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 @@
 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, uint8_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 @@
   virtual void WaitCompletion() = 0;
   virtual void SwitchChannels(int iAudioStream, bool bAudioOnAllSpeakers) = 0;
 
+protected:
+  CPCMRemap m_remap;
+
 private:
 };
 
Index: xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp
===================================================================
--- xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp	(revision 26715)
+++ xbmc/cores/AudioRenderers/PulseAudioDirectSound.cpp	(working copy)
@@ -143,7 +143,7 @@
 {
 }
 
-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, uint8_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)
Index: xbmc/cores/AudioRenderers/NullDirectSound.cpp
===================================================================
--- xbmc/cores/AudioRenderers/NullDirectSound.cpp	(revision 26715)
+++ xbmc/cores/AudioRenderers/NullDirectSound.cpp	(working copy)
@@ -41,7 +41,7 @@
 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, uint8_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)
Index: xbmc/cores/AudioRenderers/AudioRendererFactory.cpp
===================================================================
--- xbmc/cores/AudioRenderers/AudioRendererFactory.cpp	(revision 26715)
+++ xbmc/cores/AudioRenderers/AudioRendererFactory.cpp	(working copy)
@@ -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, uint8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
 {
   IAudioRenderer* audioSink = NULL;
 
@@ -91,7 +91,7 @@
 #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 @@
 #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;
 }
 
Index: xbmc/cores/AudioRenderers/PulseAudioDirectSound.h
===================================================================
--- xbmc/cores/AudioRenderers/PulseAudioDirectSound.h	(revision 26715)
+++ xbmc/cores/AudioRenderers/PulseAudioDirectSound.h	(working copy)
@@ -47,7 +47,7 @@
   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, uint8_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);
Index: xbmc/cores/AudioRenderers/NullDirectSound.h
===================================================================
--- xbmc/cores/AudioRenderers/NullDirectSound.h	(revision 26715)
+++ xbmc/cores/AudioRenderers/NullDirectSound.h	(working copy)
@@ -41,7 +41,7 @@
   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, uint8_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);
Index: xbmc/cores/AudioRenderers/ALSADirectSound.cpp
===================================================================
--- xbmc/cores/AudioRenderers/ALSADirectSound.cpp	(revision 26715)
+++ xbmc/cores/AudioRenderers/ALSADirectSound.cpp	(working copy)
@@ -47,8 +47,15 @@
   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, uint8_t *channelMap, unsigned int uiSamplesPerSec, unsigned int uiBitsPerSample, bool bResample, const char* strAudioCodec, bool bIsMusic, bool bPassthrough)
 {
+  static uint8_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());
@@ -56,6 +63,10 @@
   if (iChannels == 0)
     iChannels = 2;
 
+  /* setup the channel mapping */
+  m_remap.SetInputFormat (iChannels, channelMap, uiBitsPerSample / 8);
+  m_remap.SetOutputFormat(iChannels, ALSAChannelMap);
+
   bool bAudioOnAllSpeakers(false);
   g_audioContext.SetupSpeakerConfig(iChannels, bAudioOnAllSpeakers, bIsMusic);
   g_audioContext.SetActiveDevice(CAudioContext::DIRECTSOUND_DEVICE);
@@ -124,6 +135,7 @@
     || deviceuse == "spdif")
       deviceuse = "plug:" + deviceuse;
 
+/*
     if(g_guiSettings.GetBool("audiooutput.downmixmultichannel"))
     {
       if(iChannels == 6)
@@ -133,6 +145,7 @@
     }
     else
     {
+*/
       if(deviceuse == "default")
       {
         if(iChannels == 6)
@@ -142,6 +155,7 @@
         else if(iChannels == 4)
           deviceuse = "surround40";
       }
+/*
     }
 
     // setup channel mapping to linux default
@@ -167,7 +181,6 @@
         deviceuse = "xbmc_ogg50:'" + EscapeDevice(deviceuse) + "'";
     }
 
-
     if(deviceuse != device)
     {
       snd_input_t* input;
@@ -186,6 +199,7 @@
         deviceuse = device;
       }
     }
+*/
   }
 
   CLog::Log(LOGDEBUG, "%s - using alsa device %s", __FUNCTION__, deviceuse.c_str());
@@ -471,7 +485,14 @@
     writeResult = snd_pcm_writei(m_pPlayHandle, dummy, framesToWrite);
   }
   else
-    writeResult = snd_pcm_writei(m_pPlayHandle, pcmPtr, framesToWrite);
+  {
+    /* remap the data to the correct channels */
+    uint8_t outData[bytesToWrite];
+    m_remap.Remap((void*)pcmPtr, outData, framesToWrite);
+
+    /* write it out */
+    writeResult = snd_pcm_writei(m_pPlayHandle, outData, framesToWrite);
+  }
   if (  writeResult == -EPIPE  ) {
     CLog::Log(LOGDEBUG, "CALSADirectSound::AddPackets - buffer underun (tried to write %d frames)",
             framesToWrite);
Index: xbmc/cores/AudioRenderers/AudioRendererFactory.h
===================================================================
--- xbmc/cores/AudioRenderers/AudioRendererFactory.h	(revision 26715)
+++ xbmc/cores/AudioRenderers/AudioRendererFactory.h	(working copy)
@@ -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, uint8_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);
Index: xbmc/cores/AudioRenderers/ALSADirectSound.h
===================================================================
--- xbmc/cores/AudioRenderers/ALSADirectSound.h	(revision 26715)
+++ xbmc/cores/AudioRenderers/ALSADirectSound.h	(working copy)
@@ -51,7 +51,7 @@
   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, uint8_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);
Index: xbmc/cores/paplayer/PAPlayer.h
===================================================================
--- xbmc/cores/paplayer/PAPlayer.h	(revision 26715)
+++ xbmc/cores/paplayer/PAPlayer.h	(working copy)
@@ -166,6 +166,7 @@
 
   unsigned int     m_SampleRate;
   unsigned int     m_Channels;
+  uint8_t*         m_ChannelMap;
   unsigned int     m_BitsPerSample;
 
   unsigned int     m_SampleRateOutput;
@@ -179,6 +180,7 @@
 
   // format (this should be stored/retrieved from the audio device object probably)
   unsigned int     m_channelCount[2];
+  uint8_t*         m_channelMap[2];
   unsigned int     m_sampleRate[2];
   unsigned int     m_bitsPerSample[2];
   unsigned int     m_BytesPerSecond;
Index: xbmc/cores/paplayer/PAPlayer.cpp
===================================================================
--- xbmc/cores/paplayer/PAPlayer.cpp	(revision 26715)
+++ xbmc/cores/paplayer/PAPlayer.cpp	(working copy)
@@ -372,7 +372,7 @@
     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;
 
Index: xbmc/utils/Makefile
===================================================================
--- xbmc/utils/Makefile	(revision 26715)
+++ xbmc/utils/Makefile	(working copy)
@@ -32,6 +32,7 @@
      Win32Exception.cpp \
      CPUInfo.cpp \
      PCMAmplifier.cpp \
+     PCMRemap.cpp \
      LabelFormatter.cpp \
      Network.cpp \
      BitstreamStats.cpp \