Merge pull request #4594 from FernetMenta/paplayer
[xbmc.git] / xbmc / cores / paplayer / DVDPlayerCodec.cpp
blobc60abc860c17c9f2e042e5e1ccf2d57dd06e77c1
1 /*
2 * Copyright (C) 2005-2013 Team XBMC
3 * http://xbmc.org
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.
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.
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/>.
21 #include "DVDPlayerCodec.h"
22 #include "cores/AudioEngine/Utils/AEUtil.h"
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"
34 #include "AudioDecoder.h"
36 DVDPlayerCodec::DVDPlayerCodec()
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;
51 DVDPlayerCodec::~DVDPlayerCodec()
53 DeInit();
56 void DVDPlayerCodec::SetContentType(const CStdString &strContent)
58 m_strContentType = strContent;
61 bool DVDPlayerCodec::Init(const CStdString &strFile, unsigned int filecache)
63 // take precaution if Init()ialized earlier
64 if (m_bInited)
66 // keep things as is if Init() was done with known strFile
67 if (m_strFileName == strFile)
68 return true;
70 // got differing filename, so cleanup before starting over
71 DeInit();
74 m_decoded = NULL;
75 m_nDecodedLen = 0;
77 CStdString strFileToOpen = strFile;
79 CURL urlFile(strFile);
80 if (urlFile.GetProtocol() == "shout" )
81 strFileToOpen.replace(0, 8, "http://");
83 m_pInputStream = CDVDFactoryInputStream::CreateInputStream(NULL, strFileToOpen, m_strContentType);
84 if (!m_pInputStream)
86 CLog::Log(LOGERROR, "%s: Error creating input stream for %s", __FUNCTION__, strFileToOpen.c_str());
87 return false;
90 if (!m_pInputStream->Open(strFileToOpen.c_str(), m_strContentType))
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;
99 m_pDemuxer = NULL;
103 m_pDemuxer = CDVDFactoryDemuxer::CreateDemuxer(m_pInputStream);
104 if (!m_pDemuxer)
106 delete m_pInputStream;
107 m_pInputStream = NULL;
108 CLog::Log(LOGERROR, "%s: Error creating demuxer", __FUNCTION__);
109 return false;
112 catch(...)
114 CLog::Log(LOGERROR, "%s: Exception thrown when opening demuxer", __FUNCTION__);
115 if (m_pDemuxer)
117 delete m_pDemuxer;
118 m_pDemuxer = NULL;
120 delete m_pInputStream;
121 m_pInputStream = NULL;
122 return false;
125 CDemuxStream* pStream = NULL;
126 m_nAudioStream = -1;
127 for (int i = 0; i < m_pDemuxer->GetNrOfStreams(); i++)
129 pStream = m_pDemuxer->GetStream(i);
130 if (pStream && pStream->type == STREAM_AUDIO)
132 m_nAudioStream = i;
133 break;
137 if (m_nAudioStream == -1)
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;
147 CDVDStreamInfo hint(*pStream, true);
149 m_pAudioCodec = CDVDFactoryCodec::CreateAudioCodec(hint);
150 if (!m_pAudioCodec)
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;
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);
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++)
177 BYTE dummy[256];
178 int nSize = 256;
179 if (ReadPCM(dummy, nSize, &nSize) == READ_ERROR)
180 ++nErrors;
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;
190 if (nErrors >= 10)
192 CLog::Log(LOGDEBUG, "%s: Could not decode data", __FUNCTION__);
193 return false;
196 // test if seeking is supported
197 if (Seek(1) != DVD_NOPTS_VALUE)
199 // rewind stream to beginning
200 Seek(0);
201 m_bCanSeek = true;
203 else
205 m_pInputStream->Seek(0, SEEK_SET);
206 m_pDemuxer->Reset();
207 m_bCanSeek = false;
210 if (m_Channels == 0) // no data - just guess and hope for the best
211 m_Channels = 2;
213 if (m_SampleRate == 0)
214 m_SampleRate = 44100;
216 m_TotalTime = m_pDemuxer->GetStreamLength();
217 m_Bitrate = m_pAudioCodec->GetBitRate();
218 if (!m_Bitrate && m_TotalTime)
220 m_Bitrate = (int)(((m_pInputStream->GetLength()*1000) / m_TotalTime) * 8);
222 m_pDemuxer->GetStreamCodecName(m_nAudioStream,m_CodecName);
224 m_strFileName = strFile;
225 m_bInited = true;
227 return true;
230 void DVDPlayerCodec::DeInit()
232 if (m_pPacket)
233 CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
234 m_pPacket = NULL;
236 if (m_pDemuxer != NULL)
238 delete m_pDemuxer;
239 m_pDemuxer = NULL;
242 if (m_pInputStream != NULL)
244 delete m_pInputStream;
245 m_pInputStream = NULL;
248 if (m_pAudioCodec != NULL)
250 delete m_pAudioCodec;
251 m_pAudioCodec = NULL;
254 // cleanup format information
255 m_TotalTime = 0;
256 m_SampleRate = 0;
257 m_EncodedSampleRate = 0;
258 m_BitsPerSample = 0;
259 m_DataFormat = AE_FMT_INVALID;
260 m_Channels = 0;
261 m_Bitrate = 0;
263 m_audioPos = 0;
264 m_decoded = NULL;
265 m_nDecodedLen = 0;
267 m_strFileName = "";
268 m_bInited = false;
271 int64_t DVDPlayerCodec::Seek(int64_t iSeekTime)
273 if (m_pPacket)
274 CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
275 m_pPacket = NULL;
277 bool ret = m_pDemuxer->SeekTime((int)iSeekTime, false);
278 m_pAudioCodec->Reset();
280 m_decoded = NULL;
281 m_nDecodedLen = 0;
283 if (!ret)
284 return DVD_NOPTS_VALUE;
286 return iSeekTime;
289 int DVDPlayerCodec::ReadPCM(BYTE *pBuffer, int size, int *actualsize)
291 if (m_decoded && m_nDecodedLen > 0)
293 int nLen = (size<m_nDecodedLen)?size:m_nDecodedLen;
294 *actualsize = nLen;
295 memcpy(pBuffer, m_decoded, *actualsize);
296 m_nDecodedLen -= nLen;
297 m_decoded += (*actualsize);
298 return READ_SUCCESS;
301 m_decoded = NULL;
302 m_nDecodedLen = 0;
304 // dvdplayer returns a read error on a single invalid packet, while
305 // in paplayer READ_ERROR is a fatal error.
306 // Therefore skip over invalid packets here.
307 int decodeLen = -1;
308 for (int tries = 0; decodeLen < 0 && tries < 2; ++tries)
310 if (m_pPacket && m_audioPos >= m_pPacket->iSize)
312 CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
313 m_audioPos = 0;
314 m_pPacket = NULL;
317 if (m_pPacket == NULL)
321 m_pPacket = m_pDemuxer->Read();
322 } while (m_pPacket && m_pPacket->iStreamId != m_nAudioStream);
324 if (!m_pPacket)
326 return READ_EOF;
328 m_audioPos = 0;
331 decodeLen = m_pAudioCodec->Decode(m_pPacket->pData + m_audioPos, m_pPacket->iSize - m_audioPos);
333 if (decodeLen < 0)
334 m_audioPos = m_pPacket->iSize; // skip packet
337 if (decodeLen < 0)
339 CDVDDemuxUtils::FreeDemuxPacket(m_pPacket);
340 m_pPacket = NULL;
341 m_audioPos = 0;
342 return READ_ERROR;
345 m_audioPos += decodeLen;
347 m_nDecodedLen = m_pAudioCodec->GetData(&m_decoded);
349 *actualsize = (m_nDecodedLen <= size) ? m_nDecodedLen : size;
350 if (*actualsize > 0)
352 memcpy(pBuffer, m_decoded, *actualsize);
353 m_nDecodedLen -= *actualsize;
354 m_decoded += (*actualsize);
357 return READ_SUCCESS;
360 bool DVDPlayerCodec::CanInit()
362 return true;
365 bool DVDPlayerCodec::CanSeek()
367 return m_bCanSeek;