All pastes #1789681 Raw Edit

Unnamed

public text v1 · immutable
#1789681 ·published 2010-02-08 02:03 UTC
rendered paste body
Index: xbmc/cores/dvdplayer/Codecs/DllAvCodec.h
===================================================================
--- xbmc/cores/dvdplayer/Codecs/DllAvCodec.h	(revision 27554)
+++ xbmc/cores/dvdplayer/Codecs/DllAvCodec.h	(working copy)
@@ -23,12 +23,14 @@
 #if (defined USE_EXTERNAL_FFMPEG)
   #if (defined HAVE_LIBAVCODEC_AVCODEC_H)
     #include <libavcodec/avcodec.h>
+    #include <libavcodec/ac3.h>
     #include <libavutil/crc.h>
     #if (defined AVPACKET_IN_AVFORMAT)
       #include <libavformat/avformat.h>
     #endif
   #elif (defined HAVE_FFMPEG_AVCODEC_H)
     #include <ffmpeg/avcodec.h>
+    #include <ffmpeg/ac3.h>
     #include <ffmpeg/crc.h>
     #if (defined AVPACKET_IN_AVFORMAT)
       #include <ffmpeg/avformat.h>
@@ -39,6 +41,7 @@
   #include "xbmc/cores/dvdplayer/Codecs/ffmpeg/libavutil/crc.h"
 #else
   #include "libavcodec/avcodec.h"
+  #include "libavcodec/ac3.h"
   #include "libavcodec/audioconvert.h"
   #include "libavutil/crc.h"
 #endif
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/Makefile.in
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/Makefile.in	(revision 27554)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/Makefile.in	(working copy)
@@ -13,6 +13,7 @@
 	DVDAudioCodecPassthrough.cpp \
         DVDAudioCodecPassthroughFFmpeg.cpp \
 	DVDAudioCodecPcm.cpp \
+	Encoders/DVDAudioEncoderAC3.cpp
 
 LIB=Audio.a
 
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp	(revision 27554)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp	(working copy)
@@ -33,13 +33,15 @@
 
 /* Lookup tables */
 static const uint16_t AC3Bitrates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640};
-static const uint16_t AC3FSCod   [] = {48000, 41000, 32000, 0};
+static const uint16_t AC3FSCod   [] = {48000, 44100, 32000, 0};
 
 CDVDAudioCodecPassthroughFFmpeg::CDVDAudioCodecPassthroughFFmpeg(void)
 {
   m_pFormat      = NULL;
   m_pStream      = NULL;
   m_pSyncFrame   = NULL;
+  m_codec        = NULL;
+  m_encoder      = NULL;
 
   m_OutputSize   = 0;
   m_OutputBuffer = (BYTE*)_aligned_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE, 16);
@@ -52,141 +54,177 @@
   Dispose();
 }
 
+bool CDVDAudioCodecPassthroughFFmpeg::SetupEncoder(CDVDStreamInfo &hints)
+{
+  /* there is no point encoding < 2 channel sources, and we dont support anything but AC3 at the moment */
+  if (hints.channels <= 2 || !m_bSupportsAC3Out)
+    return false;
+
+  CLog::Log(LOGDEBUG, "CDVDAudioCodecPassthroughFFmpeg::SetupEncoder - Setting up encoder for on the fly transcode");
+
+  /* we need to decode the incoming audio data, so we can re-encode it as we need it */
+  m_codec = CDVDFactoryCodec::CreateAudioCodec(hints, false);
+  if (!m_codec)
+  {
+    CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupEncoder - Unable to create a decoder for transcode");
+    return false;
+  }
+
+  /* try to open the encoder */
+  m_encoder = new CDVDAudioEncoderAC3();
+  if (!m_encoder->Initialize(m_codec->GetChannels(), m_codec->GetChannelMap(), m_codec->GetBitsPerSample(), m_codec->GetSampleRate()))
+  {
+    CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::SetupEncoder - Unable to create a encoder for transcode");
+    Dispose();
+    return false;
+  }
+
+  /* adjust the hints according to the encorders output */
+  hints.codec      = m_encoder->GetCodecID   ();
+  hints.bitrate    = m_encoder->GetBitRate   ();
+  hints.channels   = OUT_CHANNELS;
+
+  CLog::Log(LOGDEBUG, "CDVDAudioCodecPassthroughFFmpeg::SetupEncoder - Ready to transcode");
+  return true;
+}
+
 bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
 {
-  bool bSupportsAC3Out = false;
-  bool bSupportsDTSOut = false;
-  bool bSupportsAACOut = false;
-  bool bSupportsMP1Out = false;
-  bool bSupportsMP2Out = false;
-  bool bSupportsMP3Out = false;
-
   // TODO - move this stuff somewhere else
   if (g_guiSettings.GetInt("audiooutput.mode") == AUDIO_DIGITAL)
   {
-    bSupportsAC3Out = g_guiSettings.GetBool("audiooutput.ac3passthrough");
-    bSupportsDTSOut = g_guiSettings.GetBool("audiooutput.dtspassthrough");
-    bSupportsAACOut = g_guiSettings.GetBool("audiooutput.aacpassthrough");
-    bSupportsMP1Out = g_guiSettings.GetBool("audiooutput.mp1passthrough");
-    bSupportsMP2Out = g_guiSettings.GetBool("audiooutput.mp2passthrough");
-    bSupportsMP3Out = g_guiSettings.GetBool("audiooutput.mp3passthrough");
+    m_bSupportsAC3Out = g_guiSettings.GetBool("audiooutput.ac3passthrough");
+    m_bSupportsDTSOut = g_guiSettings.GetBool("audiooutput.dtspassthrough");
+    m_bSupportsAACOut = g_guiSettings.GetBool("audiooutput.aacpassthrough");
+    m_bSupportsMP1Out = g_guiSettings.GetBool("audiooutput.mp1passthrough");
+    m_bSupportsMP2Out = g_guiSettings.GetBool("audiooutput.mp2passthrough");
+    m_bSupportsMP3Out = g_guiSettings.GetBool("audiooutput.mp3passthrough");
   }
+  else
+    return false;
 
-  //Samplerate cannot be checked here as we don't know it at this point in time.
-  //We should probably have a way to try to decode data so that we know what samplerate it is.
-  if ((hints.codec == CODEC_ID_AC3 && bSupportsAC3Out)
-   || (hints.codec == CODEC_ID_DTS && bSupportsDTSOut)
-   || (hints.codec == CODEC_ID_AAC && bSupportsAACOut)
-   || (hints.codec == CODEC_ID_MP1 && bSupportsMP1Out)
-   || (hints.codec == CODEC_ID_MP2 && bSupportsMP2Out)
-   || (hints.codec == CODEC_ID_MP3 && bSupportsMP3Out))
+  // TODO - this is only valid for video files, and should be moved somewhere else
+  if( hints.channels == 2 && g_settings.m_currentVideoSettings.m_OutputToAllSpeakers )
   {
+    CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::Open - disabled passthrough due to video OTAS");
+    return false;
+  }
 
-    // TODO - this is only valid for video files, and should be moved somewhere else
-    if( hints.channels == 2 && g_settings.m_currentVideoSettings.m_OutputToAllSpeakers )
-    {
-      CLog::Log(LOGINFO, "CDVDAudioCodecPassthroughFFmpeg::Open - disabled passthrough due to video OTAS");
+  /* see if the muxer supports our codec (see spdif.c for supported formats) */
+  m_pSyncFrame = NULL;
+  bool setupEncoder = true;
+  while(true) {
+         if (m_bSupportsAC3Out && hints.codec == CODEC_ID_AC3) m_pSyncFrame = &CDVDAudioCodecPassthroughFFmpeg::SyncAC3;
+    else if (m_bSupportsDTSOut && hints.codec == CODEC_ID_DTS) m_pSyncFrame = &CDVDAudioCodecPassthroughFFmpeg::SyncDTS;
+    else if (m_bSupportsAACOut && hints.codec == CODEC_ID_AAC);
+    else if (m_bSupportsMP1Out && hints.codec == CODEC_ID_MP1);
+    else if (m_bSupportsMP2Out && hints.codec == CODEC_ID_MP2);
+    else if (m_bSupportsMP3Out && hints.codec == CODEC_ID_MP3);
+    else {
+      if (setupEncoder && SetupEncoder(hints))
+      {
+        setupEncoder = false;
+        continue;
+      }
+      CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - FFmpeg SPDIF muxer does not support this codec");
+      Dispose();
       return false;
     }
 
-    if (!m_dllAvFormat.Load() || !m_dllAvUtil.Load() || !m_dllAvCodec.Load())
-      return false;
+    break;
+  }
 
-    /* get the muxer */
-    AVOutputFormat *outFormat;
+  if (!m_dllAvFormat.Load() || !m_dllAvUtil.Load() || !m_dllAvCodec.Load())
+    return false;
+
+  /* get the muxer */
+  AVOutputFormat *outFormat;
 #if LIBAVFORMAT_VERSION_MAJOR < 53
-    outFormat = m_dllAvFormat.guess_format("spdif", NULL, NULL);
+  outFormat = m_dllAvFormat.guess_format("spdif", NULL, NULL);
 #else
-    outFormat = m_dllAvFormat.av_guess_format("spdif", NULL, NULL);
+  outFormat = m_dllAvFormat.av_guess_format("spdif", NULL, NULL);
 #endif
-    if (!outFormat)
-    {
-      CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to get the ffmpeg spdif muxer");
-      Dispose();
-      return false;
-    }
+  if (!outFormat)
+  {
+    CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to get the ffmpeg spdif muxer");
+    Dispose();
+    return false;
+  }
 
-    /* see if the muxer supports our codec (see spdif.c for supported formats) */
-    m_pSyncFrame = NULL;
-    switch(hints.codec) {
-      case CODEC_ID_AC3: m_pSyncFrame = &CDVDAudioCodecPassthroughFFmpeg::SyncAC3; break;
-      case CODEC_ID_DTS: m_pSyncFrame = &CDVDAudioCodecPassthroughFFmpeg::SyncDTS; break;
-      case CODEC_ID_MP1:
-      case CODEC_ID_MP2:
-      case CODEC_ID_MP3:
-      case CODEC_ID_AAC:
-        break;
+  /* allocate a the format context */
+  m_pFormat = m_dllAvFormat.avformat_alloc_context();
+  if (!m_pFormat)
+  {
+    CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to allocate AVFormat context");
+    Dispose();
+    return false;
+  }
+  m_pFormat->oformat = outFormat;
 
-      default:
-        CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - ffmpeg SPDIF muxer does not support this codec");
-        Dispose();
-        return false;
-    }
+  /* allocate a put_byte struct so we can grab the output */
+  m_pFormat->pb = m_dllAvFormat.av_alloc_put_byte(m_bcBuffer, AVCODEC_MAX_AUDIO_FRAME_SIZE, URL_RDONLY, this,  NULL, _BCReadPacket, NULL);
+  if (!m_pFormat->pb)
+  {
+    CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to allocate ByteIOContext");
+    Dispose();
+    return false;
+  }
 
-    /* allocate a the format context */
-    m_pFormat = m_dllAvFormat.avformat_alloc_context();
-    if (!m_pFormat)
-    {
-      CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to allocate AVFormat context");
-      Dispose();
-      return false;
-    }
-    m_pFormat->oformat = outFormat;
+  /* this is streamed, no file, and ignore the index */
+  m_pFormat->pb->is_streamed   = 1;
+  m_pFormat->flags            |= AVFMT_NOFILE | AVFMT_FLAG_IGNIDX;
+  m_pFormat->bit_rate          = hints.bitrate;
 
-    /* allocate a put_byte struct so we can grab the output */
-    m_pFormat->pb = m_dllAvFormat.av_alloc_put_byte(m_bcBuffer, AVCODEC_MAX_AUDIO_FRAME_SIZE, URL_RDONLY, this,  NULL, _BCReadPacket, NULL);
-    if (!m_pFormat->pb)
-    {
-      CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to allocate ByteIOContext");
-      Dispose();
-      return false;
-    }
+  /* setup the muxer */
+  AVFormatParameters params;
+  memset(&params, 0, sizeof(params));
+  params.channels    = hints.channels;
+  params.sample_rate = OUT_SAMPLERATE;
+  params.channel     = 0;
+  if (m_dllAvFormat.av_set_parameters(m_pFormat, &params) != 0)
+  {
+    CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to set the spdif muxer parameters");
+    Dispose();
+    return false;
+  }
 
-    /* this is streamed, no file, and ignore the index */
-    m_pFormat->pb->is_streamed   = 1;
-    m_pFormat->flags            |= AVFMT_NOFILE | AVFMT_FLAG_IGNIDX;
-    m_pFormat->bit_rate          = hints.bitrate;
+  /* add a stream to it */
+  m_pStream = m_dllAvFormat.av_new_stream(m_pFormat, 1);
+  if (!m_pStream)
+  {
+    CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to allocate AVStream context");
+    Dispose();
+    return false;
+  }
 
-    /* setup the muxer */
-    AVFormatParameters params;
-    memset(&params, 0, sizeof(params));
-    params.channels    = hints.channels;
-    params.sample_rate = OUT_SAMPLERATE;
-    params.channel     = 0;
-    if (m_dllAvFormat.av_set_parameters(m_pFormat, &params) != 0)
-    {
-      CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to set the spdif muxer parameters");
-      Dispose();
-      return false;
-    }
+  /* set the stream's parameters */
+  m_pStream->stream_copy        = 1;
+  m_pStream->codec->codec_type  = CODEC_TYPE_AUDIO;
+  m_pStream->codec->codec_id    = hints.codec;
+  m_pStream->codec->sample_rate = hints.samplerate;
+  m_pStream->codec->channels    = hints.channels;
 
-    /* add a stream to it */
-    m_pStream = m_dllAvFormat.av_new_stream(m_pFormat, 1);
-    if (!m_pStream)
-    {
-      CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - Failed to allocate AVStream context");
-      Dispose();
-      return false;
-    }
+  /* we will check the first packet's crc */
+  m_lostSync = true;
+  return true;
+}
 
-    /* set the stream's parameters */
-    m_pStream->stream_copy        = 1;
-    m_pStream->codec->codec_type  = CODEC_TYPE_AUDIO;
-    m_pStream->codec->codec_id    = hints.codec;
-    m_pStream->codec->sample_rate = hints.samplerate;
-    m_pStream->codec->channels    = hints.channels;
+void CDVDAudioCodecPassthroughFFmpeg::Dispose()
+{
+  if (m_encoder)
+  {
+    delete m_encoder;
+    m_encoder = NULL;
+  }
 
-    /* we will check the first packet's crc */
-    m_lostSync = true;
-    return true;
+  if (m_codec)
+  {
+    delete m_codec;
+    m_codec   = NULL;
   }
 
-  return false;
-}
-
-void CDVDAudioCodecPassthroughFFmpeg::Dispose()
-{
-  if (m_pFormat) {
+  if (m_pFormat)
+  {
     if (m_pFormat->pb)
       m_dllAvUtil.av_freep(&m_pFormat->pb);
     m_dllAvUtil.av_freep(&m_pFormat);
@@ -218,7 +256,6 @@
     /* search for an ac3 sync word */
     if(pData[0] != 0x0b || pData[1] != 0x77)
       continue;
- 
     uint8_t fscod      = pData[4] >> 6;
     uint8_t frmsizecod = pData[4] & 0x3F;
     uint8_t bsid       = pData[5] >> 3;
@@ -280,11 +317,11 @@
     ) continue;
 
     /* if it is not a termination frame, check the next 6 bits */
-    if (pData[4] & 0x80 != 0 && pData[4] & 0x7C != 0x7C)
+    if ((pData[4] & 0x80) != 0 && (pData[4] & 0x7C) != 0x7C)
       continue;
 
     /* get and validate the framesize */
-    *fSize = ((pData[5] & 0x3) << 8 | pData[6]) << 4 | ((pData[7] & 0xF0) >> 4) + 1;
+    *fSize = ((((pData[5] & 0x3) << 8 | pData[6]) << 4) | ((pData[7] & 0xF0) >> 4)) + 1;
     if (*fSize < 95 || *fSize > 16383)
       continue;
 
@@ -298,14 +335,36 @@
 
 int CDVDAudioCodecPassthroughFFmpeg::Decode(BYTE* pData, int iSize)
 {
-  int fSize = iSize;
-  if (m_pSyncFrame)
+  int used, fSize;
+  used = fSize = iSize;
+
+  /* if we are transcoding */
+  if (m_encoder)
   {
-    int skip = (this->*m_pSyncFrame)(pData, iSize, &fSize);
-    if (skip > 0)
-      return skip;
+    BYTE *decData;
+    BYTE encData[6114];
+    used  = m_codec  ->Decode (pData, iSize);
+    fSize = m_codec  ->GetData(&decData);
+    fSize = m_encoder->Encode (decData, fSize);
+    fSize = m_encoder->GetData(encData, 6114);
+    pData = encData;
+
+    /* if the encoder has not got anything yet, return the consumed bytes */
+    if (fSize == 0)
+      return used;
   }
+  else
+  {
+    if (m_pSyncFrame)
+    {
+      int skip = (this->*m_pSyncFrame)(pData, iSize, &fSize);
+      if (skip > 0)
+        return skip;
 
+      used = fSize;
+    }
+  }
+
   AVPacket pkt;
   m_dllAvCodec.av_init_packet(&pkt);
   pkt.data = pData;
@@ -314,7 +373,8 @@
   m_dllAvFormat.av_write_header (m_pFormat);
   m_dllAvFormat.av_write_frame  (m_pFormat, &pkt);
   m_dllAvFormat.av_write_trailer(m_pFormat);
-  return fSize;
+
+  return used;
 }
 
 int CDVDAudioCodecPassthroughFFmpeg::GetData(BYTE** dst)
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h	(revision 27554)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h	(working copy)
@@ -25,7 +25,10 @@
 #include "Codecs/DllAvFormat.h"
 #include "Codecs/DllAvCodec.h"
 
+#include "../DVDFactoryCodec.h"
 #include "DVDAudioCodec.h"
+#include "Encoders/IDVDAudioEncoder.h"
+#include "Encoders/DVDAudioEncoderAC3.h"
 
 class CDVDAudioCodecPassthroughFFmpeg : public CDVDAudioCodec
 {
@@ -46,6 +49,17 @@
   virtual const char* GetName()  { return "PassthroughFFmpeg"; }
 
 private:
+  bool m_bSupportsAC3Out;
+  bool m_bSupportsDTSOut;
+  bool m_bSupportsAACOut;
+  bool m_bSupportsMP1Out;
+  bool m_bSupportsMP2Out;
+  bool m_bSupportsMP3Out;
+
+  CDVDAudioCodec   *m_codec  ;
+  IDVDAudioEncoder *m_encoder;
+  bool SetupEncoder(CDVDStreamInfo &hints);
+
   int (CDVDAudioCodecPassthroughFFmpeg::*m_pSyncFrame)(BYTE* pData, int iSize, int *fSize);
   int SyncAC3(BYTE* pData, int iSize, int *fSize);
   int SyncDTS(BYTE* pData, int iSize, int *fSize);
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/DVDAudioEncoderAC3.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/DVDAudioEncoderAC3.cpp	(revision 0)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/DVDAudioEncoderAC3.cpp	(revision 0)
@@ -0,0 +1,184 @@
+/*
+ *      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 "DVDAudioEncoderAC3.h"
+#include <string.h>
+
+CDVDAudioEncoderAC3::CDVDAudioEncoderAC3():
+  m_codecCtx  (NULL)
+{
+}
+
+CDVDAudioEncoderAC3::~CDVDAudioEncoderAC3()
+{
+  Reset();
+}
+
+bool CDVDAudioEncoderAC3::Initialize(unsigned int channels, enum PCMChannels *channelMap, unsigned int bitsPerSample, unsigned int sampleRate)
+{
+  Reset();
+  if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load())
+    return false;
+
+  AVCodec *codec;
+  codec = m_dllAvCodec.avcodec_find_encoder(CODEC_ID_AC3);
+  if (!codec)
+    return false;
+
+  /* always assume 6 channels, 5.1... m_remap will give us what we want */
+  m_codecCtx = m_dllAvCodec.avcodec_alloc_context();
+  m_codecCtx->bit_rate       = 448000;
+  m_codecCtx->sample_rate    = sampleRate;
+  m_codecCtx->channels       = 6;
+  m_codecCtx->channel_layout = CH_LAYOUT_5POINT1;
+
+  switch(bitsPerSample)
+  {
+    case  8: m_codecCtx->sample_fmt = SAMPLE_FMT_U8 ; break;
+    case 16: m_codecCtx->sample_fmt = SAMPLE_FMT_S16; break;
+    case 32: m_codecCtx->sample_fmt = SAMPLE_FMT_S32; break;
+    default:
+      m_dllAvUtil.av_freep(&m_codecCtx);
+      return false;
+  }
+
+  if (m_dllAvCodec.avcodec_open(m_codecCtx, codec))
+  {
+    m_dllAvUtil.av_freep(&m_codecCtx);
+    return false;
+  }
+
+  /* remap the channels according to the specified channel layout */
+  int index = 0;
+  if (m_codecCtx->channel_layout && CH_FRONT_LEFT           ) m_channelMap[index++] = PCM_FRONT_LEFT           ;
+  if (m_codecCtx->channel_layout && CH_FRONT_RIGHT          ) m_channelMap[index++] = PCM_FRONT_RIGHT          ;
+  if (m_codecCtx->channel_layout && CH_FRONT_CENTER         ) m_channelMap[index++] = PCM_FRONT_CENTER         ;
+  if (m_codecCtx->channel_layout && CH_LOW_FREQUENCY        ) m_channelMap[index++] = PCM_LOW_FREQUENCY        ;
+  if (m_codecCtx->channel_layout && CH_BACK_LEFT            ) m_channelMap[index++] = PCM_BACK_LEFT            ;
+  if (m_codecCtx->channel_layout && CH_BACK_RIGHT           ) m_channelMap[index++] = PCM_BACK_RIGHT           ;
+  if (m_codecCtx->channel_layout && CH_FRONT_LEFT_OF_CENTER ) m_channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ;
+  if (m_codecCtx->channel_layout && CH_FRONT_RIGHT_OF_CENTER) m_channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER;
+  if (m_codecCtx->channel_layout && CH_BACK_CENTER          ) m_channelMap[index++] = PCM_BACK_CENTER          ;
+  if (m_codecCtx->channel_layout && CH_SIDE_LEFT            ) m_channelMap[index++] = PCM_SIDE_LEFT            ;
+  if (m_codecCtx->channel_layout && CH_SIDE_RIGHT           ) m_channelMap[index++] = PCM_SIDE_RIGHT           ;
+  if (m_codecCtx->channel_layout && CH_TOP_CENTER           ) m_channelMap[index++] = PCM_TOP_CENTER           ;
+  if (m_codecCtx->channel_layout && CH_TOP_FRONT_LEFT       ) m_channelMap[index++] = PCM_TOP_FRONT_LEFT       ;
+  if (m_codecCtx->channel_layout && CH_TOP_FRONT_CENTER     ) m_channelMap[index++] = PCM_TOP_FRONT_CENTER     ;
+  if (m_codecCtx->channel_layout && CH_TOP_FRONT_RIGHT      ) m_channelMap[index++] = PCM_TOP_FRONT_RIGHT      ;
+  if (m_codecCtx->channel_layout && CH_TOP_BACK_LEFT        ) m_channelMap[index++] = PCM_TOP_BACK_LEFT        ;
+  if (m_codecCtx->channel_layout && CH_TOP_BACK_CENTER      ) m_channelMap[index++] = PCM_TOP_BACK_CENTER      ;
+  if (m_codecCtx->channel_layout && CH_TOP_BACK_RIGHT       ) m_channelMap[index++] = PCM_TOP_BACK_RIGHT       ;
+
+  m_remap.SetInputFormat (channels, channelMap, bitsPerSample / 8);
+  m_remap.SetOutputFormat(index   , m_channelMap);
+
+  if (!m_remap.CanRemap())
+  {
+    m_dllAvUtil.av_freep(&m_codecCtx);
+    return false; 
+  }
+
+  return true;
+}
+
+void CDVDAudioEncoderAC3::Reset()
+{
+  while(!m_packets.empty())
+  {
+    DSPAC3PacketInfo *info;
+    info = m_packets.front();
+    m_packets.pop_front();
+    delete[] info->data;
+    delete   info;
+  }
+}
+
+unsigned int CDVDAudioEncoderAC3::GetBitRate()
+{
+  return m_codecCtx->bit_rate;
+}
+
+CodecID CDVDAudioEncoderAC3::GetCodecID()
+{
+  return CODEC_ID_AC3;
+}
+
+int CDVDAudioEncoderAC3::Encode(void *data, int size)
+{
+  uint8_t *pos      = (uint8_t*)data;
+  int      consumed = 0;
+  int      frames   = m_remap.InBytesToFrames (size);
+  int      outsize  = m_remap.FramesToOutBytes(frames);
+  int      stride   = m_remap.FramesToInBytes (256);
+
+  /* remap the data and encode it in blocks of 256 frames */
+  while(frames >= 256)
+  {
+    uint8_t remapped[outsize];
+    m_remap.Remap(pos, remapped, 256);
+
+    DSPAC3PacketInfo *info;
+    info       = new DSPAC3PacketInfo();
+    info->size = outsize;
+    info->data = new uint8_t[AC3_MAX_CODED_FRAME_SIZE];
+    info->pos  = info->data;
+    info->size = m_dllAvCodec.avcodec_encode_audio(m_codecCtx, info->data, outsize, (short*)remapped);
+
+    consumed  += stride;
+    pos       += stride;
+    frames    -= 256;
+
+    m_packets.push_back(info);
+  }
+
+  /* return the consumed bytes */
+  return consumed;
+}
+
+int CDVDAudioEncoderAC3::GetData(void *data, int size)
+{
+  if (m_packets.empty()) return 0;
+
+  DSPAC3PacketInfo *info = m_packets.front();
+
+  /* figure out how much data we can copy */
+  int available = info->size - (info->pos - info->data);
+  int use;
+  if (available > size)
+    use = size;
+  else
+    use = available;
+
+  /* copy it into the destination buffer */
+  memcpy(data, info->pos, use);
+  info->pos += use;
+
+  /* if this list item is empty, then remove it */
+  if (info->size - (info->pos - info->data) == 0)
+  {
+    delete[] info->data;
+    delete   info;
+    m_packets.pop_front();
+  }
+
+  return use;
+}
+
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/DVDAudioEncoderAC3.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/DVDAudioEncoderAC3.h	(revision 0)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/DVDAudioEncoderAC3.h	(revision 0)
@@ -0,0 +1,59 @@
+#pragma once
+/*
+ *      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 <list>
+#include "IDVDAudioEncoder.h"
+#include "Codecs/DllAvCodec.h"
+#include "Codecs/DllAvFormat.h"
+
+class CDVDAudioEncoderAC3: public IDVDAudioEncoder
+{
+public:
+  CDVDAudioEncoderAC3();
+  virtual ~CDVDAudioEncoderAC3();
+  virtual bool Initialize(unsigned int channels, enum PCMChannels *channelMap, unsigned int bitsPerSample, unsigned int sampleRate);
+  virtual void Reset();
+
+  /* returns this DSPs output format */
+  virtual unsigned int      GetBitRate   ();
+  virtual CodecID           GetCodecID   ();
+
+  /* add/get packets to/from the DSP */
+  virtual int Encode (void *data, int size);
+  virtual int GetData(void *data, int size);
+private:
+  typedef struct
+  {
+    unsigned int  size;
+    uint8_t      *data;
+    uint8_t      *pos;
+  } DSPAC3PacketInfo;
+
+  std::list<DSPAC3PacketInfo*> m_packets;
+  DllAvCodec m_dllAvCodec;
+  DllAvUtil  m_dllAvUtil;
+
+  AVCodecContext   *m_codecCtx;
+  enum PCMChannels  m_channelMap[PCM_MAX_CH];
+  CPCMRemap         m_remap;
+};
+
Index: xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/IDVDAudioEncoder.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/IDVDAudioEncoder.h	(revision 0)
+++ xbmc/cores/dvdplayer/DVDCodecs/Audio/Encoders/IDVDAudioEncoder.h	(revision 0)
@@ -0,0 +1,42 @@
+#pragma once
+/*
+ *      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 "utils/PCMRemap.h"
+#include "DVDStreamInfo.h"
+
+class IDVDAudioEncoder
+{
+public:
+  IDVDAudioEncoder() {};
+  virtual ~IDVDAudioEncoder() {};
+  virtual bool Initialize(unsigned int channels, enum PCMChannels *channelMap, unsigned int bitsPerSample, unsigned int sampleRate) = 0;
+  virtual void Reset() = 0;
+
+  /* returns this DSPs output format */
+  virtual unsigned int GetBitRate() = 0;
+  virtual CodecID      GetCodecID() = 0;
+
+  /* add/get packets to/from the DSP */
+  virtual int Encode (void *data, int size) = 0;
+  virtual int GetData(void *data, int size) = 0;
+};
+
Index: xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp	(revision 27554)
+++ xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp	(working copy)
@@ -177,18 +177,21 @@
   return NULL;
 }
 
-CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec( CDVDStreamInfo &hint )
+CDVDAudioCodec* CDVDFactoryCodec::CreateAudioCodec( CDVDStreamInfo &hint, bool passthrough /* = true */)
 {
   CDVDAudioCodec* pCodec = NULL;
   CDVDCodecOptions options;
 
+  if (passthrough)
+  {
 #if defined(USE_LIBA52_DECODER) || defined(USE_LIBDTS_DECODER)
-  pCodec = OpenCodec( new CDVDAudioCodecPassthrough(), hint, options );
-  if( pCodec ) return pCodec;
+    pCodec = OpenCodec( new CDVDAudioCodecPassthrough(), hint, options );
+    if( pCodec ) return pCodec;
 #endif
 
-  pCodec = OpenCodec( new CDVDAudioCodecPassthroughFFmpeg(), hint, options);
-  if ( pCodec ) return pCodec;
+    pCodec = OpenCodec( new CDVDAudioCodecPassthroughFFmpeg(), hint, options);
+    if ( pCodec ) return pCodec;
+  }
 
   switch (hint.codec)
   {
Index: xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h
===================================================================
--- xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h	(revision 27554)
+++ xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h	(working copy)
@@ -36,7 +36,7 @@
 {
 public:
   static CDVDVideoCodec* CreateVideoCodec(CDVDStreamInfo &hint );
-  static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint );
+  static CDVDAudioCodec* CreateAudioCodec(CDVDStreamInfo &hint, bool passthrough = true );
   static CDVDOverlayCodec* CreateOverlayCodec(CDVDStreamInfo &hint );
 
   static CDVDAudioCodec* OpenCodec(CDVDAudioCodec* pCodec, CDVDStreamInfo &hint, CDVDCodecOptions &options );
Index: xbmc/utils/PCMRemap.h
===================================================================
--- xbmc/utils/PCMRemap.h	(revision 27554)
+++ xbmc/utils/PCMRemap.h	(working copy)
@@ -101,6 +101,9 @@
   void SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap);
   void Remap(void *data, void *out, unsigned int samples);
   bool CanRemap();
+  int  InBytesToFrames (int bytes );
+  int  FramesToOutBytes(int frames);
+  int  FramesToInBytes (int frames);
 };
 
 #endif
Index: xbmc/utils/PCMRemap.cpp
===================================================================
--- xbmc/utils/PCMRemap.cpp	(revision 27554)
+++ xbmc/utils/PCMRemap.cpp	(working copy)
@@ -465,3 +465,18 @@
   return (m_inSet && m_outSet);
 }
 
+int CPCMRemap::InBytesToFrames(int bytes)
+{
+  return bytes / m_inSampleSize / m_inChannels;
+}
+
+int CPCMRemap::FramesToOutBytes(int frames)
+{
+  return frames * m_inSampleSize * m_outChannels;
+}
+
+int CPCMRemap::FramesToInBytes(int frames)
+{
+  return frames * m_inSampleSize * m_inChannels;
+}
+