summaryrefslogtreecommitdiffstats
path: root/xbmc/cores
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/cores')
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp184
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h359
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp193
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h85
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp404
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h68
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp197
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h60
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp1767
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h172
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp391
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h68
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp493
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h118
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h36
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp199
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h60
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp89
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h31
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp247
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h99
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp153
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h30
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in19
24 files changed, 5522 insertions, 0 deletions
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp
new file mode 100644
index 0000000..2f833c5
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.cpp
@@ -0,0 +1,184 @@
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 "DVDDemux.h"
22#include "DVDCodecs/DVDCodecs.h"
23
24void CDemuxStreamTeletext::GetStreamInfo(std::string& strInfo)
25{
26 strInfo = "Teletext Data Stream";
27}
28
29void CDemuxStreamAudio::GetStreamType(std::string& strInfo)
30{
31 char sInfo[64];
32
33 if (codec == AV_CODEC_ID_AC3) strcpy(sInfo, "AC3 ");
34 else if (codec == AV_CODEC_ID_DTS)
35 {
36#ifdef FF_PROFILE_DTS_HD_MA
37 if (profile == FF_PROFILE_DTS_HD_MA)
38 strcpy(sInfo, "DTS-HD MA ");
39 else if (profile == FF_PROFILE_DTS_HD_HRA)
40 strcpy(sInfo, "DTS-HD HRA ");
41 else
42#endif
43 strcpy(sInfo, "DTS ");
44 }
45 else if (codec == AV_CODEC_ID_MP2) strcpy(sInfo, "MP2 ");
46 else if (codec == AV_CODEC_ID_TRUEHD) strcpy(sInfo, "Dolby TrueHD ");
47 else strcpy(sInfo, "");
48
49 if (iChannels == 1) strcat(sInfo, "Mono");
50 else if (iChannels == 2) strcat(sInfo, "Stereo");
51 else if (iChannels == 6) strcat(sInfo, "5.1");
52 else if (iChannels == 8) strcat(sInfo, "7.1");
53 else if (iChannels != 0)
54 {
55 char temp[32];
56 sprintf(temp, " %d%s", iChannels, "-chs");
57 strcat(sInfo, temp);
58 }
59 strInfo = sInfo;
60}
61
62int CDVDDemux::GetNrOfAudioStreams()
63{
64 int iCounter = 0;
65
66 for (int i = 0; i < GetNrOfStreams(); i++)
67 {
68 CDemuxStream* pStream = GetStream(i);
69 if (pStream->type == STREAM_AUDIO) iCounter++;
70 }
71
72 return iCounter;
73}
74
75int CDVDDemux::GetNrOfVideoStreams()
76{
77 int iCounter = 0;
78
79 for (int i = 0; i < GetNrOfStreams(); i++)
80 {
81 CDemuxStream* pStream = GetStream(i);
82 if (pStream->type == STREAM_VIDEO) iCounter++;
83 }
84
85 return iCounter;
86}
87
88int CDVDDemux::GetNrOfSubtitleStreams()
89{
90 int iCounter = 0;
91
92 for (int i = 0; i < GetNrOfStreams(); i++)
93 {
94 CDemuxStream* pStream = GetStream(i);
95 if (pStream->type == STREAM_SUBTITLE) iCounter++;
96 }
97
98 return iCounter;
99}
100
101int CDVDDemux::GetNrOfTeletextStreams()
102{
103 int iCounter = 0;
104
105 for (int i = 0; i < GetNrOfStreams(); i++)
106 {
107 CDemuxStream* pStream = GetStream(i);
108 if (pStream->type == STREAM_TELETEXT) iCounter++;
109 }
110
111 return iCounter;
112}
113
114CDemuxStreamAudio* CDVDDemux::GetStreamFromAudioId(int iAudioIndex)
115{
116 int counter = -1;
117 for (int i = 0; i < GetNrOfStreams(); i++)
118 {
119 CDemuxStream* pStream = GetStream(i);
120
121 if (pStream->type == STREAM_AUDIO) counter++;
122 if (iAudioIndex == counter)
123 return (CDemuxStreamAudio*)pStream;
124 }
125 return NULL;
126}
127
128CDemuxStreamVideo* CDVDDemux::GetStreamFromVideoId(int iVideoIndex)
129{
130 int counter = -1;
131 for (int i = 0; i < GetNrOfStreams(); i++)
132 {
133 CDemuxStream* pStream = GetStream(i);
134
135 if (pStream->type == STREAM_VIDEO) counter++;
136 if (iVideoIndex == counter)
137 return (CDemuxStreamVideo*)pStream;
138 }
139 return NULL;
140}
141
142CDemuxStreamSubtitle* CDVDDemux::GetStreamFromSubtitleId(int iSubtitleIndex)
143{
144 int counter = -1;
145 for (int i = 0; i < GetNrOfStreams(); i++)
146 {
147 CDemuxStream* pStream = GetStream(i);
148
149 if (pStream->type == STREAM_SUBTITLE) counter++;
150 if (iSubtitleIndex == counter)
151 return (CDemuxStreamSubtitle*)pStream;
152 }
153 return NULL;
154}
155
156CDemuxStreamTeletext* CDVDDemux::GetStreamFromTeletextId(int iTeletextIndex)
157{
158 int counter = -1;
159 for (int i = 0; i < GetNrOfStreams(); i++)
160 {
161 CDemuxStream* pStream = GetStream(i);
162
163 if (pStream->type == STREAM_TELETEXT) counter++;
164 if (iTeletextIndex == counter)
165 return (CDemuxStreamTeletext*)pStream;
166 }
167 return NULL;
168}
169
170void CDemuxStream::GetStreamName( std::string& strInfo )
171{
172 strInfo = "";
173}
174
175AVDiscard CDemuxStream::GetDiscard()
176{
177 return AVDISCARD_NONE;
178}
179
180void CDemuxStream::SetDiscard(AVDiscard discard)
181{
182 return;
183}
184
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
new file mode 100644
index 0000000..fca164d
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemux.h
@@ -0,0 +1,359 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <string>
24#include "system.h"
25#include "DVDDemuxPacket.h"
26
27class CDVDInputStream;
28
29#ifndef __GNUC__
30#pragma warning(push)
31#pragma warning(disable:4244)
32#endif
33
34#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
35 #include "config.h"
36#endif
37
38extern "C" {
39#include "libavcodec/avcodec.h"
40}
41
42#ifndef __GNUC__
43#pragma warning(pop)
44#endif
45
46enum AVDiscard;
47
48enum StreamType
49{
50 STREAM_NONE = 0,// if unknown
51 STREAM_AUDIO, // audio stream
52 STREAM_VIDEO, // video stream
53 STREAM_DATA, // data stream
54 STREAM_SUBTITLE,// subtitle stream
55 STREAM_TELETEXT // Teletext data stream
56};
57
58enum StreamSource {
59 STREAM_SOURCE_NONE = 0x000,
60 STREAM_SOURCE_DEMUX = 0x100,
61 STREAM_SOURCE_NAV = 0x200,
62 STREAM_SOURCE_DEMUX_SUB = 0x300,
63 STREAM_SOURCE_TEXT = 0x400,
64 STREAM_SOURCE_VIDEOMUX = 0x500
65};
66
67#define STREAM_SOURCE_MASK(a) ((a) & 0xf00)
68
69/*
70 * CDemuxStream
71 * Base class for all demuxer streams
72 */
73class CDemuxStream
74{
75public:
76 CDemuxStream()
77 {
78 iId = 0;
79 iPhysicalId = 0;
80 codec = (AVCodecID)0; // AV_CODEC_ID_NONE
81 codec_fourcc = 0;
82 profile = FF_PROFILE_UNKNOWN;
83 level = FF_LEVEL_UNKNOWN;
84 type = STREAM_NONE;
85 source = STREAM_SOURCE_NONE;
86 iDuration = 0;
87 pPrivate = NULL;
88 ExtraData = NULL;
89 ExtraSize = 0;
90 memset(language, 0, sizeof(language));
91 disabled = false;
92 changes = 0;
93 flags = FLAG_NONE;
94 orig_type = 0;
95 }
96
97 virtual ~CDemuxStream()
98 {
99 delete [] ExtraData;
100 }
101
102 virtual void GetStreamInfo(std::string& strInfo)
103 {
104 strInfo = "";
105 }
106
107 virtual void GetStreamName(std::string& strInfo);
108
109 virtual void SetDiscard(AVDiscard discard);
110 virtual AVDiscard GetDiscard();
111
112 int iId; // most of the time starting from 0
113 int iPhysicalId; // id
114 AVCodecID codec;
115 unsigned int codec_fourcc; // if available
116 int profile; // encoder profile of the stream reported by the decoder. used to qualify hw decoders.
117 int level; // encoder level of the stream reported by the decoder. used to qualify hw decoders.
118 StreamType type;
119 int source;
120
121 int iDuration; // in mseconds
122 void* pPrivate; // private pointer for the demuxer
123 uint8_t* ExtraData; // extra data for codec to use
124 unsigned int ExtraSize; // size of extra data
125
126 char language[4]; // ISO 639 3-letter language code (empty string if undefined)
127 bool disabled; // set when stream is disabled. (when no decoder exists)
128
129 int changes; // increment on change which player may need to know about
130
131 int orig_type; // type of original source
132
133 enum EFlags
134 { FLAG_NONE = 0x0000
135 , FLAG_DEFAULT = 0x0001
136 , FLAG_DUB = 0x0002
137 , FLAG_ORIGINAL = 0x0004
138 , FLAG_COMMENT = 0x0008
139 , FLAG_LYRICS = 0x0010
140 , FLAG_KARAOKE = 0x0020
141 , FLAG_FORCED = 0x0040
142 , FLAG_HEARING_IMPAIRED = 0x0080
143 , FLAG_VISUAL_IMPAIRED = 0x0100
144 } flags;
145};
146
147class CDemuxStreamVideo : public CDemuxStream
148{
149public:
150 CDemuxStreamVideo() : CDemuxStream()
151 {
152 iFpsScale = 0;
153 iFpsRate = 0;
154 irFpsScale = 0;
155 irFpsRate = 0;
156 iHeight = 0;
157 iWidth = 0;
158 fAspect = 0.0;
159 bVFR = false;
160 bPTSInvalid = false;
161 bForcedAspect = false;
162 type = STREAM_VIDEO;
163 iOrientation = 0;
164 iBitsPerPixel = 0;
165 }
166
167 virtual ~CDemuxStreamVideo() {}
168 int iFpsScale; // scale of 1000 and a rate of 29970 will result in 29.97 fps
169 int iFpsRate;
170 int irFpsScale;
171 int irFpsRate;
172 int iHeight; // height of the stream reported by the demuxer
173 int iWidth; // width of the stream reported by the demuxer
174 float fAspect; // display aspect of stream
175 bool bVFR; // variable framerate
176 bool bPTSInvalid; // pts cannot be trusted (avi's).
177 bool bForcedAspect; // aspect is forced from container
178 int iOrientation; // orientation of the video in degress counter clockwise
179 int iBitsPerPixel;
180 std::string stereo_mode; // expected stereo mode
181};
182
183class CDemuxStreamAudio : public CDemuxStream
184{
185public:
186 CDemuxStreamAudio() : CDemuxStream()
187 {
188 iChannels = 0;
189 iSampleRate = 0;
190 iBlockAlign = 0;
191 iBitRate = 0;
192 iBitsPerSample = 0;
193 type = STREAM_AUDIO;
194 }
195
196 virtual ~CDemuxStreamAudio() {}
197
198 void GetStreamType(std::string& strInfo);
199
200 int iChannels;
201 int iSampleRate;
202 int iBlockAlign;
203 int iBitRate;
204 int iBitsPerSample;
205};
206
207class CDemuxStreamSubtitle : public CDemuxStream
208{
209public:
210 CDemuxStreamSubtitle() : CDemuxStream()
211 {
212 type = STREAM_SUBTITLE;
213 }
214};
215
216class CDemuxStreamTeletext : public CDemuxStream
217{
218public:
219 CDemuxStreamTeletext() : CDemuxStream()
220 {
221 type = STREAM_TELETEXT;
222 }
223 virtual void GetStreamInfo(std::string& strInfo);
224};
225
226class CDVDDemux
227{
228public:
229
230 CDVDDemux() {}
231 virtual ~CDVDDemux() {}
232
233
234 /*
235 * Reset the entire demuxer (same result as closing and opening it)
236 */
237 virtual void Reset() = 0;
238
239 /*
240 * Aborts any internal reading that might be stalling main thread
241 * NOTICE - this can be called from another thread
242 */
243 virtual void Abort() = 0;
244
245 /*
246 * Flush the demuxer, if any data is kept in buffers, this should be freed now
247 */
248 virtual void Flush() = 0;
249
250 /*
251 * Read a packet, returns NULL on error
252 *
253 */
254 virtual DemuxPacket* Read() = 0;
255
256 /*
257 * Seek, time in msec calculated from stream start
258 */
259 virtual bool SeekTime(int time, bool backwords = false, double* startpts = NULL) = 0;
260
261 /*
262 * Seek to a specified chapter.
263 * startpts can be updated to the point where display should start
264 */
265 virtual bool SeekChapter(int chapter, double* startpts = NULL) { return false; }
266
267 /*
268 * Get the number of chapters available
269 */
270 virtual int GetChapterCount() { return 0; }
271
272 /*
273 * Get current chapter
274 */
275 virtual int GetChapter() { return 0; }
276
277 /*
278 * Get the name of a chapter
279 * \param strChapterName[out] Name of chapter
280 * \param chapterIdx -1 for current chapter, else a chapter index
281 */
282 virtual void GetChapterName(std::string& strChapterName, int chapterIdx=-1) {}
283
284 /*
285 * Get the position of a chapter
286 * \param chapterIdx -1 for current chapter, else a chapter index
287 */
288 virtual int64_t GetChapterPos(int chapterIdx=-1) { return 0; }
289
290 /*
291 * Set the playspeed, if demuxer can handle different
292 * speeds of playback
293 */
294 virtual void SetSpeed(int iSpeed) = 0;
295
296 /*
297 * returns the total time in msec
298 */
299 virtual int GetStreamLength() = 0;
300
301 /*
302 * returns the stream or NULL on error, starting from 0
303 */
304 virtual CDemuxStream* GetStream(int iStreamId) = 0;
305
306 /*
307 * return nr of streams, 0 if none
308 */
309 virtual int GetNrOfStreams() = 0;
310
311 /*
312 * returns opened filename
313 */
314 virtual std::string GetFileName() = 0;
315 /*
316 * return nr of audio streams, 0 if none
317 */
318 int GetNrOfAudioStreams();
319
320 /*
321 * return nr of video streams, 0 if none
322 */
323 int GetNrOfVideoStreams();
324
325 /*
326 * return nr of subtitle streams, 0 if none
327 */
328 int GetNrOfSubtitleStreams();
329
330 /*
331 * return nr of teletext streams, 0 if none
332 */
333 int GetNrOfTeletextStreams();
334
335 /*
336 * return the audio stream, or NULL if it does not exist
337 */
338 CDemuxStreamAudio* GetStreamFromAudioId(int iAudioIndex);
339
340 /*
341 * return the video stream, or NULL if it does not exist
342 */
343 CDemuxStreamVideo* GetStreamFromVideoId(int iVideoIndex);
344
345 /*
346 * return the subtitle stream, or NULL if it does not exist
347 */
348 CDemuxStreamSubtitle* GetStreamFromSubtitleId(int iSubtitleIndex);
349
350 /*
351 * return the teletext stream, or NULL if it does not exist
352 */
353 CDemuxStreamTeletext* GetStreamFromTeletextId(int iTeletextIndex);
354
355 /*
356 * return a user-presentable codec name of the given stream
357 */
358 virtual void GetStreamCodecName(int iStreamId, std::string &strName) {};
359};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp
new file mode 100644
index 0000000..9786983
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.cpp
@@ -0,0 +1,193 @@
1/*
2 * Copyright (C) 2012-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 "DVDInputStreams/DVDInputStream.h"
22#include "DVDDemuxBXA.h"
23#include "DVDDemuxUtils.h"
24#include "utils/log.h"
25#include "utils/StringUtils.h"
26#include "../DVDClock.h"
27
28// AirTunes audio Demuxer.
29
30using namespace std;
31
32class CDemuxStreamAudioBXA
33 : public CDemuxStreamAudio
34{
35 CDVDDemuxBXA *m_parent;
36 string m_codec;
37public:
38 CDemuxStreamAudioBXA(CDVDDemuxBXA *parent, const string& codec)
39 : m_parent(parent)
40 , m_codec(codec)
41
42 {}
43 void GetStreamInfo(string& strInfo)
44 {
45 strInfo = StringUtils::Format("%s", m_codec.c_str());
46 }
47};
48
49CDVDDemuxBXA::CDVDDemuxBXA() : CDVDDemux()
50{
51 m_pInput = NULL;
52 m_stream = NULL;
53 m_bytes = 0;
54 memset(&m_header, 0x0, sizeof(Demux_BXA_FmtHeader));
55}
56
57CDVDDemuxBXA::~CDVDDemuxBXA()
58{
59 Dispose();
60}
61
62bool CDVDDemuxBXA::Open(CDVDInputStream* pInput)
63{
64 Abort();
65
66 Dispose();
67
68 if(!pInput || !pInput->IsStreamType(DVDSTREAM_TYPE_FILE))
69 return false;
70
71 if(pInput->Read((uint8_t *)&m_header, sizeof(Demux_BXA_FmtHeader)) < 1)
72 return false;
73
74 // file valid?
75 if (strncmp(m_header.fourcc, "BXA ", 4) != 0 || m_header.type != BXA_PACKET_TYPE_FMT_DEMUX)
76 {
77 pInput->Seek(0, SEEK_SET);
78 return false;
79 }
80
81 m_pInput = pInput;
82
83 m_stream = new CDemuxStreamAudioBXA(this, "BXA");
84
85 if(!m_stream)
86 return false;
87
88 m_stream->iSampleRate = m_header.sampleRate;
89 m_stream->iBitsPerSample = m_header.bitsPerSample;
90 m_stream->iBitRate = m_header.sampleRate * m_header.channels * m_header.bitsPerSample;
91 m_stream->iChannels = m_header.channels;
92 m_stream->type = STREAM_AUDIO;
93 m_stream->codec = AV_CODEC_ID_PCM_S16LE;
94
95 return true;
96}
97
98void CDVDDemuxBXA::Dispose()
99{
100 delete m_stream;
101 m_stream = NULL;
102
103 m_pInput = NULL;
104 m_bytes = 0;
105
106 memset(&m_header, 0x0, sizeof(Demux_BXA_FmtHeader));
107}
108
109void CDVDDemuxBXA::Reset()
110{
111 CDVDInputStream* pInputStream = m_pInput;
112 Dispose();
113 Open(pInputStream);
114}
115
116void CDVDDemuxBXA::Abort()
117{
118 if(m_pInput)
119 return m_pInput->Abort();
120}
121
122void CDVDDemuxBXA::Flush()
123{
124}
125
126#define BXA_READ_SIZE 4096
127DemuxPacket* CDVDDemuxBXA::Read()
128{
129 if(!m_pInput)
130 return NULL;
131
132 DemuxPacket* pPacket = CDVDDemuxUtils::AllocateDemuxPacket(BXA_READ_SIZE);
133
134 if (!pPacket)
135 {
136 if (m_pInput)
137 m_pInput->Close();
138 return NULL;
139 }
140
141 pPacket->iSize = m_pInput->Read(pPacket->pData, BXA_READ_SIZE);
142 pPacket->iStreamId = 0;
143
144 if(pPacket->iSize < 1)
145 {
146 delete pPacket;
147 pPacket = NULL;
148 }
149 else
150 {
151 int n = (m_header.channels * m_header.bitsPerSample * m_header.sampleRate)>>3;
152 if (n > 0)
153 {
154 m_bytes += pPacket->iSize;
155 pPacket->dts = (double)m_bytes * DVD_TIME_BASE / n;
156 pPacket->pts = pPacket->dts;
157 }
158 else
159 {
160 pPacket->dts = DVD_NOPTS_VALUE;
161 pPacket->pts = DVD_NOPTS_VALUE;
162 }
163 }
164
165 return pPacket;
166}
167
168CDemuxStream* CDVDDemuxBXA::GetStream(int iStreamId)
169{
170 if(iStreamId != 0)
171 return NULL;
172
173 return m_stream;
174}
175
176int CDVDDemuxBXA::GetNrOfStreams()
177{
178 return (m_stream == NULL ? 0 : 1);
179}
180
181std::string CDVDDemuxBXA::GetFileName()
182{
183 if(m_pInput)
184 return m_pInput->GetFileName();
185 else
186 return "";
187}
188
189void CDVDDemuxBXA::GetStreamCodecName(int iStreamId, std::string &strName)
190{
191 if (m_stream && iStreamId == 0)
192 strName = "BXA";
193}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h
new file mode 100644
index 0000000..bdb65b4
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxBXA.h
@@ -0,0 +1,85 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DVDDemux.h"
23
24#ifdef TARGET_WINDOWS
25#define __attribute__(dummy_val)
26#else
27#include <config.h>
28#endif
29
30#ifdef TARGET_WINDOWS
31#pragma pack(push)
32#pragma pack(1)
33#endif
34
35typedef struct
36{
37 char fourcc[4];
38 uint32_t type;
39 uint32_t channels;
40 uint32_t sampleRate;
41 uint32_t bitsPerSample;
42 uint64_t durationMs;
43} __attribute__((__packed__)) Demux_BXA_FmtHeader;
44
45#ifdef TARGET_WINDOWS
46#pragma pack(pop)
47#endif
48
49#include <vector>
50
51#define BXA_PACKET_TYPE_FMT_DEMUX 1
52
53class CDemuxStreamAudioBXA;
54
55class CDVDDemuxBXA : public CDVDDemux
56{
57public:
58
59 CDVDDemuxBXA();
60 ~CDVDDemuxBXA();
61
62 bool Open(CDVDInputStream* pInput);
63 void Dispose();
64 void Reset();
65 void Abort();
66 void Flush();
67 DemuxPacket* Read();
68 bool SeekTime(int time, bool backwords = false, double* startpts = NULL) { return false; }
69 void SetSpeed(int iSpeed) {};
70 int GetStreamLength() { return (int)m_header.durationMs; }
71 CDemuxStream* GetStream(int iStreamId);
72 int GetNrOfStreams();
73 std::string GetFileName();
74 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
75
76protected:
77 friend class CDemuxStreamAudioBXA;
78 CDVDInputStream* m_pInput;
79 int64_t m_bytes;
80
81 CDemuxStreamAudioBXA *m_stream;
82
83 Demux_BXA_FmtHeader m_header;
84};
85
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp
new file mode 100644
index 0000000..24d56da
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.cpp
@@ -0,0 +1,404 @@
1/*
2 * Copyright (C) 2005-2014 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 "DVDDemuxUtils.h"
22#include "DVDClock.h"
23#include "DVDDemuxCC.h"
24#include "cores/dvdplayer/DVDCodecs/Overlay/contrib/cc_decoder708.h"
25#include "utils/log.h"
26
27#include <algorithm>
28
29class CBitstream
30{
31public:
32 CBitstream(uint8_t *data, int bits)
33 {
34 m_data = data;
35 m_offset = 0;
36 m_len = bits;
37 m_error = false;
38 }
39 unsigned int readBits(int num)
40 {
41 int r = 0;
42 while (num > 0)
43 {
44 if (m_offset >= m_len)
45 {
46 m_error = true;
47 return 0;
48 }
49 num--;
50 if (m_data[m_offset / 8] & (1 << (7 - (m_offset & 7))))
51 r |= 1 << num;
52 m_offset++;
53 }
54 return r;
55 }
56 unsigned int readGolombUE(int maxbits = 32)
57 {
58 int lzb = -1;
59 int bits = 0;
60 for (int b = 0; !b; lzb++, bits++)
61 {
62 if (bits > maxbits)
63 return 0;
64 b = readBits(1);
65 }
66 return (1 << lzb) - 1 + readBits(lzb);
67 }
68
69private:
70 uint8_t *m_data;
71 int m_offset;
72 int m_len;
73 bool m_error;
74};
75
76class CCaptionBlock
77{
78public:
79 CCaptionBlock(int size)
80 {
81 m_data = (uint8_t*)malloc(size);
82 m_size = size;
83 }
84 virtual ~CCaptionBlock()
85 {
86 free(m_data);
87 }
88 double m_pts;
89 uint8_t *m_data;
90 int m_size;
91};
92
93bool reorder_sort (CCaptionBlock *lhs, CCaptionBlock *rhs)
94{
95 return (lhs->m_pts > rhs->m_pts);
96}
97
98CDVDDemuxCC::CDVDDemuxCC(AVCodecID codec)
99{
100 m_hasData = false;
101 m_curPts = 0;
102 m_ccDecoder = NULL;
103 m_codec = codec;
104}
105
106CDVDDemuxCC::~CDVDDemuxCC()
107{
108 Dispose();
109}
110
111CDemuxStream* CDVDDemuxCC::GetStream(int iStreamId)
112{
113 return &m_streams[iStreamId];
114}
115
116int CDVDDemuxCC::GetNrOfStreams()
117{
118 return m_streams.size();
119}
120
121DemuxPacket* CDVDDemuxCC::Read(DemuxPacket *pSrcPacket)
122{
123 DemuxPacket *pPacket = NULL;
124 uint32_t startcode = 0xffffffff;
125 int picType = 0;
126 int p = 0;
127 int len;
128
129 if (!pSrcPacket)
130 {
131 pPacket = Decode();
132 return pPacket;
133 }
134 if (pSrcPacket->pts == DVD_NOPTS_VALUE)
135 {
136 return pPacket;
137 }
138
139 while (!m_ccTempBuffer.empty())
140 {
141 m_ccReorderBuffer.push_back(m_ccTempBuffer.back());
142 m_ccTempBuffer.pop_back();
143 }
144
145 while ((len = pSrcPacket->iSize - p) > 3)
146 {
147 if ((startcode & 0xffffff00) == 0x00000100)
148 {
149 if (m_codec == AV_CODEC_ID_MPEG2VIDEO)
150 {
151 int scode = startcode & 0xFF;
152 if (scode == 0x00)
153 {
154 if (len > 4)
155 {
156 uint8_t *buf = pSrcPacket->pData + p;
157 picType = (buf[1] & 0x38) >> 3;
158 }
159 }
160 else if (scode == 0xb2) // user data
161 {
162 uint8_t *buf = pSrcPacket->pData + p;
163 if (len >= 6 &&
164 buf[0] == 'G' && buf[1] == 'A' && buf[2] == '9' && buf[3] == '4' &&
165 buf[4] == 3 && (buf[5] & 0x40))
166 {
167 int cc_count = buf[5] & 0x1f;
168 if (cc_count > 0 && len >= 7 + cc_count * 3)
169 {
170 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
171 memcpy(cc->m_data, buf + 7, cc_count * 3);
172 cc->m_pts = pSrcPacket->pts;
173 if (picType == 1 || picType == 2)
174 m_ccTempBuffer.push_back(cc);
175 else
176 m_ccReorderBuffer.push_back(cc);
177 }
178 }
179 else if (len >= 6 &&
180 buf[0] == 'C' && buf[1] == 'C' && buf[2] == 1)
181 {
182 int oddidx = (buf[4] & 0x80) ? 0 : 1;
183 int cc_count = (buf[4] & 0x3e) >> 1;
184 int extrafield = buf[4] & 0x01;
185 if (extrafield)
186 cc_count++;
187
188 if (cc_count > 0 && len >= 5 + cc_count * 3 * 2)
189 {
190 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
191 uint8_t *src = buf + 5;
192 uint8_t *dst = cc->m_data;
193
194 for (int i = 0; i < cc_count; i++)
195 {
196 for (int j = 0; j < 2; j++)
197 {
198 if (i == cc_count - 1 && extrafield && j == 1)
199 break;
200
201 if ((oddidx == j) && (src[0] == 0xFF))
202 {
203 dst[0] = 0x04;
204 dst[1] = src[1];
205 dst[2] = src[2];
206 dst += 3;
207 }
208 src += 3;
209 }
210 }
211 cc->m_pts = pSrcPacket->pts;
212 m_ccReorderBuffer.push_back(cc);
213 picType = 1;
214 }
215 }
216 }
217 }
218 else if (m_codec == AV_CODEC_ID_H264)
219 {
220 int scode = startcode & 0x9F;
221 // slice data comes after SEI
222 if (scode >= 1 && scode <= 5)
223 {
224 uint8_t *buf = pSrcPacket->pData + p;
225 CBitstream bs(buf, len * 8);
226 bs.readGolombUE();
227 int sliceType = bs.readGolombUE();
228 if (sliceType == 2 || sliceType == 7) // I slice
229 picType = 1;
230 else if (sliceType == 0 || sliceType == 5) // P slice
231 picType = 2;
232 if (picType == 0)
233 {
234 while (!m_ccTempBuffer.empty())
235 {
236 m_ccReorderBuffer.push_back(m_ccTempBuffer.back());
237 m_ccTempBuffer.pop_back();
238 }
239 }
240 }
241 if (scode == 0x06) // SEI
242 {
243 uint8_t *buf = pSrcPacket->pData + p;
244 if (len >= 12 &&
245 buf[3] == 0 && buf[4] == 49 &&
246 buf[5] == 'G' && buf[6] == 'A' && buf[7] == '9' && buf[8] == '4' && buf[9] == 3)
247 {
248 uint8_t *userdata = buf + 10;
249 int cc_count = userdata[0] & 0x1f;
250 if (len >= cc_count * 3 + 10)
251 {
252 CCaptionBlock *cc = new CCaptionBlock(cc_count * 3);
253 memcpy(cc->m_data, userdata + 2, cc_count * 3);
254 cc->m_pts = pSrcPacket->pts;
255 m_ccTempBuffer.push_back(cc);
256 }
257 }
258 }
259 }
260 }
261 startcode = startcode << 8 | pSrcPacket->pData[p++];
262 }
263
264 if ((picType == 1 || picType == 2) && !m_ccReorderBuffer.empty())
265 {
266 if (!m_ccDecoder)
267 {
268 if (!OpenDecoder())
269 return NULL;
270 }
271 std::sort(m_ccReorderBuffer.begin(), m_ccReorderBuffer.end(), reorder_sort);
272 pPacket = Decode();
273 }
274 return pPacket;
275}
276
277void CDVDDemuxCC::Handler(int service, void *userdata)
278{
279 CDVDDemuxCC *ctx = (CDVDDemuxCC*)userdata;
280
281 unsigned int idx;
282
283 // switch back from 608 fallback if we got 708
284 if (ctx->m_ccDecoder->m_seen608 && ctx->m_ccDecoder->m_seen708)
285 {
286 for (idx = 0; idx < ctx->m_streamdata.size(); idx++)
287 {
288 if (ctx->m_streamdata[idx].service == 0)
289 break;
290 }
291 if (idx < ctx->m_streamdata.size())
292 {
293 ctx->m_streamdata.erase(ctx->m_streamdata.begin() + idx);
294 ctx->m_ccDecoder->m_seen608 = false;
295 }
296 if (service == 0)
297 return;
298 }
299
300 for (idx = 0; idx < ctx->m_streamdata.size(); idx++)
301 {
302 if (ctx->m_streamdata[idx].service == service)
303 break;
304 }
305 if (idx >= ctx->m_streamdata.size())
306 {
307 CDemuxStreamSubtitle stream;
308 strcpy(stream.language, "cc");
309 stream.codec = AV_CODEC_ID_TEXT;
310 stream.iPhysicalId = service;
311 stream.iId = idx;
312 ctx->m_streams.push_back(stream);
313
314 streamdata data;
315 data.streamIdx = idx;
316 data.service = service;
317 ctx->m_streamdata.push_back(data);
318
319 if (service == 0)
320 ctx->m_ccDecoder->m_seen608 = true;
321 else
322 ctx->m_ccDecoder->m_seen708 = true;
323 }
324
325 ctx->m_streamdata[idx].pts = ctx->m_curPts;
326 ctx->m_streamdata[idx].hasData = true;
327 ctx->m_hasData = true;
328}
329
330bool CDVDDemuxCC::OpenDecoder()
331{
332 m_ccDecoder = new CDecoderCC708();
333 m_ccDecoder->Init(Handler, this);
334 return true;
335}
336
337void CDVDDemuxCC::Dispose()
338{
339 m_streams.clear();
340 m_streamdata.clear();
341 delete m_ccDecoder;
342 m_ccDecoder = NULL;
343
344 while (!m_ccReorderBuffer.empty())
345 {
346 delete m_ccReorderBuffer.back();
347 m_ccReorderBuffer.pop_back();
348 }
349 while (!m_ccTempBuffer.empty())
350 {
351 delete m_ccTempBuffer.back();
352 m_ccTempBuffer.pop_back();
353 }
354}
355
356DemuxPacket* CDVDDemuxCC::Decode()
357{
358 DemuxPacket *pPacket = NULL;
359
360 while(!m_hasData && !m_ccReorderBuffer.empty())
361 {
362 CCaptionBlock *cc = m_ccReorderBuffer.back();
363 m_ccReorderBuffer.pop_back();
364 m_curPts = cc->m_pts;
365 m_ccDecoder->Decode(cc->m_data, cc->m_size);
366 delete cc;
367 }
368
369 if (m_hasData)
370 {
371 for (unsigned int i=0; i<m_streamdata.size(); i++)
372 {
373 if (m_streamdata[i].hasData)
374 {
375 int service = m_streamdata[i].service;
376
377 char *data;
378 int len;
379 if (service == 0)
380 {
381 data = m_ccDecoder->m_cc608decoder->text;
382 len = m_ccDecoder->m_cc608decoder->textlen;
383 }
384 else
385 {
386 data = m_ccDecoder->m_cc708decoders[service].text;
387 len = m_ccDecoder->m_cc708decoders[service].textlen;
388 }
389
390 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(len);
391 pPacket->iSize = len;
392 memcpy(pPacket->pData, data, pPacket->iSize);
393
394 pPacket->iStreamId = i;
395 pPacket->pts = m_streamdata[i].pts;
396 pPacket->duration = 0;
397 m_streamdata[i].hasData = false;
398 break;
399 }
400 m_hasData = false;
401 }
402 }
403 return pPacket;
404}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h
new file mode 100644
index 0000000..ae78298
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCC.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright (C) 2005-2014 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#pragma once
22#include "DVDDemux.h"
23#include <vector>
24
25class CCaptionBlock;
26class CDecoderCC708;
27
28class CDVDDemuxCC : public CDVDDemux
29{
30public:
31 CDVDDemuxCC(AVCodecID codec);
32 virtual ~CDVDDemuxCC();
33
34 virtual void Reset() {};
35 virtual void Abort() {};
36 virtual void Flush() {};
37 virtual DemuxPacket* Read() { return NULL; };
38 virtual bool SeekTime(int time, bool backwords = false, double* startpts = NULL) {return true;};
39 virtual void SetSpeed(int iSpeed) {};
40 virtual int GetStreamLength() {return 0;};
41 virtual CDemuxStream* GetStream(int iStreamId);
42 virtual int GetNrOfStreams();
43 virtual std::string GetFileName() {return "";};
44
45 DemuxPacket* Read(DemuxPacket *packet);
46 static void Handler(int service, void *userdata);
47
48protected:
49 bool OpenDecoder();
50 void Dispose();
51 DemuxPacket* Decode();
52
53 struct streamdata
54 {
55 int streamIdx;
56 int service;
57 bool hasData ;
58 double pts;
59 };
60 std::vector<streamdata> m_streamdata;
61 std::vector<CDemuxStreamSubtitle> m_streams;
62 bool m_hasData;
63 double m_curPts;
64 std::vector<CCaptionBlock*> m_ccReorderBuffer;
65 std::vector<CCaptionBlock*> m_ccTempBuffer;
66 CDecoderCC708 *m_ccDecoder;
67 AVCodecID m_codec;
68};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp
new file mode 100644
index 0000000..72067da
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.cpp
@@ -0,0 +1,197 @@
1/*
2 * Copyright (C) 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 "DVDInputStreams/DVDInputStream.h"
22#include "DVDDemuxCDDA.h"
23#include "DVDDemuxUtils.h"
24#include "utils/log.h"
25#include "../DVDClock.h"
26
27// CDDA audio demuxer based on AirTunes audio Demuxer.
28
29using namespace std;
30
31class CDemuxStreamAudioCDDA
32 : public CDemuxStreamAudio
33{
34public:
35 void GetStreamInfo(string& strInfo)
36 {
37 strInfo = "pcm";
38 }
39};
40
41CDVDDemuxCDDA::CDVDDemuxCDDA() : CDVDDemux()
42{
43 m_pInput = NULL;
44 m_stream = NULL;
45 m_bytes = 0;
46}
47
48CDVDDemuxCDDA::~CDVDDemuxCDDA()
49{
50 Dispose();
51}
52
53bool CDVDDemuxCDDA::Open(CDVDInputStream* pInput)
54{
55 Abort();
56
57 Dispose();
58
59 if(!pInput || !pInput->IsStreamType(DVDSTREAM_TYPE_FILE))
60 return false;
61
62 m_pInput = pInput;
63
64 m_stream = new CDemuxStreamAudioCDDA();
65
66 if(!m_stream)
67 return false;
68
69 m_stream->iSampleRate = 44100;
70 m_stream->iBitsPerSample = 16;
71 m_stream->iBitRate = 44100 * 2 * 16;
72 m_stream->iChannels = 2;
73 m_stream->type = STREAM_AUDIO;
74 m_stream->codec = AV_CODEC_ID_PCM_S16LE;
75
76 return true;
77}
78
79void CDVDDemuxCDDA::Dispose()
80{
81 delete m_stream;
82 m_stream = NULL;
83
84 m_pInput = NULL;
85 m_bytes = 0;
86}
87
88void CDVDDemuxCDDA::Reset()
89{
90 CDVDInputStream* pInputStream = m_pInput;
91 Dispose();
92 Open(pInputStream);
93}
94
95void CDVDDemuxCDDA::Abort()
96{
97 if(m_pInput)
98 return m_pInput->Abort();
99}
100
101void CDVDDemuxCDDA::Flush()
102{
103}
104
105#define CDDA_READ_SIZE 4096
106DemuxPacket* CDVDDemuxCDDA::Read()
107{
108 if(!m_pInput)
109 return NULL;
110
111 DemuxPacket* pPacket = CDVDDemuxUtils::AllocateDemuxPacket(CDDA_READ_SIZE);
112
113 if (!pPacket)
114 {
115 if (m_pInput)
116 m_pInput->Close();
117 return NULL;
118 }
119
120 pPacket->iSize = m_pInput->Read(pPacket->pData, CDDA_READ_SIZE);
121 pPacket->iStreamId = 0;
122
123 if(pPacket->iSize < 1)
124 {
125 delete pPacket;
126 pPacket = NULL;
127 }
128 else
129 {
130 int n = m_stream->iBitRate>>3;
131 if (n > 0)
132 {
133 m_bytes += pPacket->iSize;
134 pPacket->dts = (double)m_bytes * DVD_TIME_BASE / n;
135 pPacket->pts = pPacket->dts;
136 }
137 else
138 {
139 pPacket->dts = DVD_NOPTS_VALUE;
140 pPacket->pts = DVD_NOPTS_VALUE;
141 }
142 }
143
144 return pPacket;
145}
146
147bool CDVDDemuxCDDA::SeekTime(int time, bool backwords, double* startpts)
148{
149 int bytes_per_second = m_stream->iBitRate>>3;
150 // clamp seeks to bytes per full sample
151 int clamp_bytes = (m_stream->iBitsPerSample>>3) * m_stream->iChannels;
152
153 // time is in milliseconds
154 int64_t seekPos = m_pInput->Seek((((int64_t)time * bytes_per_second / 1000) / clamp_bytes ) * clamp_bytes, SEEK_SET) > 0;
155 if (seekPos > 0)
156 m_bytes = seekPos;
157
158 if (startpts)
159 *startpts = (double)m_bytes * DVD_TIME_BASE / bytes_per_second;
160
161 return seekPos > 0;
162};
163
164int CDVDDemuxCDDA::GetStreamLength()
165{
166 int64_t num_track_bytes = m_pInput->GetLength();
167 int bytes_per_second = (m_stream->iBitRate>>3);
168 int64_t track_mseconds = num_track_bytes*1000 / bytes_per_second;
169 return (int)track_mseconds;
170}
171
172CDemuxStream* CDVDDemuxCDDA::GetStream(int iStreamId)
173{
174 if(iStreamId != 0)
175 return NULL;
176
177 return m_stream;
178}
179
180int CDVDDemuxCDDA::GetNrOfStreams()
181{
182 return (m_stream == NULL ? 0 : 1);
183}
184
185std::string CDVDDemuxCDDA::GetFileName()
186{
187 if(m_pInput)
188 return m_pInput->GetFileName();
189 else
190 return "";
191}
192
193void CDVDDemuxCDDA::GetStreamCodecName(int iStreamId, std::string &strName)
194{
195 if (m_stream && iStreamId == 0)
196 strName = "pcm";
197}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h
new file mode 100644
index 0000000..6a3c50a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxCDDA.h
@@ -0,0 +1,60 @@
1#pragma once
2/*
3 * Copyright (C) 2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DVDDemux.h"
23#include "utils/log.h"
24
25#ifdef TARGET_WINDOWS
26#define __attribute__(dummy_val)
27#else
28#include <config.h>
29#endif
30
31class CDemuxStreamAudioCDDA;
32
33class CDVDDemuxCDDA : public CDVDDemux
34{
35public:
36
37 CDVDDemuxCDDA();
38 ~CDVDDemuxCDDA();
39
40 bool Open(CDVDInputStream* pInput);
41 void Dispose();
42 void Reset();
43 void Abort();
44 void Flush();
45 DemuxPacket* Read();
46 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
47 void SetSpeed(int iSpeed) {};
48 int GetStreamLength() ;
49 CDemuxStream* GetStream(int iStreamId);
50 int GetNrOfStreams();
51 std::string GetFileName();
52 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
53
54protected:
55 friend class CDemuxStreamAudioCDDA;
56 CDVDInputStream* m_pInput;
57 int64_t m_bytes;
58
59 CDemuxStreamAudioCDDA *m_stream;
60};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
new file mode 100644
index 0000000..f58472f
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.cpp
@@ -0,0 +1,1767 @@
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 "system.h"
22#ifndef __STDC_CONSTANT_MACROS
23#define __STDC_CONSTANT_MACROS
24#endif
25#ifndef __STDC_LIMIT_MACROS
26#define __STDC_LIMIT_MACROS
27#endif
28#ifdef TARGET_POSIX
29#include "stdint.h"
30#endif
31#include "DVDDemuxFFmpeg.h"
32#include "DVDInputStreams/DVDInputStream.h"
33#include "DVDInputStreams/DVDInputStreamNavigator.h"
34#ifdef HAVE_LIBBLURAY
35#include "DVDInputStreams/DVDInputStreamBluray.h"
36#endif
37#include "DVDInputStreams/DVDInputStreamPVRManager.h"
38#include "DVDInputStreams/DVDInputStreamFFmpeg.h"
39#include "DVDDemuxUtils.h"
40#include "DVDClock.h" // for DVD_TIME_BASE
41#include "commons/Exception.h"
42#include "settings/AdvancedSettings.h"
43#include "settings/Settings.h"
44#include "filesystem/File.h"
45#include "filesystem/CurlFile.h"
46#include "filesystem/Directory.h"
47#include "utils/log.h"
48#include "threads/Thread.h"
49#include "threads/SystemClock.h"
50#include "utils/TimeUtils.h"
51#include "utils/StringUtils.h"
52#include "URL.h"
53#include "cores/FFmpeg.h"
54
55extern "C" {
56#include "libavutil/opt.h"
57}
58
59struct StereoModeConversionMap
60{
61 const char* name;
62 const char* mode;
63};
64
65// we internally use the matroska string representation of stereoscopic modes.
66// This struct is a conversion map to convert stereoscopic mode values
67// from asf/wmv to the internally used matroska ones
68static const struct StereoModeConversionMap WmvToInternalStereoModeMap[] =
69{
70 { "SideBySideRF", "right_left" },
71 { "SideBySideLF", "left_right" },
72 { "OverUnderRT", "bottom_top" },
73 { "OverUnderLT", "top_bottom" },
74 {}
75};
76
77#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
78
79void CDemuxStreamAudioFFmpeg::GetStreamInfo(std::string& strInfo)
80{
81 if(!m_stream) return;
82 char temp[128];
83 avcodec_string(temp, 128, m_stream->codec, 0);
84 strInfo = temp;
85}
86
87void CDemuxStreamAudioFFmpeg::GetStreamName(std::string& strInfo)
88{
89 if(!m_stream) return;
90 if(!m_description.empty())
91 strInfo = m_description;
92 else
93 CDemuxStream::GetStreamName(strInfo);
94}
95
96void CDemuxStreamSubtitleFFmpeg::GetStreamName(std::string& strInfo)
97{
98 if(!m_stream) return;
99 if(!m_description.empty())
100 strInfo = m_description;
101 else
102 CDemuxStream::GetStreamName(strInfo);
103}
104
105void CDemuxStreamVideoFFmpeg::GetStreamInfo(std::string& strInfo)
106{
107 if(!m_stream) return;
108 char temp[128];
109 avcodec_string(temp, 128, m_stream->codec, 0);
110 strInfo = temp;
111}
112
113void CDemuxStreamSubtitleFFmpeg::GetStreamInfo(std::string& strInfo)
114{
115 if(!m_stream) return;
116 char temp[128];
117 avcodec_string(temp, 128, m_stream->codec, 0);
118 strInfo = temp;
119}
120
121static int interrupt_cb(void* ctx)
122{
123 CDVDDemuxFFmpeg* demuxer = static_cast<CDVDDemuxFFmpeg*>(ctx);
124 if(demuxer && demuxer->Aborted())
125 return 1;
126 return 0;
127}
128
129
130////////////////////////////////////////////////////////////////////////////////////////////////
131////////////////////////////////////////////////////////////////////////////////////////////////
132/*
133static int dvd_file_open(URLContext *h, const char *filename, int flags)
134{
135 return -1;
136}
137*/
138
139static int dvd_file_read(void *h, uint8_t* buf, int size)
140{
141 if(interrupt_cb(h))
142 return AVERROR_EXIT;
143
144 CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
145 return pInputStream->Read(buf, size);
146}
147/*
148static int dvd_file_write(URLContext *h, uint8_t* buf, int size)
149{
150 return -1;
151}
152*/
153static int64_t dvd_file_seek(void *h, int64_t pos, int whence)
154{
155 if(interrupt_cb(h))
156 return AVERROR_EXIT;
157
158 CDVDInputStream* pInputStream = static_cast<CDVDDemuxFFmpeg*>(h)->m_pInput;
159 if(whence == AVSEEK_SIZE)
160 return pInputStream->GetLength();
161 else
162 return pInputStream->Seek(pos, whence & ~AVSEEK_FORCE);
163}
164
165////////////////////////////////////////////////////////////////////////////////////////////////
166////////////////////////////////////////////////////////////////////////////////////////////////
167
168CDVDDemuxFFmpeg::CDVDDemuxFFmpeg() : CDVDDemux()
169{
170 m_pFormatContext = NULL;
171 m_pInput = NULL;
172 m_ioContext = NULL;
173 m_currentPts = DVD_NOPTS_VALUE;
174 m_bMatroska = false;
175 m_bAVI = false;
176 m_speed = DVD_PLAYSPEED_NORMAL;
177 m_program = UINT_MAX;
178 m_pkt.result = -1;
179 memset(&m_pkt.pkt, 0, sizeof(AVPacket));
180 m_streaminfo = true; /* set to true if we want to look for streams before playback */
181 m_checkvideo = false;
182}
183
184CDVDDemuxFFmpeg::~CDVDDemuxFFmpeg()
185{
186 Dispose();
187 ff_flush_avutil_log_buffers();
188}
189
190bool CDVDDemuxFFmpeg::Aborted()
191{
192 if(m_timeout.IsTimePast())
193 return true;
194
195 CDVDInputStreamFFmpeg * input = dynamic_cast<CDVDInputStreamFFmpeg*>(m_pInput);
196 if(input && input->Aborted())
197 return true;
198
199 return false;
200}
201
202bool CDVDDemuxFFmpeg::Open(CDVDInputStream* pInput, bool streaminfo, bool fileinfo)
203{
204 AVInputFormat* iformat = NULL;
205 std::string strFile;
206 m_streaminfo = streaminfo;
207 m_currentPts = DVD_NOPTS_VALUE;
208 m_speed = DVD_PLAYSPEED_NORMAL;
209 m_program = UINT_MAX;
210 const AVIOInterruptCB int_cb = { interrupt_cb, this };
211
212 if (!pInput) return false;
213
214 m_pInput = pInput;
215 strFile = m_pInput->GetFileName();
216
217 if( m_pInput->GetContent().length() > 0 )
218 {
219 std::string content = m_pInput->GetContent();
220 StringUtils::ToLower(content);
221
222 /* check if we can get a hint from content */
223 if ( content.compare("video/x-vobsub") == 0 )
224 iformat = av_find_input_format("mpeg");
225 else if( content.compare("video/x-dvd-mpeg") == 0 )
226 iformat = av_find_input_format("mpeg");
227 else if( content.compare("video/mp2t") == 0 )
228 iformat = av_find_input_format("mpegts");
229 else if( content.compare("multipart/x-mixed-replace") == 0 )
230 iformat = av_find_input_format("mjpeg");
231 }
232
233 // open the demuxer
234 m_pFormatContext = avformat_alloc_context();
235 m_pFormatContext->interrupt_callback = int_cb;
236
237 // try to abort after 30 seconds
238 m_timeout.Set(30000);
239
240 if( m_pInput->IsStreamType(DVDSTREAM_TYPE_FFMPEG) )
241 {
242 // special stream type that makes avformat handle file opening
243 // allows internal ffmpeg protocols to be used
244 CURL url = m_pInput->GetURL();
245
246 AVDictionary *options = GetFFMpegOptionsFromURL(url);
247
248 int result=-1;
249 if (url.IsProtocol("mms"))
250 {
251 // try mmsh, then mmst
252 url.SetProtocol("mmsh");
253 url.SetProtocolOptions("");
254 result = avformat_open_input(&m_pFormatContext, url.Get().c_str(), iformat, &options);
255 if (result < 0)
256 {
257 url.SetProtocol("mmst");
258 strFile = url.Get();
259 }
260 }
261 if (result < 0 && avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0 )
262 {
263 CLog::Log(LOGDEBUG, "Error, could not open file %s", CURL::GetRedacted(strFile).c_str());
264 Dispose();
265 av_dict_free(&options);
266 return false;
267 }
268 av_dict_free(&options);
269 }
270 else
271 {
272 unsigned char* buffer = (unsigned char*)av_malloc(FFMPEG_FILE_BUFFER_SIZE);
273 m_ioContext = avio_alloc_context(buffer, FFMPEG_FILE_BUFFER_SIZE, 0, this, dvd_file_read, NULL, dvd_file_seek);
274 m_ioContext->max_packet_size = m_pInput->GetBlockSize();
275 if(m_ioContext->max_packet_size)
276 m_ioContext->max_packet_size *= FFMPEG_FILE_BUFFER_SIZE / m_ioContext->max_packet_size;
277
278 if(m_pInput->Seek(0, SEEK_POSSIBLE) == 0)
279 m_ioContext->seekable = 0;
280
281 std::string content = m_pInput->GetContent();
282 StringUtils::ToLower(content);
283 if (StringUtils::StartsWith(content, "audio/l16"))
284 iformat = av_find_input_format("s16be");
285
286 if( iformat == NULL )
287 {
288 // let ffmpeg decide which demuxer we have to open
289
290 bool trySPDIFonly = (m_pInput->GetContent() == "audio/x-spdif-compressed");
291
292 if (!trySPDIFonly)
293 av_probe_input_buffer(m_ioContext, &iformat, strFile.c_str(), NULL, 0, 0);
294
295 // Use the more low-level code in case we have been built against an old
296 // FFmpeg without the above av_probe_input_buffer(), or in case we only
297 // want to probe for spdif (DTS or IEC 61937) compressed audio
298 // specifically, or in case the file is a wav which may contain DTS or
299 // IEC 61937 (e.g. ac3-in-wav) and we want to check for those formats.
300 if (trySPDIFonly || (iformat && strcmp(iformat->name, "wav") == 0))
301 {
302 AVProbeData pd;
303 uint8_t probe_buffer[FFMPEG_FILE_BUFFER_SIZE + AVPROBE_PADDING_SIZE];
304
305 // init probe data
306 pd.buf = probe_buffer;
307 pd.filename = strFile.c_str();
308
309 // av_probe_input_buffer might have changed the buffer_size beyond our allocated amount
310 int buffer_size = std::min((int) FFMPEG_FILE_BUFFER_SIZE, m_ioContext->buffer_size);
311 // read data using avformat's buffers
312 pd.buf_size = avio_read(m_ioContext, pd.buf, m_ioContext->max_packet_size ? m_ioContext->max_packet_size : buffer_size);
313 if (pd.buf_size <= 0)
314 {
315 CLog::Log(LOGERROR, "%s - error reading from input stream, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
316 return false;
317 }
318 memset(pd.buf+pd.buf_size, 0, AVPROBE_PADDING_SIZE);
319
320 // restore position again
321 avio_seek(m_ioContext , 0, SEEK_SET);
322
323 // the advancedsetting is for allowing the user to force outputting the
324 // 44.1 kHz DTS wav file as PCM, so that an A/V receiver can decode
325 // it (this is temporary until we handle 44.1 kHz passthrough properly)
326 if (trySPDIFonly || (iformat && strcmp(iformat->name, "wav") == 0 && !g_advancedSettings.m_dvdplayerIgnoreDTSinWAV))
327 {
328 // check for spdif and dts
329 // This is used with wav files and audio CDs that may contain
330 // a DTS or AC3 track padded for S/PDIF playback. If neither of those
331 // is present, we assume it is PCM audio.
332 // AC3 is always wrapped in iec61937 (ffmpeg "spdif"), while DTS
333 // may be just padded.
334 AVInputFormat *iformat2;
335 iformat2 = av_find_input_format("spdif");
336
337 if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4)
338 {
339 iformat = iformat2;
340 }
341 else
342 {
343 // not spdif or no spdif demuxer, try dts
344 iformat2 = av_find_input_format("dts");
345
346 if (iformat2 && iformat2->read_probe(&pd) > AVPROBE_SCORE_MAX / 4)
347 {
348 iformat = iformat2;
349 }
350 else if (trySPDIFonly)
351 {
352 // not dts either, return false in case we were explicitely
353 // requested to only check for S/PDIF padded compressed audio
354 CLog::Log(LOGDEBUG, "%s - not spdif or dts file, fallbacking", __FUNCTION__);
355 return false;
356 }
357 }
358 }
359 }
360
361 if(!iformat)
362 {
363 std::string content = m_pInput->GetContent();
364
365 /* check if we can get a hint from content */
366 if( content.compare("audio/aacp") == 0 )
367 iformat = av_find_input_format("aac");
368 else if( content.compare("audio/aac") == 0 )
369 iformat = av_find_input_format("aac");
370 else if( content.compare("video/flv") == 0 )
371 iformat = av_find_input_format("flv");
372 else if( content.compare("video/x-flv") == 0 )
373 iformat = av_find_input_format("flv");
374 }
375
376 if (!iformat)
377 {
378 CLog::Log(LOGERROR, "%s - error probing input format, %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
379 return false;
380 }
381 else
382 {
383 if (iformat->name)
384 CLog::Log(LOGDEBUG, "%s - probing detected format [%s]", __FUNCTION__, iformat->name);
385 else
386 CLog::Log(LOGDEBUG, "%s - probing detected unnamed format", __FUNCTION__);
387 }
388 }
389
390
391 m_pFormatContext->pb = m_ioContext;
392
393 AVDictionary *options = NULL;
394 if (iformat->name && (strcmp(iformat->name, "mp3") == 0 || strcmp(iformat->name, "mp2") == 0))
395 {
396 CLog::Log(LOGDEBUG, "%s - setting usetoc to 0 for accurate VBR MP3 seek", __FUNCTION__);
397 av_dict_set(&options, "usetoc", "0", 0);
398 }
399
400 if (StringUtils::StartsWith(content, "audio/l16"))
401 {
402 int channels = 2;
403 int samplerate = 44100;
404 GetL16Parameters(channels, samplerate);
405 av_dict_set_int(&options, "channels", channels, 0);
406 av_dict_set_int(&options, "sample_rate", samplerate, 0);
407 }
408
409 if (avformat_open_input(&m_pFormatContext, strFile.c_str(), iformat, &options) < 0)
410 {
411 CLog::Log(LOGERROR, "%s - Error, could not open file %s", __FUNCTION__, CURL::GetRedacted(strFile).c_str());
412 Dispose();
413 av_dict_free(&options);
414 return false;
415 }
416 av_dict_free(&options);
417 }
418
419 // Avoid detecting framerate if advancedsettings.xml says so
420 if (g_advancedSettings.m_videoFpsDetect == 0)
421 m_pFormatContext->fps_probe_size = 0;
422
423 // analyse very short to speed up mjpeg playback start
424 if (iformat && (strcmp(iformat->name, "mjpeg") == 0) && m_ioContext->seekable == 0)
425 av_opt_set_int(m_pFormatContext, "analyzeduration", 500000, 0);
426
427 bool skipCreateStreams = false;
428 bool isBluray = pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY);
429 if (iformat && (strcmp(iformat->name, "mpegts") == 0) && !fileinfo && !isBluray)
430 {
431 av_opt_set_int(m_pFormatContext, "analyzeduration", 500000, 0);
432 m_checkvideo = true;
433 skipCreateStreams = true;
434 }
435 else if (!iformat || (strcmp(iformat->name, "mpegts") != 0))
436 {
437 m_streaminfo = true;
438 }
439
440 // we need to know if this is matroska or avi later
441 m_bMatroska = strncmp(m_pFormatContext->iformat->name, "matroska", 8) == 0; // for "matroska.webm"
442 m_bAVI = strcmp(m_pFormatContext->iformat->name, "avi") == 0;
443
444 if (m_streaminfo)
445 {
446 /* to speed up dvd switches, only analyse very short */
447 if(m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
448 av_opt_set_int(m_pFormatContext, "analyzeduration", 500000, 0);
449
450 CLog::Log(LOGDEBUG, "%s - avformat_find_stream_info starting", __FUNCTION__);
451 int iErr = avformat_find_stream_info(m_pFormatContext, NULL);
452 if (iErr < 0)
453 {
454 CLog::Log(LOGWARNING,"could not find codec parameters for %s", CURL::GetRedacted(strFile).c_str());
455 if (m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD)
456 || m_pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY)
457 || (m_pFormatContext->nb_streams == 1 && m_pFormatContext->streams[0]->codec->codec_id == AV_CODEC_ID_AC3))
458 {
459 // special case, our codecs can still handle it.
460 }
461 else
462 {
463 Dispose();
464 return false;
465 }
466 }
467 CLog::Log(LOGDEBUG, "%s - av_find_stream_info finished", __FUNCTION__);
468
469 if (m_checkvideo)
470 {
471 // make sure we start video with an i-frame
472 ResetVideoStreams();
473 }
474 }
475 else
476 {
477 m_program = 0;
478 m_checkvideo = true;
479 skipCreateStreams = true;
480 }
481
482 // reset any timeout
483 m_timeout.SetInfinite();
484
485 // if format can be nonblocking, let's use that
486 m_pFormatContext->flags |= AVFMT_FLAG_NONBLOCK;
487
488 // print some extra information
489 av_dump_format(m_pFormatContext, 0, strFile.c_str(), 0);
490
491 UpdateCurrentPTS();
492
493 // in case of mpegts and we have not seen pat/pmt, defer creation of streams
494 if (!skipCreateStreams || m_pFormatContext->nb_programs > 0)
495 CreateStreams();
496
497 // allow IsProgramChange to return true
498 if (skipCreateStreams && GetNrOfStreams() == 0)
499 m_program = 0;
500
501 return true;
502}
503
504void CDVDDemuxFFmpeg::Dispose()
505{
506 m_pkt.result = -1;
507 av_free_packet(&m_pkt.pkt);
508
509 if (m_pFormatContext)
510 {
511 if (m_ioContext && m_pFormatContext->pb && m_pFormatContext->pb != m_ioContext)
512 {
513 CLog::Log(LOGWARNING, "CDVDDemuxFFmpeg::Dispose - demuxer changed our byte context behind our back, possible memleak");
514 m_ioContext = m_pFormatContext->pb;
515 }
516 avformat_close_input(&m_pFormatContext);
517 }
518
519 if(m_ioContext)
520 {
521 av_free(m_ioContext->buffer);
522 av_free(m_ioContext);
523 }
524
525 m_ioContext = NULL;
526 m_pFormatContext = NULL;
527 m_speed = DVD_PLAYSPEED_NORMAL;
528
529 DisposeStreams();
530
531 m_pInput = NULL;
532}
533
534void CDVDDemuxFFmpeg::Reset()
535{
536 CDVDInputStream* pInputStream = m_pInput;
537 Dispose();
538 Open(pInputStream, m_streaminfo);
539}
540
541void CDVDDemuxFFmpeg::Flush()
542{
543 // naughty usage of an internal ffmpeg function
544 if (m_pFormatContext)
545 av_read_frame_flush(m_pFormatContext);
546
547 m_currentPts = DVD_NOPTS_VALUE;
548
549 m_pkt.result = -1;
550 av_free_packet(&m_pkt.pkt);
551}
552
553void CDVDDemuxFFmpeg::Abort()
554{
555 m_timeout.SetExpired();
556}
557
558void CDVDDemuxFFmpeg::SetSpeed(int iSpeed)
559{
560 if(!m_pFormatContext)
561 return;
562
563 if(m_speed != DVD_PLAYSPEED_PAUSE && iSpeed == DVD_PLAYSPEED_PAUSE)
564 {
565 m_pInput->Pause(m_currentPts);
566 av_read_pause(m_pFormatContext);
567 }
568 else if(m_speed == DVD_PLAYSPEED_PAUSE && iSpeed != DVD_PLAYSPEED_PAUSE)
569 {
570 m_pInput->Pause(m_currentPts);
571 av_read_play(m_pFormatContext);
572 }
573 m_speed = iSpeed;
574
575 AVDiscard discard = AVDISCARD_NONE;
576 if(m_speed > 4*DVD_PLAYSPEED_NORMAL)
577 discard = AVDISCARD_NONKEY;
578 else if(m_speed > 2*DVD_PLAYSPEED_NORMAL)
579 discard = AVDISCARD_BIDIR;
580 else if(m_speed < DVD_PLAYSPEED_PAUSE)
581 discard = AVDISCARD_NONKEY;
582
583
584 for(unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
585 {
586 if(m_pFormatContext->streams[i])
587 {
588 if(m_pFormatContext->streams[i]->discard != AVDISCARD_ALL)
589 m_pFormatContext->streams[i]->discard = discard;
590 }
591 }
592}
593
594AVDictionary *CDVDDemuxFFmpeg::GetFFMpegOptionsFromURL(const CURL &url)
595{
596
597 AVDictionary *options = NULL;
598
599 if (url.IsProtocol("http") || url.IsProtocol("https"))
600 {
601 std::map<std::string, std::string> protocolOptions;
602 url.GetProtocolOptions(protocolOptions);
603 std::string headers;
604 bool hasUserAgent = false;
605 for(std::map<std::string, std::string>::const_iterator it = protocolOptions.begin(); it != protocolOptions.end(); ++it)
606 {
607 std::string name = it->first; StringUtils::ToLower(name);
608 const std::string &value = it->second;
609
610 if (name == "seekable")
611 av_dict_set(&options, "seekable", value.c_str(), 0);
612 else if (name == "user-agent")
613 {
614 av_dict_set(&options, "user-agent", value.c_str(), 0);
615 hasUserAgent = true;
616 }
617 else if (name != "auth" && name != "encoding")
618 // all other protocol options can be added as http header.
619 headers.append(it->first).append(": ").append(value).append("\r\n");
620 }
621 if (!hasUserAgent)
622 // set default xbmc user-agent.
623 av_dict_set(&options, "user-agent", g_advancedSettings.m_userAgent.c_str(), 0);
624
625 if (!headers.empty())
626 av_dict_set(&options, "headers", headers.c_str(), 0);
627
628 std::string cookies;
629 if (XFILE::CCurlFile::GetCookies(url, cookies))
630 av_dict_set(&options, "cookies", cookies.c_str(), 0);
631
632 }
633 return options;
634}
635
636double CDVDDemuxFFmpeg::ConvertTimestamp(int64_t pts, int den, int num)
637{
638 if (pts == (int64_t)AV_NOPTS_VALUE)
639 return DVD_NOPTS_VALUE;
640
641 // do calculations in floats as they can easily overflow otherwise
642 // we don't care for having a completly exact timestamp anyway
643 double timestamp = (double)pts * num / den;
644 double starttime = 0.0f;
645
646 // for dvd's we need the original time
647 if(CDVDInputStream::IMenus* menu = dynamic_cast<CDVDInputStream::IMenus*>(m_pInput))
648 starttime = menu->GetTimeStampCorrection() / DVD_TIME_BASE;
649 else if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE)
650 starttime = (double)m_pFormatContext->start_time / AV_TIME_BASE;
651
652 if(timestamp > starttime)
653 timestamp -= starttime;
654 // allow for largest possible difference in pts and dts for a single packet
655 else if( timestamp + 0.5f > starttime )
656 timestamp = 0;
657
658 return timestamp*DVD_TIME_BASE;
659}
660
661DemuxPacket* CDVDDemuxFFmpeg::Read()
662{
663 DemuxPacket* pPacket = NULL;
664 // on some cases where the received packet is invalid we will need to return an empty packet (0 length) otherwise the main loop (in CDVDPlayer)
665 // would consider this the end of stream and stop.
666 bool bReturnEmpty = false;
667 { CSingleLock lock(m_critSection); // open lock scope
668 if (m_pFormatContext)
669 {
670 // assume we are not eof
671 if(m_pFormatContext->pb)
672 m_pFormatContext->pb->eof_reached = 0;
673
674 // check for saved packet after a program change
675 if (m_pkt.result < 0)
676 {
677 // keep track if ffmpeg doesn't always set these
678 m_pkt.pkt.size = 0;
679 m_pkt.pkt.data = NULL;
680
681 // timeout reads after 100ms
682 m_timeout.Set(20000);
683 m_pkt.result = av_read_frame(m_pFormatContext, &m_pkt.pkt);
684 m_timeout.SetInfinite();
685 }
686
687 if (m_pkt.result == AVERROR(EINTR) || m_pkt.result == AVERROR(EAGAIN))
688 {
689 // timeout, probably no real error, return empty packet
690 bReturnEmpty = true;
691 }
692 else if (m_pkt.result < 0)
693 {
694 Flush();
695 }
696 else if (IsProgramChange())
697 {
698 // update streams
699 CreateStreams(m_program);
700
701 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0);
702 pPacket->iStreamId = DMX_SPECIALID_STREAMCHANGE;
703
704 return pPacket;
705 }
706 // check size and stream index for being in a valid range
707 else if (m_pkt.pkt.size < 0 ||
708 m_pkt.pkt.stream_index < 0 ||
709 m_pkt.pkt.stream_index >= (int)m_pFormatContext->nb_streams)
710 {
711 // XXX, in some cases ffmpeg returns a negative packet size
712 if(m_pFormatContext->pb && !m_pFormatContext->pb->eof_reached)
713 {
714 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::Read() no valid packet");
715 bReturnEmpty = true;
716 Flush();
717 }
718 else
719 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::Read() returned invalid packet and eof reached");
720
721 m_pkt.result = -1;
722 av_free_packet(&m_pkt.pkt);
723 }
724 else
725 {
726 ParsePacket(&m_pkt.pkt);
727
728 AVStream *stream = m_pFormatContext->streams[m_pkt.pkt.stream_index];
729
730 if (IsVideoReady())
731 {
732 if (m_program != UINT_MAX)
733 {
734 /* check so packet belongs to selected program */
735 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
736 {
737 if(m_pkt.pkt.stream_index == (int)m_pFormatContext->programs[m_program]->stream_index[i])
738 {
739 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
740 break;
741 }
742 }
743
744 if (!pPacket)
745 bReturnEmpty = true;
746 }
747 else
748 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(m_pkt.pkt.size);
749 }
750 else
751 bReturnEmpty = true;
752
753 if (pPacket)
754 {
755 // lavf sometimes bugs out and gives 0 dts/pts instead of no dts/pts
756 // since this could only happens on initial frame under normal
757 // circomstances, let's assume it is wrong all the time
758 if(m_pkt.pkt.dts == 0)
759 m_pkt.pkt.dts = AV_NOPTS_VALUE;
760 if(m_pkt.pkt.pts == 0)
761 m_pkt.pkt.pts = AV_NOPTS_VALUE;
762
763 if(m_bMatroska && stream->codec && stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
764 { // matroska can store different timestamps
765 // for different formats, for native stored
766 // stuff it is pts, but for ms compatibility
767 // tracks, it is really dts. sadly ffmpeg
768 // sets these two timestamps equal all the
769 // time, so we select it here instead
770 if(stream->codec->codec_tag == 0)
771 m_pkt.pkt.dts = AV_NOPTS_VALUE;
772 else
773 m_pkt.pkt.pts = AV_NOPTS_VALUE;
774 }
775
776 // we need to get duration slightly different for matroska embedded text subtitels
777 if(m_bMatroska && stream->codec && stream->codec->codec_id == AV_CODEC_ID_TEXT && m_pkt.pkt.convergence_duration != 0)
778 m_pkt.pkt.duration = m_pkt.pkt.convergence_duration;
779
780 if(m_bAVI && stream->codec && stream->codec->codec_type == AVMEDIA_TYPE_VIDEO)
781 {
782 // AVI's always have borked pts, specially if m_pFormatContext->flags includes
783 // AVFMT_FLAG_GENPTS so always use dts
784 m_pkt.pkt.pts = AV_NOPTS_VALUE;
785 }
786
787 // copy contents into our own packet
788 pPacket->iSize = m_pkt.pkt.size;
789
790 // maybe we can avoid a memcpy here by detecting where pkt.destruct is pointing too?
791 if (m_pkt.pkt.data)
792 memcpy(pPacket->pData, m_pkt.pkt.data, pPacket->iSize);
793
794 pPacket->pts = ConvertTimestamp(m_pkt.pkt.pts, stream->time_base.den, stream->time_base.num);
795 pPacket->dts = ConvertTimestamp(m_pkt.pkt.dts, stream->time_base.den, stream->time_base.num);
796 pPacket->duration = DVD_SEC_TO_TIME((double)m_pkt.pkt.duration * stream->time_base.num / stream->time_base.den);
797
798 // used to guess streamlength
799 if (pPacket->dts != DVD_NOPTS_VALUE && (pPacket->dts > m_currentPts || m_currentPts == DVD_NOPTS_VALUE))
800 m_currentPts = pPacket->dts;
801
802
803 // check if stream has passed full duration, needed for live streams
804 bool bAllowDurationExt = (stream->codec && (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO || stream->codec->codec_type == AVMEDIA_TYPE_AUDIO));
805 if(bAllowDurationExt && m_pkt.pkt.dts != (int64_t)AV_NOPTS_VALUE)
806 {
807 int64_t duration;
808 duration = m_pkt.pkt.dts;
809 if(stream->start_time != (int64_t)AV_NOPTS_VALUE)
810 duration -= stream->start_time;
811
812 if(duration > stream->duration)
813 {
814 stream->duration = duration;
815 duration = av_rescale_rnd(stream->duration, (int64_t)stream->time_base.num * AV_TIME_BASE, stream->time_base.den, AV_ROUND_NEAR_INF);
816 if ((m_pFormatContext->duration == (int64_t)AV_NOPTS_VALUE)
817 || (m_pFormatContext->duration != (int64_t)AV_NOPTS_VALUE && duration > m_pFormatContext->duration))
818 m_pFormatContext->duration = duration;
819 }
820 }
821
822 // store internal id until we know the continuous id presented to player
823 // the stream might not have been created yet
824 pPacket->iStreamId = m_pkt.pkt.stream_index;
825 }
826 m_pkt.result = -1;
827 av_free_packet(&m_pkt.pkt);
828 }
829 }
830 } // end of lock scope
831 if (bReturnEmpty && !pPacket)
832 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(0);
833
834 if (!pPacket) return NULL;
835
836 // check streams, can we make this a bit more simple?
837 if (pPacket && pPacket->iStreamId >= 0)
838 {
839 CDemuxStream *stream = GetStreamInternal(pPacket->iStreamId);
840 if (!stream ||
841 stream->pPrivate != m_pFormatContext->streams[pPacket->iStreamId] ||
842 stream->codec != m_pFormatContext->streams[pPacket->iStreamId]->codec->codec_id)
843 {
844 // content has changed, or stream did not yet exist
845 stream = AddStream(pPacket->iStreamId);
846 }
847 // we already check for a valid m_streams[pPacket->iStreamId] above
848 else if (stream->type == STREAM_AUDIO)
849 {
850 if (((CDemuxStreamAudio*)stream)->iChannels != m_pFormatContext->streams[pPacket->iStreamId]->codec->channels ||
851 ((CDemuxStreamAudio*)stream)->iSampleRate != m_pFormatContext->streams[pPacket->iStreamId]->codec->sample_rate)
852 {
853 // content has changed
854 stream = AddStream(pPacket->iStreamId);
855 }
856 }
857 else if (stream->type == STREAM_VIDEO)
858 {
859 if (((CDemuxStreamVideo*)stream)->iWidth != m_pFormatContext->streams[pPacket->iStreamId]->codec->width ||
860 ((CDemuxStreamVideo*)stream)->iHeight != m_pFormatContext->streams[pPacket->iStreamId]->codec->height)
861 {
862 // content has changed
863 stream = AddStream(pPacket->iStreamId);
864 }
865 }
866 if (!stream)
867 {
868 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::AddStream - internal error, stream is null");
869 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
870 return NULL;
871 }
872 // set continuous stream id for player
873 pPacket->iStreamId = stream->iId;
874 }
875 return pPacket;
876}
877
878bool CDVDDemuxFFmpeg::SeekTime(int time, bool backwords, double *startpts)
879{
880 if (!m_pInput)
881 return false;
882
883 if(time < 0)
884 time = 0;
885
886 m_pkt.result = -1;
887 av_free_packet(&m_pkt.pkt);
888
889 CDVDInputStream::ISeekTime* ist = dynamic_cast<CDVDInputStream::ISeekTime*>(m_pInput);
890 if (ist)
891 {
892 if (!ist->SeekTime(time))
893 return false;
894
895 if(startpts)
896 *startpts = DVD_NOPTS_VALUE;
897
898 Flush();
899
900 // also empty the internal ffmpeg buffer
901 m_ioContext->buf_ptr = m_ioContext->buf_end;
902
903 return true;
904 }
905
906 if(!m_pInput->Seek(0, SEEK_POSSIBLE)
907 && !m_pInput->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
908 {
909 CLog::Log(LOGDEBUG, "%s - input stream reports it is not seekable", __FUNCTION__);
910 return false;
911 }
912
913 int64_t seek_pts = (int64_t)time * (AV_TIME_BASE / 1000);
914 bool ismp3 = m_pFormatContext->iformat && (strcmp(m_pFormatContext->iformat->name, "mp3") == 0);
915 if (m_pFormatContext->start_time != (int64_t)AV_NOPTS_VALUE && !ismp3)
916 seek_pts += m_pFormatContext->start_time;
917
918 int ret;
919 {
920 CSingleLock lock(m_critSection);
921 ret = av_seek_frame(m_pFormatContext, -1, seek_pts, backwords ? AVSEEK_FLAG_BACKWARD : 0);
922
923 // demuxer will return failure, if you seek behind eof
924 if (ret < 0 && m_pFormatContext->duration && seek_pts >= (m_pFormatContext->duration + m_pFormatContext->start_time))
925 ret = 0;
926 else if (ret < 0 && m_pInput->IsEOF())
927 ret = 0;
928
929 if(ret >= 0)
930 UpdateCurrentPTS();
931 }
932
933 if(m_currentPts == DVD_NOPTS_VALUE)
934 CLog::Log(LOGDEBUG, "%s - unknown position after seek", __FUNCTION__);
935 else
936 CLog::Log(LOGDEBUG, "%s - seek ended up on time %d", __FUNCTION__, (int)(m_currentPts / DVD_TIME_BASE * 1000));
937
938 // in this case the start time is requested time
939 if(startpts)
940 *startpts = DVD_MSEC_TO_TIME(time);
941
942 return (ret >= 0);
943}
944
945bool CDVDDemuxFFmpeg::SeekByte(int64_t pos)
946{
947 CSingleLock lock(m_critSection);
948 int ret = av_seek_frame(m_pFormatContext, -1, pos, AVSEEK_FLAG_BYTE);
949
950 if(ret >= 0)
951 UpdateCurrentPTS();
952
953 m_pkt.result = -1;
954 av_free_packet(&m_pkt.pkt);
955
956 return (ret >= 0);
957}
958
959void CDVDDemuxFFmpeg::UpdateCurrentPTS()
960{
961 m_currentPts = DVD_NOPTS_VALUE;
962
963 int idx = av_find_default_stream_index(m_pFormatContext);
964 if (idx >= 0)
965 {
966 AVStream *stream = m_pFormatContext->streams[idx];
967 if(stream && stream->cur_dts != (int64_t)AV_NOPTS_VALUE)
968 {
969 double ts = ConvertTimestamp(stream->cur_dts, stream->time_base.den, stream->time_base.num);
970 if(m_currentPts == DVD_NOPTS_VALUE || m_currentPts > ts )
971 m_currentPts = ts;
972 }
973 }
974}
975
976int CDVDDemuxFFmpeg::GetStreamLength()
977{
978 if (!m_pFormatContext)
979 return 0;
980
981 if (m_pFormatContext->duration < 0)
982 return 0;
983
984 return (int)(m_pFormatContext->duration / (AV_TIME_BASE / 1000));
985}
986
987/**
988 * @brief Finds stream based on demuxer index
989 */
990CDemuxStream* CDVDDemuxFFmpeg::GetStream(int iStreamId)
991{
992 if(iStreamId >= 0 && (size_t)iStreamId < m_stream_index.size())
993 return m_stream_index[iStreamId]->second;
994 else
995 return NULL;
996}
997
998/**
999 * @brief Finds stream based on ffmpeg index
1000 */
1001CDemuxStream* CDVDDemuxFFmpeg::GetStreamInternal(int iId)
1002{
1003 std::map<int, CDemuxStream*>::iterator it = m_streams.find(iId);
1004 if (it == m_streams.end())
1005 return NULL;
1006 else
1007 return it->second;
1008}
1009
1010int CDVDDemuxFFmpeg::GetNrOfStreams()
1011{
1012 return m_stream_index.size();
1013}
1014
1015static double SelectAspect(AVStream* st, bool* forced)
1016{
1017 *forced = false;
1018 /* if stream aspect is 1:1 or 0:0 use codec aspect */
1019 if((st->sample_aspect_ratio.den == 1 || st->sample_aspect_ratio.den == 0)
1020 && (st->sample_aspect_ratio.num == 1 || st->sample_aspect_ratio.num == 0)
1021 && st->codec->sample_aspect_ratio.num != 0)
1022 return av_q2d(st->codec->sample_aspect_ratio);
1023
1024 *forced = true;
1025 if(st->sample_aspect_ratio.num != 0)
1026 return av_q2d(st->sample_aspect_ratio);
1027
1028 return 0.0;
1029}
1030
1031void CDVDDemuxFFmpeg::CreateStreams(unsigned int program)
1032{
1033 DisposeStreams();
1034
1035 // add the ffmpeg streams to our own stream map
1036 if (m_pFormatContext->nb_programs)
1037 {
1038 // check if desired program is available
1039 if (program < m_pFormatContext->nb_programs && m_pFormatContext->programs[program]->nb_stream_indexes > 0)
1040 {
1041 m_program = program;
1042 }
1043 else
1044 m_program = UINT_MAX;
1045
1046 // look for first non empty stream and discard nonselected programs
1047 for (unsigned int i = 0; i < m_pFormatContext->nb_programs; i++)
1048 {
1049 if(m_program == UINT_MAX && m_pFormatContext->programs[i]->nb_stream_indexes > 0)
1050 {
1051 m_program = i;
1052 }
1053
1054 if(i != m_program)
1055 m_pFormatContext->programs[i]->discard = AVDISCARD_ALL;
1056 }
1057 if(m_program != UINT_MAX)
1058 {
1059 // add streams from selected program
1060 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
1061 AddStream(m_pFormatContext->programs[m_program]->stream_index[i]);
1062 }
1063 }
1064 else
1065 m_program = UINT_MAX;
1066
1067 // if there were no programs or they were all empty, add all streams
1068 if (m_program == UINT_MAX)
1069 {
1070 for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
1071 AddStream(i);
1072 }
1073}
1074
1075void CDVDDemuxFFmpeg::DisposeStreams()
1076{
1077 std::map<int, CDemuxStream*>::iterator it;
1078 for(it = m_streams.begin(); it != m_streams.end(); ++it)
1079 delete it->second;
1080 m_streams.clear();
1081 m_stream_index.clear();
1082}
1083
1084CDemuxStream* CDVDDemuxFFmpeg::AddStream(int iId)
1085{
1086 AVStream* pStream = m_pFormatContext->streams[iId];
1087 if (pStream)
1088 {
1089 CDemuxStream* stream = NULL;
1090
1091 switch (pStream->codec->codec_type)
1092 {
1093 case AVMEDIA_TYPE_AUDIO:
1094 {
1095 CDemuxStreamAudioFFmpeg* st = new CDemuxStreamAudioFFmpeg(this, pStream);
1096 stream = st;
1097 st->iChannels = pStream->codec->channels;
1098 st->iSampleRate = pStream->codec->sample_rate;
1099 st->iBlockAlign = pStream->codec->block_align;
1100 st->iBitRate = pStream->codec->bit_rate;
1101 st->iBitsPerSample = pStream->codec->bits_per_raw_sample;
1102 if (st->iBitsPerSample == 0)
1103 st->iBitsPerSample = pStream->codec->bits_per_coded_sample;
1104
1105 if(av_dict_get(pStream->metadata, "title", NULL, 0))
1106 st->m_description = av_dict_get(pStream->metadata, "title", NULL, 0)->value;
1107
1108 break;
1109 }
1110 case AVMEDIA_TYPE_VIDEO:
1111 {
1112 CDemuxStreamVideoFFmpeg* st = new CDemuxStreamVideoFFmpeg(this, pStream);
1113 stream = st;
1114 if(strcmp(m_pFormatContext->iformat->name, "flv") == 0)
1115 st->bVFR = true;
1116 else
1117 st->bVFR = false;
1118
1119 // never trust pts in avi files with h264.
1120 if (m_bAVI && pStream->codec->codec_id == AV_CODEC_ID_H264)
1121 st->bPTSInvalid = true;
1122
1123#if defined(AVFORMAT_HAS_STREAM_GET_R_FRAME_RATE)
1124 AVRational r_frame_rate = av_stream_get_r_frame_rate(pStream);
1125#else
1126 AVRational r_frame_rate = pStream->r_frame_rate;
1127#endif
1128
1129 //average fps is more accurate for mkv files
1130 if (m_bMatroska && pStream->avg_frame_rate.den && pStream->avg_frame_rate.num)
1131 {
1132 st->iFpsRate = pStream->avg_frame_rate.num;
1133 st->iFpsScale = pStream->avg_frame_rate.den;
1134 }
1135 else if(r_frame_rate.den && r_frame_rate.num)
1136 {
1137 st->iFpsRate = r_frame_rate.num;
1138 st->iFpsScale = r_frame_rate.den;
1139 }
1140 else
1141 {
1142 st->iFpsRate = 0;
1143 st->iFpsScale = 0;
1144 }
1145
1146 // added for aml hw decoder, mkv frame-rate can be wrong.
1147 if (r_frame_rate.den && r_frame_rate.num)
1148 {
1149 st->irFpsRate = r_frame_rate.num;
1150 st->irFpsScale = r_frame_rate.den;
1151 }
1152 else
1153 {
1154 st->irFpsRate = 0;
1155 st->irFpsScale = 0;
1156 }
1157
1158 if (pStream->codec_info_nb_frames > 0
1159 && pStream->codec_info_nb_frames <= 2
1160 && m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD))
1161 {
1162 CLog::Log(LOGDEBUG, "%s - fps may be unreliable since ffmpeg decoded only %d frame(s)", __FUNCTION__, pStream->codec_info_nb_frames);
1163 st->iFpsRate = 0;
1164 st->iFpsScale = 0;
1165 }
1166
1167 st->iWidth = pStream->codec->width;
1168 st->iHeight = pStream->codec->height;
1169 st->fAspect = SelectAspect(pStream, &st->bForcedAspect) * pStream->codec->width / pStream->codec->height;
1170 st->iOrientation = 0;
1171 st->iBitsPerPixel = pStream->codec->bits_per_coded_sample;
1172
1173 AVDictionaryEntry *rtag = av_dict_get(pStream->metadata, "rotate", NULL, 0);
1174 if (rtag)
1175 st->iOrientation = atoi(rtag->value);
1176
1177 // detect stereoscopic mode
1178 std::string stereoMode = GetStereoModeFromMetadata(pStream->metadata);
1179 // check for metadata in file if detection in stream failed
1180 if (stereoMode.empty())
1181 stereoMode = GetStereoModeFromMetadata(m_pFormatContext->metadata);
1182 if (!stereoMode.empty())
1183 st->stereo_mode = stereoMode;
1184
1185
1186 if ( m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD) )
1187 {
1188 if (pStream->codec->codec_id == AV_CODEC_ID_PROBE)
1189 {
1190 // fix MPEG-1/MPEG-2 video stream probe returning AV_CODEC_ID_PROBE for still frames.
1191 // ffmpeg issue 1871, regression from ffmpeg r22831.
1192 if ((pStream->id & 0xF0) == 0xE0)
1193 {
1194 pStream->codec->codec_id = AV_CODEC_ID_MPEG2VIDEO;
1195 pStream->codec->codec_tag = MKTAG('M','P','2','V');
1196 CLog::Log(LOGERROR, "%s - AV_CODEC_ID_PROBE detected, forcing AV_CODEC_ID_MPEG2VIDEO", __FUNCTION__);
1197 }
1198 }
1199 }
1200 break;
1201 }
1202 case AVMEDIA_TYPE_DATA:
1203 {
1204 stream = new CDemuxStream();
1205 stream->type = STREAM_DATA;
1206 break;
1207 }
1208 case AVMEDIA_TYPE_SUBTITLE:
1209 {
1210 if (pStream->codec->codec_id == AV_CODEC_ID_DVB_TELETEXT && CSettings::Get().GetBool("videoplayer.teletextenabled"))
1211 {
1212 CDemuxStreamTeletext* st = new CDemuxStreamTeletext();
1213 stream = st;
1214 stream->type = STREAM_TELETEXT;
1215 break;
1216 }
1217 else
1218 {
1219 CDemuxStreamSubtitleFFmpeg* st = new CDemuxStreamSubtitleFFmpeg(this, pStream);
1220 stream = st;
1221
1222 if(av_dict_get(pStream->metadata, "title", NULL, 0))
1223 st->m_description = av_dict_get(pStream->metadata, "title", NULL, 0)->value;
1224
1225 break;
1226 }
1227 }
1228 case AVMEDIA_TYPE_ATTACHMENT:
1229 { //mkv attachments. Only bothering with fonts for now.
1230 if(pStream->codec->codec_id == AV_CODEC_ID_TTF
1231 || pStream->codec->codec_id == AV_CODEC_ID_OTF
1232 )
1233 {
1234 std::string fileName = "special://temp/fonts/";
1235 XFILE::CDirectory::Create(fileName);
1236 AVDictionaryEntry *nameTag = av_dict_get(pStream->metadata, "filename", NULL, 0);
1237 if (!nameTag)
1238 {
1239 CLog::Log(LOGERROR, "%s: TTF attachment has no name", __FUNCTION__);
1240 }
1241 else
1242 {
1243 fileName += nameTag->value;
1244 XFILE::CFile file;
1245 if(pStream->codec->extradata && file.OpenForWrite(fileName))
1246 {
1247 if (file.Write(pStream->codec->extradata, pStream->codec->extradata_size) != pStream->codec->extradata_size)
1248 {
1249 file.Close();
1250 XFILE::CFile::Delete(fileName);
1251 CLog::Log(LOGDEBUG, "%s: Error saving font file \"%s\"", __FUNCTION__, fileName.c_str());
1252 }
1253 }
1254 }
1255 }
1256 stream = new CDemuxStream();
1257 stream->type = STREAM_NONE;
1258 break;
1259 }
1260 default:
1261 {
1262 stream = new CDemuxStream();
1263 stream->type = STREAM_NONE;
1264 break;
1265 }
1266 }
1267
1268 // set ffmpeg type
1269 stream->orig_type = pStream->codec->codec_type;
1270
1271 // generic stuff
1272 if (pStream->duration != (int64_t)AV_NOPTS_VALUE)
1273 stream->iDuration = (int)((pStream->duration / AV_TIME_BASE) & 0xFFFFFFFF);
1274
1275 stream->codec = pStream->codec->codec_id;
1276 stream->codec_fourcc = pStream->codec->codec_tag;
1277 stream->profile = pStream->codec->profile;
1278 stream->level = pStream->codec->level;
1279
1280 stream->source = STREAM_SOURCE_DEMUX;
1281 stream->pPrivate = pStream;
1282 stream->flags = (CDemuxStream::EFlags)pStream->disposition;
1283
1284 AVDictionaryEntry *langTag = av_dict_get(pStream->metadata, "language", NULL, 0);
1285 if (langTag)
1286 strncpy(stream->language, langTag->value, 3);
1287
1288 if( pStream->codec->extradata && pStream->codec->extradata_size > 0 )
1289 {
1290 stream->ExtraSize = pStream->codec->extradata_size;
1291 stream->ExtraData = new uint8_t[pStream->codec->extradata_size];
1292 memcpy(stream->ExtraData, pStream->codec->extradata, pStream->codec->extradata_size);
1293 }
1294
1295#ifdef HAVE_LIBBLURAY
1296 if( m_pInput->IsStreamType(DVDSTREAM_TYPE_BLURAY) )
1297 static_cast<CDVDInputStreamBluray*>(m_pInput)->GetStreamInfo(pStream->id, stream->language);
1298#endif
1299 if( m_pInput->IsStreamType(DVDSTREAM_TYPE_DVD) )
1300 {
1301 // this stuff is really only valid for dvd's.
1302 // this is so that the physicalid matches the
1303 // id's reported from libdvdnav
1304 switch(stream->codec)
1305 {
1306 case AV_CODEC_ID_AC3:
1307 stream->iPhysicalId = pStream->id - 128;
1308 break;
1309 case AV_CODEC_ID_DTS:
1310 stream->iPhysicalId = pStream->id - 136;
1311 break;
1312 case AV_CODEC_ID_MP2:
1313 stream->iPhysicalId = pStream->id - 448;
1314 break;
1315 case AV_CODEC_ID_PCM_S16BE:
1316 stream->iPhysicalId = pStream->id - 160;
1317 break;
1318 case AV_CODEC_ID_DVD_SUBTITLE:
1319 stream->iPhysicalId = pStream->id - 0x20;
1320 break;
1321 default:
1322 stream->iPhysicalId = pStream->id & 0x1f;
1323 break;
1324 }
1325 }
1326 else
1327 stream->iPhysicalId = pStream->id;
1328
1329 AddStream(iId, stream);
1330 return stream;
1331 }
1332 else
1333 return NULL;
1334}
1335
1336/**
1337 * @brief Adds or updates a demux stream based in ffmpeg id
1338 */
1339void CDVDDemuxFFmpeg::AddStream(int iId, CDemuxStream* stream)
1340{
1341 std::pair<std::map<int, CDemuxStream*>::iterator, bool> res;
1342
1343 res = m_streams.insert(std::make_pair(iId, stream));
1344 if(res.second)
1345 {
1346 /* was new stream */
1347 stream->iId = m_stream_index.size();
1348 m_stream_index.push_back(res.first);
1349 }
1350 else
1351 {
1352 /* replace old stream, keeping old index */
1353 stream->iId = res.first->second->iId;
1354
1355 delete res.first->second;
1356 res.first->second = stream;
1357 }
1358 if(g_advancedSettings.m_logLevel > LOG_LEVEL_NORMAL)
1359 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::AddStream(%d, ...) -> %d", iId, stream->iId);
1360}
1361
1362
1363std::string CDVDDemuxFFmpeg::GetFileName()
1364{
1365 if(m_pInput)
1366 return m_pInput->GetFileName();
1367 else
1368 return "";
1369}
1370
1371int CDVDDemuxFFmpeg::GetChapterCount()
1372{
1373 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1374 if(ich)
1375 return ich->GetChapterCount();
1376
1377 if(m_pFormatContext == NULL)
1378 return 0;
1379
1380 return m_pFormatContext->nb_chapters;
1381}
1382
1383int CDVDDemuxFFmpeg::GetChapter()
1384{
1385 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1386 if(ich)
1387 return ich->GetChapter();
1388
1389 if(m_pFormatContext == NULL
1390 || m_currentPts == DVD_NOPTS_VALUE)
1391 return 0;
1392
1393 for(unsigned i = 0; i < m_pFormatContext->nb_chapters; i++)
1394 {
1395 AVChapter *chapter = m_pFormatContext->chapters[i];
1396 if(m_currentPts >= ConvertTimestamp(chapter->start, chapter->time_base.den, chapter->time_base.num)
1397 && m_currentPts < ConvertTimestamp(chapter->end, chapter->time_base.den, chapter->time_base.num))
1398 return i + 1;
1399 }
1400
1401 return 0;
1402}
1403
1404void CDVDDemuxFFmpeg::GetChapterName(std::string& strChapterName, int chapterIdx)
1405{
1406 if (chapterIdx <= 0 || chapterIdx > GetChapterCount())
1407 chapterIdx = GetChapter();
1408 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1409 if(ich)
1410 ich->GetChapterName(strChapterName, chapterIdx);
1411 else
1412 {
1413 if(chapterIdx <= 0)
1414 return;
1415
1416 AVDictionaryEntry *titleTag = av_dict_get(m_pFormatContext->chapters[chapterIdx-1]->metadata,
1417 "title", NULL, 0);
1418 if (titleTag)
1419 strChapterName = titleTag->value;
1420 }
1421}
1422
1423int64_t CDVDDemuxFFmpeg::GetChapterPos(int chapterIdx)
1424{
1425 if (chapterIdx <= 0 || chapterIdx > GetChapterCount())
1426 chapterIdx = GetChapter();
1427 if(chapterIdx <= 0)
1428 return 0;
1429
1430 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1431 if(ich)
1432 return ich->GetChapterPos(chapterIdx);
1433
1434 return m_pFormatContext->chapters[chapterIdx-1]->start*av_q2d(m_pFormatContext->chapters[chapterIdx-1]->time_base);
1435}
1436
1437bool CDVDDemuxFFmpeg::SeekChapter(int chapter, double* startpts)
1438{
1439 if(chapter < 1)
1440 chapter = 1;
1441
1442 CDVDInputStream::IChapter* ich = dynamic_cast<CDVDInputStream::IChapter*>(m_pInput);
1443 if(ich)
1444 {
1445 CLog::Log(LOGDEBUG, "%s - chapter seeking using input stream", __FUNCTION__);
1446 if(!ich->SeekChapter(chapter))
1447 return false;
1448
1449 if(startpts)
1450 {
1451 *startpts = DVD_SEC_TO_TIME(ich->GetChapterPos(chapter));
1452 }
1453
1454 Flush();
1455 return true;
1456 }
1457
1458 if(m_pFormatContext == NULL)
1459 return false;
1460
1461 if(chapter < 1 || chapter > (int)m_pFormatContext->nb_chapters)
1462 return false;
1463
1464 AVChapter *ch = m_pFormatContext->chapters[chapter-1];
1465 double dts = ConvertTimestamp(ch->start, ch->time_base.den, ch->time_base.num);
1466 return SeekTime(DVD_TIME_TO_MSEC(dts), true, startpts);
1467}
1468
1469void CDVDDemuxFFmpeg::GetStreamCodecName(int iStreamId, std::string &strName)
1470{
1471 CDemuxStream *stream = GetStream(iStreamId);
1472 if (stream)
1473 {
1474 unsigned int in = stream->codec_fourcc;
1475 // FourCC codes are only valid on video streams, audio codecs in AVI/WAV
1476 // are 2 bytes and audio codecs in transport streams have subtle variation
1477 // e.g AC-3 instead of ac3
1478 if (stream->type == STREAM_VIDEO && in != 0)
1479 {
1480 char fourcc[5];
1481#if defined(__powerpc__)
1482 fourcc[0] = in & 0xff;
1483 fourcc[1] = (in >> 8) & 0xff;
1484 fourcc[2] = (in >> 16) & 0xff;
1485 fourcc[3] = (in >> 24) & 0xff;
1486#else
1487 memcpy(fourcc, &in, 4);
1488#endif
1489 fourcc[4] = 0;
1490 // fourccs have to be 4 characters
1491 if (strlen(fourcc) == 4)
1492 {
1493 strName = fourcc;
1494 StringUtils::ToLower(strName);
1495 return;
1496 }
1497 }
1498
1499#ifdef FF_PROFILE_DTS_HD_MA
1500 /* use profile to determine the DTS type */
1501 if (stream->codec == AV_CODEC_ID_DTS)
1502 {
1503 if (stream->profile == FF_PROFILE_DTS_HD_MA)
1504 strName = "dtshd_ma";
1505 else if (stream->profile == FF_PROFILE_DTS_HD_HRA)
1506 strName = "dtshd_hra";
1507 else
1508 strName = "dca";
1509 return;
1510 }
1511#endif
1512
1513 AVCodec *codec = avcodec_find_decoder(stream->codec);
1514 if (codec)
1515 strName = codec->name;
1516 }
1517}
1518
1519bool CDVDDemuxFFmpeg::IsProgramChange()
1520{
1521 if (m_program == UINT_MAX)
1522 return false;
1523
1524 if (m_program == 0 && !m_pFormatContext->nb_programs)
1525 return false;
1526
1527 if(m_pFormatContext->programs[m_program]->nb_stream_indexes != m_streams.size())
1528 return true;
1529
1530 if (m_program >= m_pFormatContext->nb_programs)
1531 return true;
1532
1533 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
1534 {
1535 int idx = m_pFormatContext->programs[m_program]->stream_index[i];
1536 CDemuxStream *stream = GetStreamInternal(idx);
1537 if(!stream)
1538 return true;
1539 if(m_pFormatContext->streams[idx]->codec->codec_type != stream->orig_type)
1540 return true;
1541 }
1542 return false;
1543}
1544
1545std::string CDVDDemuxFFmpeg::GetStereoModeFromMetadata(AVDictionary *pMetadata)
1546{
1547 std::string stereoMode;
1548 AVDictionaryEntry *tag = NULL;
1549
1550 // matroska
1551 tag = av_dict_get(pMetadata, "stereo_mode", NULL, 0);
1552 if (tag && tag->value)
1553 stereoMode = tag->value;
1554
1555 // asf / wmv
1556 if (stereoMode.empty())
1557 {
1558 tag = av_dict_get(pMetadata, "Stereoscopic", NULL, 0);
1559 if (tag && tag->value)
1560 {
1561 tag = av_dict_get(pMetadata, "StereoscopicLayout", NULL, 0);
1562 if (tag && tag->value)
1563 stereoMode = ConvertCodecToInternalStereoMode(tag->value, WmvToInternalStereoModeMap);
1564 }
1565 }
1566
1567 return stereoMode;
1568}
1569
1570std::string CDVDDemuxFFmpeg::ConvertCodecToInternalStereoMode(const std::string &mode, const StereoModeConversionMap *conversionMap)
1571{
1572 size_t i = 0;
1573 while (conversionMap[i].name)
1574 {
1575 if (mode == conversionMap[i].name)
1576 return conversionMap[i].mode;
1577 i++;
1578 }
1579 return "";
1580}
1581
1582void CDVDDemuxFFmpeg::ParsePacket(AVPacket *pkt)
1583{
1584 AVStream *st = m_pFormatContext->streams[pkt->stream_index];
1585 CDemuxStream *stream = GetStreamInternal(pkt->stream_index);
1586
1587 // if the stream is new, tell ffmpeg to parse the stream
1588 if (!stream && !st->parser)
1589 {
1590 st->need_parsing = AVSTREAM_PARSE_FULL;
1591 }
1592
1593 // split extradata
1594 if(st->parser && st->parser->parser->split && !st->codec->extradata)
1595 {
1596 int i = st->parser->parser->split(st->codec, pkt->data, pkt->size);
1597 if (i > 0 && i < FF_MAX_EXTRADATA_SIZE)
1598 {
1599 // Found extradata, fill it in. This will cause
1600 // a new stream to be created and used.
1601 st->codec->extradata_size = i;
1602 st->codec->extradata = (uint8_t*)av_malloc(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
1603 if (st->codec->extradata)
1604 {
1605 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::Read() fetching extradata, extradata_size(%d)", st->codec->extradata_size);
1606 memcpy(st->codec->extradata, pkt->data, st->codec->extradata_size);
1607 memset(st->codec->extradata + i, 0, FF_INPUT_BUFFER_PADDING_SIZE);
1608 }
1609 else
1610 {
1611 st->codec->extradata_size = 0;
1612 }
1613 }
1614 }
1615
1616 // for video we need a decoder to get desired information into codec context
1617 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO && st->codec->extradata &&
1618 (!st->codec->width || st->codec->pix_fmt == PIX_FMT_NONE))
1619 {
1620 // open a decoder, it will be cleared down by ffmpeg on closing the stream
1621 if (!st->codec->codec)
1622 {
1623 const AVCodec* codec;
1624 AVDictionary *thread_opt = NULL;
1625 codec = avcodec_find_decoder(st->codec->codec_id);
1626 // Force thread count to 1 since the h264 decoder will not extract
1627 // SPS and PPS to extradata during multi-threaded decoding
1628 av_dict_set(&thread_opt, "threads", "1", 0);
1629 int res = avcodec_open2(st->codec, codec, &thread_opt);
1630 if(res < 0)
1631 CLog::Log(LOGERROR, "CDVDDemuxFFmpeg::ParsePacket() unable to open codec %d", res);
1632 av_dict_free(&thread_opt);
1633 }
1634
1635 // We don't need to actually decode here
1636 // we just want to transport SPS data into codec context
1637 st->codec->skip_idct = AVDISCARD_ALL;
1638 // extradata is not decoded if skip_frame >= AVDISCARD_NONREF
1639// st->codec->skip_frame = AVDISCARD_ALL;
1640 st->codec->skip_loop_filter = AVDISCARD_ALL;
1641
1642 // We are looking for an IDR frame
1643 AVFrame picture;
1644 memset(&picture, 0, sizeof(AVFrame));
1645 picture.pts = picture.pkt_dts = picture.pkt_pts = picture.best_effort_timestamp = AV_NOPTS_VALUE;
1646 picture.pkt_pos = -1;
1647 picture.key_frame = 1;
1648 picture.format = -1;
1649
1650 int got_picture = 0;
1651 avcodec_decode_video2(st->codec, &picture, &got_picture, pkt);
1652 }
1653}
1654
1655bool CDVDDemuxFFmpeg::IsVideoReady()
1656{
1657 AVStream *st;
1658 bool hasVideo = false;
1659
1660 if(!m_checkvideo)
1661 return true;
1662
1663 if (m_program == 0 && !m_pFormatContext->nb_programs)
1664 return false;
1665
1666 if(m_program != UINT_MAX)
1667 {
1668 for (unsigned int i = 0; i < m_pFormatContext->programs[m_program]->nb_stream_indexes; i++)
1669 {
1670 int idx = m_pFormatContext->programs[m_program]->stream_index[i];
1671 st = m_pFormatContext->streams[idx];
1672 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
1673 {
1674 if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE)
1675 return true;
1676 hasVideo = true;
1677 }
1678 }
1679 }
1680 else
1681 {
1682 for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
1683 {
1684 st = m_pFormatContext->streams[i];
1685 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
1686 {
1687 if (st->codec->width && st->codec->pix_fmt != PIX_FMT_NONE)
1688 return true;
1689 hasVideo = true;
1690 }
1691 }
1692 }
1693 return !hasVideo;
1694}
1695
1696void CDVDDemuxFFmpeg::ResetVideoStreams()
1697{
1698 AVStream *st;
1699 for (unsigned int i = 0; i < m_pFormatContext->nb_streams; i++)
1700 {
1701 st = m_pFormatContext->streams[i];
1702 if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)
1703 {
1704 if (st->codec->extradata)
1705 av_free(st->codec->extradata);
1706 st->codec->extradata = NULL;
1707 st->codec->width = 0;
1708 }
1709 }
1710}
1711
1712void CDVDDemuxFFmpeg::GetL16Parameters(int &channels, int &samplerate)
1713{
1714 std::string content;
1715 if (XFILE::CCurlFile::GetContentType(m_pInput->GetURL(), content))
1716 {
1717 StringUtils::ToLower(content);
1718 const size_t len = content.length();
1719 size_t pos = content.find(';');
1720 while (pos < len)
1721 {
1722 // move to the next non-whitespace character
1723 pos = content.find_first_not_of(" \t", pos + 1);
1724
1725 if (pos != std::string::npos)
1726 {
1727 if (content.compare(pos, 9, "channels=", 9) == 0)
1728 {
1729 pos += 9; // move position to char after 'channels='
1730 size_t len = content.find(';', pos);
1731 if (len != std::string::npos)
1732 len -= pos;
1733 std::string no_channels(content, pos, len);
1734 // as we don't support any charset with ';' in name
1735 StringUtils::Trim(no_channels, " \t");
1736 if (!no_channels.empty())
1737 {
1738 int val = strtol(no_channels.c_str(), NULL, 0);
1739 if (val > 0)
1740 channels = val;
1741 else
1742 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::%s - no parameter for channels", __FUNCTION__);
1743 }
1744 }
1745 else if (content.compare(pos, 5, "rate=", 5) == 0)
1746 {
1747 pos += 5; // move position to char after 'rate='
1748 size_t len = content.find(';', pos);
1749 if (len != std::string::npos)
1750 len -= pos;
1751 std::string rate(content, pos, len);
1752 // as we don't support any charset with ';' in name
1753 StringUtils::Trim(rate, " \t");
1754 if (!rate.empty())
1755 {
1756 int val = strtol(rate.c_str(), NULL, 0);
1757 if (val > 0)
1758 samplerate = val;
1759 else
1760 CLog::Log(LOGDEBUG, "CDVDDemuxFFmpeg::%s - no parameter for samplerate", __FUNCTION__);
1761 }
1762 }
1763 pos = content.find(';', pos); // find next parameter
1764 }
1765 }
1766 }
1767}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
new file mode 100644
index 0000000..d180e40
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxFFmpeg.h
@@ -0,0 +1,172 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemux.h"
24#include "threads/CriticalSection.h"
25#include "threads/SystemClock.h"
26#include <map>
27#include <vector>
28
29extern "C" {
30#include "libavformat/avformat.h"
31}
32
33class CDVDDemuxFFmpeg;
34class CURL;
35
36class CDemuxStreamVideoFFmpeg
37 : public CDemuxStreamVideo
38{
39 CDVDDemuxFFmpeg *m_parent;
40 AVStream* m_stream;
41public:
42 CDemuxStreamVideoFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream)
43 : m_parent(parent)
44 , m_stream(stream)
45 {}
46 virtual void GetStreamInfo(std::string& strInfo);
47};
48
49
50class CDemuxStreamAudioFFmpeg
51 : public CDemuxStreamAudio
52{
53 CDVDDemuxFFmpeg *m_parent;
54 AVStream* m_stream;
55public:
56 CDemuxStreamAudioFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream)
57 : m_parent(parent)
58 , m_stream(stream)
59 {}
60 std::string m_description;
61
62 virtual void GetStreamInfo(std::string& strInfo);
63 virtual void GetStreamName(std::string& strInfo);
64};
65
66class CDemuxStreamSubtitleFFmpeg
67 : public CDemuxStreamSubtitle
68{
69 CDVDDemuxFFmpeg *m_parent;
70 AVStream* m_stream;
71public:
72 CDemuxStreamSubtitleFFmpeg(CDVDDemuxFFmpeg *parent, AVStream* stream)
73 : m_parent(parent)
74 , m_stream(stream)
75 {}
76 std::string m_description;
77
78 virtual void GetStreamInfo(std::string& strInfo);
79 virtual void GetStreamName(std::string& strInfo);
80
81};
82
83#define FFMPEG_FILE_BUFFER_SIZE 32768 // default reading size for ffmpeg
84#define FFMPEG_DVDNAV_BUFFER_SIZE 2048 // for dvd's
85
86struct StereoModeConversionMap;
87
88class CDVDDemuxFFmpeg : public CDVDDemux
89{
90public:
91 CDVDDemuxFFmpeg();
92 virtual ~CDVDDemuxFFmpeg();
93
94 bool Open(CDVDInputStream* pInput, bool streaminfo = true, bool fileinfo = false);
95 void Dispose();
96 void Reset();
97 void Flush();
98 void Abort();
99 void SetSpeed(int iSpeed);
100 virtual std::string GetFileName();
101
102 DemuxPacket* Read();
103
104 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
105 bool SeekByte(int64_t pos);
106 int GetStreamLength();
107 CDemuxStream* GetStream(int iStreamId);
108 int GetNrOfStreams();
109
110 bool SeekChapter(int chapter, double* startpts = NULL);
111 int GetChapterCount();
112 int GetChapter();
113 void GetChapterName(std::string& strChapterName, int chapterIdx=-1);
114 int64_t GetChapterPos(int chapterIdx=-1);
115 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
116
117 bool Aborted();
118
119 AVFormatContext* m_pFormatContext;
120 CDVDInputStream* m_pInput;
121
122protected:
123 friend class CDemuxStreamAudioFFmpeg;
124 friend class CDemuxStreamVideoFFmpeg;
125 friend class CDemuxStreamSubtitleFFmpeg;
126
127 int ReadFrame(AVPacket *packet);
128 CDemuxStream* AddStream(int iId);
129 void AddStream(int iId, CDemuxStream* stream);
130 CDemuxStream* GetStreamInternal(int iStreamId);
131 void CreateStreams(unsigned int program = UINT_MAX);
132 void DisposeStreams();
133 void ParsePacket(AVPacket *pkt);
134 bool IsVideoReady();
135 void ResetVideoStreams();
136
137 AVDictionary *GetFFMpegOptionsFromURL(const CURL &url);
138 double ConvertTimestamp(int64_t pts, int den, int num);
139 void UpdateCurrentPTS();
140 bool IsProgramChange();
141
142 std::string GetStereoModeFromMetadata(AVDictionary *pMetadata);
143 std::string ConvertCodecToInternalStereoMode(const std::string &mode, const StereoModeConversionMap *conversionMap);
144
145 void GetL16Parameters(int &channels, int &samplerate);
146
147 CCriticalSection m_critSection;
148 std::map<int, CDemuxStream*> m_streams;
149 std::vector<std::map<int, CDemuxStream*>::iterator> m_stream_index;
150
151 AVIOContext* m_ioContext;
152
153 double m_currentPts; // used for stream length estimation
154 bool m_bMatroska;
155 bool m_bAVI;
156 int m_speed;
157 unsigned m_program;
158 XbmcThreads::EndTime m_timeout;
159
160 // Due to limitations of ffmpeg, we only can detect a program change
161 // with a packet. This struct saves the packet for the next read and
162 // signals STREAMCHANGE to player
163 struct
164 {
165 AVPacket pkt; // packet ffmpeg returned
166 int result; // result from av_read_packet
167 }m_pkt;
168
169 bool m_streaminfo;
170 bool m_checkvideo;
171};
172
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp
new file mode 100644
index 0000000..3674416
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.cpp
@@ -0,0 +1,391 @@
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
22#include "DVDCodecs/DVDCodecs.h"
23#include "DVDInputStreams/DVDInputStream.h"
24#include "DVDInputStreams/DVDInputStreamHTSP.h"
25#include "DVDDemuxHTSP.h"
26#include "DVDDemuxUtils.h"
27#include "DVDClock.h"
28#include "dialogs/GUIDialogKaiToast.h"
29#include "utils/log.h"
30#include "utils/StringUtils.h"
31#include <arpa/inet.h>
32
33extern "C" {
34#include "lib/libhts/net.h"
35#include "lib/libhts/htsmsg.h"
36#include "lib/libhts/htsmsg_binary.h"
37}
38
39using namespace std;
40using namespace HTSP;
41
42class CDemuxStreamVideoHTSP
43 : public CDemuxStreamVideo
44{
45 CDVDDemuxHTSP *m_parent;
46 string m_codec;
47public:
48 CDemuxStreamVideoHTSP(CDVDDemuxHTSP *parent, const string& codec)
49 : m_parent(parent)
50 , m_codec(codec)
51 {}
52 void GetStreamInfo(std::string& strInfo)
53 {
54 strInfo = StringUtils::Format("%s, delay: %u, drops: %ub %up %ui"
55 , m_codec.c_str()
56 , m_parent->m_QueueStatus.delay
57 , m_parent->m_QueueStatus.bdrops
58 , m_parent->m_QueueStatus.pdrops
59 , m_parent->m_QueueStatus.idrops);
60 }
61};
62
63class CDemuxStreamAudioHTSP
64 : public CDemuxStreamAudio
65{
66 CDVDDemuxHTSP *m_parent;
67 string m_codec;
68public:
69 CDemuxStreamAudioHTSP(CDVDDemuxHTSP *parent, const string& codec)
70 : m_parent(parent)
71 , m_codec(codec)
72
73 {}
74 void GetStreamInfo(string& strInfo)
75 {
76 strInfo = StringUtils::Format("%s", m_codec.c_str());
77 }
78};
79
80CDVDDemuxHTSP::CDVDDemuxHTSP()
81 : CDVDDemux()
82 , m_Input(NULL)
83 , m_StatusCount(0)
84{
85}
86
87CDVDDemuxHTSP::~CDVDDemuxHTSP()
88{
89 Dispose();
90}
91
92bool CDVDDemuxHTSP::Open(CDVDInputStream* input)
93{
94 Dispose();
95
96 if(!input->IsStreamType(DVDSTREAM_TYPE_HTSP))
97 return false;
98
99 m_Input = (CDVDInputStreamHTSP*)input;
100 m_StatusCount = 0;
101
102 while(m_Streams.empty() && m_StatusCount == 0)
103 {
104 DemuxPacket* pkg = Read();
105 if(!pkg)
106 return false;
107 CDVDDemuxUtils::FreeDemuxPacket(pkg);
108 }
109
110 return true;
111}
112
113void CDVDDemuxHTSP::Dispose()
114{
115}
116
117void CDVDDemuxHTSP::Reset()
118{
119}
120
121
122void CDVDDemuxHTSP::Flush()
123{
124}
125
126bool CDVDDemuxHTSP::ReadStream(uint8_t* buf, int len)
127{
128 while(len > 0)
129 {
130 int ret = m_Input->Read(buf, len);
131 if(ret <= 0)
132 return false;
133 len -= ret;
134 buf += ret;
135 }
136 return true;
137}
138
139htsmsg_t* CDVDDemuxHTSP::ReadStream()
140{
141 if(m_Input->IsStreamType(DVDSTREAM_TYPE_HTSP))
142 return ((CDVDInputStreamHTSP*)m_Input)->ReadStream();
143
144 uint32_t l;
145 if(!ReadStream((uint8_t*)&l, 4))
146 return NULL;
147
148 l = ntohl(l);
149 if(l == 0)
150 return htsmsg_create_map();
151
152 uint8_t* buf = (uint8_t*)malloc(l);
153 if(!buf)
154 return NULL;
155
156 if(!ReadStream(buf, l))
157 return NULL;
158
159 return htsmsg_binary_deserialize(buf, l, buf); /* consumes 'buf' */
160}
161
162DemuxPacket* CDVDDemuxHTSP::Read()
163{
164 htsmsg_t * msg;
165 while((msg = ReadStream()))
166 {
167 const char* method = htsmsg_get_str(msg, "method");
168 if(method == NULL)
169 break;
170
171 if (strcmp("subscriptionStart", method) == 0)
172 SubscriptionStart(msg);
173 else if(strcmp("subscriptionStop", method) == 0)
174 SubscriptionStop (msg);
175 else if(strcmp("subscriptionStatus", method) == 0)
176 SubscriptionStatus(msg);
177 else if(strcmp("queueStatus" , method) == 0)
178 CHTSPSession::ParseQueueStatus(msg, m_QueueStatus);
179 else if(strcmp("muxpkt" , method) == 0)
180 {
181 uint32_t index, duration;
182 const void* bin;
183 size_t binlen;
184 int64_t ts;
185
186 if(htsmsg_get_u32(msg, "stream" , &index) ||
187 htsmsg_get_bin(msg, "payload", &bin, &binlen))
188 break;
189
190 DemuxPacket* pkt = CDVDDemuxUtils::AllocateDemuxPacket(binlen);
191
192 memcpy(pkt->pData, bin, binlen);
193 pkt->iSize = binlen;
194
195 if(!htsmsg_get_u32(msg, "duration", &duration))
196 pkt->duration = (double)duration * DVD_TIME_BASE / 1000000;
197
198 if(!htsmsg_get_s64(msg, "dts", &ts))
199 pkt->dts = (double)ts * DVD_TIME_BASE / 1000000;
200 else
201 pkt->dts = DVD_NOPTS_VALUE;
202
203 if(!htsmsg_get_s64(msg, "pts", &ts))
204 pkt->pts = (double)ts * DVD_TIME_BASE / 1000000;
205 else
206 pkt->pts = DVD_NOPTS_VALUE;
207
208 pkt->iStreamId = -1;
209 for(int i = 0; i < (int)m_Streams.size(); i++)
210 {
211 if(m_Streams[i]->iPhysicalId == (int)index)
212 {
213 pkt->iStreamId = i;
214 break;
215 }
216 }
217
218 htsmsg_destroy(msg);
219 return pkt;
220 }
221
222 break;
223 }
224
225 if(msg)
226 {
227 htsmsg_destroy(msg);
228 return CDVDDemuxUtils::AllocateDemuxPacket(0);
229 }
230 return NULL;
231}
232
233void CDVDDemuxHTSP::SubscriptionStart (htsmsg_t *m)
234{
235 htsmsg_t *streams;
236 htsmsg_t *info;
237 htsmsg_field_t *f;
238
239 if((info = htsmsg_get_map(m, "sourceinfo")))
240 {
241 HTSMSG_FOREACH(f, info)
242 {
243 if(f->hmf_type != HMF_STR)
244 continue;
245 CLog::Log(LOGDEBUG, "CDVDDemuxHTSP::SubscriptionStart - %s: %s", f->hmf_name, htsmsg_field_get_string(f));
246 }
247 }
248
249 if((streams = htsmsg_get_list(m, "streams")) == NULL)
250 {
251 CLog::Log(LOGERROR, "CDVDDemuxHTSP::SubscriptionStart - malformed message");
252 return;
253 }
254
255 for(int i = 0; i < (int)m_Streams.size(); i++)
256 delete m_Streams[i];
257 m_Streams.clear();
258
259 HTSMSG_FOREACH(f, streams)
260 {
261 uint32_t index;
262 const char* type;
263 const char* lang;
264 htsmsg_t* sub;
265
266 if(f->hmf_type != HMF_MAP)
267 continue;
268 sub = &f->hmf_msg;
269
270 if((type = htsmsg_get_str(sub, "type")) == NULL)
271 continue;
272
273 if(htsmsg_get_u32(sub, "index", &index))
274 continue;
275
276 union {
277 CDemuxStream* g;
278 CDemuxStreamAudio* a;
279 CDemuxStreamVideo* v;
280 CDemuxStreamSubtitle* s;
281 CDemuxStreamTeletext* t;
282 } st;
283
284 CLog::Log(LOGDEBUG, "CDVDDemuxHTSP::SubscriptionStart - id: %d, type: %s", index, type);
285
286 if(!strcmp(type, "AC3")) {
287 st.a = new CDemuxStreamAudioHTSP(this, type);
288 st.a->codec = AV_CODEC_ID_AC3;
289 } else if(!strcmp(type, "EAC3")) {
290 st.a = new CDemuxStreamAudioHTSP(this, type);
291 st.a->codec = AV_CODEC_ID_EAC3;
292 } else if(!strcmp(type, "MPEG2AUDIO")) {
293 st.a = new CDemuxStreamAudioHTSP(this, type);
294 st.a->codec = AV_CODEC_ID_MP2;
295 } else if(!strcmp(type, "AAC")) {
296 st.a = new CDemuxStreamAudioHTSP(this, type);
297 st.a->codec = AV_CODEC_ID_AAC;
298 } else if(!strcmp(type, "MPEG2VIDEO")) {
299 st.v = new CDemuxStreamVideoHTSP(this, type);
300 st.v->codec = AV_CODEC_ID_MPEG2VIDEO;
301 st.v->iWidth = htsmsg_get_u32_or_default(sub, "width" , 0);
302 st.v->iHeight = htsmsg_get_u32_or_default(sub, "height", 0);
303 } else if(!strcmp(type, "H264")) {
304 st.v = new CDemuxStreamVideoHTSP(this, type);
305 st.v->codec = AV_CODEC_ID_H264;
306 st.v->iWidth = htsmsg_get_u32_or_default(sub, "width" , 0);
307 st.v->iHeight = htsmsg_get_u32_or_default(sub, "height", 0);
308 } else if(!strcmp(type, "DVBSUB")) {
309 st.s = new CDemuxStreamSubtitle();
310 st.s->codec = AV_CODEC_ID_DVB_SUBTITLE;
311 uint32_t composition_id = 0, ancillary_id = 0;
312 htsmsg_get_u32(sub, "composition_id", &composition_id);
313 htsmsg_get_u32(sub, "ancillary_id" , &ancillary_id);
314 if(composition_id || ancillary_id)
315 {
316 st.s->ExtraData = new uint8_t[4];
317 st.s->ExtraSize = 4;
318 st.s->ExtraData[0] = (composition_id >> 8) & 0xff;
319 st.s->ExtraData[1] = (composition_id >> 0) & 0xff;
320 st.s->ExtraData[2] = (ancillary_id >> 8) & 0xff;
321 st.s->ExtraData[3] = (ancillary_id >> 0) & 0xff;
322 }
323 } else if(!strcmp(type, "TEXTSUB")) {
324 st.s = new CDemuxStreamSubtitle();
325 st.s->codec = AV_CODEC_ID_TEXT;
326 } else if(!strcmp(type, "TELETEXT")) {
327 st.t = new CDemuxStreamTeletext();
328 st.t->codec = AV_CODEC_ID_DVB_TELETEXT;
329 } else {
330 continue;
331 }
332
333 if((lang = htsmsg_get_str(sub, "language")))
334 {
335 strncpy(st.g->language, lang, sizeof(st.g->language));
336 st.g->language[sizeof(st.g->language) - 1] = '\0';
337 }
338
339 st.g->iId = m_Streams.size();
340 st.g->iPhysicalId = index;
341 m_Streams.push_back(st.g);
342 }
343}
344void CDVDDemuxHTSP::SubscriptionStop (htsmsg_t *m)
345{
346 for(int i = 0; i < (int)m_Streams.size(); i++)
347 delete m_Streams[i];
348 m_Streams.clear();
349}
350
351void CDVDDemuxHTSP::SubscriptionStatus(htsmsg_t *m)
352{
353 const char* status;
354 status = htsmsg_get_str(m, "status");
355 if(status == NULL)
356 m_Status = "";
357 else
358 {
359 m_StatusCount++;
360 m_Status = status;
361 CLog::Log(LOGDEBUG, "CDVDDemuxHTSP::SubscriptionStatus - %s", status);
362 CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Info, "TVHeadend Status", status, TOAST_DISPLAY_TIME, false);
363 }
364}
365
366CDemuxStream* CDVDDemuxHTSP::GetStream(int iStreamId)
367{
368 if(iStreamId >= 0 && iStreamId < (int)m_Streams.size())
369 return m_Streams[iStreamId];
370
371 return NULL;
372}
373
374int CDVDDemuxHTSP::GetNrOfStreams()
375{
376 return m_Streams.size();
377}
378
379std::string CDVDDemuxHTSP::GetFileName()
380{
381 if(m_Input)
382 return m_Input->GetFileName();
383 else
384 return "";
385}
386
387void CDVDDemuxHTSP::Abort()
388{
389 if(m_Input)
390 return m_Input->Abort();
391}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h
new file mode 100644
index 0000000..6d73a9d
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxHTSP.h
@@ -0,0 +1,68 @@
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#pragma once
22#include "DVDDemux.h"
23#include "filesystem/HTSPSession.h"
24
25class CDVDInputStreamHTSP;
26typedef struct htsmsg htsmsg_t;
27
28class CDVDDemuxHTSP : public CDVDDemux
29{
30public:
31 CDVDDemuxHTSP();
32 virtual ~CDVDDemuxHTSP();
33
34 bool Open(CDVDInputStream* input);
35 void Dispose();
36 void Reset();
37 void Flush();
38 void Abort();
39 void SetSpeed(int iSpeed){};
40
41 std::string GetFileName();
42
43 DemuxPacket* Read();
44
45 bool SeekTime(int time, bool backwords = false, double* startpts = NULL) { return false; }
46 int GetStreamLength() { return 0; }
47
48 CDemuxStream* GetStream(int iStreamId);
49 int GetNrOfStreams();
50
51protected:
52 friend class CDemuxStreamVideoHTSP;
53
54 void SubscriptionStart (htsmsg_t *m);
55 void SubscriptionStop (htsmsg_t *m);
56 void SubscriptionStatus(htsmsg_t *m);
57
58 htsmsg_t* ReadStream();
59 bool ReadStream(uint8_t* buf, int len);
60
61 typedef std::vector<CDemuxStream*> TStreams;
62
63 CDVDInputStream* m_Input;
64 TStreams m_Streams;
65 std::string m_Status;
66 int m_StatusCount;
67 HTSP::SQueueStatus m_QueueStatus;
68};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
new file mode 100644
index 0000000..4ed2d5c
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
@@ -0,0 +1,493 @@
1/*
2 * Copyright (C) 2012-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 "DVDInputStreams/DVDInputStream.h"
22#include "DVDDemuxPVRClient.h"
23#include "DVDDemuxUtils.h"
24#include "utils/log.h"
25#include "pvr/PVRManager.h"
26#include "pvr/addons/PVRClients.h"
27#include "../DVDClock.h"
28
29#define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
30
31using namespace PVR;
32
33CDemuxStreamPVRInternal::CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent)
34 : m_parent(parent)
35 , m_parser(NULL)
36 , m_context(NULL)
37 , m_parser_split(false)
38{
39}
40
41CDemuxStreamPVRInternal::~CDemuxStreamPVRInternal()
42{
43 DisposeParser();
44}
45
46void CDemuxStreamPVRInternal::DisposeParser()
47{
48 if (m_parser)
49 {
50 av_parser_close(m_parser);
51 m_parser = NULL;
52 }
53 if (m_context)
54 {
55 avcodec_close(m_context);
56 m_context = NULL;
57 }
58}
59
60void CDemuxStreamVideoPVRClient::GetStreamInfo(std::string& strInfo)
61{
62 switch (codec)
63 {
64 case AV_CODEC_ID_MPEG2VIDEO:
65 strInfo = "mpeg2video";
66 break;
67 case AV_CODEC_ID_H264:
68 strInfo = "h264";
69 break;
70 default:
71 break;
72 }
73}
74
75void CDemuxStreamAudioPVRClient::GetStreamInfo(std::string& strInfo)
76{
77 switch (codec)
78 {
79 case AV_CODEC_ID_AC3:
80 strInfo = "ac3";
81 break;
82 case AV_CODEC_ID_EAC3:
83 strInfo = "eac3";
84 break;
85 case AV_CODEC_ID_MP2:
86 strInfo = "mpeg2audio";
87 break;
88 case AV_CODEC_ID_AAC:
89 strInfo = "aac";
90 break;
91 case AV_CODEC_ID_DTS:
92 strInfo = "dts";
93 break;
94 default:
95 break;
96 }
97}
98
99void CDemuxStreamSubtitlePVRClient::GetStreamInfo(std::string& strInfo)
100{
101}
102
103CDVDDemuxPVRClient::CDVDDemuxPVRClient() : CDVDDemux()
104{
105 m_pInput = NULL;
106 for (int i = 0; i < MAX_STREAMS; i++) m_streams[i] = NULL;
107}
108
109CDVDDemuxPVRClient::~CDVDDemuxPVRClient()
110{
111 Dispose();
112}
113
114bool CDVDDemuxPVRClient::Open(CDVDInputStream* pInput)
115{
116 Abort();
117
118 m_pInput = pInput;
119 if (!g_PVRClients->GetPlayingClient(m_pvrClient))
120 return false;
121
122 return true;
123}
124
125void CDVDDemuxPVRClient::Dispose()
126{
127 for (int i = 0; i < MAX_STREAMS; i++)
128 {
129 delete m_streams[i];
130 m_streams[i] = NULL;
131 }
132
133 m_pInput = NULL;
134}
135
136void CDVDDemuxPVRClient::DisposeStream(int iStreamId)
137{
138 if (iStreamId < 0 || iStreamId >= MAX_STREAMS)
139 return;
140 delete m_streams[iStreamId];
141 m_streams[iStreamId] = NULL;
142}
143
144void CDVDDemuxPVRClient::Reset()
145{
146 if(m_pInput && g_PVRManager.IsStarted())
147 m_pvrClient->DemuxReset();
148
149 CDVDInputStream* pInputStream = m_pInput;
150 Dispose();
151 Open(pInputStream);
152}
153
154void CDVDDemuxPVRClient::Abort()
155{
156 if(m_pInput)
157 m_pvrClient->DemuxAbort();
158}
159
160void CDVDDemuxPVRClient::Flush()
161{
162 if(m_pInput && g_PVRManager.IsStarted())
163 m_pvrClient->DemuxFlush();
164}
165
166void CDVDDemuxPVRClient::ParsePacket(DemuxPacket* pkt)
167{
168 CDemuxStream* st = m_streams[pkt->iStreamId];
169 if (st == NULL)
170 return;
171
172 if (st->ExtraSize)
173 return;
174
175 CDemuxStreamPVRInternal* pvr = dynamic_cast<CDemuxStreamPVRInternal*>(st);
176
177 if(pvr == NULL
178 || pvr->m_parser == NULL)
179 return;
180
181 if(pvr->m_context == NULL)
182 {
183 AVCodec *codec = avcodec_find_decoder(st->codec);
184 if (codec == NULL)
185 {
186 CLog::Log(LOGERROR, "%s - can't find decoder", __FUNCTION__);
187 pvr->DisposeParser();
188 return;
189 }
190
191 pvr->m_context = avcodec_alloc_context3(codec);
192 if(pvr->m_context == NULL)
193 {
194 CLog::Log(LOGERROR, "%s - can't allocate context", __FUNCTION__);
195 pvr->DisposeParser();
196 return;
197 }
198 pvr->m_context->time_base.num = 1;
199 pvr->m_context->time_base.den = DVD_TIME_BASE;
200 }
201
202 if(pvr->m_parser_split && pvr->m_parser->parser->split)
203 {
204 int len = pvr->m_parser->parser->split(pvr->m_context, pkt->pData, pkt->iSize);
205 if (len > 0 && len < FF_MAX_EXTRADATA_SIZE)
206 {
207 if (st->ExtraData)
208 delete[] (uint8_t*)st->ExtraData;
209 st->changes++;
210 st->disabled = false;
211 st->ExtraSize = len;
212 st->ExtraData = new uint8_t[len+FF_INPUT_BUFFER_PADDING_SIZE];
213 memcpy(st->ExtraData, pkt->pData, len);
214 memset((uint8_t*)st->ExtraData + len, 0 , FF_INPUT_BUFFER_PADDING_SIZE);
215 pvr->m_parser_split = false;
216 }
217 }
218
219
220 uint8_t *outbuf = NULL;
221 int outbuf_size = 0;
222 int len = av_parser_parse2(pvr->m_parser
223 , pvr->m_context, &outbuf, &outbuf_size
224 , pkt->pData, pkt->iSize
225 , (int64_t)(pkt->pts * DVD_TIME_BASE)
226 , (int64_t)(pkt->dts * DVD_TIME_BASE)
227 , 0);
228 /* our parse is setup to parse complete frames, so we don't care about outbufs */
229 if(len >= 0)
230 {
231#define CHECK_UPDATE(st, trg, src, invalid) do { \
232 if(src != invalid \
233 && src != st->trg) { \
234 CLog::Log(LOGDEBUG, "%s - {%d} " #trg " changed from %d to %d", __FUNCTION__, st->iId, st->trg, src); \
235 st->trg = src; \
236 st->changes++; \
237 st->disabled = false; \
238 } \
239 } while(0)
240
241
242 CHECK_UPDATE(st, profile, pvr->m_context->profile , FF_PROFILE_UNKNOWN);
243 CHECK_UPDATE(st, level , pvr->m_context->level , FF_LEVEL_UNKNOWN);
244
245 switch (st->type)
246 {
247 case STREAM_AUDIO: {
248 CDemuxStreamAudioPVRClient* sta = static_cast<CDemuxStreamAudioPVRClient*>(st);
249 CHECK_UPDATE(sta, iChannels , pvr->m_context->channels , 0);
250 CHECK_UPDATE(sta, iSampleRate , pvr->m_context->sample_rate, 0);
251 break;
252 }
253 case STREAM_VIDEO: {
254 CDemuxStreamVideoPVRClient* stv = static_cast<CDemuxStreamVideoPVRClient*>(st);
255 CHECK_UPDATE(stv, iWidth , pvr->m_context->width , 0);
256 CHECK_UPDATE(stv, iHeight , pvr->m_context->height, 0);
257 break;
258 }
259
260 default:
261 break;
262 }
263
264#undef CHECK_UPDATE
265 }
266 else
267 CLog::Log(LOGDEBUG, "%s - parser returned error %d", __FUNCTION__, len);
268
269 return;
270}
271
272DemuxPacket* CDVDDemuxPVRClient::Read()
273{
274 if (!g_PVRManager.IsStarted())
275 return CDVDDemuxUtils::AllocateDemuxPacket(0);
276
277 DemuxPacket* pPacket = m_pvrClient->DemuxRead();
278 if (!pPacket)
279 {
280 if (m_pInput)
281 m_pInput->Close();
282 return NULL;
283 }
284
285 if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO)
286 {
287 RequestStreams();
288 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
289 return CDVDDemuxUtils::AllocateDemuxPacket(0);
290 }
291 else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE)
292 {
293 RequestStreams();
294 }
295 else if (pPacket->iStreamId >= 0
296 && pPacket->iStreamId < MAX_STREAMS
297 && m_streams[pPacket->iStreamId])
298 {
299 ParsePacket(pPacket);
300 }
301
302 return pPacket;
303}
304
305CDemuxStream* CDVDDemuxPVRClient::GetStream(int iStreamId)
306{
307 if (iStreamId < 0 || iStreamId >= MAX_STREAMS) return NULL;
308 return m_streams[iStreamId];
309}
310
311void CDVDDemuxPVRClient::RequestStreams()
312{
313 if (!g_PVRManager.IsStarted())
314 return;
315
316 PVR_STREAM_PROPERTIES props = {};
317 m_pvrClient->GetStreamProperties(&props);
318 unsigned int i;
319
320 for (i = 0; i < props.iStreamCount; ++i)
321 {
322 CDemuxStream *stm = m_streams[i];
323
324 if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_AUDIO)
325 {
326 CDemuxStreamAudioPVRClient* st = NULL;
327 if (stm)
328 {
329 st = dynamic_cast<CDemuxStreamAudioPVRClient*>(stm);
330 if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
331 DisposeStream(i);
332 }
333 if (!m_streams[i])
334 {
335 st = new CDemuxStreamAudioPVRClient(this);
336 st->m_parser = av_parser_init(props.stream[i].iCodecId);
337 if(st->m_parser)
338 st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
339 }
340 st->iChannels = props.stream[i].iChannels;
341 st->iSampleRate = props.stream[i].iSampleRate;
342 st->iBlockAlign = props.stream[i].iBlockAlign;
343 st->iBitRate = props.stream[i].iBitRate;
344 st->iBitsPerSample = props.stream[i].iBitsPerSample;
345 m_streams[i] = st;
346 st->m_parser_split = true;
347 st->changes++;
348 }
349 else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_VIDEO)
350 {
351 CDemuxStreamVideoPVRClient* st = NULL;
352 if (stm)
353 {
354 st = dynamic_cast<CDemuxStreamVideoPVRClient*>(stm);
355 if (!st
356 || (st->codec != (AVCodecID)props.stream[i].iCodecId)
357 || (st->iWidth != props.stream[i].iWidth)
358 || (st->iHeight != props.stream[i].iHeight))
359 DisposeStream(i);
360 }
361 if (!m_streams[i])
362 {
363 st = new CDemuxStreamVideoPVRClient(this);
364 st->m_parser = av_parser_init(props.stream[i].iCodecId);
365 if(st->m_parser)
366 st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
367 }
368 st->iFpsScale = props.stream[i].iFPSScale;
369 st->iFpsRate = props.stream[i].iFPSRate;
370 st->iHeight = props.stream[i].iHeight;
371 st->iWidth = props.stream[i].iWidth;
372 st->fAspect = props.stream[i].fAspect;
373 st->stereo_mode = "mono";
374 m_streams[i] = st;
375 st->m_parser_split = true;
376 }
377 else if (props.stream[i].iCodecId == AV_CODEC_ID_DVB_TELETEXT)
378 {
379 if (stm)
380 {
381 if (stm->codec != (AVCodecID)props.stream[i].iCodecId)
382 DisposeStream(i);
383 }
384 if (!m_streams[i])
385 m_streams[i] = new CDemuxStreamTeletext();
386 }
387 else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_SUBTITLE)
388 {
389 CDemuxStreamSubtitlePVRClient* st = NULL;
390 if (stm)
391 {
392 st = dynamic_cast<CDemuxStreamSubtitlePVRClient*>(stm);
393 if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
394 DisposeStream(i);
395 }
396 if (!m_streams[i])
397 {
398 st = new CDemuxStreamSubtitlePVRClient(this);
399 }
400 if(props.stream[i].iIdentifier)
401 {
402 st->ExtraData = new uint8_t[4];
403 st->ExtraSize = 4;
404 st->ExtraData[0] = (props.stream[i].iIdentifier >> 8) & 0xff;
405 st->ExtraData[1] = (props.stream[i].iIdentifier >> 0) & 0xff;
406 st->ExtraData[2] = (props.stream[i].iIdentifier >> 24) & 0xff;
407 st->ExtraData[3] = (props.stream[i].iIdentifier >> 16) & 0xff;
408 }
409 m_streams[i] = st;
410 }
411 else
412 {
413 if (m_streams[i])
414 DisposeStream(i);
415 m_streams[i] = new CDemuxStream();
416 }
417
418 m_streams[i]->codec = (AVCodecID)props.stream[i].iCodecId;
419 m_streams[i]->iId = i;
420 m_streams[i]->iPhysicalId = props.stream[i].iPhysicalId;
421 m_streams[i]->language[0] = props.stream[i].strLanguage[0];
422 m_streams[i]->language[1] = props.stream[i].strLanguage[1];
423 m_streams[i]->language[2] = props.stream[i].strLanguage[2];
424 m_streams[i]->language[3] = props.stream[i].strLanguage[3];
425
426 CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): added/updated stream %d:%d with codec_id %d",
427 m_streams[i]->iId,
428 m_streams[i]->iPhysicalId,
429 m_streams[i]->codec);
430 }
431 // check if we need to dispose any streams no longer in props
432 for (unsigned int j = i; j < MAX_STREAMS; j++)
433 {
434 if (m_streams[j])
435 {
436 CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): disposed stream %d:%d with codec_id %d",
437 m_streams[j]->iId,
438 m_streams[j]->iPhysicalId,
439 m_streams[j]->codec);
440 DisposeStream(j);
441 }
442 }
443}
444
445int CDVDDemuxPVRClient::GetNrOfStreams()
446{
447 int i = 0;
448 while (i < MAX_STREAMS && m_streams[i]) i++;
449 return i;
450}
451
452std::string CDVDDemuxPVRClient::GetFileName()
453{
454 if(m_pInput)
455 return m_pInput->GetFileName();
456 else
457 return "";
458}
459
460void CDVDDemuxPVRClient::GetStreamCodecName(int iStreamId, std::string &strName)
461{
462 CDemuxStream *stream = GetStream(iStreamId);
463 if (stream)
464 {
465 if (stream->codec == AV_CODEC_ID_AC3)
466 strName = "ac3";
467 else if (stream->codec == AV_CODEC_ID_MP2)
468 strName = "mp2";
469 else if (stream->codec == AV_CODEC_ID_AAC)
470 strName = "aac";
471 else if (stream->codec == AV_CODEC_ID_DTS)
472 strName = "dca";
473 else if (stream->codec == AV_CODEC_ID_MPEG2VIDEO)
474 strName = "mpeg2video";
475 else if (stream->codec == AV_CODEC_ID_H264)
476 strName = "h264";
477 else if (stream->codec == AV_CODEC_ID_EAC3)
478 strName = "eac3";
479 }
480}
481
482bool CDVDDemuxPVRClient::SeekTime(int timems, bool backwards, double *startpts)
483{
484 if (m_pInput)
485 return m_pvrClient->SeekTime(timems, backwards, startpts);
486 return false;
487}
488
489void CDVDDemuxPVRClient::SetSpeed ( int speed )
490{
491 if (m_pInput)
492 m_pvrClient->SetSpeed(speed);
493}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h
new file mode 100644
index 0000000..2fc3c63
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.h
@@ -0,0 +1,118 @@
1#pragma once
2/*
3 * Copyright (C) 2012-2013 Team XBMC
4 * http://xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include "DVDDemux.h"
23#include <map>
24#include "pvr/addons/PVRClient.h"
25
26extern "C" {
27#include "libavcodec/avcodec.h"
28#include "libavformat/avformat.h"
29}
30
31class CDVDDemuxPVRClient;
32struct PVR_STREAM_PROPERTIES;
33
34class CDemuxStreamPVRInternal
35{
36public:
37 CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent);
38 ~CDemuxStreamPVRInternal();
39
40 void DisposeParser();
41
42 CDVDDemuxPVRClient * m_parent;
43 AVCodecParserContext* m_parser;
44 AVCodecContext * m_context;
45 bool m_parser_split;
46};
47
48class CDemuxStreamVideoPVRClient
49 : public CDemuxStreamVideo
50 , public CDemuxStreamPVRInternal
51{
52public:
53 CDemuxStreamVideoPVRClient(CDVDDemuxPVRClient *parent)
54 : CDemuxStreamPVRInternal(parent)
55 {}
56 virtual void GetStreamInfo(std::string& strInfo);
57};
58
59class CDemuxStreamAudioPVRClient
60 : public CDemuxStreamAudio
61 , public CDemuxStreamPVRInternal
62{
63public:
64 CDemuxStreamAudioPVRClient(CDVDDemuxPVRClient *parent)
65 : CDemuxStreamPVRInternal(parent)
66 {}
67 virtual void GetStreamInfo(std::string& strInfo);
68};
69
70class CDemuxStreamSubtitlePVRClient
71 : public CDemuxStreamSubtitle
72 , public CDemuxStreamPVRInternal
73{
74public:
75 CDemuxStreamSubtitlePVRClient(CDVDDemuxPVRClient *parent)
76 : CDemuxStreamPVRInternal(parent)
77 {}
78 virtual void GetStreamInfo(std::string& strInfo);
79};
80
81
82class CDVDDemuxPVRClient : public CDVDDemux
83{
84 friend class CDemuxStreamPVRInternal;
85
86public:
87
88 CDVDDemuxPVRClient();
89 ~CDVDDemuxPVRClient();
90
91 bool Open(CDVDInputStream* pInput);
92 void Dispose();
93 void Reset();
94 void Abort();
95 void Flush();
96 DemuxPacket* Read();
97 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
98 void SetSpeed(int iSpeed);
99 int GetStreamLength() { return 0; }
100 CDemuxStream* GetStream(int iStreamId);
101 int GetNrOfStreams();
102 std::string GetFileName();
103 virtual void GetStreamCodecName(int iStreamId, std::string &strName);
104
105protected:
106 CDVDInputStream* m_pInput;
107#ifndef MAX_STREAMS
108 #define MAX_STREAMS 100
109#endif
110 CDemuxStream* m_streams[MAX_STREAMS]; // maximum number of streams that ffmpeg can handle
111 std::shared_ptr<PVR::CPVRClient> m_pvrClient;
112
113private:
114 void RequestStreams();
115 void ParsePacket(DemuxPacket* pPacket);
116 void DisposeStream(int iStreamId);
117};
118
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
new file mode 100644
index 0000000..d64fbb3
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPacket.h
@@ -0,0 +1,36 @@
1#pragma once
2
3/*
4 * Copyright (C) 2012-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#define DMX_SPECIALID_STREAMINFO -10
24#define DMX_SPECIALID_STREAMCHANGE -11
25
26 typedef struct DemuxPacket
27{
28 unsigned char* pData; // data
29 int iSize; // data size
30 int iStreamId; // integer representing the stream index
31 int iGroupId; // the group this data belongs to, used to group data from different streams together
32
33 double pts; // pts in DVD_TIME_BASE
34 double dts; // dts in DVD_TIME_BASE
35 double duration; // duration in DVD_TIME_BASE if available
36} DemuxPacket;
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp
new file mode 100644
index 0000000..a69342a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.cpp
@@ -0,0 +1,199 @@
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 "DVDCodecs/DVDCodecs.h"
22#include "DVDInputStreams/DVDInputStreamHttp.h"
23#include "DVDDemuxShoutcast.h"
24#include "DVDDemuxUtils.h"
25#include "DVDClock.h" // for DVD_TIME_BASE
26#include "../../../utils/HttpHeader.h"
27
28#define ICY_NOTICE1 "icy-notice1" // string
29#define ICY_NOTICE2 "icy-notice2" // string
30#define ICY_NAME "icy-name" // string
31#define ICY_GENRE "icy-genre" // string
32#define ICY_URL "icy-url" // string
33#define ICY_PUBLIC "icy-pub" // int (1 / 0)
34#define ICY_BITRATE "icy-br" // int (bitrate = val * 1000 ?)
35#define ICY_METAINTERVAL "icy-metaint" // int
36
37#define CONTENT_TYPE_MP3 "audio/mpeg"
38#define CONTENT_TYPE_AAC "audio/aac"
39#define CONTENT_TYPE_AACPLUS "audio/aacp"
40
41// class CDemuxStreamVideoFFmpeg
42void CDemuxStreamAudioShoutcast::GetStreamInfo(std::string& strInfo)
43{
44 strInfo = "Shoutcast";
45}
46
47CDVDDemuxShoutcast::CDVDDemuxShoutcast() : CDVDDemux()
48{
49 m_pInput = NULL;
50 m_pDemuxStream = NULL;
51 m_iMetaStreamInterval = 0;
52}
53
54CDVDDemuxShoutcast::~CDVDDemuxShoutcast()
55{
56 Dispose();
57}
58
59bool CDVDDemuxShoutcast::Open(CDVDInputStream* pInput)
60{
61 Dispose();
62
63 m_pInput = pInput;
64
65 // the input stream should be a http stream
66 if (!pInput->IsStreamType(DVDSTREAM_TYPE_HTTP)) return false;
67 CDVDInputStreamHttp* pInputStreamHttp = (CDVDInputStreamHttp*)pInput;
68
69 CHttpHeader* pHeader = pInputStreamHttp->GetHttpHeader();
70
71 std::string strMetaInt = pHeader->GetValue(ICY_METAINTERVAL);
72 std::string strMimeType = pHeader->GetMimeType();
73
74 // create new demuxer stream
75 m_pDemuxStream = new CDemuxStreamAudioShoutcast();
76 m_pDemuxStream->iId = 0;
77 m_pDemuxStream->iPhysicalId = 0;
78 m_pDemuxStream->iDuration = 0;
79 m_pDemuxStream->iChannels = 2;
80 m_pDemuxStream->iSampleRate = 0;
81
82 // set meta interval
83 m_iMetaStreamInterval = atoi(strMetaInt.c_str());
84
85 if (stricmp(strMimeType.c_str(), CONTENT_TYPE_AAC) == 0 ||
86 stricmp(strMimeType.c_str(), CONTENT_TYPE_AACPLUS) == 0)
87 {
88 // need an aac decoder first
89 m_pDemuxStream->codec = AV_CODEC_ID_AAC;
90 }
91 else // (stricmp(strMimeType, CONTENT_TYPE_MP3) == 0)
92 {
93 // default to mp3
94 m_pDemuxStream->codec = AV_CODEC_ID_MP3;
95 }
96
97 return true;
98}
99
100void CDVDDemuxShoutcast::Dispose()
101{
102 if (m_pDemuxStream) delete m_pDemuxStream;
103 m_pDemuxStream = NULL;
104
105 m_pInput = NULL;
106}
107
108void CDVDDemuxShoutcast::Reset()
109{
110 CDVDInputStream* pInputStream = m_pInput;
111 Dispose();
112 Open(pInputStream);
113}
114
115void CDVDDemuxShoutcast::Flush()
116{
117}
118
119DemuxPacket* CDVDDemuxShoutcast::Read()
120{
121 // XXX
122 // if meta interval is greater than FileCurl's max read size (currently 64k)
123 // it will simply fail becuse the meta-interval will get incorrect
124
125 int iDataToRead = SHOUTCAST_BUFFER_SIZE;
126 if (m_iMetaStreamInterval > 0) iDataToRead = m_iMetaStreamInterval;
127
128 DemuxPacket* pPacket;
129 pPacket = CDVDDemuxUtils::AllocateDemuxPacket(iDataToRead);
130 if (pPacket)
131 {
132 pPacket->dts = DVD_NOPTS_VALUE;
133 pPacket->pts = DVD_NOPTS_VALUE;
134 pPacket->iStreamId = 0;
135
136 // read the data
137 int iRead = m_pInput->Read(pPacket->pData, iDataToRead);
138
139 pPacket->iSize = iRead;
140
141 if (iRead <= 0)
142 {
143 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
144 pPacket = NULL;
145 }
146 }
147
148 if (m_iMetaStreamInterval > 0)
149 {
150 // we already have read m_iMetaStreamInterval bytes of streaming data
151 // metadata follows
152 uint8_t l;
153 int iRead = m_pInput->Read(&l, 1);
154 if (iRead > 0)
155 {
156 int iMetaLength = l * 16;
157
158 if (iMetaLength > 0)
159 {
160 // iMetaLength cannot be larger then 16 * 255
161 uint8_t buffer[16 * 255];
162
163 // skip meta data for now
164 m_pInput->Read(buffer, iMetaLength);
165 }
166 }
167 }
168
169 return pPacket;
170}
171
172bool CDVDDemuxShoutcast::SeekTime(int time, bool backwords, double* startpts)
173{
174 return false;
175}
176
177int CDVDDemuxShoutcast::GetStreamLength()
178{
179 return 0;
180}
181
182CDemuxStream* CDVDDemuxShoutcast::GetStream(int iStreamId)
183{
184 return m_pDemuxStream;
185}
186
187int CDVDDemuxShoutcast::GetNrOfStreams()
188{
189 return 1;
190}
191
192std::string CDVDDemuxShoutcast::GetFileName()
193{
194 if(m_pInput)
195 return m_pInput->GetFileName();
196 else
197 return "";
198}
199
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h
new file mode 100644
index 0000000..a802167
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxShoutcast.h
@@ -0,0 +1,60 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemux.h"
24
25class CDemuxStreamAudioShoutcast : public CDemuxStreamAudio
26{
27public:
28 virtual void GetStreamInfo(std::string& strInfo);
29};
30
31#define SHOUTCAST_BUFFER_SIZE 1024 * 32
32
33class CDVDDemuxShoutcast : public CDVDDemux
34{
35public:
36 CDVDDemuxShoutcast();
37 virtual ~CDVDDemuxShoutcast();
38
39 bool Open(CDVDInputStream* pInput);
40 void Dispose();
41 void Reset();
42 void Flush();
43 void Abort(){}
44 void SetSpeed(int iSpeed){};
45 virtual std::string GetFileName();
46
47 DemuxPacket* Read();
48
49 bool SeekTime(int time, bool backwords = false, double* startpts = NULL);
50 int GetStreamLength();
51 CDemuxStream* GetStream(int iStreamId);
52 int GetNrOfStreams();
53
54protected:
55
56 CDemuxStreamAudioShoutcast* m_pDemuxStream;
57
58 int m_iMetaStreamInterval;
59 CDVDInputStream* m_pInput;
60};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp
new file mode 100644
index 0000000..ab298b2
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.cpp
@@ -0,0 +1,89 @@
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#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
22 #include "config.h"
23#endif
24#include "DVDDemuxUtils.h"
25#include "DVDClock.h"
26#include "utils/log.h"
27
28extern "C" {
29#include "libavcodec/avcodec.h"
30}
31
32void CDVDDemuxUtils::FreeDemuxPacket(DemuxPacket* pPacket)
33{
34 if (pPacket)
35 {
36 try {
37 if (pPacket->pData) _aligned_free(pPacket->pData);
38 delete pPacket;
39 }
40 catch(...) {
41 CLog::Log(LOGERROR, "%s - Exception thrown while freeing packet", __FUNCTION__);
42 }
43 }
44}
45
46DemuxPacket* CDVDDemuxUtils::AllocateDemuxPacket(int iDataSize)
47{
48 DemuxPacket* pPacket = new DemuxPacket;
49 if (!pPacket) return NULL;
50
51 try
52 {
53 memset(pPacket, 0, sizeof(DemuxPacket));
54
55 if (iDataSize > 0)
56 {
57 // need to allocate a few bytes more.
58 // From avcodec.h (ffmpeg)
59 /**
60 * Required number of additionally allocated bytes at the end of the input bitstream for decoding.
61 * this is mainly needed because some optimized bitstream readers read
62 * 32 or 64 bit at once and could read over the end<br>
63 * Note, if the first 23 bits of the additional bytes are not 0 then damaged
64 * MPEG bitstreams could cause overread and segfault
65 */
66 pPacket->pData =(uint8_t*)_aligned_malloc(iDataSize + FF_INPUT_BUFFER_PADDING_SIZE, 16);
67 if (!pPacket->pData)
68 {
69 FreeDemuxPacket(pPacket);
70 return NULL;
71 }
72
73 // reset the last 8 bytes to 0;
74 memset(pPacket->pData + iDataSize, 0, FF_INPUT_BUFFER_PADDING_SIZE);
75 }
76
77 // setup defaults
78 pPacket->dts = DVD_NOPTS_VALUE;
79 pPacket->pts = DVD_NOPTS_VALUE;
80 pPacket->iStreamId = -1;
81 }
82 catch(...)
83 {
84 CLog::Log(LOGERROR, "%s - Exception thrown", __FUNCTION__);
85 FreeDemuxPacket(pPacket);
86 pPacket = NULL;
87 }
88 return pPacket;
89}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h
new file mode 100644
index 0000000..2c12df3
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxUtils.h
@@ -0,0 +1,31 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemuxPacket.h"
24
25class CDVDDemuxUtils
26{
27public:
28 static void FreeDemuxPacket(DemuxPacket* pPacket);
29 static DemuxPacket* AllocateDemuxPacket(int iDataSize = 0);
30};
31
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp
new file mode 100644
index 0000000..9625a19
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.cpp
@@ -0,0 +1,247 @@
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 "DVDDemuxVobsub.h"
22#include "DVDInputStreams/DVDFactoryInputStream.h"
23#include "DVDInputStreams/DVDInputStream.h"
24#include "DVDStreamInfo.h"
25#include "DVDCodecs/DVDCodecs.h"
26#include "DVDDemuxers/DVDDemuxFFmpeg.h"
27#include "DVDDemuxers/DVDDemuxUtils.h"
28#include "DVDClock.h"
29#include "DVDSubtitles/DVDSubtitleStream.h"
30
31#include <string.h>
32
33using namespace std;
34
35CDVDDemuxVobsub::CDVDDemuxVobsub()
36{
37}
38
39CDVDDemuxVobsub::~CDVDDemuxVobsub()
40{
41 for(unsigned i=0;i<m_Streams.size();i++)
42 {
43 delete m_Streams[i];
44 }
45 m_Streams.clear();
46}
47
48bool CDVDDemuxVobsub::Open(const string& filename, const string& subfilename)
49{
50 m_Filename = filename;
51
52 unique_ptr<CDVDSubtitleStream> pStream(new CDVDSubtitleStream());
53 if(!pStream->Open(filename))
54 return false;
55
56 string vobsub = subfilename;
57 if ( vobsub == "")
58 {
59 vobsub = filename;
60 vobsub.erase(vobsub.rfind('.'), vobsub.size());
61 vobsub += ".sub";
62 }
63
64 m_Input.reset(CDVDFactoryInputStream::CreateInputStream(NULL, vobsub, ""));
65 if(!m_Input.get() || !m_Input->Open(vobsub.c_str(), "video/x-vobsub"))
66 return false;
67
68 m_Demuxer.reset(new CDVDDemuxFFmpeg());
69 if(!m_Demuxer->Open(m_Input.get()))
70 return false;
71
72 CDVDStreamInfo hints;
73 CDVDCodecOptions options;
74 hints.codec = AV_CODEC_ID_DVD_SUBTITLE;
75
76 char line[2048];
77 DECLARE_UNUSED(bool,res)
78
79 SState state;
80 state.delay = 0;
81 state.id = -1;
82
83 while( pStream->ReadLine(line, sizeof(line)) )
84 {
85 if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#')
86 continue;
87 else if (strncmp("langidx:", line, 8) == 0)
88 res = ParseLangIdx(state, line + 8);
89 else if (strncmp("delay:", line, 6) == 0)
90 res = ParseDelay(state, line + 6);
91 else if (strncmp("id:", line, 3) == 0)
92 res = ParseId(state, line + 3);
93 else if (strncmp("timestamp:", line, 10) == 0)
94 res = ParseTimestamp(state, line + 10);
95 else if (strncmp("palette:", line, 8) == 0
96 || strncmp("size:", line, 5) == 0
97 || strncmp("org:", line, 4) == 0
98 || strncmp("custom colors:", line, 14) == 0
99 || strncmp("scale:", line, 6) == 0
100 || strncmp("alpha:", line, 6) == 0
101 || strncmp("fadein/out:", line, 11) == 0
102 || strncmp("forced subs:", line, 12) == 0)
103 res = ParseExtra(state, line);
104 else
105 continue;
106 }
107
108 struct sorter s;
109 sort(m_Timestamps.begin(), m_Timestamps.end(), s);
110 m_Timestamp = m_Timestamps.begin();
111
112 for(unsigned i=0;i<m_Streams.size();i++)
113 {
114 m_Streams[i]->ExtraSize = state.extra.length()+1;
115 m_Streams[i]->ExtraData = new uint8_t[m_Streams[i]->ExtraSize];
116 strcpy((char*)m_Streams[i]->ExtraData, state.extra.c_str());
117 }
118
119 return true;
120}
121
122void CDVDDemuxVobsub::Reset()
123{
124 Flush();
125}
126
127void CDVDDemuxVobsub::Flush()
128{
129 m_Demuxer->Flush();
130}
131
132bool CDVDDemuxVobsub::SeekTime(int time, bool backwords, double* startpts)
133{
134 double pts = DVD_MSEC_TO_TIME(time);
135 m_Timestamp = m_Timestamps.begin();
136 for(;m_Timestamp != m_Timestamps.end();++m_Timestamp)
137 {
138 if(m_Timestamp->pts > pts)
139 break;
140 }
141 for(unsigned i=0;i<m_Streams.size() && m_Timestamps.begin() != m_Timestamp;i++)
142 {
143 --m_Timestamp;
144 }
145 return true;
146}
147
148DemuxPacket* CDVDDemuxVobsub::Read()
149{
150 vector<STimestamp>::iterator current;
151 do {
152 if(m_Timestamp == m_Timestamps.end())
153 return NULL;
154
155 current = m_Timestamp++;
156 } while(m_Streams[current->id]->m_discard == AVDISCARD_ALL);
157
158 if(!m_Demuxer->SeekByte(current->pos))
159 return NULL;
160
161 DemuxPacket *packet = m_Demuxer->Read();
162 if(!packet)
163 return NULL;
164
165 packet->iStreamId = current->id;
166 packet->pts = current->pts;
167 packet->dts = current->pts;
168
169 return packet;
170}
171
172bool CDVDDemuxVobsub::ParseLangIdx(SState& state, char* line)
173{
174 return true;
175}
176
177bool CDVDDemuxVobsub::ParseDelay(SState& state, char* line)
178{
179 int h,m,s,ms;
180 bool negative = false;
181
182 while(*line == ' ') line++;
183 if(*line == '-')
184 {
185 line++;
186 negative = true;
187 }
188 if(sscanf(line, "%d:%d:%d:%d", &h, &m, &s, &ms) != 4)
189 return false;
190 state.delay = h*3600.0 + m*60.0 + s + ms*0.001;
191 if(negative)
192 state.delay *= -1;
193 return true;
194}
195
196bool CDVDDemuxVobsub::ParseId(SState& state, char* line)
197{
198 unique_ptr<CStream> stream(new CStream(this));
199
200 while(*line == ' ') line++;
201 strncpy(stream->language, line, 2);
202 stream->language[2] = '\0';
203 line+=2;
204
205 while(*line == ' ' || *line == ',') line++;
206 if (strncmp("index:", line, 6) == 0)
207 {
208 line+=6;
209 while(*line == ' ') line++;
210 stream->iPhysicalId = atoi(line);
211 }
212 else
213 stream->iPhysicalId = -1;
214
215 stream->codec = AV_CODEC_ID_DVD_SUBTITLE;
216 stream->iId = m_Streams.size();
217 stream->source = STREAM_SOURCE_DEMUX_SUB;
218
219 state.id = stream->iId;
220 m_Streams.push_back(stream.release());
221 return true;
222}
223
224bool CDVDDemuxVobsub::ParseExtra(SState& state, char* line)
225{
226 state.extra += line;
227 state.extra += '\n';
228 return true;
229}
230
231bool CDVDDemuxVobsub::ParseTimestamp(SState& state, char* line)
232{
233 if(state.id < 0)
234 return false;
235
236 int h,m,s,ms;
237 STimestamp timestamp;
238
239 while(*line == ' ') line++;
240 if(sscanf(line, "%d:%d:%d:%d, filepos:%" PRIx64, &h, &m, &s, &ms, &timestamp.pos) != 5)
241 return false;
242
243 timestamp.id = state.id;
244 timestamp.pts = DVD_SEC_TO_TIME(state.delay + h*3600.0 + m*60.0 + s + ms*0.001);
245 m_Timestamps.push_back(timestamp);
246 return true;
247}
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h
new file mode 100644
index 0000000..0c75c4a
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxVobsub.h
@@ -0,0 +1,99 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include "DVDDemux.h"
24
25#include <memory>
26#include <vector>
27
28class CDVDOverlayCodecFFmpeg;
29class CDVDInputStream;
30class CDVDDemuxFFmpeg;
31
32class CDVDDemuxVobsub : public CDVDDemux
33{
34public:
35 CDVDDemuxVobsub();
36 virtual ~CDVDDemuxVobsub();
37
38 virtual bool Open(const std::string& filename, const std::string& subfilename = "");
39 virtual void Reset();
40 virtual void Abort() {};
41 virtual void Flush();
42 virtual DemuxPacket* Read();
43 virtual bool SeekTime(int time, bool backwords, double* startpts = NULL);
44 virtual void SetSpeed(int speed) {}
45 virtual CDemuxStream* GetStream(int index) { return m_Streams[index]; }
46 virtual int GetNrOfStreams() { return m_Streams.size(); }
47 virtual int GetStreamLength() { return 0; }
48 virtual std::string GetFileName() { return m_Filename; }
49
50private:
51 class CStream
52 : public CDemuxStreamSubtitle
53 {
54 public:
55 CStream(CDVDDemuxVobsub* parent)
56 : m_discard(AVDISCARD_NONE), m_parent(parent)
57 {}
58 virtual void SetDiscard(AVDiscard discard) { m_discard = discard; }
59 virtual AVDiscard GetDiscard() { return m_discard; }
60
61 AVDiscard m_discard;
62 CDVDDemuxVobsub* m_parent;
63 };
64
65 typedef struct STimestamp
66 {
67 int64_t pos;
68 double pts;
69 int id;
70 } STimestamp;
71
72 std::string m_Filename;
73 std::unique_ptr<CDVDInputStream> m_Input;
74 std::unique_ptr<CDVDDemuxFFmpeg> m_Demuxer;
75 std::vector<STimestamp> m_Timestamps;
76 std::vector<STimestamp>::iterator m_Timestamp;
77 std::vector<CStream*> m_Streams;
78
79 typedef struct SState
80 {
81 int id;
82 double delay;
83 std::string extra;
84 } SState;
85
86 struct sorter
87 {
88 bool operator()(const STimestamp &p1, const STimestamp &p2)
89 {
90 return p1.pts < p2.pts || (p1.pts == p2.pts && p1.id < p2.id);
91 }
92 };
93
94 bool ParseLangIdx(SState& state, char* line);
95 bool ParseDelay(SState& state, char* line);
96 bool ParseId(SState& state, char* line);
97 bool ParseExtra(SState& state, char* line);
98 bool ParseTimestamp(SState& state, char* line);
99};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
new file mode 100644
index 0000000..f909c32
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.cpp
@@ -0,0 +1,153 @@
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 "system.h"
22#include "DVDFactoryDemuxer.h"
23
24#include "DVDInputStreams/DVDInputStream.h"
25#include "DVDInputStreams/DVDInputStreamHttp.h"
26#include "DVDInputStreams/DVDInputStreamPVRManager.h"
27
28#include "DVDDemuxFFmpeg.h"
29#include "DVDDemuxShoutcast.h"
30#ifdef HAS_FILESYSTEM_HTSP
31#include "DVDDemuxHTSP.h"
32#endif
33#include "DVDDemuxBXA.h"
34#include "DVDDemuxCDDA.h"
35#include "DVDDemuxPVRClient.h"
36#include "pvr/PVRManager.h"
37#include "pvr/addons/PVRClients.h"
38
39using namespace std;
40using namespace PVR;
41
42CDVDDemux* CDVDFactoryDemuxer::CreateDemuxer(CDVDInputStream* pInputStream, bool fileinfo)
43{
44 if (!pInputStream)
45 return NULL;
46
47 // Try to open the AirTunes demuxer
48 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("audio/x-xbmc-pcm") == 0 )
49 {
50 // audio/x-xbmc-pcm this is the used codec for AirTunes
51 // (apples audio only streaming)
52 unique_ptr<CDVDDemuxBXA> demuxer(new CDVDDemuxBXA());
53 if(demuxer->Open(pInputStream))
54 return demuxer.release();
55 else
56 return NULL;
57 }
58
59 // Try to open CDDA demuxer
60 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FILE) && pInputStream->GetContent().compare("application/octet-stream") == 0)
61 {
62 std::string filename = pInputStream->GetFileName();
63 if (filename.substr(0, 7) == "cdda://")
64 {
65 CLog::Log(LOGDEBUG, "DVDFactoryDemuxer: Stream is probably CD audio. Creating CDDA demuxer.");
66
67 unique_ptr<CDVDDemuxCDDA> demuxer(new CDVDDemuxCDDA());
68 if (demuxer->Open(pInputStream))
69 {
70 return demuxer.release();
71 }
72 }
73 }
74
75 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTTP))
76 {
77 CDVDInputStreamHttp* pHttpStream = (CDVDInputStreamHttp*)pInputStream;
78 CHttpHeader *header = pHttpStream->GetHttpHeader();
79
80 /* check so we got the meta information as requested in our http header */
81 if( header->GetValue("icy-metaint").length() > 0 )
82 {
83 unique_ptr<CDVDDemuxShoutcast> demuxer(new CDVDDemuxShoutcast());
84 if(demuxer->Open(pInputStream))
85 return demuxer.release();
86 else
87 return NULL;
88 }
89 }
90
91#ifdef HAS_FILESYSTEM_HTSP
92 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_HTSP))
93 {
94 unique_ptr<CDVDDemuxHTSP> demuxer(new CDVDDemuxHTSP());
95 if(demuxer->Open(pInputStream))
96 return demuxer.release();
97 else
98 return NULL;
99 }
100#endif
101
102 bool streaminfo = true; /* Look for streams before playback */
103 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_PVRMANAGER))
104 {
105 CDVDInputStreamPVRManager* pInputStreamPVR = (CDVDInputStreamPVRManager*)pInputStream;
106 CDVDInputStream* pOtherStream = pInputStreamPVR->GetOtherStream();
107
108 /* Don't parse the streaminfo for some cases of streams to reduce the channel switch time */
109 bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
110 streaminfo = !useFastswitch;
111
112 if(pOtherStream)
113 {
114 /* Used for MediaPortal PVR addon (uses PVR otherstream for playback of rtsp streams) */
115 if (pOtherStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
116 {
117 unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg());
118 if(demuxer->Open(pOtherStream, streaminfo))
119 return demuxer.release();
120 else
121 return NULL;
122 }
123 }
124
125 /* Use PVR demuxer only for live streams */
126 if (URIUtils::IsPVRChannel(pInputStream->GetFileName()))
127 {
128 std::shared_ptr<CPVRClient> client;
129 if (g_PVRClients->GetPlayingClient(client) &&
130 client->HandlesDemuxing())
131 {
132 unique_ptr<CDVDDemuxPVRClient> demuxer(new CDVDDemuxPVRClient());
133 if(demuxer->Open(pInputStream))
134 return demuxer.release();
135 else
136 return NULL;
137 }
138 }
139 }
140
141 if (pInputStream->IsStreamType(DVDSTREAM_TYPE_FFMPEG))
142 {
143 bool useFastswitch = URIUtils::IsUsingFastSwitch(pInputStream->GetFileName());
144 streaminfo = !useFastswitch;
145 }
146
147 unique_ptr<CDVDDemuxFFmpeg> demuxer(new CDVDDemuxFFmpeg());
148 if(demuxer->Open(pInputStream, streaminfo, fileinfo))
149 return demuxer.release();
150 else
151 return NULL;
152}
153
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h
new file mode 100644
index 0000000..8281d28
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/DVDFactoryDemuxer.h
@@ -0,0 +1,30 @@
1#pragma once
2
3/*
4 * Copyright (C) 2005-2013 Team XBMC
5 * http://xbmc.org
6 *
7 * This Program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * This Program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with XBMC; see the file COPYING. If not, see
19 * <http://www.gnu.org/licenses/>.
20 *
21 */
22
23class CDVDDemux;
24class CDVDInputStream;
25
26class CDVDFactoryDemuxer
27{
28public:
29 static CDVDDemux* CreateDemuxer(CDVDInputStream* pInputStream, bool fileinfo = false);
30};
diff --git a/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in b/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
new file mode 100644
index 0000000..98493fe
--- /dev/null
+++ b/xbmc/cores/dvdplayer/DVDDemuxers/Makefile.in
@@ -0,0 +1,19 @@
1INCLUDES+=-I@abs_top_srcdir@/xbmc/cores/dvdplayer
2
3SRCS = DVDDemux.cpp
4SRCS += DVDDemuxBXA.cpp
5SRCS += DVDDemuxCDDA.cpp
6SRCS += DVDDemuxFFmpeg.cpp
7SRCS += DVDDemuxHTSP.cpp
8SRCS += DVDDemuxPVRClient.cpp
9SRCS += DVDDemuxShoutcast.cpp
10SRCS += DVDDemuxUtils.cpp
11SRCS += DVDDemuxVobsub.cpp
12SRCS += DVDDemuxCC.cpp
13SRCS += DVDFactoryDemuxer.cpp
14
15LIB = DVDDemuxers.a
16
17include @abs_top_srcdir@/Makefile.include
18-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
19