Merge pull request #4619 from fritsch/aefixes
[vuplus_xbmc] / xbmc / cores / AudioEngine / Engines / ActiveAE / ActiveAEStream.cpp
index d5b01ea..0287e73 100644 (file)
@@ -23,8 +23,8 @@
 #include "utils/log.h"
 #include "utils/MathUtils.h"
 
-#include "AEFactory.h"
-#include "Utils/AEUtil.h"
+#include "cores/AudioEngine/AEFactory.h"
+#include "cores/AudioEngine/Utils/AEUtil.h"
 
 #include "ActiveAE.h"
 #include "ActiveAEStream.h"
@@ -56,11 +56,16 @@ CActiveAEStream::CActiveAEStream(AEAudioFormat *format)
   m_leftoverBuffer = new uint8_t[m_format.m_frameSize];
   m_leftoverBytes = 0;
   m_forceResampler = false;
+  m_remapper = NULL;
+  m_remapBuffer = NULL;
+  m_streamResampleRatio = 1.0;
 }
 
 CActiveAEStream::~CActiveAEStream()
 {
   delete [] m_leftoverBuffer;
+  delete m_remapper;
+  delete m_remapBuffer;
 }
 
 void CActiveAEStream::IncFreeBuffers()
@@ -81,6 +86,105 @@ void CActiveAEStream::ResetFreeBuffers()
   m_streamFreeBuffers = 0;
 }
 
+void CActiveAEStream::InitRemapper()
+{
+  // check if input format follows ffmpeg channel mask
+  bool needRemap = false;
+  unsigned int avLast, avCur = 0;
+  for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
+  {
+    avLast = avCur;
+    avCur = CActiveAEResample::GetAVChannel(m_format.m_channelLayout[i]);
+    if(avCur < avLast)
+    {
+      needRemap = true;
+      break;
+    }
+  }
+
+  if(needRemap)
+  {
+    CLog::Log(LOGDEBUG, "CActiveAEStream::%s - initialize remapper", __FUNCTION__);
+
+    m_remapper = new CActiveAEResample();
+    uint64_t avLayout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
+
+    // build layout according to ffmpeg channel order
+    // we need this for reference
+    CAEChannelInfo ffmpegLayout;
+    ffmpegLayout.Reset();
+    int idx = 0;
+    for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
+    {
+      for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
+      {
+        idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
+        if (idx == (int)i)
+        {
+          ffmpegLayout += m_format.m_channelLayout[j];
+          break;
+        }
+      }
+    }
+
+    // build remap layout we can pass to resampler as destination layout
+    CAEChannelInfo remapLayout;
+    remapLayout.Reset();
+    for(unsigned int i=0; i<m_format.m_channelLayout.Count(); i++)
+    {
+      for(unsigned int j=0; j<m_format.m_channelLayout.Count(); j++)
+      {
+        idx = m_remapper->GetAVChannelIndex(m_format.m_channelLayout[j], avLayout);
+        if (idx == (int)i)
+        {
+          remapLayout += ffmpegLayout[j];
+          break;
+        }
+      }
+    }
+
+    // initialize resampler for only doing remapping
+    m_remapper->Init(avLayout,
+                     m_format.m_channelLayout.Count(),
+                     m_format.m_sampleRate,
+                     CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
+                     CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
+                     avLayout,
+                     m_format.m_channelLayout.Count(),
+                     m_format.m_sampleRate,
+                     CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
+                     CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
+                     false,
+                     false,
+                     &remapLayout,
+                     AE_QUALITY_LOW); // not used for remapping
+
+    // extra sound packet, we can't resample to the same buffer
+    m_remapBuffer = new CSoundPacket(m_inputBuffers->m_allSamples[0]->pkt->config, m_inputBuffers->m_allSamples[0]->pkt->max_nb_samples);
+  }
+}
+
+void CActiveAEStream::RemapBuffer()
+{
+  if(m_remapper)
+  {
+    int samples = m_remapper->Resample(m_remapBuffer->data, m_remapBuffer->max_nb_samples,
+                                       m_currentBuffer->pkt->data, m_currentBuffer->pkt->nb_samples,
+                                       1.0);
+
+    if (samples != m_currentBuffer->pkt->nb_samples)
+    {
+      CLog::Log(LOGERROR, "CActiveAEStream::%s - error remapping", __FUNCTION__);
+    }
+
+    // swap sound packets
+    CSoundPacket *tmp = m_remapBuffer;
+    tmp = m_currentBuffer->pkt;
+    m_currentBuffer->pkt = m_remapBuffer;
+    m_remapBuffer = tmp;
+  }
+}
+
 unsigned int CActiveAEStream::GetSpace()
 {
   CSingleLock lock(m_streamLock);
@@ -96,7 +200,7 @@ unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
 
   while(copied < size)
   {
-    buf = (uint8_t*)data;
+    buf = ((uint8_t*)data) + copied;
     bytesToCopy = size - copied;
 
     if (m_currentBuffer)
@@ -105,9 +209,8 @@ unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
       if (m_leftoverBytes && bytesToCopy >= (m_format.m_frameSize - m_leftoverBytes))
       {
         int fillbytes = m_format.m_frameSize - m_leftoverBytes;
-        memcpy(m_leftoverBuffer+m_leftoverBytes, (uint8_t*)data, fillbytes);
-        data = (uint8_t*)data + fillbytes;
-        size -= fillbytes;
+        memcpy(m_leftoverBuffer+m_leftoverBytes, buf, fillbytes);
+        copied += fillbytes;
         // leftover buffer will be copied on next cycle
         buf = m_leftoverBuffer;
         bytesToCopy = m_format.m_frameSize;
@@ -125,7 +228,7 @@ unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
       // if we don't have a full frame, copy to leftover buffer
       if (!availableSamples && bytesToCopy)
       {
-        memcpy(m_leftoverBuffer+m_leftoverBytes, buf+copied, bytesToCopy);
+        memcpy(m_leftoverBuffer+m_leftoverBytes, buf, bytesToCopy);
         m_leftoverBytes = bytesToCopy;
         copied += bytesToCopy;
       }
@@ -135,9 +238,9 @@ unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
 
       //TODO: handle planar formats
       if (m_convertFn)
-        m_convertFn(buf+copied, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
+        m_convertFn(buf, samples*m_currentBuffer->pkt->config.channels, (float*)(m_currentBuffer->pkt->data[0] + start));
       else
-        memcpy(m_currentBuffer->pkt->data[0] + start, buf+copied, bytes);
+        memcpy(m_currentBuffer->pkt->data[0] + start, buf, bytes);
       {
         CSingleLock lock(*m_statsLock);
         m_currentBuffer->pkt->nb_samples += samples;
@@ -150,6 +253,7 @@ unsigned int CActiveAEStream::AddData(void *data, unsigned int size)
         MsgStreamSample msgData;
         msgData.buffer = m_currentBuffer;
         msgData.stream = this;
+        RemapBuffer();
         m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
         m_currentBuffer = NULL;
       }
@@ -234,6 +338,7 @@ void CActiveAEStream::Drain(bool wait)
     MsgStreamSample msgData;
     msgData.buffer = m_currentBuffer;
     msgData.stream = this;
+    RemapBuffer();
     m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
     m_currentBuffer = NULL;
   }