Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActiveAE: check input stream for ffmpeg channel order, remap if it does ... #3846

Merged
merged 1 commit into from Dec 19, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAE.cpp
Expand Up @@ -1007,6 +1007,9 @@ void CActiveAE::Configure(AEAudioFormat *desiredFmt)
(*it)->m_inputBuffers = new CActiveAEBufferPool((*it)->m_format);
(*it)->m_inputBuffers->Create(MAX_CACHE_LEVEL*1000);
(*it)->m_streamSpace = (*it)->m_format.m_frameSize * (*it)->m_format.m_frames;

// if input format does not follow ffmpeg channel mask, we may need to remap channels
(*it)->InitRemapper();
}
if (initSink && (*it)->m_resampleBuffers)
{
Expand Down
5 changes: 4 additions & 1 deletion xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
Expand Up @@ -25,6 +25,9 @@ using namespace ActiveAE;
CActiveAEResample::CActiveAEResample()
{
m_pContext = NULL;
m_loaded = false;
if (m_dllAvUtil.Load() && m_dllSwResample.Load())
m_loaded = true;
}

CActiveAEResample::~CActiveAEResample()
Expand All @@ -38,7 +41,7 @@ CActiveAEResample::~CActiveAEResample()

bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
{
if (!m_dllAvUtil.Load() || !m_dllSwResample.Load())
if (!m_loaded)
return false;

m_dst_chan_layout = dst_chan_layout;
Expand Down
1 change: 1 addition & 0 deletions xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
Expand Up @@ -51,6 +51,7 @@ class CActiveAEResample
protected:
DllAvUtil m_dllAvUtil;
DllSwResample m_dllSwResample;
bool m_loaded;
uint64_t m_src_chan_layout, m_dst_chan_layout;
int m_src_rate, m_dst_rate;
int m_src_channels, m_dst_channels;
Expand Down
106 changes: 106 additions & 0 deletions xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.cpp
Expand Up @@ -56,11 +56,15 @@ 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;
}

CActiveAEStream::~CActiveAEStream()
{
delete [] m_leftoverBuffer;
delete m_remapper;
delete m_remapBuffer;
}

void CActiveAEStream::IncFreeBuffers()
Expand All @@ -81,6 +85,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 == 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 == 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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand All @@ -248,6 +353,7 @@ void CActiveAEStream::Drain(bool wait)
MsgStreamSample msgData;
msgData.stream = this;
msgData.buffer = *((CSampleBuffer**)msg->data);
RemapBuffer();
msg->Reply(CActiveAEDataProtocol::STREAMSAMPLE, &msgData, sizeof(MsgStreamSample));
DecFreeBuffers();
continue;
Expand Down
6 changes: 5 additions & 1 deletion xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEStream.h
Expand Up @@ -38,6 +38,8 @@ class CActiveAEStream : public IAEStream
void IncFreeBuffers();
void DecFreeBuffers();
void ResetFreeBuffers();
void InitRemapper();
void RemapBuffer();

public:
virtual unsigned int GetSpace();
Expand Down Expand Up @@ -94,12 +96,14 @@ class CActiveAEStream : public IAEStream
CCriticalSection m_streamLock;
uint8_t *m_leftoverBuffer;
int m_leftoverBytes;
CSampleBuffer *m_currentBuffer;
CSoundPacket *m_remapBuffer;
CActiveAEResample *m_remapper;

// only accessed by engine
CActiveAEBufferPool *m_inputBuffers;
CActiveAEBufferPoolResample *m_resampleBuffers;
std::deque<CSampleBuffer*> m_processingSamples;
CSampleBuffer *m_currentBuffer;
CActiveAEDataProtocol *m_streamPort;
CEvent m_inMsgEvent;
CCriticalSection *m_statsLock;
Expand Down