Merge pull request #4196 from arnova/sub_fallback
[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_pFrame1 = NULL;
49   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
50 }
51
52 CDVDAudioCodecFFmpeg::~CDVDAudioCodecFFmpeg()
53 {
54   Dispose();
55 }
56
57 bool CDVDAudioCodecFFmpeg::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
58 {
59   AVCodec* pCodec;
60   m_bOpenedCodec = false;
61
62   if (!m_dllAvUtil.Load() || !m_dllAvCodec.Load() || !m_dllSwResample.Load())
63     return false;
64
65   m_dllAvCodec.avcodec_register_all();
66
67   pCodec = m_dllAvCodec.avcodec_find_decoder(hints.codec);
68   if (!pCodec)
69   {
70     CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to find codec %d", hints.codec);
71     return false;
72   }
73
74   m_pCodecContext = m_dllAvCodec.avcodec_alloc_context3(pCodec);
75   m_pCodecContext->debug_mv = 0;
76   m_pCodecContext->debug = 0;
77   m_pCodecContext->workaround_bugs = 1;
78
79   if (pCodec->capabilities & CODEC_CAP_TRUNCATED)
80     m_pCodecContext->flags |= CODEC_FLAG_TRUNCATED;
81
82   m_channels = 0;
83   m_pCodecContext->channels = hints.channels;
84   m_pCodecContext->sample_rate = hints.samplerate;
85   m_pCodecContext->block_align = hints.blockalign;
86   m_pCodecContext->bit_rate = hints.bitrate;
87   m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
88
89   if(m_pCodecContext->bits_per_coded_sample == 0)
90     m_pCodecContext->bits_per_coded_sample = 16;
91
92   if( hints.extradata && hints.extrasize > 0 )
93   {
94     m_pCodecContext->extradata = (uint8_t*)m_dllAvUtil.av_mallocz(hints.extrasize + FF_INPUT_BUFFER_PADDING_SIZE);
95     if(m_pCodecContext->extradata)
96     {
97       m_pCodecContext->extradata_size = hints.extrasize;
98       memcpy(m_pCodecContext->extradata, hints.extradata, hints.extrasize);
99     }
100   }
101
102   if (m_dllAvCodec.avcodec_open2(m_pCodecContext, pCodec, NULL) < 0)
103   {
104     CLog::Log(LOGDEBUG,"CDVDAudioCodecFFmpeg::Open() Unable to open codec");
105     Dispose();
106     return false;
107   }
108
109   m_pFrame1 = m_dllAvCodec.avcodec_alloc_frame();
110   m_bOpenedCodec = true;
111   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
112
113   return true;
114 }
115
116 void CDVDAudioCodecFFmpeg::Dispose()
117 {
118   if (m_pFrame1) m_dllAvUtil.av_free(m_pFrame1);
119   m_pFrame1 = NULL;
120
121   if (m_pConvert)
122     m_dllSwResample.swr_free(&m_pConvert);
123
124   if (m_pBuffer2)
125     m_dllAvUtil.av_freep(&m_pBuffer2);
126
127   if (m_pCodecContext)
128   {
129     if (m_bOpenedCodec) m_dllAvCodec.avcodec_close(m_pCodecContext);
130     m_bOpenedCodec = false;
131     m_dllAvUtil.av_free(m_pCodecContext);
132     m_pCodecContext = NULL;
133   }
134
135   m_dllAvCodec.Unload();
136   m_dllAvUtil.Unload();
137   m_dllSwResample.Unload();
138
139   m_iBufferSize1 = 0;
140   m_iBufferSize2 = 0;
141   m_iBufferTotalSize2 = 0;
142   m_iBuffered = 0;
143 }
144
145 int CDVDAudioCodecFFmpeg::Decode(uint8_t* pData, int iSize)
146 {
147   int iBytesUsed, got_frame;
148   if (!m_pCodecContext) return -1;
149
150   m_iBufferSize2 = 0;
151
152   AVPacket avpkt;
153   m_dllAvCodec.av_init_packet(&avpkt);
154   avpkt.data = pData;
155   avpkt.size = iSize;
156   iBytesUsed = m_dllAvCodec.avcodec_decode_audio4( m_pCodecContext
157                                                  , m_pFrame1
158                                                  , &got_frame
159                                                  , &avpkt);
160   if (iBytesUsed < 0 || !got_frame)
161   {
162     m_iBufferSize1 = 0;
163     return iBytesUsed;
164   }
165   m_iBufferSize1 = m_pFrame1->nb_samples * m_pCodecContext->channels * m_dllAvUtil.av_get_bytes_per_sample(m_pCodecContext->sample_fmt);
166
167   /* some codecs will attempt to consume more data than what we gave */
168   if (iBytesUsed > iSize)
169   {
170     CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - decoder attempted to consume more data than given");
171     iBytesUsed = iSize;
172   }
173
174   if(m_iBufferSize1 == 0 && iBytesUsed >= 0)
175     m_iBuffered += iBytesUsed;
176   else
177     m_iBuffered = 0;
178   
179   bool convert = false;
180   switch(m_pCodecContext->sample_fmt)
181   {
182     case AV_SAMPLE_FMT_U8:
183     case AV_SAMPLE_FMT_S16:
184     case AV_SAMPLE_FMT_S32:
185     case AV_SAMPLE_FMT_FLT:
186     case AV_SAMPLE_FMT_DBL:
187       break;
188     case AV_SAMPLE_FMT_NONE:
189       CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - invalid data format");
190       return -1;
191     default:
192       convert = true;
193   }
194   if(convert)
195     ConvertToFloat();
196
197   return iBytesUsed;
198 }
199
200 void CDVDAudioCodecFFmpeg::ConvertToFloat()
201 {
202   if(m_pCodecContext->sample_fmt != AV_SAMPLE_FMT_FLT && m_iBufferSize1 > 0)
203   {
204     if(m_pConvert && (m_pCodecContext->sample_fmt != m_iSampleFormat || m_channels != m_pCodecContext->channels))
205       m_dllSwResample.swr_free(&m_pConvert);
206
207     if(!m_pConvert)
208     {
209       m_iSampleFormat = m_pCodecContext->sample_fmt;
210       m_pConvert = m_dllSwResample.swr_alloc_set_opts(NULL,
211                       m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels), AV_SAMPLE_FMT_FLT, m_pCodecContext->sample_rate,
212                       m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels), m_pCodecContext->sample_fmt, m_pCodecContext->sample_rate,
213                       0, NULL);
214
215       if(!m_pConvert || m_dllSwResample.swr_init(m_pConvert) < 0)
216       {
217           CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", m_pCodecContext->sample_fmt);
218           m_iBufferSize1 = 0;
219           m_iBufferSize2 = 0;
220           return;
221       }
222     }
223
224     int needed_buf_size = m_dllAvUtil.av_samples_get_buffer_size(NULL, m_pCodecContext->channels, m_pFrame1->nb_samples, AV_SAMPLE_FMT_FLT, 0);
225     if(m_iBufferTotalSize2 < needed_buf_size)
226     {
227         m_pBuffer2 = (uint8_t*)m_dllAvUtil.av_realloc(m_pBuffer2, needed_buf_size);
228         if(!m_pBuffer2)
229         {
230             CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to allocate a %i bytes buffer for resampling", needed_buf_size);
231             m_iBufferSize1 = 0;
232             m_iBufferSize2 = 0;
233             m_iBufferTotalSize2 = 0;
234             return;
235         }
236         m_iBufferTotalSize2 = needed_buf_size;
237     }
238
239     int outsamples;
240     outsamples = m_dllSwResample.swr_convert(m_pConvert, &m_pBuffer2, m_iBufferTotalSize2, (const uint8_t**)m_pFrame1->extended_data, m_pFrame1->nb_samples);
241
242     if(outsamples < 0)
243     {
244       CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::Decode - Unable to convert %d to AV_SAMPLE_FMT_FLT", (int)m_pCodecContext->sample_fmt);
245       m_iBufferSize1 = 0;
246       m_iBufferSize2 = 0;
247       return;
248     }
249
250     if(outsamples < m_pFrame1->nb_samples)
251     {
252       CLog::Log(LOGWARNING, "CDVDAudioCodecFFmpeg::Decode - Resampler produced less samples than what it was given");
253     }
254
255     m_iBufferSize1 = 0;
256     m_iBufferSize2 = m_pFrame1->nb_samples * m_pCodecContext->channels * m_dllAvUtil.av_get_bytes_per_sample(AV_SAMPLE_FMT_FLT);
257   }
258 }
259
260 int CDVDAudioCodecFFmpeg::GetData(uint8_t** dst)
261 {
262   if(m_iBufferSize1)
263   {
264     *dst = m_pFrame1->data[0];
265     return m_iBufferSize1;
266   }
267
268   if(m_iBufferSize2)
269   {
270     *dst = m_pBuffer2;
271     return m_iBufferSize2;
272   }
273
274   return 0;
275 }
276
277 void CDVDAudioCodecFFmpeg::Reset()
278 {
279   if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
280   m_iBufferSize1 = 0;
281   m_iBufferSize2 = 0;
282   m_iBuffered = 0;
283 }
284
285 int CDVDAudioCodecFFmpeg::GetChannels()
286 {
287   return m_pCodecContext->channels;
288 }
289
290 int CDVDAudioCodecFFmpeg::GetSampleRate()
291 {
292   if (m_pCodecContext)
293     return m_pCodecContext->sample_rate;
294   return 0;
295 }
296
297 int CDVDAudioCodecFFmpeg::GetEncodedSampleRate()
298 {
299   if (m_pCodecContext)
300     return m_pCodecContext->sample_rate;
301   return 0;
302 }
303
304 enum AEDataFormat CDVDAudioCodecFFmpeg::GetDataFormat()
305 {
306   switch(m_pCodecContext->sample_fmt)
307   {
308     case AV_SAMPLE_FMT_U8 : return AE_FMT_U8;
309     case AV_SAMPLE_FMT_S16: return AE_FMT_S16NE;
310     case AV_SAMPLE_FMT_S32: return AE_FMT_S32NE;
311     case AV_SAMPLE_FMT_FLT: return AE_FMT_FLOAT;
312     case AV_SAMPLE_FMT_DBL: return AE_FMT_DOUBLE;
313     case AV_SAMPLE_FMT_NONE:
314       CLog::Log(LOGERROR, "CDVDAudioCodecFFmpeg::GetDataFormat - invalid data format");
315       return AE_FMT_INVALID;
316     default:
317       return AE_FMT_FLOAT;
318   }
319 }
320
321 int CDVDAudioCodecFFmpeg::GetBitRate()
322 {
323   if (m_pCodecContext) return m_pCodecContext->bit_rate;
324   return 0;
325 }
326
327 static unsigned count_bits(int64_t value)
328 {
329   unsigned bits = 0;
330   for(;value;++bits)
331     value &= value - 1;
332   return bits;
333 }
334
335 void CDVDAudioCodecFFmpeg::BuildChannelMap()
336 {
337   if (m_channels == m_pCodecContext->channels && m_layout == m_pCodecContext->channel_layout)
338     return; //nothing to do here
339
340   m_channels = m_pCodecContext->channels;
341   m_layout   = m_pCodecContext->channel_layout;
342
343   int64_t layout;
344
345   int bits = count_bits(m_pCodecContext->channel_layout);
346   if (bits == m_pCodecContext->channels)
347     layout = m_pCodecContext->channel_layout;
348   else
349   {
350     CLog::Log(LOGINFO, "CDVDAudioCodecFFmpeg::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits);
351     layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels);
352   }
353
354   m_channelLayout.Reset();
355
356   if (layout & AV_CH_FRONT_LEFT           ) m_channelLayout += AE_CH_FL  ;
357   if (layout & AV_CH_FRONT_RIGHT          ) m_channelLayout += AE_CH_FR  ;
358   if (layout & AV_CH_FRONT_CENTER         ) m_channelLayout += AE_CH_FC  ;
359   if (layout & AV_CH_LOW_FREQUENCY        ) m_channelLayout += AE_CH_LFE ;
360   if (layout & AV_CH_BACK_LEFT            ) m_channelLayout += AE_CH_BL  ;
361   if (layout & AV_CH_BACK_RIGHT           ) m_channelLayout += AE_CH_BR  ;
362   if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
363   if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
364   if (layout & AV_CH_BACK_CENTER          ) m_channelLayout += AE_CH_BC  ;
365   if (layout & AV_CH_SIDE_LEFT            ) m_channelLayout += AE_CH_SL  ;
366   if (layout & AV_CH_SIDE_RIGHT           ) m_channelLayout += AE_CH_SR  ;
367   if (layout & AV_CH_TOP_CENTER           ) m_channelLayout += AE_CH_TC  ;
368   if (layout & AV_CH_TOP_FRONT_LEFT       ) m_channelLayout += AE_CH_TFL ;
369   if (layout & AV_CH_TOP_FRONT_CENTER     ) m_channelLayout += AE_CH_TFC ;
370   if (layout & AV_CH_TOP_FRONT_RIGHT      ) m_channelLayout += AE_CH_TFR ;
371   if (layout & AV_CH_TOP_BACK_LEFT        ) m_channelLayout += AE_CH_BL  ;
372   if (layout & AV_CH_TOP_BACK_CENTER      ) m_channelLayout += AE_CH_BC  ;
373   if (layout & AV_CH_TOP_BACK_RIGHT       ) m_channelLayout += AE_CH_BR  ;
374
375   m_channels = m_pCodecContext->channels;
376 }
377
378 CAEChannelInfo CDVDAudioCodecFFmpeg::GetChannelMap()
379 {
380   BuildChannelMap();
381   return m_channelLayout;
382 }