summaryrefslogtreecommitdiffstats
path: root/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp')
-rw-r--r--xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp493
1 files changed, 493 insertions, 0 deletions
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}