All pastes #1788904 Raw Edit

Untitled

public text v1 · immutable
#1788904 ·published 2010-02-07 10:04 UTC
rendered paste body
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp
index 96958da..1c1d330 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.cpp
@@ -26,6 +26,9 @@
 #include "Settings.h"
 #include "utils/log.h"
 
+#include "../DVDFactoryCodec.h"
+#include "Encoders/DVDAudioEncoderAC3.h"
+
 //These values are forced to allow spdif out
 #define OUT_SAMPLESIZE 16
 #define OUT_CHANNELS   2
@@ -40,6 +43,7 @@ CDVDAudioCodecPassthroughFFmpeg::CDVDAudioCodecPassthroughFFmpeg(void)
   m_pFormat      = NULL;
   m_pStream      = NULL;
   m_pSyncFrame   = NULL;
+  m_codec        = NULL;
 
   m_OutputSize   = 0;
   m_OutputBuffer = (BYTE*)_aligned_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE, 16);
@@ -52,34 +56,57 @@ CDVDAudioCodecPassthroughFFmpeg::~CDVDAudioCodecPassthroughFFmpeg(void)
   Dispose();
 }
 
-bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
+bool CDVDAudioCodecPassthroughFFmpeg::SetupEncoder(CDVDStreamInfo &hints)
 {
-  bool bSupportsAC3Out = false;
-  bool bSupportsDTSOut = false;
-  bool bSupportsAACOut = false;
-  bool bSupportsMP1Out = false;
-  bool bSupportsMP2Out = false;
-  bool bSupportsMP3Out = false;
+  /* 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;
+
+  /* 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)
+    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()))
+  {
+    Dispose();
+    return false;
+  }
+
+  /* adjust the hints according to the encorders output */
+  hints.codec      = m_encoder->GetCodecID   ();
+  hints.channels   = m_encoder->GetChannels  ();
+  hints.bitrate    = m_encoder->GetBitRate   ();
+  hints.samplerate = m_encoder->GetSampleRate();
+
+  return true;
+}
 
+bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
+{
   // 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))
+  if ((hints.codec == CODEC_ID_AC3 && m_bSupportsAC3Out)
+   || (hints.codec == CODEC_ID_DTS && m_bSupportsDTSOut)
+   || (hints.codec == CODEC_ID_AAC && m_bSupportsAACOut)
+   || (hints.codec == CODEC_ID_MP1 && m_bSupportsMP1Out)
+   || (hints.codec == CODEC_ID_MP2 && m_bSupportsMP2Out)
+   || (hints.codec == CODEC_ID_MP3 && m_bSupportsMP3Out))
   {
 
     // TODO - this is only valid for video files, and should be moved somewhere else
@@ -108,19 +135,28 @@ bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptio
 
     /* 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;
-
-      default:
-        CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - ffmpeg SPDIF muxer does not support this codec");
-        Dispose();
-        return false;
+    bool setupEncoder = true;
+    while(true) {
+      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;
+
+        default:
+          if (setupEncoder && SetupEncoder(hints))
+          {
+            setupEncoder = false;
+            continue;
+          }
+          CLog::Log(LOGERROR, "CDVDAudioCodecPassthroughFFmpeg::Open - FFmpeg SPDIF muxer does not support this codec");
+          Dispose();
+          return false;
+      }
+      break;
     }
 
     /* allocate a the format context */
@@ -186,7 +222,20 @@ bool CDVDAudioCodecPassthroughFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptio
 
 void CDVDAudioCodecPassthroughFFmpeg::Dispose()
 {
-  if (m_pFormat) {
+  if (m_encoder)
+  {
+    delete m_encoder;
+    m_encoder = NULL;
+  }
+
+  if (m_codec)
+  {
+    delete m_codec;
+    m_codec   = NULL;
+  }
+
+  if (m_pFormat)
+  {
     if (m_pFormat->pb)
       m_dllAvUtil.av_freep(&m_pFormat->pb);
     m_dllAvUtil.av_freep(&m_pFormat);
@@ -280,11 +329,11 @@ int CDVDAudioCodecPassthroughFFmpeg::SyncDTS(BYTE* pData, int iSize, int *fSize)
     ) 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,12 +347,32 @@ int CDVDAudioCodecPassthroughFFmpeg::SyncDTS(BYTE* pData, int iSize, int *fSize)
 
 int CDVDAudioCodecPassthroughFFmpeg::Decode(BYTE* pData, int iSize)
 {
-  int fSize = iSize;
-  if (m_pSyncFrame)
+  int used, fSize;
+  used = fSize = iSize;
+
+  /* if we are encoding */
+  if (m_encoder)
   {
-    int skip = (this->*m_pSyncFrame)(pData, iSize, &fSize);
-    if (skip > 0)
-      return skip;
+    BYTE *decData;
+    BYTE encData[6144];
+    used  = m_codec  ->Decode (pData, iSize);
+    iSize = m_codec  ->GetData(&decData);
+    iSize = m_encoder->Encode (decData, iSize);
+    fSize = m_encoder->GetData(encData, 6144);
+    pData = encData;
+
+    /* if the encoder has not got anything yet, return the consumed bytes */
+    if (iSize == 0)
+      return used;
+  }
+  else
+  {
+    if (m_pSyncFrame)
+    {
+      int skip = (this->*m_pSyncFrame)(pData, iSize, &fSize);
+      if (skip > 0)
+        return skip;
+    }
   }
 
   AVPacket pkt;
@@ -314,7 +383,8 @@ int CDVDAudioCodecPassthroughFFmpeg::Decode(BYTE* pData, int iSize)
   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)
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
index 1971c56..25d6f50 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/Audio/DVDAudioCodecPassthroughFFmpeg.h
@@ -26,6 +26,7 @@
 #include "Codecs/DllAvCodec.h"
 
 #include "DVDAudioCodec.h"
+#include "Encoders/IDVDAudioEncoder.h"
 
 class CDVDAudioCodecPassthroughFFmpeg : public CDVDAudioCodec
 {
@@ -46,6 +47,17 @@ public:
   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);
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
index 2530221..f802616 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
@@ -177,18 +177,21 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec( CDVDStreamInfo &hint )
   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)
   {
diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h
index 09885b0..317100e 100644
--- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h
+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h
@@ -36,7 +36,7 @@ class CDVDFactoryCodec
 {
 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 );