DVDAudioCodecFFmpeg: do not reopen the resample context for each frame.
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Audio / DVDAudioCodecFFmpeg.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "DVDAudioCodecFFmpeg.h"
22 #ifdef TARGET_POSIX
23 #include "XMemUtils.h"
24 #endif
25 #include "../../DVDStreamInfo.h"
26 #include "utils/log.h"
27
28 #if defined(TARGET_DARWIN)
29 #include "settings/Settings.h"
30 #include "cores/AudioEngine/Utils/AEUtil.h"
31 #endif
32
33 CDVDAudioCodecFFmpeg::CDVDAudioCodecFFmpeg() : CDVDAudioCodec()
34 {
35   m_iBufferSize1 = 0;
36   m_iBufferSize2 = 0;
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);
39
40   m_iBuffered = 0;
41   m_pCodecContext = NULL;
42   m_pConvert = NULL;
43   m_bOpenedCodec = false;
44
45   m_channels = 0;
46   m_layout = 0;
47   
48   m_bLpcmMode = false;
49   m_bNeedConversion = false;
50
51   m_pFrame1 = NULL;
52   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
53 }
54
55 CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()
56 {
57   _aligned_free(m_pBuffer2);
58   Dispose();
59 }
60
61 bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
62 {
63   AVCodec* pCodec;
64   m_bOpenedCodec = false;
65
66   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwResample.Load())
67     return false;
68
69   m_dllAvCodec.avcodec_register_all();
70
71   pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
72   if (!pCodec)
73   {
74     CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
75     return false;
76   }
77
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");
82 #endif
83
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;
88
89   if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
90     m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
91
92   m_channels = 0;
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;
98
99   if(m_pCodecContext->bits_per_coded_sample == 0)
100     m_pCodecContext->bits_per_coded_sample = 16;
101
102   if( hints.extradata && hints.extrasize > 0 )
103   {
104     m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
105     if(m_pCodecContext->extradata)
106     {
107       m_pCodecContext->extradata_size = hints.extrasize;
108       memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
109     }
110   }
111
112   if (m_dllAvCodec.avcodec_open2(m_pCodecContext, pCodec, NULL) < 0)
113   {
114     CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to open codec");
115     Dispose();
116     return false;
117   }
118
119   m_pFrame1 = m_dllAvCodec.avcodec_alloc_frame();
120   m_bOpenedCodec = true;
121   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
122   return true;
123 }
124
125 void CDVDAudioCodecFFmpeg::Dispose()
126 {
127   if (m_pFrame1) m_dllAvUtil.av_free(m_pFrame1);
128   m_pFrame1 = NULL;
129
130   if (m_pConvert)
131     m_dllSwResample.swr_free(&m_pConvert);
132
133   if (m_pCodecContext)
134   {
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;
139   }
140
141   m_dllAvCodec.Unload();
142   m_dllAvUtil.Unload();
143   m_dllSwResample.Unload();
144
145   m_iBufferSize1 = 0;
146   m_iBufferSize2 = 0;
147   m_iBuffered = 0;
148 }
149
150 int CDVDAudioCodecFFmpeg::Decode(uint8_t* pData, int iSize)
151 {
152   int iBytesUsed, got_frame;
153   if (!m_pCodecContext) return -1;
154
155   m_iBufferSize1 = AVCODEC_MAX_AUDIO_FRAME_SIZE ;
156   m_iBufferSize2 = 0;
157
158   AVPacket avpkt;
159   m_dllAvCodec.av_init_packet(&avpkt);
160   avpkt.data = pData;
161   avpkt.size = iSize;
162   iBytesUsed = m_dllAvCodec.avcodec_decode_audio4( m_pCodecContext
163                                                  , m_pFrame1
164                                                  , &got_frame
165                                                  , &avpkt);
166   if (iBytesUsed < 0 || !got_frame)
167   {
168     m_iBufferSize1 = 0;
169     return iBytesUsed;
170   }
171   m_iBufferSize1 = m_dllAvUtil.av_samples_get_buffer_size(NULL, m_pCodecContext->channels, m_pFrame1->nb_samples, m_pCodecContext->sample_fmt, 1);
172
173   /* some codecs will attempt to consume more data than what we gave */
174   if (iBytesUsed > iSize)
175   {
176     CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - decoder attempted to consume more data than given");
177     iBytesUsed = iSize;
178   }
179
180   if(m_iBufferSize1 == 0 && iBytesUsed >= 0)
181     m_iBuffered += iBytesUsed;
182   else
183     m_iBuffered = 0;
184     
185   if(m_bLpcmMode || m_bNeedConversion)
186     ConvertToFloat();
187
188   return iBytesUsed;
189 }
190
191 void CDVDAudioCodecFFmpeg::ConvertToFloat()
192 {
193   if(m_pCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && m_iBufferSize1 > 0)
194   {
195     if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels))
196       m_dllSwResample.swr_free(&m_pConvert);
197
198     if(!m_pConvert)
199     {
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,
204                       0, NULL);
205
206       if(!m_pConvert || m_dllSwResample.swr_init(m_pConvert) < 0)
207       {
208           CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", m_pCodecContext->sample_fmt);
209           m_iBufferSize1 = 0;
210           m_iBufferSize2 = 0;
211           return;
212       }
213     }
214
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)
217     {
218       CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", (int)m_pCodecContext->sample_fmt);
219       m_iBufferSize1 = 0;
220       m_iBufferSize2 = 0;
221       return;
222     }
223
224     m_iBufferSize1 = 0;
225     m_iBufferSize2 = len * m_dllAvUtil.av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT);
226   }
227 }
228
229 int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst)
230 {
231   if(m_iBufferSize1)
232   {
233     *dst = m_pFrame1->data[0];
234     return m_iBufferSize1;
235   }
236
237   if(m_iBufferSize2)
238   {
239     *dst = m_pBuffer2;
240     return m_iBufferSize2;
241   }
242
243   return 0;
244 }
245
246 void CDVDAudioCodecFFmpeg::Reset()
247 {
248   if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
249   m_iBufferSize1 = 0;
250   m_iBufferSize2 = 0;
251   m_iBuffered = 0;
252 }
253
254 int CDVDAudioCodecFFmpeg::GetChannels()
255 {
256   return m_pCodecContext->channels;
257 }
258
259 int CDVDAudioCodecFFmpeg::GetSampleRate()
260 {
261   if (m_pCodecContext)
262     return m_pCodecContext->sample_rate;
263   return 0;
264 }
265
266 int CDVDAudioCodecFFmpeg::GetEncodedSampleRate()
267 {
268   if (m_pCodecContext)
269     return m_pCodecContext->sample_rate;
270   return 0;
271 }
272
273 enum AEDataFormat CDVDAudioCodecFFmpeg::GetDataFormat()
274 {
275   if(m_bLpcmMode)
276   {
277     return AE_FMT_LPCM;
278   }
279   else
280   {
281     switch(m_pCodecContext->sample_fmt)
282     {
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:
289         assert(false);
290         return AE_FMT_INVALID;
291       default:
292         m_bNeedConversion = true;
293         return AE_FMT_FLOAT;
294     }
295   }
296 }
297
298 int CDVDAudioCodecFFmpeg::GetBitRate()
299 {
300   if (m_pCodecContext) return m_pCodecContext->bit_rate;
301   return 0;
302 }
303
304 static unsigned count_bits(int64_t value)
305 {
306   unsigned bits = 0;
307   for(;value;++bits)
308     value &= value - 1;
309   return bits;
310 }
311
312 void CDVDAudioCodecFFmpeg::BuildChannelMap()
313 {
314   if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout)
315     return; //nothing to do here
316
317   m_channels = m_pCodecContext->channels;
318   m_layout   = m_pCodecContext->channel_layout;
319
320   int64_t layout;
321
322   int bits = count_bits(m_pCodecContext->channel_layout);
323   if (bits == m_pCodecContext->channels)
324     layout = m_pCodecContext->channel_layout;
325   else
326   {
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);
329   }
330
331   m_channelLayout.Reset();
332
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  ;
351
352   m_channels = m_pCodecContext->channels;
353 }
354
355 CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap()
356 {
357   BuildChannelMap();
358   return m_channelLayout;
359 }