Merge pull request #3819 from arnova/subtitles_for_stacks
[vuplus_xbmc] / xbmc / cores / dvdplayer / DVDCodecs / Audio / DVDAudioCodecFFmpeg.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://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_iBufferTotalSize2 = 0;
38   m_pBuffer2     = NULL;
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
50   m_pFrame1 = NULL;
51   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
52 }
53
54 CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()
55 {
56   Dispose();
57 }
58
59 bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
60 {
61   AVCodec* pCodec;
62   m_bOpenedCodec = false;
63
64   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwResample.Load())
65     return false;
66
67   m_dllAvCodec.avcodec_register_all();
68
69   pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
70   if (!pCodec)
71   {
72     CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
73     return false;
74   }
75
76 #if defined(TARGET_DARWIN_OSX)
77   if (CSettings::Get().GetInt("audiooutput.channels") >  AE_CH_LAYOUT_2_0)
78     m_bLpcmMode = true;
79 #endif
80
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;
85
86   if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
87     m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
88
89   m_channels = 0;
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;
95
96   if(m_pCodecContext->bits_per_coded_sample == 0)
97     m_pCodecContext->bits_per_coded_sample = 16;
98
99   if( hints.extradata && hints.extrasize > 0 )
100   {
101     m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
102     if(m_pCodecContext->extradata)
103     {
104       m_pCodecContext->extradata_size = hints.extrasize;
105       memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
106     }
107   }
108
109   if (m_dllAvCodec.avcodec_open2(m_pCodecContext, pCodec, NULL) < 0)
110   {
111     CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to open codec");
112     Dispose();
113     return false;
114   }
115
116   m_pFrame1 = m_dllAvCodec.avcodec_alloc_frame();
117   m_bOpenedCodec = true;
118   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
119
120   return true;
121 }
122
123 void CDVDAudioCodecFFmpeg::Dispose()
124 {
125   if (m_pFrame1) m_dllAvUtil.av_free(m_pFrame1);
126   m_pFrame1 = NULL;
127
128   if (m_pConvert)
129     m_dllSwResample.swr_free(&m_pConvert);
130
131   if (m_pBuffer2)
132     m_dllAvUtil.av_freep(&m_pBuffer2);
133
134   if (m_pCodecContext)
135   {
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;
140   }
141
142   m_dllAvCodec.Unload();
143   m_dllAvUtil.Unload();
144   m_dllSwResample.Unload();
145
146   m_iBufferSize1 = 0;
147   m_iBufferSize2 = 0;
148   m_iBufferTotalSize2 = 0;
149   m_iBuffered = 0;
150 }
151
152 int CDVDAudioCodecFFmpeg::Decode(uint8_t* pData, int iSize)
153 {
154   int iBytesUsed, got_frame;
155   if (!m_pCodecContext) return -1;
156
157   m_iBufferSize2 = 0;
158
159   AVPacket avpkt;
160   m_dllAvCodec.av_init_packet(&avpkt);
161   avpkt.data = pData;
162   avpkt.size = iSize;
163   iBytesUsed = m_dllAvCodec.avcodec_decode_audio4( m_pCodecContext
164                                                  , m_pFrame1
165                                                  , &got_frame
166                                                  , &avpkt);
167   if (iBytesUsed < 0 || !got_frame)
168   {
169     m_iBufferSize1 = 0;
170     return iBytesUsed;
171   }
172   m_iBufferSize1 = m_pFrame1->nb_samples * m_pCodecContext->channels * m_dllAvUtil.av_get_bytes_per_sample(m_pCodecContext->sample_fmt);
173
174   /* some codecs will attempt to consume more data than what we gave */
175   if (iBytesUsed > iSize)
176   {
177     CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - decoder attempted to consume more data than given");
178     iBytesUsed = iSize;
179   }
180
181   if(m_iBufferSize1 == 0 && iBytesUsed >= 0)
182     m_iBuffered += iBytesUsed;
183   else
184     m_iBuffered = 0;
185   
186   bool convert = false;
187   switch(m_pCodecContext->sample_fmt)
188   {
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:
194       break;
195     case AV_SAMPLE_FMT_NONE:
196       CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - invalid data format");
197       return -1;
198     default:
199       convert = true;
200   }
201   if(m_bLpcmMode || convert)
202     ConvertToFloat();
203
204   return iBytesUsed;
205 }
206
207 void CDVDAudioCodecFFmpeg::ConvertToFloat()
208 {
209   if(m_pCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && m_iBufferSize1 > 0)
210   {
211     if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels))
212       m_dllSwResample.swr_free(&m_pConvert);
213
214     if(!m_pConvert)
215     {
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,
220                       0, NULL);
221
222       if(!m_pConvert || m_dllSwResample.swr_init(m_pConvert) < 0)
223       {
224           CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", m_pCodecContext->sample_fmt);
225           m_iBufferSize1 = 0;
226           m_iBufferSize2 = 0;
227           return;
228       }
229     }
230
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)
233     {
234         m_pBuffer2 = (uint8_t*)m_dllAvUtil.av_realloc(m_pBuffer2, needed_buf_size);
235         if(!m_pBuffer2)
236         {
237             CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to allocate a %i bytes buffer for resampling", needed_buf_size);
238             m_iBufferSize1 = 0;
239             m_iBufferSize2 = 0;
240             m_iBufferTotalSize2 = 0;
241             return;
242         }
243         m_iBufferTotalSize2 = needed_buf_size;
244     }
245
246     int outsamples;
247     outsamples = m_dllSwResample.swr_convert(m_pConvert, &m_pBuffer2, m_iBufferTotalSize2, (const uint8_t**)m_pFrame1->extended_data, m_pFrame1->nb_samples);
248
249     if(outsamples < 0)
250     {
251       CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", (int)m_pCodecContext->sample_fmt);
252       m_iBufferSize1 = 0;
253       m_iBufferSize2 = 0;
254       return;
255     }
256
257     if(outsamples < m_pFrame1->nb_samples)
258     {
259       CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - Resampler produced less samples than what it was given");
260     }
261
262     m_iBufferSize1 = 0;
263     m_iBufferSize2 = m_pFrame1->nb_samples * m_pCodecContext->channels * m_dllAvUtil.av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT);
264   }
265 }
266
267 int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst)
268 {
269   if(m_iBufferSize1)
270   {
271     *dst = m_pFrame1->data[0];
272     return m_iBufferSize1;
273   }
274
275   if(m_iBufferSize2)
276   {
277     *dst = m_pBuffer2;
278     return m_iBufferSize2;
279   }
280
281   return 0;
282 }
283
284 void CDVDAudioCodecFFmpeg::Reset()
285 {
286   if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
287   m_iBufferSize1 = 0;
288   m_iBufferSize2 = 0;
289   m_iBuffered = 0;
290 }
291
292 int CDVDAudioCodecFFmpeg::GetChannels()
293 {
294   return m_pCodecContext->channels;
295 }
296
297 int CDVDAudioCodecFFmpeg::GetSampleRate()
298 {
299   if (m_pCodecContext)
300     return m_pCodecContext->sample_rate;
301   return 0;
302 }
303
304 int CDVDAudioCodecFFmpeg::GetEncodedSampleRate()
305 {
306   if (m_pCodecContext)
307     return m_pCodecContext->sample_rate;
308   return 0;
309 }
310
311 enum AEDataFormat CDVDAudioCodecFFmpeg::GetDataFormat()
312 {
313   if(m_bLpcmMode)
314   {
315     return AE_FMT_LPCM;
316   }
317   else
318   {
319     switch(m_pCodecContext->sample_fmt)
320     {
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;
329       default:
330         return AE_FMT_FLOAT;
331     }
332   }
333 }
334
335 int CDVDAudioCodecFFmpeg::GetBitRate()
336 {
337   if (m_pCodecContext) return m_pCodecContext->bit_rate;
338   return 0;
339 }
340
341 static unsigned count_bits(int64_t value)
342 {
343   unsigned bits = 0;
344   for(;value;++bits)
345     value &= value - 1;
346   return bits;
347 }
348
349 void CDVDAudioCodecFFmpeg::BuildChannelMap()
350 {
351   if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout)
352     return; //nothing to do here
353
354   m_channels = m_pCodecContext->channels;
355   m_layout   = m_pCodecContext->channel_layout;
356
357   int64_t layout;
358
359   int bits = count_bits(m_pCodecContext->channel_layout);
360   if (bits == m_pCodecContext->channels)
361     layout = m_pCodecContext->channel_layout;
362   else
363   {
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);
366   }
367
368   m_channelLayout.Reset();
369
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  ;
388
389   m_channels = m_pCodecContext->channels;
390 }
391
392 CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap()
393 {
394   BuildChannelMap();
395   return m_channelLayout;
396 }