Merge pull request #4878 from FernetMenta/xfade
[vuplus_xbmc] / xbmc / cores / AudioEngine / Engines / ActiveAE / ActiveAEBuffer.cpp
1 /*
2  *      Copyright (C) 2010-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2.1 of the License, or (at your option) any later version.
9  *
10  *  This library 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 GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #include "ActiveAEBuffer.h"
22 #include "cores/AudioEngine/AEFactory.h"
23 #include "cores/AudioEngine/Engines/ActiveAE/ActiveAE.h"
24 #include "cores/AudioEngine/Utils/AEUtil.h"
25
26 using namespace ActiveAE;
27
28 /* typecast AE to CActiveAE */
29 #define AE (*((CActiveAE*)CAEFactory::GetEngine()))
30
31 CSoundPacket::CSoundPacket(SampleConfig conf, int samples) : config(conf)
32 {
33   data = AE.AllocSoundSample(config, samples, bytes_per_sample, planes, linesize);
34   max_nb_samples = samples;
35   nb_samples = 0;
36 }
37
38 CSoundPacket::~CSoundPacket()
39 {
40   if (data)
41     AE.FreeSoundSample(data);
42 }
43
44 CSampleBuffer::CSampleBuffer() : pkt(NULL), pool(NULL)
45 {
46   refCount = 0;
47 }
48
49 CSampleBuffer::~CSampleBuffer()
50 {
51   delete pkt;
52 }
53
54 CSampleBuffer* CSampleBuffer::Acquire()
55 {
56   refCount++;
57   return this;
58 }
59
60 void CSampleBuffer::Return()
61 {
62   refCount--;
63   if (pool && refCount <= 0)
64     pool->ReturnBuffer(this);
65 }
66
67 CActiveAEBufferPool::CActiveAEBufferPool(AEAudioFormat format)
68 {
69   m_format = format;
70   if (AE_IS_RAW(m_format.m_dataFormat))
71     m_format.m_dataFormat = AE_FMT_S16NE;
72 }
73
74 CActiveAEBufferPool::~CActiveAEBufferPool()
75 {
76   CSampleBuffer *buffer;
77   while(!m_allSamples.empty())
78   {
79     buffer = m_allSamples.front();
80     m_allSamples.pop_front();
81     delete buffer;
82   }
83 }
84
85 CSampleBuffer* CActiveAEBufferPool::GetFreeBuffer()
86 {
87   CSampleBuffer* buf = NULL;
88
89   if (!m_freeSamples.empty())
90   {
91     buf = m_freeSamples.front();
92     m_freeSamples.pop_front();
93     buf->refCount = 1;
94   }
95   return buf;
96 }
97
98 void CActiveAEBufferPool::ReturnBuffer(CSampleBuffer *buffer)
99 {
100   buffer->pkt->nb_samples = 0;
101   m_freeSamples.push_back(buffer);
102 }
103
104 bool CActiveAEBufferPool::Create(unsigned int totaltime)
105 {
106   CSampleBuffer *buffer;
107   SampleConfig config;
108   config.fmt = CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat);
109   config.bits_per_sample = CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat);
110   config.channels = m_format.m_channelLayout.Count();
111   config.sample_rate = m_format.m_sampleRate;
112   config.channel_layout = CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout);
113
114   unsigned int time = 0;
115   unsigned int buffertime = (m_format.m_frames*1000) / m_format.m_sampleRate;
116   unsigned int n = 0;
117   while (time < totaltime || n < 5)
118   {
119     buffer = new CSampleBuffer();
120     buffer->pool = this;
121     buffer->pkt = new CSoundPacket(config, m_format.m_frames);
122
123     m_allSamples.push_back(buffer);
124     m_freeSamples.push_back(buffer);
125     time += buffertime;
126     n++;
127   }
128
129   return true;
130 }
131
132 //-----------------------------------------------------------------------------
133
134 CActiveAEBufferPoolResample::CActiveAEBufferPoolResample(AEAudioFormat inputFormat, AEAudioFormat outputFormat, AEQuality quality)
135   : CActiveAEBufferPool(outputFormat)
136 {
137   m_inputFormat = inputFormat;
138   if (AE_IS_RAW(m_inputFormat.m_dataFormat))
139     m_inputFormat.m_dataFormat = AE_FMT_S16NE;
140   m_resampler = NULL;
141   m_fillPackets = false;
142   m_drain = false;
143   m_empty = true;
144   m_procSample = NULL;
145   m_resampleRatio = 1.0;
146   m_resampleQuality = quality;
147   m_changeResampler = false;
148   m_stereoUpmix = false;
149   m_normalize = true;
150 }
151
152 CActiveAEBufferPoolResample::~CActiveAEBufferPoolResample()
153 {
154   delete m_resampler;
155 }
156
157 bool CActiveAEBufferPoolResample::Create(unsigned int totaltime, bool remap, bool upmix, bool normalize)
158 {
159   CActiveAEBufferPool::Create(totaltime);
160
161   m_stereoUpmix = upmix;
162   m_normalize = true;
163   if ((m_format.m_channelLayout.Count() < m_inputFormat.m_channelLayout.Count() && !normalize))
164     m_normalize = false;
165
166   if (m_inputFormat.m_channelLayout != m_format.m_channelLayout ||
167       m_inputFormat.m_sampleRate != m_format.m_sampleRate ||
168       m_inputFormat.m_dataFormat != m_format.m_dataFormat ||
169       m_changeResampler)
170   {
171     m_resampler = new CActiveAEResample();
172     m_resampler->Init(CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout),
173                                 m_format.m_channelLayout.Count(),
174                                 m_format.m_sampleRate,
175                                 CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
176                                 CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
177                                 CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout),
178                                 m_inputFormat.m_channelLayout.Count(),
179                                 m_inputFormat.m_sampleRate,
180                                 CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
181                                 CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
182                                 upmix,
183                                 m_normalize,
184                                 remap ? &m_format.m_channelLayout : NULL,
185                                 m_resampleQuality);
186   }
187
188   m_changeResampler = false;
189
190   return true;
191 }
192
193 void CActiveAEBufferPoolResample::ChangeResampler()
194 {
195   delete m_resampler;
196
197   m_resampler = new CActiveAEResample();
198   m_resampler->Init(CActiveAEResample::GetAVChannelLayout(m_format.m_channelLayout),
199                                 m_format.m_channelLayout.Count(),
200                                 m_format.m_sampleRate,
201                                 CActiveAEResample::GetAVSampleFormat(m_format.m_dataFormat),
202                                 CAEUtil::DataFormatToUsedBits(m_format.m_dataFormat),
203                                 CActiveAEResample::GetAVChannelLayout(m_inputFormat.m_channelLayout),
204                                 m_inputFormat.m_channelLayout.Count(),
205                                 m_inputFormat.m_sampleRate,
206                                 CActiveAEResample::GetAVSampleFormat(m_inputFormat.m_dataFormat),
207                                 CAEUtil::DataFormatToUsedBits(m_inputFormat.m_dataFormat),
208                                 m_stereoUpmix,
209                                 m_normalize,
210                                 NULL,
211                                 m_resampleQuality);
212
213   m_changeResampler = false;
214 }
215
216 bool CActiveAEBufferPoolResample::ResampleBuffers(unsigned int timestamp)
217 {
218   bool busy = false;
219   CSampleBuffer *in;
220
221   if (!m_resampler)
222   {
223     if (m_changeResampler)
224     {
225       ChangeResampler();
226       return true;
227     }
228     while(!m_inputSamples.empty())
229     {
230       in = m_inputSamples.front();
231       m_inputSamples.pop_front();
232       in->timestamp = timestamp;
233       m_outputSamples.push_back(in);
234       busy = true;
235     }
236   }
237   else if (m_procSample || !m_freeSamples.empty())
238   {
239     // GetBufferedSamples is not accurate because of rounding errors
240     int out_samples = m_resampler->GetBufferedSamples();
241     int free_samples;
242     if (m_procSample)
243       free_samples = m_procSample->pkt->max_nb_samples - m_procSample->pkt->nb_samples;
244     else
245       free_samples = m_format.m_frames;
246
247     bool skipInput = false;
248     // avoid that ffmpeg resample buffer grows too large
249     if (out_samples > free_samples * 2 && !m_empty)
250       skipInput = true;
251
252     bool hasInput = !m_inputSamples.empty();
253
254     if (hasInput || skipInput || m_drain || m_changeResampler)
255     {
256       if (!m_procSample)
257       {
258         m_procSample = GetFreeBuffer();
259       }
260
261       if (hasInput && !skipInput && !m_changeResampler)
262       {
263         in = m_inputSamples.front();
264         m_inputSamples.pop_front();
265       }
266       else
267         in = NULL;
268
269       int start = m_procSample->pkt->nb_samples *
270                   m_procSample->pkt->bytes_per_sample *
271                   m_procSample->pkt->config.channels /
272                   m_procSample->pkt->planes;
273
274       for(int i=0; i<m_procSample->pkt->planes; i++)
275       {
276         m_planes[i] = m_procSample->pkt->data[i] + start;
277       }
278
279       out_samples = m_resampler->Resample(m_planes,
280                                           m_procSample->pkt->max_nb_samples - m_procSample->pkt->nb_samples,
281                                           in ? in->pkt->data : NULL,
282                                           in ? in->pkt->nb_samples : 0,
283                                           m_resampleRatio);
284       m_procSample->pkt->nb_samples += out_samples;
285       busy = true;
286       m_empty = (out_samples == 0);
287
288       if ((m_drain || m_changeResampler) && m_empty)
289       {
290         if (m_fillPackets && m_procSample->pkt->nb_samples != 0)
291         {
292           // pad with zero
293           start = m_procSample->pkt->nb_samples *
294                   m_procSample->pkt->bytes_per_sample *
295                   m_procSample->pkt->config.channels /
296                   m_procSample->pkt->planes;
297           for(int i=0; i<m_procSample->pkt->planes; i++)
298           {
299             memset(m_procSample->pkt->data[i]+start, 0, m_procSample->pkt->linesize-start);
300           }
301         }
302         m_procSample->timestamp = timestamp;
303
304         // check if draining is finished
305         if (m_drain && m_procSample->pkt->nb_samples == 0)
306         {
307           m_procSample->Return();
308           busy = false;
309         }
310         else
311           m_outputSamples.push_back(m_procSample);
312
313         m_procSample = NULL;
314         if (m_changeResampler)
315           ChangeResampler();
316       }
317       // some methods like encode require completely filled packets
318       else if (!m_fillPackets || (m_procSample->pkt->nb_samples == m_procSample->pkt->max_nb_samples))
319       {
320         m_procSample->timestamp = timestamp;
321         m_outputSamples.push_back(m_procSample);
322         m_procSample = NULL;
323       }
324
325       if (in)
326         in->Return();
327     }
328   }
329   return busy;
330 }
331
332 float CActiveAEBufferPoolResample::GetDelay()
333 {
334   float delay = 0;
335   std::deque<CSampleBuffer*>::iterator itBuf;
336
337   if (m_procSample)
338     delay += m_procSample->pkt->nb_samples / m_procSample->pkt->config.sample_rate;
339
340   for(itBuf=m_inputSamples.begin(); itBuf!=m_inputSamples.end(); ++itBuf)
341   {
342     delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate;
343   }
344
345   for(itBuf=m_outputSamples.begin(); itBuf!=m_outputSamples.end(); ++itBuf)
346   {
347     delay += (float)(*itBuf)->pkt->nb_samples / (*itBuf)->pkt->config.sample_rate;
348   }
349
350   if (m_resampler)
351   {
352     int samples = m_resampler->GetBufferedSamples();
353     delay += (float)samples / m_format.m_sampleRate;
354   }
355
356   return delay;
357 }
358
359 void CActiveAEBufferPoolResample::Flush()
360 {
361   if (m_procSample)
362   {
363     m_procSample->Return();
364     m_procSample = NULL;
365   }
366   while (!m_inputSamples.empty())
367   {
368     m_inputSamples.front()->Return();
369     m_inputSamples.pop_front();
370   }
371   while (!m_outputSamples.empty())
372   {
373     m_outputSamples.front()->Return();
374     m_outputSamples.pop_front();
375   }
376 }