[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / cores / paplayer / DVDPlayerCodec.cpp
1 /*
2  *      Copyright (C) 2005-2013 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, 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/GUISettings.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 }
47
48 DVDPlayerCodec::~DVDPlayerCodec()
49 {
50   DeInit();
51 }
52
53 void DVDPlayerCodec::SetContentType(const CStdString &strContent)
54 {
55   m_strContentType = strContent;
56 }
57
58 bool DVDPlayerCodec::Init(const CStdString &strFile, unsigned int filecache)
59 {
60   m_decoded = NULL;;
61   m_nDecodedLen = 0;
62
63   CStdString strFileToOpen = strFile;
64
65   CURL urlFile(strFile);
66   if (urlFile.GetProtocol() == "shout" )
67     strFileToOpen.Replace("shout://","http://");
68
69   m_pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strFileToOpen, m_strContentType);
70   if (!m_pInputStream)
71   {
72     CLog::Log(LOGERROR, "%s: Error creating input stream for %s", __FUNCTION__, strFileToOpen.c_str());
73     return false;
74   }
75
76   if (!m_pInputStream->Open(strFileToOpen.c_str(), m_strContentType))
77   {
78     CLog::Log(LOGERROR, "%s: Error opening file %s", __FUNCTION__, strFileToOpen.c_str());
79     if (m_pInputStream)
80       delete m_pInputStream;
81     m_pInputStream = NULL;
82     return false;
83   }
84
85   m_pDemuxer = NULL;
86
87   try
88   {
89     m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
90     if (!m_pDemuxer)
91     {
92       delete m_pInputStream;
93       m_pInputStream = NULL;
94       CLog::Log(LOGERROR, "%s: Error creating demuxer", __FUNCTION__);
95       return false;
96     }
97   }
98   catch(...)
99   {
100     CLog::Log(LOGERROR, "%s: Exception thrown when opeing demuxer", __FUNCTION__);
101     if (m_pDemuxer)
102     {
103       delete m_pDemuxer;
104       m_pDemuxer = NULL;
105     }
106     delete m_pInputStream;
107     m_pInputStream = NULL;
108     return false;
109   }
110
111   CDemuxStream* pStream = NULL;
112   m_nAudioStream = -1;
113   for (int i = 0; i < m_pDemuxer->GetNrOfStreams(); i++)
114   {
115     pStream = m_pDemuxer->GetStream(i);
116     if (pStream && pStream->type == STREAM_AUDIO)
117     {
118       m_nAudioStream = i;
119       break;
120     }
121   }
122
123   if (m_nAudioStream == -1)
124   {
125     CLog::Log(LOGERROR, "%s: Could not find audio stream", __FUNCTION__);
126     delete m_pDemuxer;
127     m_pDemuxer = NULL;
128     delete m_pInputStream;
129     m_pInputStream = NULL;
130     return false;
131   }
132
133   CDVDStreamInfo hint(*pStream, true);
134
135   bool passthrough = AUDIO_IS_BITSTREAM(g_guiSettings.GetInt("audiooutput.mode"));
136   m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint, passthrough);
137   if (!m_pAudioCodec)
138   {
139     CLog::Log(LOGERROR, "%s: Could not create audio codec", __FUNCTION__);
140     delete m_pDemuxer;
141     m_pDemuxer = NULL;
142     delete m_pInputStream;
143     m_pInputStream = NULL;
144     return false;
145   }
146
147   // we have to decode initial data in order to get channels/samplerate
148   // for sanity - we read no more than 10 packets
149   int nErrors = 0;
150   for (int nPacket=0; nPacket < 10 && (m_Channels == 0 || m_SampleRate == 0); nPacket++)
151   {
152     BYTE dummy[256];
153     int nSize = 256;
154     if (ReadPCM(dummy, nSize, &nSize) == READ_ERROR)
155       ++nErrors;
156
157     m_DataFormat    = m_pAudioCodec->GetDataFormat();
158     m_BitsPerSample = CAEUtil::DataFormatToBits(m_DataFormat);
159     m_SampleRate = m_pAudioCodec->GetSampleRate();
160     m_EncodedSampleRate = m_pAudioCodec->GetEncodedSampleRate();
161     m_Channels = m_pAudioCodec->GetChannels();
162     m_ChannelInfo = m_pAudioCodec->GetChannelMap();
163
164   }
165   if (nErrors >= 10)
166   {
167     CLog::Log(LOGDEBUG, "%s: Could not decode data", __FUNCTION__);
168     return false;
169   }
170
171   m_nDecodedLen = 0;
172
173   if (m_Channels == 0) // no data - just guess and hope for the best
174     m_Channels = 2;
175
176   if (m_SampleRate == 0)
177     m_SampleRate = 44100;
178
179   m_TotalTime = m_pDemuxer->GetStreamLength();
180   m_Bitrate = m_pAudioCodec->GetBitRate();
181   m_pDemuxer->GetStreamCodecName(m_nAudioStream,m_CodecName);
182
183   return true;
184 }
185
186 void DVDPlayerCodec::DeInit()
187 {
188   if (m_pPacket)
189     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
190   m_pPacket = NULL;
191
192   if (m_pDemuxer != NULL)
193   {
194     delete m_pDemuxer;
195     m_pDemuxer = NULL;
196   }
197
198   if (m_pInputStream != NULL)
199   {
200     delete m_pInputStream;
201     m_pInputStream = NULL;
202   }
203
204   if (m_pAudioCodec != NULL)
205   {
206     delete m_pAudioCodec;
207     m_pAudioCodec = NULL;
208   }
209
210   m_audioPos = 0;
211   m_decoded = NULL;;
212   m_nDecodedLen = 0;
213 }
214
215 int64_t DVDPlayerCodec::Seek(int64_t iSeekTime)
216 {
217   if (m_pPacket)
218     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
219   m_pPacket = NULL;
220
221   m_pDemuxer->SeekTime((int)iSeekTime, false);
222   m_pAudioCodec->Reset();
223
224   m_decoded = NULL;;
225   m_nDecodedLen = 0;
226
227   return iSeekTime;
228 }
229
230 int DVDPlayerCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
231 {
232   if (m_decoded && m_nDecodedLen > 0)
233   {
234     int nLen = (size<m_nDecodedLen)?size:m_nDecodedLen;
235     *actualsize = nLen;
236     memcpy(pBuffer, m_decoded, *actualsize);
237     m_nDecodedLen -= nLen;
238     m_decoded += (*actualsize);
239     return READ_SUCCESS;
240   }
241
242   m_decoded = NULL;
243   m_nDecodedLen = 0;
244
245   // dvdplayer returns a read error on a single invalid packet, while
246   // in paplayer READ_ERROR is a fatal error.
247   // Therefore skip over invalid packets here.
248   int decodeLen = -1;
249   for (int tries = 0; decodeLen < 0 && tries < 2; ++tries)
250   {
251     if (m_pPacket && m_audioPos >= m_pPacket->iSize)
252     {
253       CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
254       m_audioPos = 0;
255       m_pPacket = NULL;
256     }
257
258     if (m_pPacket == NULL)
259     {
260       do
261       {
262         m_pPacket = m_pDemuxer->Read();
263       } while (m_pPacket && m_pPacket->iStreamId != m_nAudioStream);
264
265       if (!m_pPacket)
266       {
267         return READ_EOF;
268       }
269       m_audioPos = 0;
270     }
271
272     decodeLen = m_pAudioCodec->Decode(m_pPacket->pData + m_audioPos, m_pPacket->iSize - m_audioPos);
273
274     if (decodeLen < 0)
275       m_audioPos = m_pPacket->iSize; // skip packet
276   }
277
278   if (decodeLen < 0)
279   {
280     CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
281     m_pPacket = NULL;
282     m_audioPos = 0;
283     return READ_ERROR;
284   }
285
286   m_audioPos += decodeLen;
287
288   m_nDecodedLen = m_pAudioCodec->GetData(&m_decoded);
289
290   *actualsize = (m_nDecodedLen <= size) ? m_nDecodedLen : size;
291   if (*actualsize > 0)
292   {
293     memcpy(pBuffer, m_decoded, *actualsize);
294     m_nDecodedLen -= *actualsize;
295     m_decoded += (*actualsize);
296   }
297
298   return READ_SUCCESS;
299 }
300
301 bool DVDPlayerCodec::CanInit()
302 {
303   return true;
304 }
305
306 bool DVDPlayerCodec::CanSeek()
307 {
308   return true;
309 }