Merge pull request #3171 from stupid-boy/CSimpleDoubleCache
[vuplus_xbmc] / xbmc / cores / paplayer / DVDPlayerCodec.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 "DVDPlayerCodec.h"
22 #include "cores/AudioEngine/Utils/AEUtil.h"
23
24 #include "cores/dvdplayer/DVDInputStreams/DVDFactoryInputStream.h"
25 #include "cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h"
26 #include "cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h"
27 #include "cores/dvdplayer/DVDStreamInfo.h"
28 #include "cores/dvdplayer/DVDCodecs/DVDFactoryCodec.h"
29 #include "utils/log.h"
30 #include "settings/Settings.h"
31 #include "URL.h"
32
33 #include "AudioDecoder.h"
34
35 DVDPlayerCodec::DVDPlayerCodec()
36 {
37   m_CodecName = "DVDPlayer";
38   m_pDemuxer = NULL;
39   m_pInputStream = NULL;
40   m_pAudioCodec = NULL;
41   m_nAudioStream = -1;
42   m_audioPos = 0;
43   m_pPacket = NULL;
44   m_decoded = NULL;
45   m_nDecodedLen = 0;
46   m_strFileName = "";
47   m_bInited = false;
48 }
49
50 DVDPlayerCodec::~DVDPlayerCodec()
51 {
52   DeInit();
53 }
54
55 void DVDPlayerCodec::SetContentType(const CStdString &strContent)
56 {
57   m_strContentType = strContent;
58 }
59
60 bool DVDPlayerCodec::Init(const CStdString &strFile, unsigned int filecache)
61 {
62   // take precaution if Init()ialized earlier
63   if (m_bInited)
64   {
65     // keep things as is if Init() was done with known strFile
66     if (m_strFileName == strFile)
67       return true;
68
69     // got differing filename, so cleanup before starting over
70     DeInit();
71   }
72
73   m_decoded = NULL;
74   m_nDecodedLen = 0;
75
76   CStdString strFileToOpen = strFile;
77
78   CURL urlFile(strFile);
79   if (urlFile.GetProtocol() == "shout" )
80     strFileToOpen.Replace("shout://","http://");
81
82   m_pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strFileToOpen, m_strContentType);
83   if (!m_pInputStream)
84   {
85     CLog::Log(LOGERROR, "%s: Error creating input stream for %s", __FUNCTION__, strFileToOpen.c_str());
86     return false;
87   }
88
89   if (!m_pInputStream->Open(strFileToOpen.c_str(), m_strContentType))
90   {
91     CLog::Log(LOGERROR, "%s: Error opening file %s", __FUNCTION__, strFileToOpen.c_str());
92     if (m_pInputStream)
93       delete m_pInputStream;
94     m_pInputStream = NULL;
95     return false;
96   }
97
98   m_pDemuxer = NULL;
99
100   try
101   {
102     m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
103     if (!m_pDemuxer)
104     {
105       delete m_pInputStream;
106       m_pInputStream = NULL;
107       CLog::Log(LOGERROR, "%s: Error creating demuxer", __FUNCTION__);
108       return false;
109     }
110   }
111   catch(...)
112   {
113     CLog::Log(LOGERROR, "%s: Exception thrown when opening demuxer", __FUNCTION__);
114     if (m_pDemuxer)
115     {
116       delete m_pDemuxer;
117       m_pDemuxer = NULL;
118     }
119     delete m_pInputStream;
120     m_pInputStream = NULL;
121     return false;
122   }
123
124   CDemuxStream* pStream = NULL;
125   m_nAudioStream = -1;
126   for (int i = 0; i < m_pDemuxer->GetNrOfStreams(); i++)
127   {
128     pStream = m_pDemuxer->GetStream(i);
129     if (pStream && pStream->type == STREAM_AUDIO)
130     {
131       m_nAudioStream = i;
132       break;
133     }
134   }
135
136   if (m_nAudioStream == -1)
137   {
138     CLog::Log(LOGERROR, "%s: Could not find audio stream", __FUNCTION__);
139     delete m_pDemuxer;
140     m_pDemuxer = NULL;
141     delete m_pInputStream;
142     m_pInputStream = NULL;
143     return false;
144   }
145
146   CDVDStreamInfo hint(*pStream, true);
147
148   bool passthrough = AUDIO_IS_BITSTREAM(CSettings::Get().GetInt("audiooutput.mode"));
149   m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint, passthrough);
150   if (!m_pAudioCodec)
151   {
152     CLog::Log(LOGERROR, "%s: Could not create audio codec", __FUNCTION__);
153     delete m_pDemuxer;
154     m_pDemuxer = NULL;
155     delete m_pInputStream;
156     m_pInputStream = NULL;
157     return false;
158   }
159
160   // we have to decode initial data in order to get channels/samplerate
161   // for sanity - we read no more than 10 packets
162   int nErrors = 0;
163   for (int nPacket=0; nPacket < 10 && (m_Channels == 0 || m_SampleRate == 0); nPacket++)
164   {
165     BYTE dummy[256];
166     int nSize = 256;
167     if (ReadPCM(dummy, nSize, &nSize) == READ_ERROR)
168       ++nErrors;
169
170     m_DataFormat    = m_pAudioCodec->GetDataFormat();
171     m_BitsPerSample = CAEUtil::DataFormatToBits(m_DataFormat);
172     m_SampleRate = m_pAudioCodec->GetSampleRate();
173     m_EncodedSampleRate = m_pAudioCodec->GetEncodedSampleRate();
174     m_Channels = m_pAudioCodec->GetChannels();
175     m_ChannelInfo = m_pAudioCodec->GetChannelMap();
176
177   }
178   if (nErrors >= 10)
179   {
180     CLog::Log(LOGDEBUG, "%s: Could not decode data", __FUNCTION__);
181     return false;
182   }
183
184   m_nDecodedLen = 0;
185
186   if (m_Channels == 0) // no data - just guess and hope for the best
187     m_Channels = 2;
188
189   if (m_SampleRate == 0)
190     m_SampleRate = 44100;
191
192   m_TotalTime = m_pDemuxer->GetStreamLength();
193   m_Bitrate = m_pAudioCodec->GetBitRate();
194   m_pDemuxer->GetStreamCodecName(m_nAudioStream,m_CodecName);
195
196   m_strFileName = strFile;
197   m_bInited = true;
198
199   return true;
200 }
201
202 void DVDPlayerCodec::DeInit()
203 {
204   if (m_pPacket)
205     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
206   m_pPacket = NULL;
207
208   if (m_pDemuxer != NULL)
209   {
210     delete m_pDemuxer;
211     m_pDemuxer = NULL;
212   }
213
214   if (m_pInputStream != NULL)
215   {
216     delete m_pInputStream;
217     m_pInputStream = NULL;
218   }
219
220   if (m_pAudioCodec != NULL)
221   {
222     delete m_pAudioCodec;
223     m_pAudioCodec = NULL;
224   }
225
226   // cleanup format information
227   m_TotalTime = 0;
228   m_SampleRate = 0;
229   m_EncodedSampleRate = 0;
230   m_BitsPerSample = 0;
231   m_DataFormat = AE_FMT_INVALID;
232   m_Channels = 0;
233   m_Bitrate = 0;
234
235   m_audioPos = 0;
236   m_decoded = NULL;
237   m_nDecodedLen = 0;
238
239   m_strFileName = "";
240   m_bInited = false;
241 }
242
243 int64_t DVDPlayerCodec::Seek(int64_t iSeekTime)
244 {
245   if (m_pPacket)
246     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
247   m_pPacket = NULL;
248
249   m_pDemuxer->SeekTime((int)iSeekTime, false);
250   m_pAudioCodec->Reset();
251
252   m_decoded = NULL;
253   m_nDecodedLen = 0;
254
255   return iSeekTime;
256 }
257
258 int DVDPlayerCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
259 {
260   if (m_decoded && m_nDecodedLen > 0)
261   {
262     int nLen = (size<m_nDecodedLen)?size:m_nDecodedLen;
263     *actualsize = nLen;
264     memcpy(pBuffer, m_decoded, *actualsize);
265     m_nDecodedLen -= nLen;
266     m_decoded += (*actualsize);
267     return READ_SUCCESS;
268   }
269
270   m_decoded = NULL;
271   m_nDecodedLen = 0;
272
273   // dvdplayer returns a read error on a single invalid packet, while
274   // in paplayer READ_ERROR is a fatal error.
275   // Therefore skip over invalid packets here.
276   int decodeLen = -1;
277   for (int tries = 0; decodeLen < 0 && tries < 2; ++tries)
278   {
279     if (m_pPacket && m_audioPos >= m_pPacket->iSize)
280     {
281       CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
282       m_audioPos = 0;
283       m_pPacket = NULL;
284     }
285
286     if (m_pPacket == NULL)
287     {
288       do
289       {
290         m_pPacket = m_pDemuxer->Read();
291       } while (m_pPacket && m_pPacket->iStreamId != m_nAudioStream);
292
293       if (!m_pPacket)
294       {
295         return READ_EOF;
296       }
297       m_audioPos = 0;
298     }
299
300     decodeLen = m_pAudioCodec->Decode(m_pPacket->pData + m_audioPos, m_pPacket->iSize - m_audioPos);
301
302     if (decodeLen < 0)
303       m_audioPos = m_pPacket->iSize; // skip packet
304   }
305
306   if (decodeLen < 0)
307   {
308     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
309     m_pPacket = NULL;
310     m_audioPos = 0;
311     return READ_ERROR;
312   }
313
314   m_audioPos += decodeLen;
315
316   m_nDecodedLen = m_pAudioCodec->GetData(&m_decoded);
317
318   *actualsize = (m_nDecodedLen <= size) ? m_nDecodedLen : size;
319   if (*actualsize > 0)
320   {
321     memcpy(pBuffer, m_decoded, *actualsize);
322     m_nDecodedLen -= *actualsize;
323     m_decoded += (*actualsize);
324   }
325
326   return READ_SUCCESS;
327 }
328
329 bool DVDPlayerCodec::CanInit()
330 {
331   return true;
332 }
333
334 bool DVDPlayerCodec::CanSeek()
335 {
336   return true;
337 }