From 38f05eea130bc0640411864c890767c00f7150d9 Mon Sep 17 00:00:00 2001 From: popcornmix Date: Tue, 22 Oct 2013 22:00:32 +0100 Subject: [PATCH] Added multichannel PCM output support Requires updated firmware (22/10/13). --- OMXAudio.cpp | 258 +++++++++++++++++++++---------------------- OMXAudio.h | 15 ++- OMXAudioCodecOMX.cpp | 109 ++---------------- OMXAudioCodecOMX.h | 6 +- OMXPlayerAudio.cpp | 12 +- OMXPlayerAudio.h | 4 +- README.md | 1 + omxplayer.cpp | 23 +++- utils/PCMRemap.cpp | 27 ++++- utils/PCMRemap.h | 6 +- 10 files changed, 202 insertions(+), 259 deletions(-) diff --git a/OMXAudio.cpp b/OMXAudio.cpp index c7ca399c..b46c5924 100644 --- a/OMXAudio.cpp +++ b/OMXAudio.cpp @@ -39,68 +39,14 @@ using namespace std; -#define OMX_MAX_CHANNELS 10 // the size of the audio_render output port buffers #define AUDIO_DECODE_OUTPUT_BUFFER (32*1024) -static enum PCMChannels OMXChannelMap[OMX_MAX_CHANNELS] = -{ - PCM_FRONT_LEFT , PCM_FRONT_RIGHT, - PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, - PCM_BACK_LEFT , PCM_BACK_RIGHT, - PCM_SIDE_LEFT , PCM_SIDE_RIGHT, - PCM_BACK_CENTER -}; - -static enum OMX_AUDIO_CHANNELTYPE OMXChannels[OMX_MAX_CHANNELS] = -{ - OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF, - OMX_AUDIO_ChannelCF, OMX_AUDIO_ChannelLFE, - OMX_AUDIO_ChannelLR, OMX_AUDIO_ChannelRR, - OMX_AUDIO_ChannelLS, OMX_AUDIO_ChannelRS, - OMX_AUDIO_ChannelCS, OMX_AUDIO_ChannelNone -}; - -static unsigned int WAVEChannels[OMX_MAX_CHANNELS] = -{ - SPEAKER_FRONT_LEFT, SPEAKER_FRONT_RIGHT, - SPEAKER_TOP_FRONT_CENTER, SPEAKER_LOW_FREQUENCY, - SPEAKER_BACK_LEFT, SPEAKER_BACK_RIGHT, - SPEAKER_SIDE_LEFT, SPEAKER_SIDE_RIGHT, - SPEAKER_BACK_CENTER, 0 -}; - 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, 44100, 32000, 0}; static const uint16_t DTSFSCod [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0}; -// 7.1 downmixing coefficients -const float downmixing_coefficients_8[OMX_AUDIO_MAXCHANNELS] = { - // L R - /* L */ 1, 0, - /* R */ 0, 1, - /* C */ 0.7071, 0.7071, - /* LFE */ 0.7071, 0.7071, - /* Ls */ 0.7071, 0, - /* Rs */ 0, 0.7071, - /* Lr */ 0.7071, 0, - /* Rr */ 0, 0.7071 -}; - -// 7.1 downmixing coefficients with boosted centre channel -const float downmixing_coefficients_8_boostcentre[OMX_AUDIO_MAXCHANNELS] = { - // L R - /* L */ 0.7071, 0, - /* R */ 0, 0.7071, - /* C */ 1, 1, - /* LFE */ 0.7071, 0.7071, - /* Ls */ 0.7071, 0, - /* Rs */ 0, 0.7071, - /* Lr */ 0.7071, 0, - /* Rr */ 0, 0.7071 -}; - ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -117,7 +63,7 @@ COMXAudio::COMXAudio() : m_BufferLen (0 ), m_ChunkLen (0 ), m_InputChannels (0 ), - m_downmix_channels(0 ), + m_OutputChannels (0 ), m_BitsPerSample (0 ), m_maxLevel (0.0f ), m_amplification (1.0f ), @@ -182,9 +128,8 @@ bool COMXAudio::PortSettingsChanged() m_pcm_output.nPortIndex = m_omx_mixer.GetOutputPort(); /* mixer output is always stereo */ - m_pcm_output.eChannelMapping[0] = OMX_AUDIO_ChannelLF; - m_pcm_output.eChannelMapping[1] = OMX_AUDIO_ChannelRF; - m_pcm_output.nChannels = 2; + memcpy(m_pcm_output.eChannelMapping, m_output_channels, sizeof(m_output_channels)); + m_pcm_output.nChannels = m_OutputChannels; omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output); if(omx_err != OMX_ErrorNone) @@ -274,8 +219,8 @@ bool COMXAudio::PortSettingsChanged() return true; } -bool COMXAudio::Initialize(const CStdString& device, int iChannels, enum PCMChannels *channelMap, - COMXStreamInfo &hints, unsigned int downmixChannels, unsigned int uiSampleRate, unsigned int uiBitsPerSample, bool boostOnDownmix, +bool COMXAudio::Initialize(const CStdString& device, int iChannels, uint64_t channelMap, + COMXStreamInfo &hints, enum PCMLayout layout, unsigned int uiSampleRate, unsigned int uiBitsPerSample, bool boostOnDownmix, OMXClock *clock, bool bUsePassthrough, bool bUseHWDecode, bool is_live, float fifo_size) { CSingleLock lock (m_critSection); @@ -296,7 +241,6 @@ bool COMXAudio::Initialize(const CStdString& device, int iChannels, enum PCMChan m_Passthrough = bUsePassthrough; m_InputChannels = iChannels; m_fifo_size = fifo_size; - m_downmix_channels = downmixChannels; m_normalize_downmix = !boostOnDownmix; m_live = is_live; @@ -339,54 +283,29 @@ bool COMXAudio::Initialize(const CStdString& device, int iChannels, enum PCMChan m_drc = 0; memset(m_input_channels, 0x0, sizeof(m_input_channels)); - + memset(m_output_channels, 0x0, sizeof(m_output_channels)); memset(&m_wave_header, 0x0, sizeof(m_wave_header)); - for(int i = 0; i < OMX_AUDIO_MAXCHANNELS; i++) - { - m_pcm_input.eChannelMapping[i] = OMX_AUDIO_ChannelNone; - m_input_channels[i] = OMX_AUDIO_ChannelMax; - } - - m_input_channels[0] = OMX_AUDIO_ChannelLF; - m_input_channels[1] = OMX_AUDIO_ChannelRF; - m_input_channels[2] = OMX_AUDIO_ChannelMax; - m_wave_header.Format.nChannels = 2; m_wave_header.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; // set the input format, and get the channel layout so we know what we need to open - enum PCMChannels *outLayout = NULL; - - m_remap.Reset(); if (!m_Passthrough && channelMap) - outLayout = m_remap.SetInputFormat (iChannels, channelMap, uiBitsPerSample / 8, uiSampleRate);; - - if (!m_Passthrough && channelMap && outLayout) { - /* setup input channel map */ - int map = 0; - int chan = 0; - - for (unsigned int ch = 0; ch < m_InputChannels; ++ch) - { - for(map = 0; map < OMX_MAX_CHANNELS; ++map) - { - if (channelMap[ch] == OMXChannelMap[map]) - { - m_input_channels[chan] = OMXChannels[map]; - m_wave_header.dwChannelMask |= WAVEChannels[map]; - chan++; - break; - } - } - } + enum PCMChannels inLayout[OMX_AUDIO_MAXCHANNELS]; + enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS]; + BuildChannelMap(inLayout, channelMap); + m_OutputChannels = BuildChannelMapCEA(outLayout, GetChannelLayout(layout)); + CPCMRemap m_remap; + m_remap.Reset(); + /*outLayout = */m_remap.SetInputFormat (iChannels, inLayout, uiBitsPerSample / 8, uiSampleRate, layout, boostOnDownmix); + m_remap.SetOutputFormat(m_OutputChannels, outLayout); + m_remap.GetDownmixMatrix(m_downmix_matrix); + m_wave_header.dwChannelMask = channelMap; + BuildChannelMapOMX(m_input_channels, channelMap); + BuildChannelMapOMX(m_output_channels, GetChannelLayout(layout)); } - OMX_INIT_STRUCTURE(m_pcm_input); - - memcpy(m_pcm_input.eChannelMapping, m_input_channels, sizeof(m_input_channels)); - m_SampleRate = uiSampleRate; m_BitsPerSample = uiBitsPerSample; m_BufferLen = m_BytesPerSec = m_SampleRate * (16 >> 3) * m_InputChannels; @@ -411,6 +330,8 @@ bool COMXAudio::Initialize(const CStdString& device, int iChannels, enum PCMChan m_wave_header.Format.cbSize = 0; m_wave_header.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + OMX_INIT_STRUCTURE(m_pcm_input); + memcpy(m_pcm_input.eChannelMapping, m_input_channels, sizeof(m_input_channels)); m_pcm_input.eNumData = OMX_NumericalDataSigned; m_pcm_input.eEndian = OMX_EndianLittle; m_pcm_input.bInterleaved = OMX_TRUE; @@ -697,7 +618,6 @@ float COMXAudio::GetVolume() bool COMXAudio::ApplyVolume(void) { float m_ac3Gain = 12.0f; - bool m_boostcentre = false; CSingleLock lock (m_critSection); if(!m_Initialized || m_Passthrough) @@ -708,48 +628,22 @@ bool COMXAudio::ApplyVolume(void) // the analogue volume is too quiet for some. Allow use of an advancedsetting to boost this (at risk of distortion) (deprecated) double gain = pow(10, (m_ac3Gain - 12.0f) / 20.0); - double r = 1.0; - const float* coeff = downmixing_coefficients_8; - - // alternate coefficients that boost centre channel more - if(m_boostcentre && m_InputChannels > 2) - coeff = downmixing_coefficients_8_boostcentre; - - // normally we normalise the levels, can be skipped (boosted) at risk of distortion - if(!m_normalize_downmix) - { - double sum_L = 0; - double sum_R = 0; - - for(size_t i = 0; i < OMX_AUDIO_MAXCHANNELS; ++i) - { - if (m_input_channels[i] == OMX_AUDIO_ChannelMax) - break; - if(i & 1) - sum_R += coeff[i]; - else - sum_L += coeff[i]; - } - - r /= max(sum_L, sum_R); - } - - r *= gain; + const float* coeff = m_downmix_matrix; - OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS mix; + OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix; OMX_INIT_STRUCTURE(mix); OMX_ERRORTYPE omx_err; - assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 16); + assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64); if (m_amplification != 1.0) { // reduce scaling so overflow can be seen - for(size_t i = 0; i < 16; ++i) - mix.coeff[i] = static_cast(0x10000 * (coeff[i] * r * 0.01f)); + for(size_t i = 0; i < 8*8; ++i) + mix.coeff[i] = static_cast(0x10000 * (coeff[i] * gain * 0.01f)); mix.nPortIndex = m_omx_decoder.GetInputPort(); - omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix); + omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix); if(omx_err != OMX_ErrorNone) { CLog::Log(LOGERROR, "%s::%s - error setting decoder OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n", @@ -757,11 +651,11 @@ bool COMXAudio::ApplyVolume(void) return false; } } - for(size_t i = 0; i < 16; ++i) - mix.coeff[i] = static_cast(0x10000 * (coeff[i] * r * fVolume * m_amplification * m_attenuation)); + for(size_t i = 0; i < 8*8; ++i) + mix.coeff[i] = static_cast(0x10000 * (coeff[i] * gain * fVolume * m_amplification * m_attenuation)); mix.nPortIndex = m_omx_mixer.GetInputPort(); - omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients, &mix); + omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix); if(omx_err != OMX_ErrorNone) { CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n", @@ -1484,3 +1378,97 @@ unsigned int COMXAudio::SyncAC3(BYTE* pData, unsigned int iSize) return iSize; } +void COMXAudio::BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout) +{ + int index = 0; + if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = PCM_FRONT_LEFT ; + if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = PCM_FRONT_RIGHT ; + if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = PCM_FRONT_CENTER ; + if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = PCM_LOW_FREQUENCY ; + if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = PCM_BACK_LEFT ; + if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = PCM_BACK_RIGHT ; + if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ; + if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER; + if (layout & AV_CH_BACK_CENTER ) channelMap[index++] = PCM_BACK_CENTER ; + if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = PCM_SIDE_LEFT ; + if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = PCM_SIDE_RIGHT ; + if (layout & AV_CH_TOP_CENTER ) channelMap[index++] = PCM_TOP_CENTER ; + if (layout & AV_CH_TOP_FRONT_LEFT ) channelMap[index++] = PCM_TOP_FRONT_LEFT ; + if (layout & AV_CH_TOP_FRONT_CENTER ) channelMap[index++] = PCM_TOP_FRONT_CENTER ; + if (layout & AV_CH_TOP_FRONT_RIGHT ) channelMap[index++] = PCM_TOP_FRONT_RIGHT ; + if (layout & AV_CH_TOP_BACK_LEFT ) channelMap[index++] = PCM_TOP_BACK_LEFT ; + if (layout & AV_CH_TOP_BACK_CENTER ) channelMap[index++] = PCM_TOP_BACK_CENTER ; + if (layout & AV_CH_TOP_BACK_RIGHT ) channelMap[index++] = PCM_TOP_BACK_RIGHT ; + while (index 4 ? 8 : num_channels > 2 ? 4 : num_channels; + return num_channels; +} + +void COMXAudio::BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE * channelMap, uint64_t layout) +{ + int index = 0; + + if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLF; + if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRF; + if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = OMX_AUDIO_ChannelCF; + if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = OMX_AUDIO_ChannelLFE; + if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLR; + if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRR; + if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLS; + if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRS; + if (layout & AV_CH_BACK_CENTER ) channelMap[index++] = OMX_AUDIO_ChannelCS; + // following are not in openmax spec, but gpu does accept them + if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)10; + if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)11; + if (layout & AV_CH_TOP_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)12; + if (layout & AV_CH_TOP_FRONT_LEFT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)13; + if (layout & AV_CH_TOP_FRONT_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)14; + if (layout & AV_CH_TOP_FRONT_RIGHT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)15; + if (layout & AV_CH_TOP_BACK_LEFT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)16; + if (layout & AV_CH_TOP_BACK_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)17; + if (layout & AV_CH_TOP_BACK_RIGHT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)18; + + while (index m_ampqueue; + float m_downmix_matrix[OMX_AUDIO_MAXCHANNELS*OMX_AUDIO_MAXCHANNELS]; protected: COMXCoreComponent m_omx_render; @@ -144,8 +151,6 @@ class COMXAudio COMXCoreTunel m_omx_tunnel_mixer; COMXCoreTunel m_omx_tunnel_decoder; DllAvUtil m_dllAvUtil; - OMX_AUDIO_CHANNELTYPE m_input_channels[OMX_AUDIO_MAXCHANNELS]; - CPCMRemap m_remap; CCriticalSection m_critSection; }; #endif diff --git a/OMXAudioCodecOMX.cpp b/OMXAudioCodecOMX.cpp index cdddaaac..210b64cd 100644 --- a/OMXAudioCodecOMX.cpp +++ b/OMXAudioCodecOMX.cpp @@ -34,9 +34,7 @@ COMXAudioCodecOMX::COMXAudioCodecOMX() m_pConvert = NULL; m_bOpenedCodec = false; - m_channelMap[0] = PCM_INVALID; m_channels = 0; - m_layout = 0; m_pFrame1 = NULL; m_bGotFrame = false; m_iSampleFormat = AV_SAMPLE_FMT_NONE; @@ -194,7 +192,10 @@ int COMXAudioCodecOMX::GetData(BYTE** dst) if(m_pCodecContext->sample_fmt != m_desiredSampleFormat) { if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels)) + { m_dllSwResample.swr_free(&m_pConvert); + m_channels = m_pCodecContext->channels; + } if(!m_pConvert) { @@ -290,106 +291,18 @@ static unsigned count_bits(int64_t value) return bits; } -void COMXAudioCodecOMX::BuildChannelMap() +uint64_t COMXAudioCodecOMX::GetChannelMap() { - if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout) - return; //nothing to do here - - m_channels = m_pCodecContext->channels; - m_layout = m_pCodecContext->channel_layout; - - int index = 0; - if(m_pCodecContext->codec_id == CODEC_ID_AAC && m_pCodecContext->channels == 3) - { - m_channelMap[index++] = PCM_FRONT_CENTER; - m_channelMap[index++] = PCM_FRONT_LEFT; - m_channelMap[index++] = PCM_FRONT_RIGHT; - } - else if(m_pCodecContext->codec_id == CODEC_ID_AAC && m_pCodecContext->channels == 4) - { - m_channelMap[index++] = PCM_FRONT_CENTER; - m_channelMap[index++] = PCM_FRONT_LEFT; - m_channelMap[index++] = PCM_FRONT_RIGHT; - m_channelMap[index++] = PCM_BACK_CENTER; - } - else if(m_pCodecContext->codec_id == CODEC_ID_AAC && m_pCodecContext->channels == 5) - { - m_channelMap[index++] = PCM_FRONT_CENTER; - m_channelMap[index++] = PCM_FRONT_LEFT; - m_channelMap[index++] = PCM_FRONT_RIGHT; - m_channelMap[index++] = PCM_BACK_LEFT; - m_channelMap[index++] = PCM_BACK_RIGHT; - } - else if(m_pCodecContext->codec_id == CODEC_ID_AAC && m_pCodecContext->channels == 6) - { - m_channelMap[index++] = PCM_FRONT_CENTER; - m_channelMap[index++] = PCM_FRONT_LEFT; - m_channelMap[index++] = PCM_FRONT_RIGHT; - m_channelMap[index++] = PCM_BACK_LEFT; - m_channelMap[index++] = PCM_BACK_RIGHT; - m_channelMap[index++] = PCM_LOW_FREQUENCY; - } - else if(m_pCodecContext->codec_id == CODEC_ID_AAC && m_pCodecContext->channels == 7) - { - m_channelMap[index++] = PCM_FRONT_CENTER; - m_channelMap[index++] = PCM_FRONT_LEFT; - m_channelMap[index++] = PCM_FRONT_RIGHT; - m_channelMap[index++] = PCM_BACK_LEFT; - m_channelMap[index++] = PCM_BACK_RIGHT; - m_channelMap[index++] = PCM_BACK_CENTER; - m_channelMap[index++] = PCM_LOW_FREQUENCY; - } - else if(m_pCodecContext->codec_id == CODEC_ID_AAC && m_pCodecContext->channels == 8) - { - m_channelMap[index++] = PCM_FRONT_CENTER; - m_channelMap[index++] = PCM_SIDE_LEFT; - m_channelMap[index++] = PCM_SIDE_RIGHT; - m_channelMap[index++] = PCM_FRONT_LEFT; - m_channelMap[index++] = PCM_FRONT_RIGHT; - m_channelMap[index++] = PCM_BACK_LEFT; - m_channelMap[index++] = PCM_BACK_RIGHT; - m_channelMap[index++] = PCM_LOW_FREQUENCY; - } + uint64_t layout; + int bits = count_bits(m_pCodecContext->channel_layout); + if (bits == m_pCodecContext->channels) + layout = m_pCodecContext->channel_layout; else { - - int64_t layout; - int bits = count_bits(m_pCodecContext->channel_layout); - if (bits == m_pCodecContext->channels) - layout = m_pCodecContext->channel_layout; - else - { - CLog::Log(LOGINFO, "COMXAudioCodecOMX::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits); - layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels); - } - - if (layout & AV_CH_FRONT_LEFT ) m_channelMap[index++] = PCM_FRONT_LEFT ; - if (layout & AV_CH_FRONT_RIGHT ) m_channelMap[index++] = PCM_FRONT_RIGHT ; - if (layout & AV_CH_FRONT_CENTER ) m_channelMap[index++] = PCM_FRONT_CENTER ; - if (layout & AV_CH_LOW_FREQUENCY ) m_channelMap[index++] = PCM_LOW_FREQUENCY ; - if (layout & AV_CH_BACK_LEFT ) m_channelMap[index++] = PCM_BACK_LEFT ; - if (layout & AV_CH_BACK_RIGHT ) m_channelMap[index++] = PCM_BACK_RIGHT ; - if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ; - if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER; - if (layout & AV_CH_BACK_CENTER ) m_channelMap[index++] = PCM_BACK_CENTER ; - if (layout & AV_CH_SIDE_LEFT ) m_channelMap[index++] = PCM_SIDE_LEFT ; - if (layout & AV_CH_SIDE_RIGHT ) m_channelMap[index++] = PCM_SIDE_RIGHT ; - if (layout & AV_CH_TOP_CENTER ) m_channelMap[index++] = PCM_TOP_CENTER ; - if (layout & AV_CH_TOP_FRONT_LEFT ) m_channelMap[index++] = PCM_TOP_FRONT_LEFT ; - if (layout & AV_CH_TOP_FRONT_CENTER ) m_channelMap[index++] = PCM_TOP_FRONT_CENTER ; - if (layout & AV_CH_TOP_FRONT_RIGHT ) m_channelMap[index++] = PCM_TOP_FRONT_RIGHT ; - if (layout & AV_CH_TOP_BACK_LEFT ) m_channelMap[index++] = PCM_TOP_BACK_LEFT ; - if (layout & AV_CH_TOP_BACK_CENTER ) m_channelMap[index++] = PCM_TOP_BACK_CENTER ; - if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelMap[index++] = PCM_TOP_BACK_RIGHT ; + CLog::Log(LOGINFO, "COMXAudioCodecOMX::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits); + layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels); } -} - -enum PCMChannels* COMXAudioCodecOMX::GetChannelMap() -{ - BuildChannelMap(); - if (m_channelMap[0] == PCM_INVALID) - return NULL; - return m_channelMap; + return layout; } diff --git a/OMXAudioCodecOMX.h b/OMXAudioCodecOMX.h index c64341a0..63770acd 100644 --- a/OMXAudioCodecOMX.h +++ b/OMXAudioCodecOMX.h @@ -41,7 +41,7 @@ class COMXAudioCodecOMX int GetData(BYTE** dst); void Reset(); int GetChannels(); - enum PCMChannels *GetChannelMap(); + uint64_t GetChannelMap(); int GetSampleRate(); int GetBitsPerSample(); static const char* GetName() { return "FFmpeg"; } @@ -52,7 +52,6 @@ class COMXAudioCodecOMX SwrContext* m_pConvert; enum AVSampleFormat m_iSampleFormat; enum AVSampleFormat m_desiredSampleFormat; - enum PCMChannels m_channelMap[PCM_MAX_CH + 1]; AVFrame* m_pFrame1; @@ -62,13 +61,10 @@ class COMXAudioCodecOMX bool m_bOpenedCodec; int m_channels; - uint64_t m_layout; bool m_bFirstFrame; bool m_bGotFrame; DllAvCodec m_dllAvCodec; DllAvUtil m_dllAvUtil; DllSwResample m_dllSwResample; - - void BuildChannelMap(); }; diff --git a/OMXPlayerAudio.cpp b/OMXPlayerAudio.cpp index 9606e913..50b1334c 100644 --- a/OMXPlayerAudio.cpp +++ b/OMXPlayerAudio.cpp @@ -42,12 +42,12 @@ OMXPlayerAudio::OMXPlayerAudio() m_decoder = NULL; m_flush = false; m_cached_size = 0; - m_pChannelMap = NULL; m_pAudioCodec = NULL; m_player_error = true; m_max_data_size = 3 * 1024 * 1024; m_fifo_size = 2.0f; m_live = false; + m_layout = PCM_LAYOUT_2_0; pthread_cond_init(&m_packet_cond, NULL); pthread_cond_init(&m_audio_cond, NULL); @@ -91,7 +91,7 @@ void OMXPlayerAudio::UnLockDecoder() bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader *omx_reader, std::string device, bool passthrough, bool hw_decode, - bool boost_on_downmix, bool use_thread, bool is_live, float queue_size, float fifo_size) + bool boost_on_downmix, bool use_thread, bool is_live, enum PCMLayout layout, float queue_size, float fifo_size) { if(ThreadHandle()) Close(); @@ -115,9 +115,9 @@ bool OMXPlayerAudio::Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader * m_use_thread = use_thread; m_flush = false; m_live = is_live; + m_layout = layout; m_cached_size = 0; m_pAudioCodec = NULL; - m_pChannelMap = NULL; if (queue_size != 0.0) m_max_data_size = queue_size * 1024 * 1024; if (fifo_size != 0.0) @@ -382,7 +382,6 @@ bool OMXPlayerAudio::OpenAudioCodec() return false; } - m_pChannelMap = m_pAudioCodec->GetChannelMap(); return true; } @@ -431,9 +430,8 @@ bool OMXPlayerAudio::OpenDecoder() if(m_passthrough) m_hw_decode = false; - unsigned int downmix_channels = m_hints.channels; - bAudioRenderOpen = m_decoder->Initialize(m_device.substr(4), m_hints.channels, m_pChannelMap, - m_hints, downmix_channels, m_hints.samplerate, m_pAudioCodec->GetBitsPerSample(), m_boost_on_downmix, + bAudioRenderOpen = m_decoder->Initialize(m_device.substr(4), m_hints.channels, m_pAudioCodec->GetChannelMap(), + m_hints, m_layout, m_hints.samplerate, m_pAudioCodec->GetBitsPerSample(), m_boost_on_downmix, m_av_clock, m_passthrough, m_hw_decode, m_live, m_fifo_size); m_codec_name = m_omx_reader->GetCodecName(OMXSTREAM_AUDIO); diff --git a/OMXPlayerAudio.h b/OMXPlayerAudio.h index 428d7fd6..2d512f6b 100644 --- a/OMXPlayerAudio.h +++ b/OMXPlayerAudio.h @@ -72,7 +72,7 @@ class OMXPlayerAudio : public OMXThread bool m_use_thread; bool m_flush; bool m_live; - enum PCMChannels *m_pChannelMap; + enum PCMLayout m_layout; unsigned int m_cached_size; unsigned int m_max_data_size; float m_fifo_size; @@ -89,7 +89,7 @@ class OMXPlayerAudio : public OMXThread ~OMXPlayerAudio(); bool Open(COMXStreamInfo &hints, OMXClock *av_clock, OMXReader *omx_reader, std::string device, bool passthrough, bool hw_decode, - bool boost_on_downmix, bool use_thread, bool is_live, float queue_size, float fifo_size); + bool boost_on_downmix, bool use_thread, bool is_live, enum PCMLayout layout, float queue_size, float fifo_size); bool Close(); bool Decode(OMXPacket *pkt); void Process(); diff --git a/README.md b/README.md index 2cfed8a1..3f7cf4b7 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ Using OMXPlayer --threshold n Amount of buffered data required to come out of buffering in seconds --orientation n Set orientation of video (0, 90, 180 or 270) --live Set for live tv or vod type stream + --layout Set output speaker layout (e.g. 5.1) --key-config Uses key bindings specified in instead of the default For example: diff --git a/omxplayer.cpp b/omxplayer.cpp index 79de5485..5e851c28 100644 --- a/omxplayer.cpp +++ b/omxplayer.cpp @@ -184,6 +184,7 @@ void print_usage() printf(" --threshold n Amount of buffered data required to come out of buffering in seconds\n"); printf(" --orientation n Set orientation of video (0, 90, 180 or 270)\n"); printf(" --live Set for live tv or vod type stream\n"); + printf(" --layout Set output speaker layout (e.g. 5.1)\n"); printf(" --key-config Uses key bindings specified in instead of the default\n"); } @@ -545,6 +546,7 @@ int main(int argc, char *argv[]) float m_threshold = -1.0f; // amount of audio/video required to come out of buffering int m_orientation = -1; // unset bool m_live = false; // set to true for live tv or vod for low buffering + enum PCMLayout m_layout = PCM_LAYOUT_2_0; TV_DISPLAY_STATE_T tv_state; const int font_opt = 0x100; @@ -569,6 +571,7 @@ int main(int argc, char *argv[]) const int no_osd_opt = 0x202; const int orientation_opt = 0x204; const int live_opt = 0x205; + const int layout_opt = 0x206; struct option longopts[] = { { "info", no_argument, NULL, 'i' }, @@ -611,6 +614,7 @@ int main(int argc, char *argv[]) { "no-osd", no_argument, NULL, no_osd_opt }, { "orientation", required_argument, NULL, orientation_opt }, { "live", no_argument, NULL, live_opt }, + { "layout", required_argument, NULL, layout_opt }, { 0, 0, 0, 0 } }; @@ -764,6 +768,23 @@ int main(int argc, char *argv[]) case live_opt: m_live = true; break; + case layout_opt: + { + const char *layouts[] = {"2.0", "2.1", "3.0", "3.1", "4.0", "4.1", "5.0", "5.1", "7.0", "7.1"}; + unsigned i; + for (i=0; i= PCM_MAX_LAYOUT) m_channelLayout = PCM_LAYOUT_2_0; @@ -483,7 +484,7 @@ enum PCMChannels *CPCMRemap::SetInputFormat(unsigned int channels, enum PCMChann return m_layoutMap; } -#if 0 + /* sets the output format supported by the audio renderer */ void CPCMRemap::SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout/* = false */) { @@ -501,6 +502,7 @@ void CPCMRemap::SetOutputFormat(unsigned int channels, enum PCMChannels *channel m_holdCounter = 0; } +#if 0 void CPCMRemap::Remap(void *data, void *out, unsigned int samples, long drc) { float gain = 1.0f; @@ -790,3 +792,20 @@ CStdString CPCMRemap::PCMLayoutStr(enum PCMLayout ename) return namestr; } #endif + + +void CPCMRemap::GetDownmixMatrix(float *downmix) +{ + for (int i=0; i<8*8; i++) + downmix[i] = 0.0f; + + for (unsigned int ch = 0; ch < m_outChannels; ch++) + { + struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]]; + if (info->channel == PCM_INVALID) + continue; + + for(; info->channel != PCM_INVALID; info++) + downmix[8*ch + (info->in_offset>>1)] = info->level; + } +} diff --git a/utils/PCMRemap.h b/utils/PCMRemap.h index c64eff31..6419cea8 100644 --- a/utils/PCMRemap.h +++ b/utils/PCMRemap.h @@ -112,6 +112,7 @@ class CPCMRemap float m_sampleRate; unsigned int m_holdCounter; bool m_limiterEnabled; + bool m_dontnormalize; struct PCMMapInfo* ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector path, struct PCMMapInfo *tablePtr); void ResolveChannels(); //!< Partial BuildMap(), just enough to see which output channels are active @@ -133,9 +134,9 @@ class CPCMRemap ~CPCMRemap(); void Reset(); - enum PCMChannels *SetInputFormat (unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate); -#if 0 + enum PCMChannels *SetInputFormat (unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate, enum PCMLayout channelLayout, bool dontnormalize); void SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout = false); +#if 0 void Remap(void *data, void *out, unsigned int samples, long drc); void Remap(void *data, void *out, unsigned int samples, float gain = 1.0f); bool CanRemap(); @@ -144,6 +145,7 @@ class CPCMRemap int FramesToInBytes (int frames); #endif float GetCurrentAttenuation() { return m_attenuationMin; } + void GetDownmixMatrix(float *downmix); }; #endif