PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/cores/dvdplayer/DVDDemuxers/DVDDemuxPVRClient.cpp

https://gitlab.com/jothow/kodi
C++ | 503 lines | 429 code | 53 blank | 21 comment | 123 complexity | 320c63bb57441e7c4c8dad3a1f52f6e3 MD5 | raw file
  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. #include "DVDInputStreams/DVDInputStream.h"
  21. #include "DVDDemuxPVRClient.h"
  22. #include "DVDDemuxUtils.h"
  23. #include "utils/log.h"
  24. #include "pvr/PVRManager.h"
  25. #include "pvr/addons/PVRClients.h"
  26. #include "../DVDClock.h"
  27. #define FF_MAX_EXTRADATA_SIZE ((1 << 28) - FF_INPUT_BUFFER_PADDING_SIZE)
  28. using namespace PVR;
  29. CDemuxStreamPVRInternal::CDemuxStreamPVRInternal(CDVDDemuxPVRClient *parent)
  30. : m_parent(parent)
  31. , m_parser(NULL)
  32. , m_context(NULL)
  33. , m_parser_split(false)
  34. {
  35. }
  36. CDemuxStreamPVRInternal::~CDemuxStreamPVRInternal()
  37. {
  38. DisposeParser();
  39. }
  40. void CDemuxStreamPVRInternal::DisposeParser()
  41. {
  42. if (m_parser)
  43. {
  44. av_parser_close(m_parser);
  45. m_parser = NULL;
  46. }
  47. if (m_context)
  48. {
  49. avcodec_close(m_context);
  50. m_context = NULL;
  51. }
  52. }
  53. void CDemuxStreamVideoPVRClient::GetStreamInfo(std::string& strInfo)
  54. {
  55. switch (codec)
  56. {
  57. case AV_CODEC_ID_MPEG2VIDEO:
  58. strInfo = "mpeg2video";
  59. break;
  60. case AV_CODEC_ID_H264:
  61. strInfo = "h264";
  62. break;
  63. default:
  64. break;
  65. }
  66. }
  67. void CDemuxStreamAudioPVRClient::GetStreamInfo(std::string& strInfo)
  68. {
  69. switch (codec)
  70. {
  71. case AV_CODEC_ID_AC3:
  72. strInfo = "ac3";
  73. break;
  74. case AV_CODEC_ID_EAC3:
  75. strInfo = "eac3";
  76. break;
  77. case AV_CODEC_ID_MP2:
  78. strInfo = "mpeg2audio";
  79. break;
  80. case AV_CODEC_ID_AAC:
  81. strInfo = "aac";
  82. break;
  83. case AV_CODEC_ID_DTS:
  84. strInfo = "dts";
  85. break;
  86. default:
  87. break;
  88. }
  89. }
  90. void CDemuxStreamSubtitlePVRClient::GetStreamInfo(std::string& strInfo)
  91. {
  92. }
  93. CDVDDemuxPVRClient::CDVDDemuxPVRClient() : CDVDDemux()
  94. {
  95. m_pInput = NULL;
  96. for (int i = 0; i < MAX_STREAMS; i++) m_streams[i] = NULL;
  97. }
  98. CDVDDemuxPVRClient::~CDVDDemuxPVRClient()
  99. {
  100. Dispose();
  101. }
  102. bool CDVDDemuxPVRClient::Open(CDVDInputStream* pInput)
  103. {
  104. Abort();
  105. m_pInput = pInput;
  106. if (!g_PVRClients->GetPlayingClient(m_pvrClient))
  107. return false;
  108. return true;
  109. }
  110. void CDVDDemuxPVRClient::Dispose()
  111. {
  112. for (int i = 0; i < MAX_STREAMS; i++)
  113. {
  114. delete m_streams[i];
  115. m_streams[i] = NULL;
  116. }
  117. m_pInput = NULL;
  118. }
  119. void CDVDDemuxPVRClient::DisposeStream(int iStreamId)
  120. {
  121. if (iStreamId < 0 || iStreamId >= MAX_STREAMS)
  122. return;
  123. delete m_streams[iStreamId];
  124. m_streams[iStreamId] = NULL;
  125. }
  126. void CDVDDemuxPVRClient::Reset()
  127. {
  128. if(m_pInput && g_PVRManager.IsStarted())
  129. m_pvrClient->DemuxReset();
  130. CDVDInputStream* pInputStream = m_pInput;
  131. Dispose();
  132. Open(pInputStream);
  133. }
  134. void CDVDDemuxPVRClient::Abort()
  135. {
  136. if(m_pInput)
  137. m_pvrClient->DemuxAbort();
  138. }
  139. void CDVDDemuxPVRClient::Flush()
  140. {
  141. if(m_pInput && g_PVRManager.IsStarted())
  142. m_pvrClient->DemuxFlush();
  143. }
  144. void CDVDDemuxPVRClient::ParsePacket(DemuxPacket* pkt)
  145. {
  146. CDemuxStream* st = m_streams[pkt->iStreamId];
  147. if (st == NULL)
  148. return;
  149. if (st->ExtraSize)
  150. return;
  151. CDemuxStreamPVRInternal* pvr = dynamic_cast<CDemuxStreamPVRInternal*>(st);
  152. if(pvr == NULL
  153. || pvr->m_parser == NULL)
  154. return;
  155. if(pvr->m_context == NULL)
  156. {
  157. AVCodec *codec = avcodec_find_decoder(st->codec);
  158. if (codec == NULL)
  159. {
  160. CLog::Log(LOGERROR, "%s - can't find decoder", __FUNCTION__);
  161. pvr->DisposeParser();
  162. return;
  163. }
  164. pvr->m_context = avcodec_alloc_context3(codec);
  165. if(pvr->m_context == NULL)
  166. {
  167. CLog::Log(LOGERROR, "%s - can't allocate context", __FUNCTION__);
  168. pvr->DisposeParser();
  169. return;
  170. }
  171. pvr->m_context->time_base.num = 1;
  172. pvr->m_context->time_base.den = DVD_TIME_BASE;
  173. }
  174. if(pvr->m_parser_split && pvr->m_parser->parser->split)
  175. {
  176. int len = pvr->m_parser->parser->split(pvr->m_context, pkt->pData, pkt->iSize);
  177. if (len > 0 && len < FF_MAX_EXTRADATA_SIZE)
  178. {
  179. if (st->ExtraData)
  180. delete[] (uint8_t*)st->ExtraData;
  181. st->changes++;
  182. st->disabled = false;
  183. st->ExtraSize = len;
  184. st->ExtraData = new uint8_t[len+FF_INPUT_BUFFER_PADDING_SIZE];
  185. memcpy(st->ExtraData, pkt->pData, len);
  186. memset((uint8_t*)st->ExtraData + len, 0 , FF_INPUT_BUFFER_PADDING_SIZE);
  187. pvr->m_parser_split = false;
  188. }
  189. }
  190. uint8_t *outbuf = NULL;
  191. int outbuf_size = 0;
  192. int len = av_parser_parse2(pvr->m_parser
  193. , pvr->m_context, &outbuf, &outbuf_size
  194. , pkt->pData, pkt->iSize
  195. , (int64_t)(pkt->pts * DVD_TIME_BASE)
  196. , (int64_t)(pkt->dts * DVD_TIME_BASE)
  197. , 0);
  198. /* our parse is setup to parse complete frames, so we don't care about outbufs */
  199. if(len >= 0)
  200. {
  201. #define CHECK_UPDATE(st, trg, src, invalid) do { \
  202. if(src != invalid \
  203. && src != st->trg) { \
  204. CLog::Log(LOGDEBUG, "%s - {%d} " #trg " changed from %d to %d", __FUNCTION__, st->iId, st->trg, src); \
  205. st->trg = src; \
  206. st->changes++; \
  207. st->disabled = false; \
  208. } \
  209. } while(0)
  210. CHECK_UPDATE(st, profile, pvr->m_context->profile , FF_PROFILE_UNKNOWN);
  211. CHECK_UPDATE(st, level , pvr->m_context->level , FF_LEVEL_UNKNOWN);
  212. switch (st->type)
  213. {
  214. case STREAM_AUDIO: {
  215. CDemuxStreamAudioPVRClient* sta = static_cast<CDemuxStreamAudioPVRClient*>(st);
  216. CHECK_UPDATE(sta, iChannels , pvr->m_context->channels , 0);
  217. CHECK_UPDATE(sta, iSampleRate , pvr->m_context->sample_rate, 0);
  218. break;
  219. }
  220. case STREAM_VIDEO: {
  221. CDemuxStreamVideoPVRClient* stv = static_cast<CDemuxStreamVideoPVRClient*>(st);
  222. CHECK_UPDATE(stv, iWidth , pvr->m_context->width , 0);
  223. CHECK_UPDATE(stv, iHeight , pvr->m_context->height, 0);
  224. if((pkt->duration > 0) && (pkt->duration != stv->iFpsScale))
  225. {
  226. CLog::Log(LOGDEBUG, "%s - {%d} iFpsScale changed from %d to %d", __FUNCTION__, stv->iId, stv->iFpsScale, pkt->duration);
  227. stv->iFpsScale = pkt->duration;
  228. CLog::Log(LOGDEBUG, "%s - {%d} iFpsRate changed from %d to %d", __FUNCTION__, stv->iId, stv->iFpsRate, DVD_TIME_BASE);
  229. stv->iFpsRate = DVD_TIME_BASE;
  230. stv->changes += 2;
  231. stv->disabled = false;
  232. }
  233. break;
  234. }
  235. default:
  236. break;
  237. }
  238. #undef CHECK_UPDATE
  239. }
  240. else
  241. CLog::Log(LOGDEBUG, "%s - parser returned error %d", __FUNCTION__, len);
  242. return;
  243. }
  244. DemuxPacket* CDVDDemuxPVRClient::Read()
  245. {
  246. if (!g_PVRManager.IsStarted())
  247. return CDVDDemuxUtils::AllocateDemuxPacket(0);
  248. DemuxPacket* pPacket = m_pvrClient->DemuxRead();
  249. if (!pPacket)
  250. {
  251. if (m_pInput)
  252. m_pInput->Close();
  253. return NULL;
  254. }
  255. if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO)
  256. {
  257. RequestStreams();
  258. CDVDDemuxUtils::FreeDemuxPacket(pPacket);
  259. return CDVDDemuxUtils::AllocateDemuxPacket(0);
  260. }
  261. else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE)
  262. {
  263. RequestStreams();
  264. }
  265. else if (pPacket->iStreamId >= 0
  266. && pPacket->iStreamId < MAX_STREAMS
  267. && m_streams[pPacket->iStreamId])
  268. {
  269. ParsePacket(pPacket);
  270. }
  271. return pPacket;
  272. }
  273. CDemuxStream* CDVDDemuxPVRClient::GetStream(int iStreamId)
  274. {
  275. if (iStreamId < 0 || iStreamId >= MAX_STREAMS) return NULL;
  276. return m_streams[iStreamId];
  277. }
  278. void CDVDDemuxPVRClient::RequestStreams()
  279. {
  280. if (!g_PVRManager.IsStarted())
  281. return;
  282. PVR_STREAM_PROPERTIES props = {};
  283. m_pvrClient->GetStreamProperties(&props);
  284. unsigned int i;
  285. for (i = 0; i < props.iStreamCount; ++i)
  286. {
  287. CDemuxStream *stm = m_streams[i];
  288. if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_AUDIO)
  289. {
  290. CDemuxStreamAudioPVRClient* st = NULL;
  291. if (stm)
  292. {
  293. st = dynamic_cast<CDemuxStreamAudioPVRClient*>(stm);
  294. if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
  295. DisposeStream(i);
  296. }
  297. if (!m_streams[i])
  298. {
  299. st = new CDemuxStreamAudioPVRClient(this);
  300. st->m_parser = av_parser_init(props.stream[i].iCodecId);
  301. if(st->m_parser)
  302. st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
  303. }
  304. st->iChannels = props.stream[i].iChannels;
  305. st->iSampleRate = props.stream[i].iSampleRate;
  306. st->iBlockAlign = props.stream[i].iBlockAlign;
  307. st->iBitRate = props.stream[i].iBitRate;
  308. st->iBitsPerSample = props.stream[i].iBitsPerSample;
  309. m_streams[i] = st;
  310. st->m_parser_split = true;
  311. st->changes++;
  312. }
  313. else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_VIDEO)
  314. {
  315. CDemuxStreamVideoPVRClient* st = NULL;
  316. if (stm)
  317. {
  318. st = dynamic_cast<CDemuxStreamVideoPVRClient*>(stm);
  319. if (!st
  320. || (st->codec != (AVCodecID)props.stream[i].iCodecId)
  321. || (st->iWidth != props.stream[i].iWidth)
  322. || (st->iHeight != props.stream[i].iHeight))
  323. DisposeStream(i);
  324. }
  325. if (!m_streams[i])
  326. {
  327. st = new CDemuxStreamVideoPVRClient(this);
  328. st->m_parser = av_parser_init(props.stream[i].iCodecId);
  329. if(st->m_parser)
  330. st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
  331. }
  332. st->iFpsScale = props.stream[i].iFPSScale;
  333. st->iFpsRate = props.stream[i].iFPSRate;
  334. st->iHeight = props.stream[i].iHeight;
  335. st->iWidth = props.stream[i].iWidth;
  336. st->fAspect = props.stream[i].fAspect;
  337. st->stereo_mode = "mono";
  338. m_streams[i] = st;
  339. st->m_parser_split = true;
  340. }
  341. else if (props.stream[i].iCodecId == AV_CODEC_ID_DVB_TELETEXT)
  342. {
  343. if (stm)
  344. {
  345. if (stm->codec != (AVCodecID)props.stream[i].iCodecId)
  346. DisposeStream(i);
  347. }
  348. if (!m_streams[i])
  349. m_streams[i] = new CDemuxStreamTeletext();
  350. }
  351. else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_SUBTITLE)
  352. {
  353. CDemuxStreamSubtitlePVRClient* st = NULL;
  354. if (stm)
  355. {
  356. st = dynamic_cast<CDemuxStreamSubtitlePVRClient*>(stm);
  357. if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
  358. DisposeStream(i);
  359. }
  360. if (!m_streams[i])
  361. {
  362. st = new CDemuxStreamSubtitlePVRClient(this);
  363. }
  364. if(props.stream[i].iIdentifier)
  365. {
  366. st->ExtraData = new uint8_t[4];
  367. st->ExtraSize = 4;
  368. st->ExtraData[0] = (props.stream[i].iIdentifier >> 8) & 0xff;
  369. st->ExtraData[1] = (props.stream[i].iIdentifier >> 0) & 0xff;
  370. st->ExtraData[2] = (props.stream[i].iIdentifier >> 24) & 0xff;
  371. st->ExtraData[3] = (props.stream[i].iIdentifier >> 16) & 0xff;
  372. }
  373. m_streams[i] = st;
  374. }
  375. else
  376. {
  377. if (m_streams[i])
  378. DisposeStream(i);
  379. m_streams[i] = new CDemuxStream();
  380. }
  381. m_streams[i]->codec = (AVCodecID)props.stream[i].iCodecId;
  382. m_streams[i]->iId = i;
  383. m_streams[i]->iPhysicalId = props.stream[i].iPhysicalId;
  384. m_streams[i]->language[0] = props.stream[i].strLanguage[0];
  385. m_streams[i]->language[1] = props.stream[i].strLanguage[1];
  386. m_streams[i]->language[2] = props.stream[i].strLanguage[2];
  387. m_streams[i]->language[3] = props.stream[i].strLanguage[3];
  388. CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): added/updated stream %d:%d with codec_id %d",
  389. m_streams[i]->iId,
  390. m_streams[i]->iPhysicalId,
  391. m_streams[i]->codec);
  392. }
  393. // check if we need to dispose any streams no longer in props
  394. for (unsigned int j = i; j < MAX_STREAMS; j++)
  395. {
  396. if (m_streams[j])
  397. {
  398. CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): disposed stream %d:%d with codec_id %d",
  399. m_streams[j]->iId,
  400. m_streams[j]->iPhysicalId,
  401. m_streams[j]->codec);
  402. DisposeStream(j);
  403. }
  404. }
  405. }
  406. int CDVDDemuxPVRClient::GetNrOfStreams()
  407. {
  408. int i = 0;
  409. while (i < MAX_STREAMS && m_streams[i]) i++;
  410. return i;
  411. }
  412. std::string CDVDDemuxPVRClient::GetFileName()
  413. {
  414. if(m_pInput)
  415. return m_pInput->GetFileName();
  416. else
  417. return "";
  418. }
  419. void CDVDDemuxPVRClient::GetStreamCodecName(int iStreamId, std::string &strName)
  420. {
  421. CDemuxStream *stream = GetStream(iStreamId);
  422. if (stream)
  423. {
  424. if (stream->codec == AV_CODEC_ID_AC3)
  425. strName = "ac3";
  426. else if (stream->codec == AV_CODEC_ID_MP2)
  427. strName = "mp2";
  428. else if (stream->codec == AV_CODEC_ID_AAC)
  429. strName = "aac";
  430. else if (stream->codec == AV_CODEC_ID_DTS)
  431. strName = "dca";
  432. else if (stream->codec == AV_CODEC_ID_MPEG2VIDEO)
  433. strName = "mpeg2video";
  434. else if (stream->codec == AV_CODEC_ID_H264)
  435. strName = "h264";
  436. else if (stream->codec == AV_CODEC_ID_EAC3)
  437. strName = "eac3";
  438. }
  439. }
  440. bool CDVDDemuxPVRClient::SeekTime(int timems, bool backwards, double *startpts)
  441. {
  442. if (m_pInput)
  443. return m_pvrClient->SeekTime(timems, backwards, startpts);
  444. return false;
  445. }
  446. void CDVDDemuxPVRClient::SetSpeed ( int speed )
  447. {
  448. if (m_pInput)
  449. m_pvrClient->SetSpeed(speed);
  450. }