Merge pull request #4624 from FernetMenta/paplayer
[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 "music/tags/TagLoaderTagLib.h"
30 #include "utils/log.h"
31 #include "settings/Settings.h"
32 #include "URL.h"
33
34 #include "AudioDecoder.h"
35
36 DVDPlayerCodec::DVDPlayerCodec()
37 {
38   m_CodecName = "DVDPlayer";
39   m_pDemuxer = NULL;
40   m_pInputStream = NULL;
41   m_pAudioCodec = NULL;
42   m_nAudioStream = -1;
43   m_audioPos = 0;
44   m_pPacket = NULL;
45   m_decoded = NULL;
46   m_nDecodedLen = 0;
47   m_strFileName = "";
48   m_bInited = false;
49 }
50
51 DVDPlayerCodec::~DVDPlayerCodec()
52 {
53   DeInit();
54 }
55
56 void DVDPlayerCodec::SetContentType(const CStdString &strContent)
57 {
58   m_strContentType = strContent;
59 }
60
61 bool DVDPlayerCodec::Init(const CStdString &strFile, unsigned int filecache)
62 {
63   // take precaution if Init()ialized earlier
64   if (m_bInited)
65   {
66     // keep things as is if Init() was done with known strFile
67     if (m_strFileName == strFile)
68       return true;
69
70     // got differing filename, so cleanup before starting over
71     DeInit();
72   }
73
74   m_decoded = NULL;
75   m_nDecodedLen = 0;
76
77   CStdString strFileToOpen = strFile;
78
79   CURL urlFile(strFile);
80   if (urlFile.GetProtocol() == "shout" )
81     strFileToOpen.replace(0, 8, "http://");
82
83   m_pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strFileToOpen, m_strContentType);
84   if (!m_pInputStream)
85   {
86     CLog::Log(LOGERROR, "%s: Error creating input stream for %s", __FUNCTION__, strFileToOpen.c_str());
87     return false;
88   }
89
90   if (!m_pInputStream->Open(strFileToOpen.c_str(), m_strContentType))
91   {
92     CLog::Log(LOGERROR, "%s: Error opening file %s", __FUNCTION__, strFileToOpen.c_str());
93     if (m_pInputStream)
94       delete m_pInputStream;
95     m_pInputStream = NULL;
96     return false;
97   }
98
99   m_pDemuxer = NULL;
100
101   try
102   {
103     m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
104     if (!m_pDemuxer)
105     {
106       delete m_pInputStream;
107       m_pInputStream = NULL;
108       CLog::Log(LOGERROR, "%s: Error creating demuxer", __FUNCTION__);
109       return false;
110     }
111   }
112   catch(...)
113   {
114     CLog::Log(LOGERROR, "%s: Exception thrown when opening demuxer", __FUNCTION__);
115     if (m_pDemuxer)
116     {
117       delete m_pDemuxer;
118       m_pDemuxer = NULL;
119     }
120     delete m_pInputStream;
121     m_pInputStream = NULL;
122     return false;
123   }
124
125   CDemuxStream* pStream = NULL;
126   m_nAudioStream = -1;
127   for (int i = 0; i < m_pDemuxer->GetNrOfStreams(); i++)
128   {
129     pStream = m_pDemuxer->GetStream(i);
130     if (pStream && pStream->type == STREAM_AUDIO)
131     {
132       m_nAudioStream = i;
133       break;
134     }
135   }
136
137   if (m_nAudioStream == -1)
138   {
139     CLog::Log(LOGERROR, "%s: Could not find audio stream", __FUNCTION__);
140     delete m_pDemuxer;
141     m_pDemuxer = NULL;
142     delete m_pInputStream;
143     m_pInputStream = NULL;
144     return false;
145   }
146
147   CDVDStreamInfo hint(*pStream, true);
148
149   m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint);
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   //  Extract ReplayGain info
161   // tagLoaderTagLib.Load will try to determine tag type by file extension, so set fallback by contentType
162   CStdString strFallbackFileExtension = "";
163   if (m_strContentType.Equals("audio/aacp") || m_strContentType.Equals("audio/aacp" "audio/aac"))
164     strFallbackFileExtension = "m4a";
165   else if (m_strContentType.Equals("audio/x-ms-wma"))
166     strFallbackFileExtension = "wma";
167   else if (m_strContentType.Equals("audio/x-ape") || m_strContentType.Equals("audio/ape"))
168     strFallbackFileExtension = "ape";
169   CTagLoaderTagLib tagLoaderTagLib;
170   tagLoaderTagLib.Load(strFile, m_tag, strFallbackFileExtension);
171
172   // we have to decode initial data in order to get channels/samplerate
173   // for sanity - we read no more than 10 packets
174   int nErrors = 0;
175   for (int nPacket=0; nPacket < 10 && (m_Channels == 0 || m_SampleRate == 0); nPacket++)
176   {
177     BYTE dummy[256];
178     int nSize = 256;
179     if (ReadPCM(dummy, nSize, &nSize) == READ_ERROR)
180       ++nErrors;
181
182     m_DataFormat    = m_pAudioCodec->GetDataFormat();
183     m_BitsPerSample = CAEUtil::DataFormatToBits(m_DataFormat);
184     m_SampleRate = m_pAudioCodec->GetSampleRate();
185     m_EncodedSampleRate = m_pAudioCodec->GetEncodedSampleRate();
186     m_Channels = m_pAudioCodec->GetChannels();
187     m_ChannelInfo = m_pAudioCodec->GetChannelMap();
188     m_BitsPerCodedSample = static_cast<CDemuxStreamAudio*>(pStream)->iBitsPerSample;
189   }
190   if (nErrors >= 10)
191   {
192     CLog::Log(LOGDEBUG, "%s: Could not decode data", __FUNCTION__);
193     return false;
194   }
195
196   // test if seeking is supported
197   m_bCanSeek = false;
198   if (m_pInputStream->Seek(0, SEEK_POSSIBLE))
199   {
200     // reset eof flag of stream, with eof set seek returns always success
201     m_pInputStream->Seek(0, SEEK_SET);
202     if (Seek(1) != DVD_NOPTS_VALUE)
203     {
204       // rewind stream to beginning
205       Seek(0);
206     }
207     else
208     {
209       m_pInputStream->Seek(0, SEEK_SET);
210       m_pDemuxer->Reset();
211     }
212   }
213
214   if (m_Channels == 0) // no data - just guess and hope for the best
215     m_Channels = 2;
216
217   if (m_SampleRate == 0)
218     m_SampleRate = 44100;
219
220   m_TotalTime = m_pDemuxer->GetStreamLength();
221   m_Bitrate = m_pAudioCodec->GetBitRate();
222   if (!m_Bitrate && m_TotalTime)
223   {
224     m_Bitrate = (int)(((m_pInputStream->GetLength()*1000) / m_TotalTime) * 8);
225   }
226   m_pDemuxer->GetStreamCodecName(m_nAudioStream,m_CodecName);
227
228   m_strFileName = strFile;
229   m_bInited = true;
230
231   return true;
232 }
233
234 void DVDPlayerCodec::DeInit()
235 {
236   if (m_pPacket)
237     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
238   m_pPacket = NULL;
239
240   if (m_pDemuxer != NULL)
241   {
242     delete m_pDemuxer;
243     m_pDemuxer = NULL;
244   }
245
246   if (m_pInputStream != NULL)
247   {
248     delete m_pInputStream;
249     m_pInputStream = NULL;
250   }
251
252   if (m_pAudioCodec != NULL)
253   {
254     delete m_pAudioCodec;
255     m_pAudioCodec = NULL;
256   }
257
258   // cleanup format information
259   m_TotalTime = 0;
260   m_SampleRate = 0;
261   m_EncodedSampleRate = 0;
262   m_BitsPerSample = 0;
263   m_DataFormat = AE_FMT_INVALID;
264   m_Channels = 0;
265   m_Bitrate = 0;
266
267   m_audioPos = 0;
268   m_decoded = NULL;
269   m_nDecodedLen = 0;
270
271   m_strFileName = "";
272   m_bInited = false;
273 }
274
275 int64_t DVDPlayerCodec::Seek(int64_t iSeekTime)
276 {
277   if (m_pPacket)
278     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
279   m_pPacket = NULL;
280
281   bool ret = m_pDemuxer->SeekTime((int)iSeekTime, false);
282   m_pAudioCodec->Reset();
283
284   m_decoded = NULL;
285   m_nDecodedLen = 0;
286
287   if (!ret)
288     return DVD_NOPTS_VALUE;
289
290   return iSeekTime;
291 }
292
293 int DVDPlayerCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
294 {
295   if (m_decoded && m_nDecodedLen > 0)
296   {
297     int nLen = (size<m_nDecodedLen)?size:m_nDecodedLen;
298     *actualsize = nLen;
299     memcpy(pBuffer, m_decoded, *actualsize);
300     m_nDecodedLen -= nLen;
301     m_decoded += (*actualsize);
302     return READ_SUCCESS;
303   }
304
305   m_decoded = NULL;
306   m_nDecodedLen = 0;
307
308   // dvdplayer returns a read error on a single invalid packet, while
309   // in paplayer READ_ERROR is a fatal error.
310   // Therefore skip over invalid packets here.
311   int decodeLen = -1;
312   for (int tries = 0; decodeLen < 0 && tries < 2; ++tries)
313   {
314     if (m_pPacket && m_audioPos >= m_pPacket->iSize)
315     {
316       CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
317       m_audioPos = 0;
318       m_pPacket = NULL;
319     }
320
321     if (m_pPacket == NULL)
322     {
323       do
324       {
325         m_pPacket = m_pDemuxer->Read();
326       } while (m_pPacket && m_pPacket->iStreamId != m_nAudioStream);
327
328       if (!m_pPacket)
329       {
330         return READ_EOF;
331       }
332       m_audioPos = 0;
333     }
334
335     decodeLen = m_pAudioCodec->Decode(m_pPacket->pData + m_audioPos, m_pPacket->iSize - m_audioPos);
336
337     if (decodeLen < 0)
338       m_audioPos = m_pPacket->iSize; // skip packet
339   }
340
341   if (decodeLen < 0)
342   {
343     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
344     m_pPacket = NULL;
345     m_audioPos = 0;
346     return READ_ERROR;
347   }
348
349   m_audioPos += decodeLen;
350
351   m_nDecodedLen = m_pAudioCodec->GetData(&m_decoded);
352
353   *actualsize = (m_nDecodedLen <= size) ? m_nDecodedLen : size;
354   if (*actualsize > 0)
355   {
356     memcpy(pBuffer, m_decoded, *actualsize);
357     m_nDecodedLen -= *actualsize;
358     m_decoded += (*actualsize);
359   }
360
361   return READ_SUCCESS;
362 }
363
364 bool DVDPlayerCodec::CanInit()
365 {
366   return true;
367 }
368
369 bool DVDPlayerCodec::CanSeek()
370 {
371   return m_bCanSeek;
372 }