2 * Copyright (C) 2012-2013 Team XBMC
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)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "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"
29 #define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
33 CDemuxStreamPVRInternal::CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent)
37 , m_parser_split(false)
41 CDemuxStreamPVRInternal::~CDemuxStreamPVRInternal()
46 void CDemuxStreamPVRInternal::DisposeParser()
50 m_parent->m_dllAvCodec.av_parser_close(m_parser);
55 m_parent->m_dllAvCodec.avcodec_close(m_context);
60 void CDemuxStreamVideoPVRClient::GetStreamInfo(std::string& strInfo)
64 case AV_CODEC_ID_MPEG2VIDEO:
65 strInfo = "mpeg2video";
67 case AV_CODEC_ID_H264:
75 void CDemuxStreamAudioPVRClient::GetStreamInfo(std::string& strInfo)
82 case AV_CODEC_ID_EAC3:
86 strInfo = "mpeg2audio";
99 void CDemuxStreamSubtitlePVRClient::GetStreamInfo(std::string& strInfo)
103 CDVDDemuxPVRClient::CDVDDemuxPVRClient() : CDVDDemux()
106 for (int i = 0; i < MAX_STREAMS; i++) m_streams[i] = NULL;
109 CDVDDemuxPVRClient::~CDVDDemuxPVRClient()
114 bool CDVDDemuxPVRClient::Open(CDVDInputStream* pInput)
116 if (!m_dllAvCodec.Load())
118 CLog::Log(LOGWARNING, "%s could not load ffmpeg", __FUNCTION__);
125 m_dllAvCodec.avcodec_register_all();
128 if (!g_PVRClients->GetPlayingClient(m_pvrClient))
135 void CDVDDemuxPVRClient::Dispose()
137 for (int i = 0; i < MAX_STREAMS; i++)
145 m_dllAvCodec.Unload();
148 void CDVDDemuxPVRClient::DisposeStream(int iStreamId)
150 if (iStreamId < 0 || iStreamId >= MAX_STREAMS)
152 delete m_streams[iStreamId];
153 m_streams[iStreamId] = NULL;
156 void CDVDDemuxPVRClient::Reset()
158 if(m_pInput && g_PVRManager.IsStarted())
159 m_pvrClient->DemuxReset();
161 CDVDInputStream* pInputStream = m_pInput;
166 void CDVDDemuxPVRClient::Abort()
169 m_pvrClient->DemuxAbort();
172 void CDVDDemuxPVRClient::Flush()
174 if(m_pInput && g_PVRManager.IsStarted())
175 m_pvrClient->DemuxFlush();
178 void CDVDDemuxPVRClient::ParsePacket(DemuxPacket* pkt)
180 CDemuxStream* st = m_streams[pkt->iStreamId];
187 CDemuxStreamPVRInternal* pvr = dynamic_cast<CDemuxStreamPVRInternal*>(st);
190 || pvr->m_parser == NULL)
193 if(pvr->m_context == NULL)
195 AVCodec *codec = m_dllAvCodec.avcodec_find_decoder(st->codec);
198 CLog::Log(LOGERROR, "%s - can't find decoder", __FUNCTION__);
199 pvr->DisposeParser();
203 pvr->m_context = m_dllAvCodec.avcodec_alloc_context3(codec);
204 if(pvr->m_context == NULL)
206 CLog::Log(LOGERROR, "%s - can't allocate context", __FUNCTION__);
207 pvr->DisposeParser();
210 pvr->m_context->time_base.num = 1;
211 pvr->m_context->time_base.den = DVD_TIME_BASE;
214 if(pvr->m_parser_split && pvr->m_parser->parser->split)
216 int len = pvr->m_parser->parser->split(pvr->m_context, pkt->pData, pkt->iSize);
217 if (len > 0 && len < FF_MAX_EXTRADATA_SIZE)
220 delete[] (uint8_t*)st->ExtraData;
222 st->disabled = false;
224 st->ExtraData = new uint8_t[len+FF_INPUT_BUFFER_PADDING_SIZE];
225 memcpy(st->ExtraData, pkt->pData, len);
226 memset((uint8_t*)st->ExtraData + len, 0 , FF_INPUT_BUFFER_PADDING_SIZE);
227 pvr->m_parser_split = false;
232 uint8_t *outbuf = NULL;
234 int len = m_dllAvCodec.av_parser_parse2(pvr->m_parser
235 , pvr->m_context, &outbuf, &outbuf_size
236 , pkt->pData, pkt->iSize
237 , (int64_t)(pkt->pts * DVD_TIME_BASE)
238 , (int64_t)(pkt->dts * DVD_TIME_BASE)
240 /* our parse is setup to parse complete frames, so we don't care about outbufs */
243 #define CHECK_UPDATE(st, trg, src, invalid) do { \
245 && src != st->trg) { \
246 CLog::Log(LOGDEBUG, "%s - {%d} " #trg " changed from %d to %d", __FUNCTION__, st->iId, st->trg, src); \
249 st->disabled = false; \
254 CHECK_UPDATE(st, profile, pvr->m_context->profile , FF_PROFILE_UNKNOWN);
255 CHECK_UPDATE(st, level , pvr->m_context->level , 0);
260 CDemuxStreamAudioPVRClient* sta = static_cast<CDemuxStreamAudioPVRClient*>(st);
261 CHECK_UPDATE(sta, iChannels , pvr->m_context->channels , 0);
262 CHECK_UPDATE(sta, iSampleRate , pvr->m_context->sample_rate, 0);
266 CDemuxStreamVideoPVRClient* stv = static_cast<CDemuxStreamVideoPVRClient*>(st);
267 CHECK_UPDATE(stv, iWidth , pvr->m_context->width , 0);
268 CHECK_UPDATE(stv, iHeight , pvr->m_context->height, 0);
279 CLog::Log(LOGDEBUG, "%s - parser returned error %d", __FUNCTION__, len);
284 DemuxPacket* CDVDDemuxPVRClient::Read()
286 if (!g_PVRManager.IsStarted())
287 return CDVDDemuxUtils::AllocateDemuxPacket(0);
289 DemuxPacket* pPacket = m_pvrClient->DemuxRead();
297 if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO)
300 CDVDDemuxUtils::FreeDemuxPacket(pPacket);
301 return CDVDDemuxUtils::AllocateDemuxPacket(0);
303 else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE)
307 else if (pPacket->iStreamId >= 0
308 && pPacket->iStreamId < MAX_STREAMS
309 && m_streams[pPacket->iStreamId])
311 ParsePacket(pPacket);
317 CDemuxStream* CDVDDemuxPVRClient::GetStream(int iStreamId)
319 if (iStreamId < 0 || iStreamId >= MAX_STREAMS) return NULL;
320 return m_streams[iStreamId];
323 void CDVDDemuxPVRClient::RequestStreams()
325 if (!g_PVRManager.IsStarted())
328 PVR_STREAM_PROPERTIES props = {};
329 m_pvrClient->GetStreamProperties(&props);
332 for (i = 0; i < props.iStreamCount; ++i)
334 CDemuxStream *stm = m_streams[i];
336 if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_AUDIO)
338 CDemuxStreamAudioPVRClient* st = NULL;
341 st = dynamic_cast<CDemuxStreamAudioPVRClient*>(stm);
343 || (st->codec != (AVCodecID)props.stream[i].iCodecId)
344 || (st->iChannels != props.stream[i].iChannels))
349 st = new CDemuxStreamAudioPVRClient(this);
350 st->m_parser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
352 st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
354 st->iChannels = props.stream[i].iChannels;
355 st->iSampleRate = props.stream[i].iSampleRate;
356 st->iBlockAlign = props.stream[i].iBlockAlign;
357 st->iBitRate = props.stream[i].iBitRate;
358 st->iBitsPerSample = props.stream[i].iBitsPerSample;
360 st->m_parser_split = true;
362 else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_VIDEO)
364 CDemuxStreamVideoPVRClient* st = NULL;
367 st = dynamic_cast<CDemuxStreamVideoPVRClient*>(stm);
369 || (st->codec != (AVCodecID)props.stream[i].iCodecId)
370 || (st->iWidth != props.stream[i].iWidth)
371 || (st->iHeight != props.stream[i].iHeight))
376 st = new CDemuxStreamVideoPVRClient(this);
377 st->m_parser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
379 st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
381 st->iFpsScale = props.stream[i].iFPSScale;
382 st->iFpsRate = props.stream[i].iFPSRate;
383 st->iHeight = props.stream[i].iHeight;
384 st->iWidth = props.stream[i].iWidth;
385 st->fAspect = props.stream[i].fAspect;
386 st->stereo_mode = "mono";
388 st->m_parser_split = true;
390 else if (props.stream[i].iCodecId == AV_CODEC_ID_DVB_TELETEXT)
394 if (stm->codec != (AVCodecID)props.stream[i].iCodecId)
398 m_streams[i] = new CDemuxStreamTeletext();
400 else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_SUBTITLE)
402 CDemuxStreamSubtitlePVRClient* st = NULL;
405 st = dynamic_cast<CDemuxStreamSubtitlePVRClient*>(stm);
406 if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
411 st = new CDemuxStreamSubtitlePVRClient(this);
413 if(props.stream[i].iIdentifier)
415 st->ExtraData = new uint8_t[4];
417 ((uint16_t*)st->ExtraData)[0] = (props.stream[i].iIdentifier >> 0) & 0xFFFFu;
418 ((uint16_t*)st->ExtraData)[1] = (props.stream[i].iIdentifier >> 4) & 0xFFFFu;
426 m_streams[i] = new CDemuxStream();
429 m_streams[i]->codec = (AVCodecID)props.stream[i].iCodecId;
430 m_streams[i]->iId = i;
431 m_streams[i]->iPhysicalId = props.stream[i].iPhysicalId;
432 m_streams[i]->language[0] = props.stream[i].strLanguage[0];
433 m_streams[i]->language[1] = props.stream[i].strLanguage[1];
434 m_streams[i]->language[2] = props.stream[i].strLanguage[2];
435 m_streams[i]->language[3] = props.stream[i].strLanguage[3];
437 CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): added/updated stream %d:%d with codec_id %d",
439 m_streams[i]->iPhysicalId,
440 m_streams[i]->codec);
442 // check if we need to dispose any streams no longer in props
443 for (unsigned int j = i; j < MAX_STREAMS; j++)
447 CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): disposed stream %d:%d with codec_id %d",
449 m_streams[j]->iPhysicalId,
450 m_streams[j]->codec);
456 int CDVDDemuxPVRClient::GetNrOfStreams()
459 while (i < MAX_STREAMS && m_streams[i]) i++;
463 std::string CDVDDemuxPVRClient::GetFileName()
466 return m_pInput->GetFileName();
471 void CDVDDemuxPVRClient::GetStreamCodecName(int iStreamId, CStdString &strName)
473 CDemuxStream *stream = GetStream(iStreamId);
476 if (stream->codec == AV_CODEC_ID_AC3)
478 else if (stream->codec == AV_CODEC_ID_MP2)
480 else if (stream->codec == AV_CODEC_ID_AAC)
482 else if (stream->codec == AV_CODEC_ID_DTS)
484 else if (stream->codec == AV_CODEC_ID_MPEG2VIDEO)
485 strName = "mpeg2video";
486 else if (stream->codec == AV_CODEC_ID_H264)
488 else if (stream->codec == AV_CODEC_ID_EAC3)
493 bool CDVDDemuxPVRClient::SeekTime(int timems, bool backwards, double *startpts)
496 return m_pvrClient->SeekTime(timems, backwards, startpts);
500 void CDVDDemuxPVRClient::SetSpeed ( int speed )
503 m_pvrClient->SetSpeed(speed);