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_iBufferTotalSize2 = 0;
41 m_pCodecContext = NULL;
43 m_bOpenedCodec = false;
51 m_iSampleFormat = AV_SAMPLE_FMT_NONE;
54 CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()
59 bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
62 m_bOpenedCodec = false;
64 if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwResample.Load())
67 m_dllAvCodec.avcodec_register_all();
69 pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
72 CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
76 #if defined(TARGET_DARWIN_OSX)
77 if (CSettings::Get().GetInt("audiooutput.channels") > AE_CH_LAYOUT_2_0)
81 m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec);
82 m_pCodecContext->debug_mv = 0;
83 m_pCodecContext->debug = 0;
84 m_pCodecContext->workaround_bugs = 1;
86 if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
87 m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
90 m_pCodecContext->channels = hints.channels;
91 m_pCodecContext->sample_rate = hints.samplerate;
92 m_pCodecContext->block_align = hints.blockalign;
93 m_pCodecContext->bit_rate = hints.bitrate;
94 m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
96 if(m_pCodecContext->bits_per_coded_sample == 0)
97 m_pCodecContext->bits_per_coded_sample = 16;
99 if( hints.extradata && hints.extrasize > 0 )
101 m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
102 if(m_pCodecContext->extradata)
104 m_pCodecContext->extradata_size = hints.extrasize;
105 memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
109 if (m_dllAvCodec.avcodec_open2(m_pCodecContext, pCodec, NULL) < 0)
111 CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to open codec");
116 m_pFrame1 = m_dllAvCodec.avcodec_alloc_frame();
117 m_bOpenedCodec = true;
118 m_iSampleFormat = AV_SAMPLE_FMT_NONE;
123 void CDVDAudioCodecFFmpeg::Dispose()
125 if (m_pFrame1) m_dllAvUtil.av_free(m_pFrame1);
129 m_dllSwResample.swr_free(&m_pConvert);
132 m_dllAvUtil.av_freep(&m_pBuffer2);
136 if (m_bOpenedCodec) m_dllAvCodec.avcodec_close(m_pCodecContext);
137 m_bOpenedCodec = false;
138 m_dllAvUtil.av_free(m_pCodecContext);
139 m_pCodecContext = NULL;
142 m_dllAvCodec.Unload();
143 m_dllAvUtil.Unload();
144 m_dllSwResample.Unload();
148 m_iBufferTotalSize2 = 0;
152 int CDVDAudioCodecFFmpeg::Decode(uint8_t* pData, int iSize)
154 int iBytesUsed, got_frame;
155 if (!m_pCodecContext) return -1;
160 m_dllAvCodec.av_init_packet(&avpkt);
163 iBytesUsed = m_dllAvCodec.avcodec_decode_audio4( m_pCodecContext
167 if (iBytesUsed < 0 || !got_frame)
172 m_iBufferSize1 = m_pFrame1->nb_samples * m_pCodecContext->channels * m_dllAvUtil.av_get_bytes_per_sample(m_pCodecContext->sample_fmt);
174 /* some codecs will attempt to consume more data than what we gave */
175 if (iBytesUsed > iSize)
177 CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - decoder attempted to consume more data than given");
181 if(m_iBufferSize1 == 0 && iBytesUsed >= 0)
182 m_iBuffered += iBytesUsed;
186 bool convert = false;
187 switch(m_pCodecContext->sample_fmt)
189 case AV_SAMPLE_FMT_U8:
190 case AV_SAMPLE_FMT_S16:
191 case AV_SAMPLE_FMT_S32:
192 case AV_SAMPLE_FMT_FLT:
193 case AV_SAMPLE_FMT_DBL:
195 case AV_SAMPLE_FMT_NONE:
196 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - invalid data format");
201 if(m_bLpcmMode || convert)
207 void CDVDAudioCodecFFmpeg::ConvertToFloat()
209 if(m_pCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && m_iBufferSize1 > 0)
211 if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels))
212 m_dllSwResample.swr_free(&m_pConvert);
216 m_iSampleFormat = m_pCodecContext->sample_fmt;
217 m_pConvert = m_dllSwResample.swr_alloc_set_opts(NULL,
218 m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels), AV_SAMPLE_FMT_FLT, m_pCodecContext->sample_rate,
219 m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels), m_pCodecContext->sample_fmt, m_pCodecContext->sample_rate,
222 if(!m_pConvert || m_dllSwResample.swr_init(m_pConvert) < 0)
224 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", m_pCodecContext->sample_fmt);
231 int needed_buf_size = m_dllAvUtil.av_samples_get_buffer_size(NULL, m_pCodecContext->channels, m_pFrame1->nb_samples, AV_SAMPLE_FMT_FLT, 0);
232 if(m_iBufferTotalSize2 < needed_buf_size)
234 m_pBuffer2 = (uint8_t*)m_dllAvUtil.av_realloc(m_pBuffer2, needed_buf_size);
237 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to allocate a %i bytes buffer for resampling", needed_buf_size);
240 m_iBufferTotalSize2 = 0;
243 m_iBufferTotalSize2 = needed_buf_size;
247 outsamples = m_dllSwResample.swr_convert(m_pConvert, &m_pBuffer2, m_iBufferTotalSize2, (const uint8_t**)m_pFrame1->extended_data, m_pFrame1->nb_samples);
251 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", (int)m_pCodecContext->sample_fmt);
257 if(outsamples < m_pFrame1->nb_samples)
259 CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - Resampler produced less samples than what it was given");
263 m_iBufferSize2 = m_pFrame1->nb_samples * m_pCodecContext->channels * m_dllAvUtil.av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT);
267 int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst)
271 *dst = m_pFrame1->data[0];
272 return m_iBufferSize1;
278 return m_iBufferSize2;
284 void CDVDAudioCodecFFmpeg::Reset()
286 if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
292 int CDVDAudioCodecFFmpeg::GetChannels()
294 return m_pCodecContext->channels;
297 int CDVDAudioCodecFFmpeg::GetSampleRate()
300 return m_pCodecContext->sample_rate;
304 int CDVDAudioCodecFFmpeg::GetEncodedSampleRate()
307 return m_pCodecContext->sample_rate;
311 enum AEDataFormat CDVDAudioCodecFFmpeg::GetDataFormat()
319 switch(m_pCodecContext->sample_fmt)
321 case AV_SAMPLE_FMT_U8 : return AE_FMT_U8;
322 case AV_SAMPLE_FMT_S16: return AE_FMT_S16NE;
323 case AV_SAMPLE_FMT_S32: return AE_FMT_S32NE;
324 case AV_SAMPLE_FMT_FLT: return AE_FMT_FLOAT;
325 case AV_SAMPLE_FMT_DBL: return AE_FMT_DOUBLE;
326 case AV_SAMPLE_FMT_NONE:
327 CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::GetDataFormat - invalid data format");
328 return AE_FMT_INVALID;
335 int CDVDAudioCodecFFmpeg::GetBitRate()
337 if (m_pCodecContext) return m_pCodecContext->bit_rate;
341 static unsigned count_bits(int64_t value)
349 void CDVDAudioCodecFFmpeg::BuildChannelMap()
351 if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout)
352 return; //nothing to do here
354 m_channels = m_pCodecContext->channels;
355 m_layout = m_pCodecContext->channel_layout;
359 int bits = count_bits(m_pCodecContext->channel_layout);
360 if (bits == m_pCodecContext->channels)
361 layout = m_pCodecContext->channel_layout;
364 CLog::Log(LOGINFO, "CDVDAudioCodecFFmpeg::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits);
365 layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels);
368 m_channelLayout.Reset();
370 if (layout & AV_CH_FRONT_LEFT ) m_channelLayout += AE_CH_FL ;
371 if (layout & AV_CH_FRONT_RIGHT ) m_channelLayout += AE_CH_FR ;
372 if (layout & AV_CH_FRONT_CENTER ) m_channelLayout += AE_CH_FC ;
373 if (layout & AV_CH_LOW_FREQUENCY ) m_channelLayout += AE_CH_LFE ;
374 if (layout & AV_CH_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
375 if (layout & AV_CH_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
376 if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
377 if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
378 if (layout & AV_CH_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
379 if (layout & AV_CH_SIDE_LEFT ) m_channelLayout += AE_CH_SL ;
380 if (layout & AV_CH_SIDE_RIGHT ) m_channelLayout += AE_CH_SR ;
381 if (layout & AV_CH_TOP_CENTER ) m_channelLayout += AE_CH_TC ;
382 if (layout & AV_CH_TOP_FRONT_LEFT ) m_channelLayout += AE_CH_TFL ;
383 if (layout & AV_CH_TOP_FRONT_CENTER ) m_channelLayout += AE_CH_TFC ;
384 if (layout & AV_CH_TOP_FRONT_RIGHT ) m_channelLayout += AE_CH_TFR ;
385 if (layout & AV_CH_TOP_BACK_LEFT ) m_channelLayout += AE_CH_BL ;
386 if (layout & AV_CH_TOP_BACK_CENTER ) m_channelLayout += AE_CH_BC ;
387 if (layout & AV_CH_TOP_BACK_RIGHT ) m_channelLayout += AE_CH_BR ;
389 m_channels = m_pCodecContext->channels;
392 CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap()
395 return m_channelLayout;