#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"
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()
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);
while(copied < size)
{
- buf = (uint8_t*)data;
+ buf = ((uint8_t*)data) + copied;
bytesToCopy = size - copied;
if (m_currentBuffer)
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;
// 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;
}
//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;
MsgStreamSample msgData;
msgData.buffer = m_currentBuffer;
msgData.stream = this;
+ RemapBuffer();
m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
m_currentBuffer = NULL;
}
MsgStreamSample msgData;
msgData.buffer = m_currentBuffer;
msgData.stream = this;
+ RemapBuffer();
m_streamPort->SendOutMessage(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
m_currentBuffer = NULL;
}