[XBOX] revert: r19196 . We need to shorten the text as much as possible on Xbox for...
[xbmc:paulepanters-xbmc.git] / xbmc / cores / dvdplayer / DVDPlayerAudio.cpp
1 /*
2  *      Copyright (C) 2005-2008 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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21  
22 #include "stdafx.h"
23 #include "DVDPlayerAudio.h"
24 #include "DVDCodecs/Audio/DVDAudioCodec.h"
25 #include "DVDCodecs/DVDCodecs.h"
26 #include "DVDCodecs/DVDFactoryCodec.h"
27 #include "DVDPerformanceCounter.h"
28 #include <sstream>
29 #include <iomanip>
30
31 using namespace std;
32
33 CPTSOutputQueue::CPTSOutputQueue()
34 {
35   Flush();
36 }
37
38 void CPTSOutputQueue::Add(double pts, double delay, double duration)
39 {
40   CSingleLock lock(m_sync);
41   
42   TPTSItem item;
43   item.pts = pts;
44   item.timestamp = CDVDClock::GetAbsoluteClock() + delay;
45   item.duration = duration;
46
47   // first one is applied directly
48   if(m_queue.empty() && m_current.pts == DVD_NOPTS_VALUE)
49     m_current = item;
50   else
51     m_queue.push(item);
52
53   // call function to make sure the queue 
54   // doesn't grow should nobody call it
55   Current();
56 }
57 void CPTSOutputQueue::Flush()
58 {
59   CSingleLock lock(m_sync);
60   
61   while( !m_queue.empty() ) m_queue.pop();
62   m_current.pts = DVD_NOPTS_VALUE;
63   m_current.timestamp = 0.0;
64   m_current.duration = 0.0;
65 }
66
67 double CPTSOutputQueue::Current()
68 {
69   CSingleLock lock(m_sync);
70
71   if(!m_queue.empty() && m_current.pts == DVD_NOPTS_VALUE)
72   {
73     m_current = m_queue.front();
74     m_queue.pop();
75   }
76
77   while( !m_queue.empty() && CDVDClock::GetAbsoluteClock() >= m_queue.front().timestamp )
78   {
79     m_current = m_queue.front();
80     m_queue.pop();
81   }
82
83   if( m_current.timestamp == 0 ) return m_current.pts;
84
85   return m_current.pts + min(m_current.duration, (CDVDClock::GetAbsoluteClock() - m_current.timestamp));
86 }  
87
88 void CPTSInputQueue::Add(__int64 bytes, double pts)
89 {
90   CSingleLock lock(m_sync);
91   
92   m_list.insert(m_list.begin(), make_pair(bytes, pts));
93 }
94
95 void CPTSInputQueue::Flush()
96 {
97   CSingleLock lock(m_sync);
98   
99   m_list.clear();
100 }
101 double CPTSInputQueue::Get(__int64 bytes, bool consume)
102 {
103   CSingleLock lock(m_sync);
104   
105   IT it = m_list.begin();
106   for(; it != m_list.end(); it++)
107   {
108     if(bytes <= it->first)
109     {
110       double pts = it->second;
111       if(consume)
112       {
113         it->second = DVD_NOPTS_VALUE;
114         m_list.erase(++it, m_list.end());        
115       }
116       return pts; 
117     }
118     bytes -= it->first;
119   }
120   return DVD_NOPTS_VALUE;
121 }
122
123 CDVDPlayerAudio::CDVDPlayerAudio(CDVDClock* pClock) 
124 : CThread()
125 , m_messageQueue("audio")
126 , m_dvdAudio((bool&)m_bStop)
127 {
128   m_pClock = pClock;
129   m_pAudioCodec = NULL;  
130   m_audioClock = 0;
131   m_droptime = 0;
132   m_speed = DVD_PLAYSPEED_NORMAL;
133   m_stalled = false;
134   m_started = false;
135
136   InitializeCriticalSection(&m_critCodecSection);
137   m_messageQueue.SetMaxDataSize(30 * 16 * 1024);
138   g_dvdPerformanceCounter.EnableAudioQueue(&m_messageQueue);
139 }
140
141 CDVDPlayerAudio::~CDVDPlayerAudio()
142 {
143   StopThread();
144   g_dvdPerformanceCounter.DisableAudioQueue();
145
146   // close the stream, and don't wait for the audio to be finished
147   // CloseStream(true);
148   DeleteCriticalSection(&m_critCodecSection);
149 }
150
151 bool CDVDPlayerAudio::OpenStream( CDVDStreamInfo &hints )                                 
152 {
153   // should alway's be NULL!!!!, it will probably crash anyway when deleting m_pAudioCodec here.
154   if (m_pAudioCodec)
155   {
156     CLog::Log(LOGFATAL, "CDVDPlayerAudio::OpenStream() m_pAudioCodec != NULL");
157     return false;
158   }
159
160   /* try to open decoder without probing, we could actually allow us to continue here */
161   if( !OpenDecoder(hints) ) return false;
162
163   m_messageQueue.Init();
164
165   m_droptime = 0;
166   m_audioClock = 0;
167   m_stalled = false;
168   m_started = false;
169
170   CLog::Log(LOGNOTICE, "Creating audio thread");
171   Create();
172
173   return true;
174 }
175
176 void CDVDPlayerAudio::CloseStream(bool bWaitForBuffers)
177 {
178   // wait until buffers are empty
179   if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
180
181   // send abort message to the audio queue
182   m_messageQueue.Abort();
183
184   CLog::Log(LOGNOTICE, "Waiting for audio thread to exit");
185
186   // shut down the adio_decode thread and wait for it
187   StopThread(); // will set this->m_bStop to true
188
189   // destroy audio device
190   CLog::Log(LOGNOTICE, "Closing audio device");
191   if (bWaitForBuffers && m_speed > 0)
192   {
193     m_bStop = false;
194     m_dvdAudio.Drain();
195     m_bStop = true;
196   }
197   m_dvdAudio.Destroy();
198
199   // uninit queue
200   m_messageQueue.End();
201
202   CLog::Log(LOGNOTICE, "Deleting audio codec");
203   if (m_pAudioCodec)
204   {
205     m_pAudioCodec->Dispose();
206     delete m_pAudioCodec;
207     m_pAudioCodec = NULL;
208   }
209
210   // flush any remaining pts values
211   m_ptsOutput.Flush();
212 }
213
214 bool CDVDPlayerAudio::OpenDecoder(CDVDStreamInfo &hints, BYTE* buffer /* = NULL*/, unsigned int size /* = 0*/)
215 {
216   EnterCriticalSection(&m_critCodecSection);
217
218   /* close current audio codec */
219   if( m_pAudioCodec )
220   {
221     CLog::Log(LOGNOTICE, "Deleting audio codec");
222     m_pAudioCodec->Dispose();
223     SAFE_DELETE(m_pAudioCodec);
224   }
225
226   /* store our stream hints */
227   m_streaminfo = hints;
228
229   CLog::Log(LOGNOTICE, "Finding audio codec for: %i", m_streaminfo.codec);
230   m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec( m_streaminfo );
231   if( !m_pAudioCodec )
232   {
233     CLog::Log(LOGERROR, "Unsupported audio codec");
234
235     m_streaminfo.Clear();
236     LeaveCriticalSection(&m_critCodecSection);
237     return false;
238   }
239
240   /* update codec information from what codec gave ut */  
241   m_streaminfo.channels = m_pAudioCodec->GetChannels();
242   m_streaminfo.samplerate = m_pAudioCodec->GetSampleRate();
243   
244   LeaveCriticalSection(&m_critCodecSection);
245
246   return true;
247 }
248
249 // decode one audio frame and returns its uncompressed size
250 int CDVDPlayerAudio::DecodeFrame(DVDAudioFrame &audioframe, bool bDropPacket)
251 {
252   int result = 0;
253   int datatimeout = 1000;
254
255   // make sure the sent frame is clean
256   memset(&audioframe, 0, sizeof(DVDAudioFrame));
257
258   while (!m_bStop)
259   {
260     /* NOTE: the audio packet can contain several frames */
261     while( !m_bStop && m_decode.size > 0 )
262     {
263       if( !m_pAudioCodec ) 
264         return DECODE_FLAG_ERROR;
265
266       /* the packet dts refers to the first audioframe that starts in the packet */      
267       double dts = m_ptsInput.Get(m_decode.size + m_pAudioCodec->GetBufferSize(), true);
268       if (dts != DVD_NOPTS_VALUE)
269         m_audioClock = dts;
270
271       int len = m_pAudioCodec->Decode(m_decode.data, m_decode.size);
272       m_audioStats.AddSampleBytes(m_decode.size);
273       if (len < 0)
274       {
275         /* if error, we skip the packet */
276         CLog::Log(LOGERROR, "CDVDPlayerAudio::DecodeFrame - Decode Error. Skipping audio packet");
277         m_decode.Release();
278         m_pAudioCodec->Reset();
279         return DECODE_FLAG_ERROR;
280       }
281
282       // fix for fucked up decoders
283       if( len > m_decode.size )
284       {        
285         CLog::Log(LOGERROR, "CDVDPlayerAudio:DecodeFrame - Codec tried to consume more data than available. Potential memory corruption");        
286         m_decode.Release();
287         m_pAudioCodec->Reset();
288         assert(0);
289       }
290
291       m_decode.data += len;
292       m_decode.size -= len;
293
294
295       // get decoded data and the size of it
296       audioframe.size = m_pAudioCodec->GetData(&audioframe.data);
297       audioframe.pts = m_audioClock;
298       audioframe.channels = m_pAudioCodec->GetChannels();
299       audioframe.bits_per_sample = m_pAudioCodec->GetBitsPerSample();
300       audioframe.sample_rate = m_pAudioCodec->GetSampleRate();
301       audioframe.passthrough = m_pAudioCodec->NeedPasstrough();
302
303       if (audioframe.size <= 0) 
304         continue;
305
306       // compute duration.
307       int n = (audioframe.channels * audioframe.bits_per_sample * audioframe.sample_rate)>>3;
308       if (n > 0)
309       {
310         // safety check, if channels == 0, n will result in 0, and that will result in a nice devide exception
311         audioframe.duration = ((double)audioframe.size * DVD_TIME_BASE) / n;
312
313         // increase audioclock to after the packet
314         m_audioClock += audioframe.duration;
315         datatimeout = (unsigned int)(DVD_TIME_TO_MSEC(audioframe.duration * 2.0));
316       }
317
318       // if demux source want's us to not display this, continue
319       if(m_decode.msg->GetPacketDrop())
320         continue;
321
322       //If we are asked to drop this packet, return a size of zero. then it won't be played
323       //we currently still decode the audio.. this is needed since we still need to know it's 
324       //duration to make sure clock is updated correctly.
325       if( bDropPacket )
326         result |= DECODE_FLAG_DROP;
327
328       return result;
329     }
330     // free the current packet
331     m_decode.Release();
332
333     if (m_messageQueue.ReceivedAbortRequest()) return DECODE_FLAG_ABORT;
334
335     CDVDMsg* pMsg;
336     int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE) ? 1 : 0;
337     // read next packet and return -1 on error
338     LeaveCriticalSection(&m_critCodecSection); //Leave here as this might stall a while
339     MsgQueueReturnCode ret = m_messageQueue.Get(&pMsg, datatimeout, iPriority);
340     EnterCriticalSection(&m_critCodecSection);
341
342     if (ret == MSGQ_TIMEOUT) 
343       return DECODE_FLAG_TIMEOUT;
344
345     if (MSGQ_IS_ERROR(ret) || ret == MSGQ_ABORT) 
346       return DECODE_FLAG_ABORT;
347
348     if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
349     {
350       m_decode.Attach((CDVDMsgDemuxerPacket*)pMsg);
351       m_ptsInput.Add( m_decode.size, m_decode.dts );
352     }
353     else if (pMsg->IsType(CDVDMsg::GENERAL_STREAMCHANGE))
354     {
355       CDVDMsgGeneralStreamChange* pMsgStreamChange = (CDVDMsgGeneralStreamChange*)pMsg;
356       CDVDStreamInfo* hints = pMsgStreamChange->GetStreamInfo();
357
358       /* received a stream change, reopen codec. */
359       /* we should really not do this until first packet arrives, to have a probe buffer */      
360
361       /* try to open decoder, if none is found keep consuming packets */
362       OpenDecoder( *hints );
363     }
364     else if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
365     {
366       ((CDVDMsgGeneralSynchronize*)pMsg)->Wait( &m_bStop, SYNCSOURCE_AUDIO );
367       CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_SYNCHRONIZE");
368     } 
369     else if (pMsg->IsType(CDVDMsg::GENERAL_RESYNC))
370     { //player asked us to set internal clock
371       CDVDMsgGeneralResync* pMsgGeneralResync = (CDVDMsgGeneralResync*)pMsg;
372
373       if (pMsgGeneralResync->m_timestamp != DVD_NOPTS_VALUE)
374         m_audioClock = pMsgGeneralResync->m_timestamp;
375
376       m_ptsOutput.Add(m_audioClock, m_dvdAudio.GetDelay(), 0);
377       if (pMsgGeneralResync->m_clock)
378       {
379         CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 1)", m_audioClock);
380         m_pClock->Discontinuity(CLOCK_DISC_NORMAL, m_ptsOutput.Current(), 0);
381       }
382       else
383         CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_RESYNC(%f, 0)", m_audioClock);
384     }
385     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH))
386     {
387       m_dvdAudio.Flush();
388       m_ptsOutput.Flush();
389       m_ptsInput.Flush();
390
391       if (m_pAudioCodec)
392         m_pAudioCodec->Reset();
393
394       m_decode.Release();
395     }
396     else if (pMsg->IsType(CDVDMsg::GENERAL_EOF))
397     {
398       CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_EOF");
399       m_dvdAudio.Finish();
400     }
401     else if (pMsg->IsType(CDVDMsg::GENERAL_DELAY))
402     {
403       if (m_speed != DVD_PLAYSPEED_PAUSE)
404       {
405         double timeout = static_cast<CDVDMsgDouble*>(pMsg)->m_value;
406
407         CLog::Log(LOGDEBUG, "CDVDPlayerAudio - CDVDMsg::GENERAL_DELAY(%f)", timeout);
408
409         timeout *= (double)DVD_PLAYSPEED_NORMAL / abs(m_speed);
410         timeout += CDVDClock::GetAbsoluteClock();
411
412         while(!m_bStop && CDVDClock::GetAbsoluteClock() < timeout)
413           Sleep(1);
414       }
415     }
416     else if (pMsg->IsType(CDVDMsg::PLAYER_SETSPEED))
417     {
418       m_speed = static_cast<CDVDMsgInt*>(pMsg)->m_value;
419
420       if (m_speed == DVD_PLAYSPEED_PAUSE)
421       {
422         m_ptsOutput.Flush();
423         m_dvdAudio.Pause();
424       }
425       else 
426         m_dvdAudio.Resume();
427     }
428     pMsg->Release();
429   }
430   return 0;
431 }
432
433 void CDVDPlayerAudio::OnStartup()
434 {
435   CThread::SetName("CDVDPlayerAudio");
436
437   m_decode.msg = NULL;
438   m_decode.Release();
439
440   g_dvdPerformanceCounter.EnableAudioDecodePerformance(ThreadHandle());
441 }
442
443 void CDVDPlayerAudio::Process()
444 {
445   CLog::Log(LOGNOTICE, "running thread: CDVDPlayerAudio::Process()");
446
447   int result;
448  
449   DVDAudioFrame audioframe;
450   m_audioStats.Start();
451
452   while (!m_bStop)
453   {
454     //Don't let anybody mess with our global variables
455     EnterCriticalSection(&m_critCodecSection);
456     result = DecodeFrame(audioframe, m_speed != DVD_PLAYSPEED_NORMAL); // blocks if no audio is available, but leaves critical section before doing so
457     LeaveCriticalSection(&m_critCodecSection);
458
459     if( result & DECODE_FLAG_ERROR ) 
460     { 
461       CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Decode Error");
462       continue;
463     }
464
465     if( result & DECODE_FLAG_TIMEOUT ) 
466     {
467       if(m_started)
468         m_stalled = true;
469       continue;
470     }
471
472     if( result & DECODE_FLAG_ABORT )
473     {
474       CLog::Log(LOGDEBUG, "CDVDPlayerAudio::Process - Abort received, exiting thread");
475       break;
476     }
477
478 #ifdef PROFILE /* during profiling we just drop all packets, after having decoded */
479     m_pClock->Discontinuity(CLOCK_DISC_NORMAL, audioframe.pts, 0);
480     continue;
481 #endif
482     
483     if( audioframe.size == 0 )
484       continue;
485
486     m_stalled = false;
487     m_started = true;
488
489     // we have succesfully decoded an audio frame, setup renderer to match
490     if (!m_dvdAudio.IsValidFormat(audioframe))
491     {
492       m_dvdAudio.Destroy();
493       if(!m_dvdAudio.Create(audioframe, m_streaminfo.codec))
494         CLog::Log(LOGERROR, "%s - failed to create audio renderer", __FUNCTION__);
495     }
496
497     if( result & DECODE_FLAG_DROP )
498     {
499       //frame should be dropped. Don't let audio move ahead of the current time thou
500       //we need to be able to start playing at any time
501       //when playing backwords, we try to keep as small buffers as possible
502
503       if(m_droptime == 0.0)
504         m_droptime = m_pClock->GetAbsoluteClock();
505       if(m_speed > 0)
506         m_droptime += audioframe.duration * DVD_PLAYSPEED_NORMAL / m_speed;
507       while( !m_bStop && m_droptime > m_pClock->GetAbsoluteClock() ) Sleep(1);
508     } 
509     else
510     {
511       m_droptime = 0.0;
512
513       // add any packets play
514       m_dvdAudio.AddPackets(audioframe);
515     }
516
517     // store the delay for this pts value so we can calculate the current playing
518     if(m_speed != DVD_PLAYSPEED_PAUSE)
519       m_ptsOutput.Add(audioframe.pts, m_dvdAudio.GetDelay() - audioframe.duration, audioframe.duration);
520
521     // don't try to fix a desynced clock, until we played out the full audio buffer
522     if( fabs(m_pClock->DistanceToDisc()) < m_dvdAudio.GetDelay() )
523       continue;
524
525     if( m_ptsOutput.Current() == DVD_NOPTS_VALUE )
526       continue;
527
528     if( m_speed != DVD_PLAYSPEED_NORMAL )
529       continue;
530
531     double clock = m_pClock->GetClock();
532     double error = m_ptsOutput.Current() - clock;
533
534     if( fabs(error) > DVD_MSEC_TO_TIME(10) )
535     {
536       m_pClock->Discontinuity(CLOCK_DISC_NORMAL, clock+error, 0);
537       if(m_speed == DVD_PLAYSPEED_NORMAL)
538         CLog::Log(LOGDEBUG, "CDVDPlayerAudio:: Discontinuty - was:%f, should be:%f, error:%f", clock, clock+error, error);
539     }
540   }
541 }
542
543 void CDVDPlayerAudio::OnExit()
544 {
545   g_dvdPerformanceCounter.DisableAudioDecodePerformance();
546
547   CLog::Log(LOGNOTICE, "thread end: CDVDPlayerAudio::OnExit()");
548 }
549
550 void CDVDPlayerAudio::SetSpeed(int speed)
551
552   if(m_messageQueue.IsInited())
553     m_messageQueue.Put( new CDVDMsgInt(CDVDMsg::PLAYER_SETSPEED, speed), 1 );
554   else
555     m_speed = speed;
556 }
557
558 void CDVDPlayerAudio::Flush()
559 {
560   m_messageQueue.Flush();
561   m_messageQueue.Put( new CDVDMsg(CDVDMsg::GENERAL_FLUSH));
562 }
563
564 void CDVDPlayerAudio::WaitForBuffers()
565 {
566   // make sure there are no more packets available
567   m_messageQueue.WaitUntilEmpty();
568   
569   // make sure almost all has been rendered
570   // leave 500ms to avound buffer underruns
571
572   while( m_dvdAudio.GetDelay() > DVD_TIME_BASE/2 )
573   {
574     Sleep(5);
575   }
576 }
577
578 string CDVDPlayerAudio::GetPlayerInfo()
579 {
580   std::ostringstream s;
581   s << "aq:" << std::setw(3) << min(99,100 * m_messageQueue.GetDataSize() / m_messageQueue.GetMaxDataSize()) << "%";
582   s << ",";
583   s << "cpu:" << (int)(100 * CThread::GetRelativeUsage()) << "%,";
584   s << "br:" << std::setprecision(6) << (double)GetAudioBitrate() / 1024.0 << "kb/s";
585   return s.str();
586 }
587
588 int CDVDPlayerAudio::GetAudioBitrate()
589 {
590   return (int)m_audioStats.GetBitrate();
591 }