2 * Copyright (c) 2002 d7o3g4q and RUNTiME
3 * Portions Copyright (c) by the authors of ffmpeg and xvid
4 * Copyright (C) 2012-2013 Team XBMC
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
23 #if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
25 #elif defined(TARGET_WINDOWS)
30 #include "Application.h"
31 #include "utils/log.h"
33 #define CLASSNAME "COMXAudio"
35 #include "linux/XMemUtils.h"
37 #include "settings/AdvancedSettings.h"
38 #include "settings/MediaSettings.h"
39 #include "settings/Settings.h"
40 #include "guilib/LocalizeStrings.h"
41 #include "cores/AudioEngine/Utils/AEConvert.h"
42 #include "cores/AudioEngine/AEFactory.h"
46 static const uint16_t AC3Bitrates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640};
47 static const uint16_t AC3FSCod [] = {48000, 44100, 32000, 0};
49 static const uint16_t DTSFSCod [] = {0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, 12000, 24000, 48000, 0, 0};
51 //////////////////////////////////////////////////////////////////////
52 // Construction/Destruction
53 //////////////////////////////////////////////////////////////////////
54 //***********************************************************************************************
55 COMXAudio::COMXAudio() :
57 m_Initialized (false ),
61 m_Passthrough (false ),
67 m_OutputChannels (0 ),
70 m_amplification (1.0f ),
71 m_attenuation (1.0f ),
75 m_settings_changed(false ),
76 m_setStartTime (false ),
79 m_eEncoding (OMX_AUDIO_CodingPCM),
82 m_last_pts (DVD_NOPTS_VALUE),
83 m_submitted_eos (false ),
86 m_vizBufferSize = m_vizRemapBufferSize = VIS_PACKET_SIZE * sizeof(float);
87 m_vizRemapBuffer = (uint8_t *)_aligned_malloc(m_vizRemapBufferSize,16);
88 m_vizBuffer = (uint8_t *)_aligned_malloc(m_vizBufferSize,16);
91 COMXAudio::~COMXAudio()
95 _aligned_free(m_vizRemapBuffer);
96 _aligned_free(m_vizBuffer);
99 bool COMXAudio::PortSettingsChanged()
101 CSingleLock lock (m_critSection);
102 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
104 if (m_settings_changed)
106 m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
107 m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
113 if(!m_omx_mixer.Initialize("OMX.broadcom.audio_mixer", OMX_IndexParamAudioInit))
116 if(CSettings::Get().GetBool("audiooutput.dualaudio"))
118 if(!m_omx_splitter.Initialize("OMX.broadcom.audio_splitter", OMX_IndexParamAudioInit))
121 if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Analogue")
123 if(!m_omx_render_analog.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
126 if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "HDMI")
128 if(!m_omx_render_hdmi.Initialize("OMX.broadcom.audio_render", OMX_IndexParamAudioInit))
132 SetDynamicRangeCompression((long)(CMediaSettings::Get().GetCurrentVideoSettings().m_VolumeAmplification * 100));
135 if( m_omx_mixer.IsInitialized() )
137 /* setup mixer output */
138 OMX_INIT_STRUCTURE(m_pcm_output);
139 m_pcm_output.nPortIndex = m_omx_decoder.GetOutputPort();
140 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
141 if(omx_err != OMX_ErrorNone)
143 CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder GetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
147 memcpy(m_pcm_output.eChannelMapping, m_output_channels, sizeof(m_output_channels));
148 // round up to power of 2
149 m_pcm_output.nChannels = m_OutputChannels > 4 ? 8 : m_OutputChannels > 2 ? 4 : m_OutputChannels;
150 /* limit samplerate (through resampling) if requested */
151 m_pcm_output.nSamplingRate = std::min(std::max((int)m_pcm_output.nSamplingRate, 8000), CSettings::Get().GetInt("audiooutput.samplerate"));
153 m_pcm_output.nPortIndex = m_omx_mixer.GetOutputPort();
154 omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
155 if(omx_err != OMX_ErrorNone)
157 CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
161 CLog::Log(LOGDEBUG, "%s::%s - Output bps %d samplerate %d channels %d buffer size %d bytes per second %d",
162 CLASSNAME, __func__, (int)m_pcm_output.nBitPerSample, (int)m_pcm_output.nSamplingRate, (int)m_pcm_output.nChannels, m_BufferLen, m_BytesPerSec);
163 PrintPCM(&m_pcm_output, std::string("output"));
165 if( m_omx_splitter.IsInitialized() )
167 m_pcm_output.nPortIndex = m_omx_splitter.GetInputPort();
168 omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
169 if(omx_err != OMX_ErrorNone)
171 CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
175 m_pcm_output.nPortIndex = m_omx_splitter.GetOutputPort();
176 omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
177 if(omx_err != OMX_ErrorNone)
179 CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
182 m_pcm_output.nPortIndex = m_omx_splitter.GetOutputPort() + 1;
183 omx_err = m_omx_splitter.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
184 if(omx_err != OMX_ErrorNone)
186 CLog::Log(LOGERROR, "%s::%s - error m_omx_splitter SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
191 if( m_omx_render_analog.IsInitialized() )
193 m_pcm_output.nPortIndex = m_omx_render_analog.GetInputPort();
194 omx_err = m_omx_render_analog.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
195 if(omx_err != OMX_ErrorNone)
197 CLog::Log(LOGERROR, "%s::%s - error m_omx_render_analog SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
202 if( m_omx_render_hdmi.IsInitialized() )
204 m_pcm_output.nPortIndex = m_omx_render_hdmi.GetInputPort();
205 omx_err = m_omx_render_hdmi.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
206 if(omx_err != OMX_ErrorNone)
208 CLog::Log(LOGERROR, "%s::%s - error m_omx_render_hdmi SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
213 if( m_omx_render_analog.IsInitialized() )
215 m_omx_tunnel_clock_analog.Initialize(m_omx_clock, m_omx_clock->GetInputPort(),
216 &m_omx_render_analog, m_omx_render_analog.GetInputPort()+1);
218 omx_err = m_omx_tunnel_clock_analog.Establish();
219 if(omx_err != OMX_ErrorNone)
221 CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_clock_analog.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
224 m_omx_render_analog.ResetEos();
226 if( m_omx_render_hdmi.IsInitialized() )
228 m_omx_tunnel_clock_hdmi.Initialize(m_omx_clock, m_omx_clock->GetInputPort() + (m_omx_render_analog.IsInitialized() ? 2 : 0),
229 &m_omx_render_hdmi, m_omx_render_hdmi.GetInputPort()+1);
231 omx_err = m_omx_tunnel_clock_hdmi.Establish();
232 if(omx_err != OMX_ErrorNone)
234 CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_clock_hdmi.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
237 m_omx_render_hdmi.ResetEos();
240 if( m_omx_render_analog.IsInitialized() )
242 // By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
243 // This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
244 if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
246 OMX_CONFIG_BOOLEANTYPE configBool;
247 OMX_INIT_STRUCTURE(configBool);
248 configBool.bEnabled = OMX_FALSE;
250 omx_err = m_omx_render_analog.SetConfig(OMX_IndexConfigBrcmClockReferenceSource, &configBool);
251 if (omx_err != OMX_ErrorNone)
255 OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
256 OMX_INIT_STRUCTURE(audioDest);
257 strncpy((char *)audioDest.sName, "local", strlen("local"));
258 omx_err = m_omx_render_analog.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest);
259 if (omx_err != OMX_ErrorNone)
261 CLog::Log(LOGERROR, "%s::%s - m_omx_render_analog.SetConfig omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
266 if( m_omx_render_hdmi.IsInitialized() )
268 // By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
269 // This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
270 if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
272 OMX_CONFIG_BOOLEANTYPE configBool;
273 OMX_INIT_STRUCTURE(configBool);
274 configBool.bEnabled = OMX_FALSE;
276 omx_err = m_omx_render_hdmi.SetConfig(OMX_IndexConfigBrcmClockReferenceSource, &configBool);
277 if (omx_err != OMX_ErrorNone)
281 OMX_CONFIG_BRCMAUDIODESTINATIONTYPE audioDest;
282 OMX_INIT_STRUCTURE(audioDest);
283 strncpy((char *)audioDest.sName, "hdmi", strlen("hdmi"));
284 omx_err = m_omx_render_hdmi.SetConfig(OMX_IndexConfigBrcmAudioDestination, &audioDest);
285 if (omx_err != OMX_ErrorNone)
287 CLog::Log(LOGERROR, "%s::%s - m_omx_render_hdmi.SetConfig omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
292 if( m_omx_splitter.IsInitialized() )
294 m_omx_tunnel_splitter_analog.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort(), &m_omx_render_analog, m_omx_render_analog.GetInputPort());
295 omx_err = m_omx_tunnel_splitter_analog.Establish();
296 if(omx_err != OMX_ErrorNone)
298 CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter_analog.Establish 0x%08x", omx_err);
302 m_omx_tunnel_splitter_hdmi.Initialize(&m_omx_splitter, m_omx_splitter.GetOutputPort() + 1, &m_omx_render_hdmi, m_omx_render_hdmi.GetInputPort());
303 omx_err = m_omx_tunnel_splitter_hdmi.Establish();
304 if(omx_err != OMX_ErrorNone)
306 CLog::Log(LOGERROR, "COMXAudio::Initialize - Error m_omx_tunnel_splitter_hdmi.Establish 0x%08x", omx_err);
310 if( m_omx_mixer.IsInitialized() )
312 m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_mixer, m_omx_mixer.GetInputPort());
313 if( m_omx_splitter.IsInitialized() )
315 m_omx_tunnel_mixer.Initialize(&m_omx_mixer, m_omx_mixer.GetOutputPort(), &m_omx_splitter, m_omx_splitter.GetInputPort());
319 if( m_omx_render_analog.IsInitialized() )
321 m_omx_tunnel_mixer.Initialize(&m_omx_mixer, m_omx_mixer.GetOutputPort(), &m_omx_render_analog, m_omx_render_analog.GetInputPort());
323 if( m_omx_render_hdmi.IsInitialized() )
325 m_omx_tunnel_mixer.Initialize(&m_omx_mixer, m_omx_mixer.GetOutputPort(), &m_omx_render_hdmi, m_omx_render_hdmi.GetInputPort());
328 CLog::Log(LOGDEBUG, "%s::%s - bits:%d mode:%d channels:%d srate:%d nopassthrough", CLASSNAME, __func__,
329 (int)m_pcm_input.nBitPerSample, m_pcm_input.ePCMMode, (int)m_pcm_input.nChannels, (int)m_pcm_input.nSamplingRate);
333 if( m_omx_render_analog.IsInitialized() )
335 m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_render_analog, m_omx_render_analog.GetInputPort());
337 else if( m_omx_render_hdmi.IsInitialized() )
339 m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_render_hdmi, m_omx_render_hdmi.GetInputPort());
341 CLog::Log(LOGDEBUG, "%s::%s - bits:%d mode:%d channels:%d srate:%d passthrough", CLASSNAME, __func__,
345 omx_err = m_omx_tunnel_decoder.Establish();
346 if(omx_err != OMX_ErrorNone)
348 CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_decoder.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
352 if( m_omx_mixer.IsInitialized() )
354 omx_err = m_omx_mixer.SetStateForComponent(OMX_StateExecuting);
355 if(omx_err != OMX_ErrorNone) {
356 CLog::Log(LOGERROR, "%s::%s - m_omx_mixer OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
361 if( m_omx_mixer.IsInitialized() )
363 omx_err = m_omx_tunnel_mixer.Establish();
364 if(omx_err != OMX_ErrorNone)
366 CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_decoder.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
371 if( m_omx_splitter.IsInitialized() )
373 omx_err = m_omx_splitter.SetStateForComponent(OMX_StateExecuting);
374 if(omx_err != OMX_ErrorNone)
376 CLog::Log(LOGERROR, "%s::%s - m_omx_splitter OMX_StateExecuting 0x%08x", CLASSNAME, __func__, omx_err);
380 if( m_omx_render_analog.IsInitialized() )
382 omx_err = m_omx_render_analog.SetStateForComponent(OMX_StateExecuting);
383 if(omx_err != OMX_ErrorNone)
385 CLog::Log(LOGERROR, "%s::%s - m_omx_render_analog OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
389 if( m_omx_render_hdmi.IsInitialized() )
391 omx_err = m_omx_render_hdmi.SetStateForComponent(OMX_StateExecuting);
392 if(omx_err != OMX_ErrorNone)
394 CLog::Log(LOGERROR, "%s::%s - m_omx_render_hdmi OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
399 m_settings_changed = true;
403 static unsigned count_bits(int64_t value)
411 bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, uint64_t channelMap, bool bUsePassthrough, bool bUseHWDecode)
413 CSingleLock lock (m_critSection);
414 OMX_ERRORTYPE omx_err;
418 if(!m_dllAvUtil.Load())
421 m_HWDecode = bUseHWDecode;
422 m_Passthrough = bUsePassthrough;
424 m_InputChannels = count_bits(channelMap);
427 if(m_InputChannels == 0)
430 if(hints.samplerate == 0)
438 /* passthrough overwrites hw decode */
445 /* check again if we are capable to hw decode the format */
446 m_HWDecode = CanHWDecode(hints.codec);
448 SetCodingType(format.m_dataFormat);
450 if(hints.extrasize > 0 && hints.extradata != NULL)
452 m_extrasize = hints.extrasize;
453 m_extradata = (uint8_t *)malloc(m_extrasize);
454 memcpy(m_extradata, hints.extradata, hints.extrasize);
457 m_omx_clock = m_av_clock->GetOMXClock();
461 memset(m_input_channels, 0x0, sizeof(m_input_channels));
462 memset(m_output_channels, 0x0, sizeof(m_output_channels));
463 memset(&m_wave_header, 0x0, sizeof(m_wave_header));
465 m_wave_header.Format.nChannels = 2;
466 m_wave_header.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT;
470 enum PCMChannels inLayout[OMX_AUDIO_MAXCHANNELS];
471 enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS];
472 enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
473 // ignore layout setting for analogue
474 if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "Analogue")
475 layout = PCM_LAYOUT_2_0;
477 // force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix
478 if (channelMap == (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT) || channelMap == AV_CH_FRONT_CENTER)
479 layout = PCM_LAYOUT_2_0;
480 BuildChannelMap(inLayout, channelMap);
481 m_OutputChannels = BuildChannelMapCEA(outLayout, GetChannelLayout(layout));
484 /*outLayout = */m_remap.SetInputFormat (m_InputChannels, inLayout, CAEUtil::DataFormatToBits(m_format.m_dataFormat) / 8, m_format.m_sampleRate, layout);
485 m_remap.SetOutputFormat(m_OutputChannels, outLayout);
486 m_remap.GetDownmixMatrix(m_downmix_matrix);
487 m_wave_header.dwChannelMask = channelMap;
488 BuildChannelMapOMX(m_input_channels, channelMap);
489 BuildChannelMapOMX(m_output_channels, GetChannelLayout(layout));
491 m_vizRemap.Initialize(GetAEChannelLayout(channelMap), CAEChannelInfo(AE_CH_LAYOUT_2_0), false, true);
494 m_SampleRate = m_format.m_sampleRate;
495 m_BitsPerSample = CAEUtil::DataFormatToBits(m_format.m_dataFormat);
496 m_BufferLen = m_BytesPerSec = m_format.m_sampleRate * (16 >> 3) * m_InputChannels;
497 m_BufferLen *= AUDIO_BUFFER_SECONDS;
498 // the audio_decode output buffer size is 32K, and typically we convert from
499 // 6 channel 32bpp float to 8 channel 16bpp in, so a full 48K input buffer will fit the outbut buffer
500 m_ChunkLen = 48*1024;
502 m_wave_header.Samples.wSamplesPerBlock = 0;
503 m_wave_header.Format.nChannels = m_InputChannels;
504 m_wave_header.Format.nBlockAlign = m_InputChannels * (m_BitsPerSample >> 3);
505 // 0x8000 is custom format interpreted by GPU as WAVE_FORMAT_IEEE_FLOAT_PLANAR
506 m_wave_header.Format.wFormatTag = m_BitsPerSample == 32 ? 0x8000 : WAVE_FORMAT_PCM;
507 m_wave_header.Format.nSamplesPerSec = m_format.m_sampleRate;
508 m_wave_header.Format.nAvgBytesPerSec = m_BytesPerSec;
509 m_wave_header.Format.wBitsPerSample = m_BitsPerSample;
510 m_wave_header.Samples.wValidBitsPerSample = m_BitsPerSample;
511 m_wave_header.Format.cbSize = 0;
512 m_wave_header.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
514 OMX_INIT_STRUCTURE(m_pcm_input);
515 memcpy(m_pcm_input.eChannelMapping, m_input_channels, sizeof(m_input_channels));
516 m_pcm_input.eNumData = OMX_NumericalDataSigned;
517 m_pcm_input.eEndian = OMX_EndianLittle;
518 m_pcm_input.bInterleaved = OMX_TRUE;
519 m_pcm_input.nBitPerSample = m_BitsPerSample;
520 m_pcm_input.ePCMMode = OMX_AUDIO_PCMModeLinear;
521 m_pcm_input.nChannels = m_InputChannels;
522 m_pcm_input.nSamplingRate = m_format.m_sampleRate;
524 if(!m_omx_decoder.Initialize("OMX.broadcom.audio_decode", OMX_IndexParamAudioInit))
527 OMX_CONFIG_BOOLEANTYPE boolType;
528 OMX_INIT_STRUCTURE(boolType);
530 boolType.bEnabled = OMX_TRUE;
532 boolType.bEnabled = OMX_FALSE;
533 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmDecoderPassThrough, &boolType);
534 if(omx_err != OMX_ErrorNone)
536 CLog::Log(LOGERROR, "COMXAudio::Initialize - Error OMX_IndexParamBrcmDecoderPassThrough 0x%08x", omx_err);
540 // set up the number/size of buffers for decoder input
541 OMX_PARAM_PORTDEFINITIONTYPE port_param;
542 OMX_INIT_STRUCTURE(port_param);
543 port_param.nPortIndex = m_omx_decoder.GetInputPort();
545 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_param);
546 if(omx_err != OMX_ErrorNone)
548 CLog::Log(LOGERROR, "COMXAudio::Initialize error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)\n", omx_err);
552 port_param.format.audio.eEncoding = m_eEncoding;
554 port_param.nBufferSize = m_ChunkLen;
555 port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, 16U);
557 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_param);
558 if(omx_err != OMX_ErrorNone)
560 CLog::Log(LOGERROR, "COMXAudio::Initialize error set OMX_IndexParamPortDefinition (intput) omx_err(0x%08x)\n", omx_err);
564 // set up the number/size of buffers for decoder output
565 OMX_INIT_STRUCTURE(port_param);
566 port_param.nPortIndex = m_omx_decoder.GetOutputPort();
568 omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_param);
569 if(omx_err != OMX_ErrorNone)
571 CLog::Log(LOGERROR, "COMXAudio::Initialize error get OMX_IndexParamPortDefinition (output) omx_err(0x%08x)\n", omx_err);
575 port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, m_BufferLen / port_param.nBufferSize);
577 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_param);
578 if(omx_err != OMX_ErrorNone)
580 CLog::Log(LOGERROR, "COMXAudio::Initialize error set OMX_IndexParamPortDefinition (output) omx_err(0x%08x)\n", omx_err);
585 OMX_AUDIO_PARAM_PORTFORMATTYPE formatType;
586 OMX_INIT_STRUCTURE(formatType);
587 formatType.nPortIndex = m_omx_decoder.GetInputPort();
589 formatType.eEncoding = m_eEncoding;
591 omx_err = m_omx_decoder.SetParameter(OMX_IndexParamAudioPortFormat, &formatType);
592 if(omx_err != OMX_ErrorNone)
594 CLog::Log(LOGERROR, "COMXAudio::Initialize error OMX_IndexParamAudioPortFormat omx_err(0x%08x)\n", omx_err);
599 omx_err = m_omx_decoder.AllocInputBuffers();
600 if(omx_err != OMX_ErrorNone)
602 CLog::Log(LOGERROR, "COMXAudio::Initialize - Error alloc buffers 0x%08x", omx_err);
606 omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
607 if(omx_err != OMX_ErrorNone) {
608 CLog::Log(LOGERROR, "COMXAudio::Initialize - Error setting OMX_StateExecuting 0x%08x", omx_err);
613 if(m_eEncoding == OMX_AUDIO_CodingPCM)
615 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer();
616 if(omx_buffer == NULL)
618 CLog::Log(LOGERROR, "COMXAudio::Initialize - buffer error 0x%08x", omx_err);
622 omx_buffer->nOffset = 0;
623 omx_buffer->nFilledLen = sizeof(m_wave_header);
624 if(omx_buffer->nFilledLen > omx_buffer->nAllocLen)
626 CLog::Log(LOGERROR, "COMXAudio::Initialize - omx_buffer->nFilledLen > omx_buffer->nAllocLen");
629 memset((unsigned char *)omx_buffer->pBuffer, 0x0, omx_buffer->nAllocLen);
630 memcpy((unsigned char *)omx_buffer->pBuffer, &m_wave_header, omx_buffer->nFilledLen);
631 omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
633 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
634 if (omx_err != OMX_ErrorNone)
636 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
642 // send decoder config
643 if(m_extrasize > 0 && m_extradata != NULL)
645 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer();
647 if(omx_buffer == NULL)
649 CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
653 omx_buffer->nOffset = 0;
654 omx_buffer->nFilledLen = m_extrasize;
655 if(omx_buffer->nFilledLen > omx_buffer->nAllocLen)
657 CLog::Log(LOGERROR, "%s::%s - omx_buffer->nFilledLen > omx_buffer->nAllocLen", CLASSNAME, __func__);
661 memset((unsigned char *)omx_buffer->pBuffer, 0x0, omx_buffer->nAllocLen);
662 memcpy((unsigned char *)omx_buffer->pBuffer, m_extradata, omx_buffer->nFilledLen);
663 omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
665 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
666 if (omx_err != OMX_ErrorNone)
668 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
674 /* return on decoder error so m_Initialized stays false */
675 if(m_omx_decoder.BadState())
678 m_Initialized = true;
679 m_settings_changed = false;
680 m_setStartTime = true;
681 m_submitted_eos = false;
682 m_failed_eos = false;
683 m_last_pts = DVD_NOPTS_VALUE;
687 CLog::Log(LOGDEBUG, "COMXAudio::Initialize Input bps %d samplerate %d channels %d buffer size %d bytes per second %d",
688 (int)m_pcm_input.nBitPerSample, (int)m_pcm_input.nSamplingRate, (int)m_pcm_input.nChannels, m_BufferLen, m_BytesPerSec);
689 PrintPCM(&m_pcm_input, std::string("input"));
690 CLog::Log(LOGDEBUG, "COMXAudio::Initialize device passthrough %d hwdecode %d",
691 m_Passthrough, m_HWDecode);
693 /* dummy call to inform PiAudioAE that audo is active */
694 CAEFactory::MakeStream((enum AEDataFormat)0, 0, 0, (CAEChannelInfo)0, 0);
699 //***********************************************************************************************
700 bool COMXAudio::Deinitialize()
702 CSingleLock lock (m_critSection);
704 if ( m_omx_tunnel_clock_analog.IsInitialized() )
705 m_omx_tunnel_clock_analog.Deestablish();
706 if ( m_omx_tunnel_clock_hdmi.IsInitialized() )
707 m_omx_tunnel_clock_hdmi.Deestablish();
709 // ignore expected errors on teardown
710 if ( m_omx_mixer.IsInitialized() )
711 m_omx_mixer.IgnoreNextError(OMX_ErrorPortUnpopulated);
714 if ( m_omx_render_hdmi.IsInitialized() )
715 m_omx_render_hdmi.IgnoreNextError(OMX_ErrorPortUnpopulated);
716 if ( m_omx_render_analog.IsInitialized() )
717 m_omx_render_analog.IgnoreNextError(OMX_ErrorPortUnpopulated);
720 m_omx_tunnel_decoder.Deestablish();
721 if ( m_omx_tunnel_mixer.IsInitialized() )
722 m_omx_tunnel_mixer.Deestablish();
723 if ( m_omx_tunnel_splitter_hdmi.IsInitialized() )
724 m_omx_tunnel_splitter_hdmi.Deestablish();
725 if ( m_omx_tunnel_splitter_analog.IsInitialized() )
726 m_omx_tunnel_splitter_analog.Deestablish();
728 m_omx_decoder.FlushInput();
730 m_omx_decoder.Deinitialize();
731 if ( m_omx_mixer.IsInitialized() )
732 m_omx_mixer.Deinitialize();
733 if ( m_omx_splitter.IsInitialized() )
734 m_omx_splitter.Deinitialize();
735 if ( m_omx_render_hdmi.IsInitialized() )
736 m_omx_render_hdmi.Deinitialize();
737 if ( m_omx_render_analog.IsInitialized() )
738 m_omx_render_analog.Deinitialize();
746 m_Initialized = false;
755 while(!m_vizqueue.empty())
758 m_dllAvUtil.Unload();
760 while(!m_ampqueue.empty())
761 m_ampqueue.pop_front();
763 m_last_pts = DVD_NOPTS_VALUE;
767 /* dummy call to inform PiAudioAE that audo is inactive */
768 CAEFactory::FreeStream(0);
773 void COMXAudio::Flush()
775 CSingleLock lock (m_critSection);
779 m_omx_decoder.FlushAll();
781 if ( m_omx_mixer.IsInitialized() )
782 m_omx_mixer.FlushAll();
784 if ( m_omx_splitter.IsInitialized() )
785 m_omx_splitter.FlushAll();
787 if ( m_omx_render_analog.IsInitialized() )
788 m_omx_render_analog.FlushAll();
789 if ( m_omx_render_hdmi.IsInitialized() )
790 m_omx_render_hdmi.FlushAll();
792 m_last_pts = DVD_NOPTS_VALUE;
796 m_setStartTime = true;
799 //***********************************************************************************************
800 void COMXAudio::SetDynamicRangeCompression(long drc)
802 CSingleLock lock (m_critSection);
803 m_amplification = powf(10.0f, (float)drc / 2000.0f);
804 if (m_settings_changed)
808 //***********************************************************************************************
809 void COMXAudio::SetMute(bool bMute)
811 CSingleLock lock (m_critSection);
813 if (m_settings_changed)
817 //***********************************************************************************************
818 void COMXAudio::SetVolume(float fVolume)
820 CSingleLock lock (m_critSection);
821 m_CurrentVolume = fVolume;
822 if (m_settings_changed)
826 //***********************************************************************************************
827 bool COMXAudio::ApplyVolume(void)
829 CSingleLock lock (m_critSection);
831 if (!m_Initialized || m_Passthrough)
834 float fVolume = m_Mute ? VOLUME_MINIMUM : m_CurrentVolume;
836 // the analogue volume is too quiet for some. Allow use of an advancedsetting to boost this (at risk of distortion) (deprecated)
837 double gain = pow(10, (g_advancedSettings.m_ac3Gain - 12.0f) / 20.0);
839 const float* coeff = m_downmix_matrix;
841 OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix;
842 OMX_INIT_STRUCTURE(mix);
843 OMX_ERRORTYPE omx_err;
845 assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64);
847 if (m_amplification != 1.0)
849 // reduce scaling so overflow can be seen
850 for(size_t i = 0; i < 8*8; ++i)
851 mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * gain * 0.01f));
853 mix.nPortIndex = m_omx_decoder.GetInputPort();
854 omx_err = m_omx_decoder.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix);
855 if(omx_err != OMX_ErrorNone)
857 CLog::Log(LOGERROR, "%s::%s - error setting decoder OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
858 CLASSNAME, __func__, omx_err);
862 for(size_t i = 0; i < 8*8; ++i)
863 mix.coeff[i] = static_cast<unsigned int>(0x10000 * (coeff[i] * gain * fVolume * m_amplification * m_attenuation));
865 mix.nPortIndex = m_omx_mixer.GetInputPort();
866 omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix);
867 if(omx_err != OMX_ErrorNone)
869 CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
870 CLASSNAME, __func__, omx_err);
873 CLog::Log(LOGINFO, "%s::%s - Volume=%.2f (* %.2f * %.2f)\n", CLASSNAME, __func__, fVolume, m_amplification, m_attenuation);
877 void COMXAudio::VizPacket(const void* data, unsigned int len, double pts)
880 unsigned int vizBufferSamples = len / (CAEUtil::DataFormatToBits(m_format.m_dataFormat) >> 3);
883 unsigned int frames = vizBufferSamples / m_InputChannels;
884 float *floatBuffer = (float *)data;
886 if (m_format.m_dataFormat != AE_FMT_FLOAT)
888 CAEConvert::AEConvertToFn m_convertFn = CAEConvert::ToFloat(m_format.m_dataFormat);
890 /* check convert buffer */
891 CheckOutputBufferSize((void **)&m_vizBuffer, &m_vizBufferSize, vizBufferSamples * (CAEUtil::DataFormatToBits(AE_FMT_FLOAT) >> 3));
893 /* convert to float */
894 m_convertFn((uint8_t *)data, vizBufferSamples, (float *)m_vizBuffer);
895 floatBuffer = (float *)m_vizBuffer;
898 // Viz channel count is 2
899 CheckOutputBufferSize((void **)&m_vizRemapBuffer, &m_vizRemapBufferSize, frames * 2 * sizeof(float));
902 m_vizRemap.Remap(floatBuffer, (float*)m_vizRemapBuffer, frames);
905 vizBufferSamples = vizBufferSamples / m_InputChannels * 2;
907 /* viz size is limited */
908 if(vizBufferSamples > VIS_PACKET_SIZE)
909 vizBufferSamples = VIS_PACKET_SIZE;
913 v.num_samples = vizBufferSamples;
914 memcpy(v.samples, m_vizRemapBuffer, vizBufferSamples * sizeof(float));
917 double stamp = m_av_clock->OMXMediaTime();
918 while(!m_vizqueue.empty())
920 vizblock_t &v = m_vizqueue.front();
921 /* if packet has almost reached media time (allow time for rendering delay) then display it */
922 /* we'll also consume if queue gets unexpectedly long to avoid filling memory */
923 if (v.pts == DVD_NOPTS_VALUE || v.pts - stamp < DVD_SEC_TO_TIME(1.0/30.0) || v.pts - stamp > DVD_SEC_TO_TIME(15.0))
925 m_pCallback->OnAudioData(v.samples, v.num_samples);
933 //***********************************************************************************************
934 unsigned int COMXAudio::AddPackets(const void* data, unsigned int len)
936 return AddPackets(data, len, 0, 0);
939 //***********************************************************************************************
940 unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dts, double pts)
942 CSingleLock lock (m_critSection);
946 CLog::Log(LOGERROR,"COMXAudio::AddPackets - sanity failed. no valid play handle!");
950 if (m_pCallback && len && !(m_Passthrough || m_HWDecode))
951 VizPacket(data, len, pts);
953 if(m_eEncoding == OMX_AUDIO_CodingDTS && m_LostSync && (m_Passthrough || m_HWDecode))
955 int skip = SyncDTS((uint8_t *)data, len);
960 if(m_eEncoding == OMX_AUDIO_CodingDDP && m_LostSync && (m_Passthrough || m_HWDecode))
962 int skip = SyncAC3((uint8_t *)data, len);
967 unsigned pitch = (m_Passthrough || m_HWDecode) ? 1:(m_BitsPerSample >> 3) * m_InputChannels;
968 unsigned int demuxer_samples = len / pitch;
969 unsigned int demuxer_samples_sent = 0;
970 uint8_t *demuxer_content = (uint8_t *)data;
972 OMX_ERRORTYPE omx_err;
974 OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
976 while(demuxer_samples_sent < demuxer_samples)
979 omx_buffer = m_omx_decoder.GetInputBuffer(200);
981 if(omx_buffer == NULL)
983 CLog::Log(LOGERROR, "COMXAudio::Decode timeout\n");
987 omx_buffer->nOffset = 0;
988 omx_buffer->nFlags = 0;
990 unsigned int remaining = demuxer_samples-demuxer_samples_sent;
991 unsigned int samples_space = omx_buffer->nAllocLen/pitch;
992 unsigned int samples = std::min(remaining, samples_space);
994 omx_buffer->nFilledLen = samples * pitch;
996 if (samples < demuxer_samples && m_BitsPerSample==32 && !(m_Passthrough || m_HWDecode))
998 uint8_t *dst = omx_buffer->pBuffer;
999 uint8_t *src = demuxer_content + demuxer_samples_sent * (m_BitsPerSample >> 3);
1000 // we need to extract samples from planar audio, so the copying needs to be done per plane
1001 for (int i=0; i<(int)m_InputChannels; i++)
1003 memcpy(dst, src, omx_buffer->nFilledLen / m_InputChannels);
1004 dst += omx_buffer->nFilledLen / m_InputChannels;
1005 src += demuxer_samples * (m_BitsPerSample >> 3);
1007 assert(dst <= omx_buffer->pBuffer + m_ChunkLen);
1011 uint8_t *dst = omx_buffer->pBuffer;
1012 uint8_t *src = demuxer_content + demuxer_samples_sent * pitch;
1013 memcpy(dst, src, omx_buffer->nFilledLen);
1016 uint64_t val = (uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts;
1020 omx_buffer->nFlags = OMX_BUFFERFLAG_STARTTIME;
1023 CLog::Log(LOGDEBUG, "COMXAudio::Decode ADec : setStartTime %f\n", (float)val / DVD_TIME_BASE);
1024 m_setStartTime = false;
1028 if(pts == DVD_NOPTS_VALUE)
1030 omx_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
1033 else if (m_last_pts != pts)
1035 if(pts > m_last_pts)
1038 omx_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;;
1040 else if (m_last_pts == pts)
1042 omx_buffer->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
1046 omx_buffer->nTimeStamp = ToOMXTime(val);
1048 demuxer_samples_sent += samples;
1050 if(demuxer_samples_sent == demuxer_samples)
1051 omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
1056 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
1057 if (omx_err == OMX_ErrorNone)
1059 //CLog::Log(LOGINFO, "AudiD: dts:%.0f pts:%.0f size:%d\n", dts, pts, len);
1064 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
1069 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() finaly failed\n", CLASSNAME, __func__);
1074 omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, 0);
1075 if (omx_err == OMX_ErrorNone)
1077 if(!PortSettingsChanged())
1079 CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged omx_err(0x%08x)\n", CLASSNAME, __func__, omx_err);
1083 m_submitted += (float)demuxer_samples / m_SampleRate;
1084 if (m_amplification != 1.0)
1085 UpdateAttenuation();
1089 void COMXAudio::UpdateAttenuation()
1091 // always called with m_critSection lock held
1092 if (!m_Initialized || m_Passthrough)
1095 if (m_amplification == 1.0)
1101 double level_pts = 0.0;
1102 float level = GetMaxLevel(level_pts);
1103 if (level_pts != 0.0)
1108 m_ampqueue.push_back(v);
1110 double stamp = m_av_clock->OMXMediaTime();
1111 // discard too old data
1112 while(!m_ampqueue.empty())
1114 amplitudes_t &v = m_ampqueue.front();
1115 /* we'll also consume if queue gets unexpectedly long to avoid filling memory */
1116 if (v.pts == DVD_NOPTS_VALUE || v.pts < stamp || v.pts - stamp > DVD_SEC_TO_TIME(15.0))
1117 m_ampqueue.pop_front();
1120 float maxlevel = 0.0f, imminent_maxlevel = 0.0f;
1121 for (int i=0; i < (int)m_ampqueue.size(); i++)
1123 amplitudes_t &v = m_ampqueue[i];
1124 maxlevel = std::max(maxlevel, v.level);
1125 // check for maximum volume in next 200ms
1126 if (v.pts != DVD_NOPTS_VALUE && v.pts < stamp + DVD_SEC_TO_TIME(0.2))
1127 imminent_maxlevel = std::max(imminent_maxlevel, v.level);
1130 if (maxlevel != 0.0)
1132 float alpha_h = -1.0f/(0.025f*log10f(0.999f));
1133 float alpha_r = -1.0f/(0.100f*log10f(0.900f));
1134 float decay = powf(10.0f, -1.0f / (alpha_h * g_advancedSettings.m_limiterHold));
1135 float attack = powf(10.0f, -1.0f / (alpha_r * g_advancedSettings.m_limiterRelease));
1136 // if we are going to clip imminently then deal with it now
1137 if (imminent_maxlevel > m_maxLevel)
1138 m_maxLevel = imminent_maxlevel;
1139 // clip but not imminently can ramp up more slowly
1140 else if (maxlevel > m_maxLevel)
1141 m_maxLevel = attack * m_maxLevel + (1.0f-attack) * maxlevel;
1142 // not clipping, decay more slowly
1144 m_maxLevel = decay * m_maxLevel + (1.0f-decay ) * maxlevel;
1146 // want m_maxLevel * amp -> 1.0
1147 float amp = m_amplification * m_attenuation;
1149 // We fade in the attenuation over first couple of seconds
1150 float start = std::min(std::max((m_submitted-1.0f), 0.0f), 1.0f);
1151 float attenuation = std::min(1.0f, std::max(m_attenuation / (amp * m_maxLevel), 1.0f/m_amplification));
1152 m_attenuation = (1.0f - start) * 1.0f/m_amplification + start * attenuation;
1156 m_attenuation = 1.0f/m_amplification;
1161 //***********************************************************************************************
1162 unsigned int COMXAudio::GetSpace()
1164 int free = m_omx_decoder.GetInputBufferSpace();
1168 float COMXAudio::GetDelay()
1170 unsigned int free = m_omx_decoder.GetInputBufferSize() - m_omx_decoder.GetInputBufferSpace();
1171 return m_BytesPerSec ? (float)free / (float)m_BytesPerSec : 0.0f;
1174 float COMXAudio::GetCacheTime()
1176 float fBufferLenFull = (float)m_BufferLen - (float)GetSpace();
1177 if(fBufferLenFull < 0)
1179 float ret = m_BytesPerSec ? fBufferLenFull / (float)m_BytesPerSec : 0.0f;
1183 float COMXAudio::GetCacheTotal()
1185 return m_BytesPerSec ? (float)m_BufferLen / (float)m_BytesPerSec : 0.0f;
1188 //***********************************************************************************************
1189 unsigned int COMXAudio::GetChunkLen()
1193 //***********************************************************************************************
1194 int COMXAudio::SetPlaySpeed(int iSpeed)
1199 void COMXAudio::RegisterAudioCallback(IAudioCallback *pCallback)
1201 CSingleLock lock (m_critSection);
1202 if(!m_Passthrough && !m_HWDecode)
1204 m_pCallback = pCallback;
1206 m_pCallback->OnInitialize(2, m_SampleRate, 32);
1212 void COMXAudio::UnRegisterAudioCallback()
1214 CSingleLock lock (m_critSection);
1218 unsigned int COMXAudio::GetAudioRenderingLatency()
1220 CSingleLock lock (m_critSection);
1225 OMX_PARAM_U32TYPE param;
1226 OMX_INIT_STRUCTURE(param);
1228 if(m_omx_render_analog.IsInitialized())
1230 param.nPortIndex = m_omx_render_analog.GetInputPort();
1232 OMX_ERRORTYPE omx_err = m_omx_render_analog.GetConfig(OMX_IndexConfigAudioRenderingLatency, ¶m);
1234 if(omx_err != OMX_ErrorNone)
1236 CLog::Log(LOGERROR, "%s::%s - error getting OMX_IndexConfigAudioRenderingLatency error 0x%08x\n",
1237 CLASSNAME, __func__, omx_err);
1241 else if(m_omx_render_hdmi.IsInitialized())
1243 param.nPortIndex = m_omx_render_hdmi.GetInputPort();
1245 OMX_ERRORTYPE omx_err = m_omx_render_hdmi.GetConfig(OMX_IndexConfigAudioRenderingLatency, ¶m);
1247 if(omx_err != OMX_ErrorNone)
1249 CLog::Log(LOGERROR, "%s::%s - error getting OMX_IndexConfigAudioRenderingLatency error 0x%08x\n",
1250 CLASSNAME, __func__, omx_err);
1258 float COMXAudio::GetMaxLevel(double &pts)
1260 CSingleLock lock (m_critSection);
1265 OMX_CONFIG_BRCMAUDIOMAXSAMPLE param;
1266 OMX_INIT_STRUCTURE(param);
1268 if(m_omx_decoder.IsInitialized())
1270 param.nPortIndex = m_omx_decoder.GetInputPort();
1272 OMX_ERRORTYPE omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigBrcmAudioMaxSample, ¶m);
1274 if(omx_err != OMX_ErrorNone)
1276 CLog::Log(LOGERROR, "%s::%s - error getting OMX_IndexConfigBrcmAudioMaxSample error 0x%08x\n",
1277 CLASSNAME, __func__, omx_err);
1281 pts = FromOMXTime(param.nTimeStamp);
1282 return (float)param.nMaxSample * (100.0f / (1<<15));
1285 void COMXAudio::SubmitEOS()
1287 CSingleLock lock (m_critSection);
1292 m_submitted_eos = true;
1293 m_failed_eos = false;
1295 OMX_ERRORTYPE omx_err = OMX_ErrorNone;
1296 OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(1000);
1298 if(omx_buffer == NULL)
1300 CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
1301 m_failed_eos = true;
1305 omx_buffer->nOffset = 0;
1306 omx_buffer->nFilledLen = 0;
1307 omx_buffer->nTimeStamp = ToOMXTime(0LL);
1309 omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME | OMX_BUFFERFLAG_EOS | OMX_BUFFERFLAG_TIME_UNKNOWN;
1311 omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
1312 if (omx_err != OMX_ErrorNone)
1314 CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n", CLASSNAME, __func__, omx_err);
1317 CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
1320 bool COMXAudio::IsEOS()
1324 unsigned int latency = GetAudioRenderingLatency();
1325 CSingleLock lock (m_critSection);
1327 if (!m_failed_eos && !(m_omx_decoder.IsEOS() && latency == 0))
1330 if (m_submitted_eos)
1332 CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
1333 m_submitted_eos = false;
1338 void COMXAudio::SwitchChannels(int iAudioStream, bool bAudioOnAllSpeakers)
1343 void COMXAudio::SetCodingType(AEDataFormat dataFormat)
1348 CLog::Log(LOGDEBUG, "COMXAudio::SetCodingType OMX_AUDIO_CodingDTS\n");
1349 m_eEncoding = OMX_AUDIO_CodingDTS;
1353 CLog::Log(LOGDEBUG, "COMXAudio::SetCodingType OMX_AUDIO_CodingDDP\n");
1354 m_eEncoding = OMX_AUDIO_CodingDDP;
1357 CLog::Log(LOGDEBUG, "COMXAudio::SetCodingType OMX_AUDIO_CodingPCM\n");
1358 m_eEncoding = OMX_AUDIO_CodingPCM;
1363 bool COMXAudio::CanHWDecode(AVCodecID codec)
1368 case AV_CODEC_ID_DTS:
1369 CLog::Log(LOGDEBUG, "COMXAudio::CanHWDecode OMX_AUDIO_CodingDTS\n");
1372 case AV_CODEC_ID_AC3:
1373 case AV_CODEC_ID_EAC3:
1374 CLog::Log(LOGDEBUG, "COMXAudio::CanHWDecode OMX_AUDIO_CodingDDP\n");
1378 CLog::Log(LOGDEBUG, "COMXAudio::CanHWDecode OMX_AUDIO_CodingPCM\n");
1386 void COMXAudio::PrintChannels(OMX_AUDIO_CHANNELTYPE eChannelMapping[])
1388 for(int i = 0; i < OMX_AUDIO_MAXCHANNELS; i++)
1390 switch(eChannelMapping[i])
1392 case OMX_AUDIO_ChannelLF:
1393 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelLF\n");
1395 case OMX_AUDIO_ChannelRF:
1396 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelRF\n");
1398 case OMX_AUDIO_ChannelCF:
1399 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelCF\n");
1401 case OMX_AUDIO_ChannelLS:
1402 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelLS\n");
1404 case OMX_AUDIO_ChannelRS:
1405 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelRS\n");
1407 case OMX_AUDIO_ChannelLFE:
1408 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelLFE\n");
1410 case OMX_AUDIO_ChannelCS:
1411 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelCS\n");
1413 case OMX_AUDIO_ChannelLR:
1414 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelLR\n");
1416 case OMX_AUDIO_ChannelRR:
1417 CLog::Log(LOGDEBUG, "OMX_AUDIO_ChannelRR\n");
1419 case OMX_AUDIO_ChannelNone:
1420 case OMX_AUDIO_ChannelKhronosExtensions:
1421 case OMX_AUDIO_ChannelVendorStartUnused:
1422 case OMX_AUDIO_ChannelMax:
1429 void COMXAudio::PrintPCM(OMX_AUDIO_PARAM_PCMMODETYPE *pcm, std::string direction)
1431 CLog::Log(LOGDEBUG, "pcm->direction : %s\n", direction.c_str());
1432 CLog::Log(LOGDEBUG, "pcm->nPortIndex : %d\n", (int)pcm->nPortIndex);
1433 CLog::Log(LOGDEBUG, "pcm->eNumData : %d\n", pcm->eNumData);
1434 CLog::Log(LOGDEBUG, "pcm->eEndian : %d\n", pcm->eEndian);
1435 CLog::Log(LOGDEBUG, "pcm->bInterleaved : %d\n", (int)pcm->bInterleaved);
1436 CLog::Log(LOGDEBUG, "pcm->nBitPerSample : %d\n", (int)pcm->nBitPerSample);
1437 CLog::Log(LOGDEBUG, "pcm->ePCMMode : %d\n", pcm->ePCMMode);
1438 CLog::Log(LOGDEBUG, "pcm->nChannels : %d\n", (int)pcm->nChannels);
1439 CLog::Log(LOGDEBUG, "pcm->nSamplingRate : %d\n", (int)pcm->nSamplingRate);
1441 PrintChannels(pcm->eChannelMapping);
1444 void COMXAudio::PrintDDP(OMX_AUDIO_PARAM_DDPTYPE *ddparm)
1446 CLog::Log(LOGDEBUG, "ddparm->nPortIndex : %d\n", (int)ddparm->nPortIndex);
1447 CLog::Log(LOGDEBUG, "ddparm->nChannels : %d\n", (int)ddparm->nChannels);
1448 CLog::Log(LOGDEBUG, "ddparm->nBitRate : %d\n", (int)ddparm->nBitRate);
1449 CLog::Log(LOGDEBUG, "ddparm->nSampleRate : %d\n", (int)ddparm->nSampleRate);
1450 CLog::Log(LOGDEBUG, "ddparm->eBitStreamId : %d\n", (int)ddparm->eBitStreamId);
1451 CLog::Log(LOGDEBUG, "ddparm->eBitStreamMode : %d\n", (int)ddparm->eBitStreamMode);
1452 CLog::Log(LOGDEBUG, "ddparm->eDolbySurroundMode : %d\n", (int)ddparm->eDolbySurroundMode);
1454 PrintChannels(ddparm->eChannelMapping);
1457 void COMXAudio::PrintDTS(OMX_AUDIO_PARAM_DTSTYPE *dtsparam)
1459 CLog::Log(LOGDEBUG, "dtsparam->nPortIndex : %d\n", (int)dtsparam->nPortIndex);
1460 CLog::Log(LOGDEBUG, "dtsparam->nChannels : %d\n", (int)dtsparam->nChannels);
1461 CLog::Log(LOGDEBUG, "dtsparam->nBitRate : %d\n", (int)dtsparam->nBitRate);
1462 CLog::Log(LOGDEBUG, "dtsparam->nSampleRate : %d\n", (int)dtsparam->nSampleRate);
1463 CLog::Log(LOGDEBUG, "dtsparam->nFormat : 0x%08x\n", (int)dtsparam->nFormat);
1464 CLog::Log(LOGDEBUG, "dtsparam->nDtsType : %d\n", (int)dtsparam->nDtsType);
1465 CLog::Log(LOGDEBUG, "dtsparam->nDtsFrameSizeBytes : %d\n", (int)dtsparam->nDtsFrameSizeBytes);
1467 PrintChannels(dtsparam->eChannelMapping);
1470 /* ========================== SYNC FUNCTIONS ========================== */
1471 unsigned int COMXAudio::SyncDTS(BYTE* pData, unsigned int iSize)
1473 OMX_INIT_STRUCTURE(m_dtsParam);
1476 unsigned int srCode;
1477 unsigned int dtsBlocks;
1480 for(skip = 0; iSize - skip > 8; ++skip, ++pData)
1482 if (pData[0] == 0x7F && pData[1] == 0xFE && pData[2] == 0x80 && pData[3] == 0x01)
1485 littleEndian = true;
1486 dtsBlocks = ((pData[4] >> 2) & 0x7f) + 1;
1487 m_dtsParam.nFormat = 0x1 | 0x2;
1489 else if (pData[0] == 0x1F && pData[1] == 0xFF && pData[2] == 0xE8 && pData[3] == 0x00 && pData[4] == 0x07 && (pData[5] & 0xF0) == 0xF0)
1492 littleEndian = true;
1493 dtsBlocks = (((pData[4] & 0x7) << 4) | (pData[7] & 0x3C) >> 2) + 1;
1494 m_dtsParam.nFormat = 0x1 | 0x0;
1496 else if (pData[1] == 0x7F && pData[0] == 0xFE && pData[3] == 0x80 && pData[2] == 0x01)
1499 littleEndian = false;
1500 dtsBlocks = ((pData[5] >> 2) & 0x7f) + 1;
1501 m_dtsParam.nFormat = 0x0 | 0x2;
1503 else if (pData[1] == 0x1F && pData[0] == 0xFF && pData[3] == 0xE8 && pData[2] == 0x00 && pData[5] == 0x07 && (pData[4] & 0xF0) == 0xF0)
1506 littleEndian = false;
1507 dtsBlocks = (((pData[5] & 0x7) << 4) | (pData[6] & 0x3C) >> 2) + 1;
1508 m_dtsParam.nFormat = 0x0 | 0x0;
1517 /* if it is not a termination frame, check the next 6 bits are set */
1518 if ((pData[4] & 0x80) == 0x80 && (pData[4] & 0x7C) != 0x7C)
1521 /* get the frame size */
1522 m_dtsParam.nDtsFrameSizeBytes = ((((pData[5] & 0x3) << 8 | pData[6]) << 4) | ((pData[7] & 0xF0) >> 4)) + 1;
1523 srCode = (pData[8] & 0x3C) >> 2;
1527 /* if it is not a termination frame, check the next 6 bits are set */
1528 if ((pData[5] & 0x80) == 0x80 && (pData[5] & 0x7C) != 0x7C)
1531 /* get the frame size */
1532 m_dtsParam.nDtsFrameSizeBytes = ((((pData[4] & 0x3) << 8 | pData[7]) << 4) | ((pData[6] & 0xF0) >> 4)) + 1;
1533 srCode = (pData[9] & 0x3C) >> 2;
1536 /* make sure the framesize is sane */
1537 if (m_dtsParam.nDtsFrameSizeBytes < 96 || m_dtsParam.nDtsFrameSizeBytes > 16384)
1540 m_dtsParam.nSampleRate = DTSFSCod[srCode];
1542 switch(dtsBlocks << 5)
1545 m_dtsParam.nDtsType = 1;
1548 m_dtsParam.nDtsType = 2;
1551 m_dtsParam.nDtsType = 3;
1554 m_dtsParam.nDtsType = 0;
1558 //m_dtsParam.nFormat = 1;
1559 m_dtsParam.nDtsType = 1;
1570 unsigned int COMXAudio::SyncAC3(BYTE* pData, unsigned int iSize)
1572 unsigned int skip = 0;
1574 for(skip = 0; iSize - skip > 6; ++skip, ++pData)
1576 /* search for an ac3 sync word */
1577 if(pData[0] != 0x0b || pData[1] != 0x77)
1580 uint8_t fscod = pData[4] >> 6;
1581 uint8_t frmsizecod = pData[4] & 0x3F;
1582 uint8_t bsid = pData[5] >> 3;
1584 /* sanity checks on the header */
1591 /* get the details we need to check crc1 and framesize */
1592 uint16_t bitrate = AC3Bitrates[frmsizecod >> 1];
1593 unsigned int framesize = 0;
1596 case 0: framesize = bitrate * 2; break;
1597 case 1: framesize = (320 * bitrate / 147 + (frmsizecod & 1 ? 1 : 0)); break;
1598 case 2: framesize = bitrate * 4; break;
1601 m_SampleRate = AC3FSCod[fscod];
1603 /* dont do extensive testing if we have not lost sync */
1604 if (!m_LostSync && skip == 0)
1607 unsigned int crc_size;
1608 /* if we have enough data, validate the entire packet, else try to validate crc2 (5/8 of the packet) */
1609 if (framesize <= iSize - skip)
1610 crc_size = framesize - 1;
1611 else crc_size = (framesize >> 1) + (framesize >> 3) - 1;
1613 if (crc_size <= iSize - skip)
1614 if(m_dllAvUtil.av_crc(m_dllAvUtil.av_crc_get_table(AV_CRC_16_ANSI), 0, &pData[2], crc_size * 2))
1617 /* if we get here, we can sync */
1622 /* if we get here, the entire packet is invalid and we have lost sync */
1627 void COMXAudio::CheckOutputBufferSize(void **buffer, int *oldSize, int newSize)
1629 if (newSize > *oldSize)
1632 _aligned_free(*buffer);
1633 *buffer = _aligned_malloc(newSize, 16);
1636 memset(*buffer, 0x0, *oldSize);
1639 void COMXAudio::BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout)
1642 if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = PCM_FRONT_LEFT ;
1643 if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = PCM_FRONT_RIGHT ;
1644 if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = PCM_FRONT_CENTER ;
1645 if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = PCM_LOW_FREQUENCY ;
1646 if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = PCM_BACK_LEFT ;
1647 if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = PCM_BACK_RIGHT ;
1648 if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ;
1649 if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER;
1650 if (layout & AV_CH_BACK_CENTER ) channelMap[index++] = PCM_BACK_CENTER ;
1651 if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = PCM_SIDE_LEFT ;
1652 if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = PCM_SIDE_RIGHT ;
1653 if (layout & AV_CH_TOP_CENTER ) channelMap[index++] = PCM_TOP_CENTER ;
1654 if (layout & AV_CH_TOP_FRONT_LEFT ) channelMap[index++] = PCM_TOP_FRONT_LEFT ;
1655 if (layout & AV_CH_TOP_FRONT_CENTER ) channelMap[index++] = PCM_TOP_FRONT_CENTER ;
1656 if (layout & AV_CH_TOP_FRONT_RIGHT ) channelMap[index++] = PCM_TOP_FRONT_RIGHT ;
1657 if (layout & AV_CH_TOP_BACK_LEFT ) channelMap[index++] = PCM_TOP_BACK_LEFT ;
1658 if (layout & AV_CH_TOP_BACK_CENTER ) channelMap[index++] = PCM_TOP_BACK_CENTER ;
1659 if (layout & AV_CH_TOP_BACK_RIGHT ) channelMap[index++] = PCM_TOP_BACK_RIGHT ;
1660 while (index<OMX_AUDIO_MAXCHANNELS)
1661 channelMap[index++] = PCM_INVALID;
1664 // See CEA spec: Table 20, Audio InfoFrame data byte 4 for the ordering here
1665 int COMXAudio::BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout)
1668 if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = PCM_FRONT_LEFT;
1669 if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = PCM_FRONT_RIGHT;
1670 if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = PCM_LOW_FREQUENCY;
1671 if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = PCM_FRONT_CENTER;
1672 if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = PCM_BACK_LEFT;
1673 if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = PCM_BACK_RIGHT;
1674 if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = PCM_SIDE_LEFT;
1675 if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = PCM_SIDE_RIGHT;
1677 while (index<OMX_AUDIO_MAXCHANNELS)
1678 channelMap[index++] = PCM_INVALID;
1680 int num_channels = 0;
1681 for (index=0; index<OMX_AUDIO_MAXCHANNELS; index++)
1682 if (channelMap[index] != PCM_INVALID)
1683 num_channels = index+1;
1684 return num_channels;
1687 void COMXAudio::BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE * channelMap, uint64_t layout)
1691 if (layout & AV_CH_FRONT_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLF;
1692 if (layout & AV_CH_FRONT_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRF;
1693 if (layout & AV_CH_FRONT_CENTER ) channelMap[index++] = OMX_AUDIO_ChannelCF;
1694 if (layout & AV_CH_LOW_FREQUENCY ) channelMap[index++] = OMX_AUDIO_ChannelLFE;
1695 if (layout & AV_CH_BACK_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLR;
1696 if (layout & AV_CH_BACK_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRR;
1697 if (layout & AV_CH_SIDE_LEFT ) channelMap[index++] = OMX_AUDIO_ChannelLS;
1698 if (layout & AV_CH_SIDE_RIGHT ) channelMap[index++] = OMX_AUDIO_ChannelRS;
1699 if (layout & AV_CH_BACK_CENTER ) channelMap[index++] = OMX_AUDIO_ChannelCS;
1700 // following are not in openmax spec, but gpu does accept them
1701 if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)10;
1702 if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)11;
1703 if (layout & AV_CH_TOP_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)12;
1704 if (layout & AV_CH_TOP_FRONT_LEFT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)13;
1705 if (layout & AV_CH_TOP_FRONT_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)14;
1706 if (layout & AV_CH_TOP_FRONT_RIGHT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)15;
1707 if (layout & AV_CH_TOP_BACK_LEFT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)16;
1708 if (layout & AV_CH_TOP_BACK_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)17;
1709 if (layout & AV_CH_TOP_BACK_RIGHT ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)18;
1711 while (index<OMX_AUDIO_MAXCHANNELS)
1712 channelMap[index++] = OMX_AUDIO_ChannelNone;
1715 uint64_t COMXAudio::GetChannelLayout(enum PCMLayout layout)
1717 uint64_t layouts[] = {
1718 /* 2.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT,
1719 /* 2.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_LOW_FREQUENCY,
1720 /* 3.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER,
1721 /* 3.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_LOW_FREQUENCY,
1722 /* 4.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
1723 /* 4.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
1724 /* 5.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
1725 /* 5.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
1726 /* 7.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
1727 /* 7.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY
1729 return (int)layout < 10 ? layouts[(int)layout] : 0;
1732 CAEChannelInfo COMXAudio::GetAEChannelLayout(uint64_t layout)
1734 CAEChannelInfo m_channelLayout;
1735 m_channelLayout.Reset();
1737 if (layout & AV_CH_FRONT_LEFT ) m_channelLayout += AE_CH_FL ;
1738 if (layout & AV_CH_FRONT_RIGHT ) m_channelLayout += AE_CH_FR ;
1739 if (layout & AV_CH_FRONT_CENTER ) m_channelLayout += AE_CH_FC ;
1740 if (layout & AV_CH_LOW_FREQUENCY ) m_channelLayout += AE_CH_LFE ;
1741 if (layout & AV_CH_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
1742 if (layout & AV_CH_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
1743 if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
1744 if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
1745 if (layout & AV_CH_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
1746 if (layout & AV_CH_SIDE_LEFT ) m_channelLayout += AE_CH_SL ;
1747 if (layout & AV_CH_SIDE_RIGHT ) m_channelLayout += AE_CH_SR ;
1748 if (layout & AV_CH_TOP_CENTER ) m_channelLayout += AE_CH_TC ;
1749 if (layout & AV_CH_TOP_FRONT_LEFT ) m_channelLayout += AE_CH_TFL ;
1750 if (layout & AV_CH_TOP_FRONT_CENTER ) m_channelLayout += AE_CH_TFC ;
1751 if (layout & AV_CH_TOP_FRONT_RIGHT ) m_channelLayout += AE_CH_TFR ;
1752 if (layout & AV_CH_TOP_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
1753 if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
1754 if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
1755 return m_channelLayout;