2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "DVDAudioCodecFFmpeg.h"
23 #include "XMemUtils.h"
25 #include "../../DVDStreamInfo.h"
26 #include "utils/log.h"
28 #if defined(TARGET_DARWIN)
29 #include "settings/Settings.h"
30 #include "cores/AudioEngine/Utils/AEUtil.h"
33 CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec()
37 m_pBuffer2 = (uint8_t*)_aligned_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE, 16);
38 memset(m_pBuffer2, 0, AVCODEC_MAX_AUDIO_FRAME_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
41 m_pCodecContext = NULL;
43 m_bOpenedCodec = false;
49 m_bNeedConversion = false;
52 m_iSampleFormat = AV_SAMPLE_FMT_NONE;
55 CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()
57 _aligned_free(m_pBuffer2);
61 bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
64 m_bOpenedCodec = false;
66 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwResample.Load())
69 m_dllAvCodec.avcodec_register_all();
71 pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
74 CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
78 #if defined(TARGET_DARWIN)
79 int audioMode = CSettings::Get().GetInt("audiooutput.mode");
80 if (audioMode == AUDIO_HDMI)
81 m_bLpcmMode = CSettings::Get().GetBool("audiooutput.multichannellpcm");
84 m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec);
85 m_pCodecContext->debug_mv = 0;
86 m_pCodecContext->debug = 0;
87 m_pCodecContext->workaround_bugs = 1;
89 if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
90 m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
93 m_pCodecContext->channels = hints.channels;
94 m_pCodecContext->sample_rate = hints.samplerate;
95 m_pCodecContext->block_align = hints.blockalign;
96 m_pCodecContext->bit_rate = hints.bitrate;
97 m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
99 if(m_pCodecContext->bits_per_coded_sample == 0)
100 m_pCodecContext->bits_per_coded_sample = 16;
102 if( hints.extradata && hints.extrasize > 0 )
104 m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
105 if(m_pCodecContext->extradata)
107 m_pCodecContext->extradata_size = hints.extrasize;
108 memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
112 if (m_dllAvCodec.avcodec_open2(m_pCodecContext, pCodec, NULL) < 0)
114 CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to open codec");
119 m_pFrame1 = m_dllAvCodec.avcodec_alloc_frame();
120 m_bOpenedCodec = true;
121 m_iSampleFormat = AV_SAMPLE_FMT_NONE;
125 void CDVDAudioCodecFFmpeg::Dispose()
127 if (m_pFrame1) m_dllAvUtil.av_free(m_pFrame1);
131 m_dllSwResample.swr_free(&m_pConvert);
135 if (m_bOpenedCodec) m_dllAvCodec.avcodec_close(m_pCodecContext);
136 m_bOpenedCodec = false;
137 m_dllAvUtil.av_free(m_pCodecContext);
138 m_pCodecContext = NULL;
141 m_dllAvCodec.Unload();
142 m_dllAvUtil.Unload();
143 m_dllSwResample.Unload();
150 int CDVDAudioCodecFFmpeg::Decode(uint8_t* pData, int iSize)
152 int iBytesUsed, got_frame;
153 if (!m_pCodecContext) return -1;
155 m_iBufferSize1 = AVCODEC_MAX_AUDIO_FRAME_SIZE ;
159 m_dllAvCodec.av_init_packet(&avpkt);
162 iBytesUsed = m_dllAvCodec.avcodec_decode_audio4( m_pCodecContext
166 if (iBytesUsed < 0 || !got_frame)
171 m_iBufferSize1 = m_dllAvUtil.av_samples_get_buffer_size(NULL, m_pCodecContext->channels, m_pFrame1->nb_samples, m_pCodecContext->sample_fmt, 1);
173 /* some codecs will attempt to consume more data than what we gave */
174 if (iBytesUsed > iSize)
176 CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - decoder attempted to consume more data than given");
180 if(m_iBufferSize1 == 0 && iBytesUsed >= 0)
181 m_iBuffered += iBytesUsed;
185 if(m_bLpcmMode || m_bNeedConversion)
191 void CDVDAudioCodecFFmpeg::ConvertToFloat()
193 if(m_pCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && m_iBufferSize1 > 0)
195 if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels))
196 m_dllSwResample.swr_free(&m_pConvert);
200 m_iSampleFormat = m_pCodecContext->sample_fmt;
201 m_pConvert = m_dllSwResample.swr_alloc_set_opts(NULL,
202 m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels), AV_SAMPLE_FMT_FLT, m_pCodecContext->sample_rate,
203 m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels), m_pCodecContext->sample_fmt, m_pCodecContext->sample_rate,
206 if(!m_pConvert || m_dllSwResample.swr_init(m_pConvert) < 0)
208 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", m_pCodecContext->sample_fmt);
215 int len = m_iBufferSize1 / m_dllAvUtil.av_get_bytes_per_sample(m_pCodecContext->sample_fmt);
216 if(m_dllSwResample.swr_convert(m_pConvert, &m_pBuffer2, len, (const uint8_t**)m_pFrame1->data, m_pFrame1->nb_samples) < 0)
218 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", (int)m_pCodecContext->sample_fmt);
225 m_iBufferSize2 = len * m_dllAvUtil.av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT);
229 int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst)
233 *dst = m_pFrame1->data[0];
234 return m_iBufferSize1;
240 return m_iBufferSize2;
246 void CDVDAudioCodecFFmpeg::Reset()
248 if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
254 int CDVDAudioCodecFFmpeg::GetChannels()
256 return m_pCodecContext->channels;
259 int CDVDAudioCodecFFmpeg::GetSampleRate()
262 return m_pCodecContext->sample_rate;
266 int CDVDAudioCodecFFmpeg::GetEncodedSampleRate()
269 return m_pCodecContext->sample_rate;
273 enum AEDataFormat CDVDAudioCodecFFmpeg::GetDataFormat()
281 switch(m_pCodecContext->sample_fmt)
283 case AV_SAMPLE_FMT_U8 : return AE_FMT_U8;
284 case AV_SAMPLE_FMT_S16: return AE_FMT_S16NE;
285 case AV_SAMPLE_FMT_S32: return AE_FMT_S32NE;
286 case AV_SAMPLE_FMT_FLT: return AE_FMT_FLOAT;
287 case AV_SAMPLE_FMT_DBL: return AE_FMT_DOUBLE;
288 case AV_SAMPLE_FMT_NONE:
290 return AE_FMT_INVALID;
292 m_bNeedConversion = true;
298 int CDVDAudioCodecFFmpeg::GetBitRate()
300 if (m_pCodecContext) return m_pCodecContext->bit_rate;
304 static unsigned count_bits(int64_t value)
312 void CDVDAudioCodecFFmpeg::BuildChannelMap()
314 if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout)
315 return; //nothing to do here
317 m_channels = m_pCodecContext->channels;
318 m_layout = m_pCodecContext->channel_layout;
322 int bits = count_bits(m_pCodecContext->channel_layout);
323 if (bits == m_pCodecContext->channels)
324 layout = m_pCodecContext->channel_layout;
327 CLog::Log(LOGINFO, "CDVDAudioCodecFFmpeg::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits);
328 layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels);
331 m_channelLayout.Reset();
333 if (layout & AV_CH_FRONT_LEFT ) m_channelLayout += AE_CH_FL ;
334 if (layout & AV_CH_FRONT_RIGHT ) m_channelLayout += AE_CH_FR ;
335 if (layout & AV_CH_FRONT_CENTER ) m_channelLayout += AE_CH_FC ;
336 if (layout & AV_CH_LOW_FREQUENCY ) m_channelLayout += AE_CH_LFE ;
337 if (layout & AV_CH_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
338 if (layout & AV_CH_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
339 if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
340 if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
341 if (layout & AV_CH_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
342 if (layout & AV_CH_SIDE_LEFT ) m_channelLayout += AE_CH_SL ;
343 if (layout & AV_CH_SIDE_RIGHT ) m_channelLayout += AE_CH_SR ;
344 if (layout & AV_CH_TOP_CENTER ) m_channelLayout += AE_CH_TC ;
345 if (layout & AV_CH_TOP_FRONT_LEFT ) m_channelLayout += AE_CH_TFL ;
346 if (layout & AV_CH_TOP_FRONT_CENTER ) m_channelLayout += AE_CH_TFC ;
347 if (layout & AV_CH_TOP_FRONT_RIGHT ) m_channelLayout += AE_CH_TFR ;
348 if (layout & AV_CH_TOP_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
349 if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
350 if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
352 m_channels = m_pCodecContext->channels;
355 CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap()
358 return m_channelLayout;