PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

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

http://github.com/xbmc/xbmc
C++ | 504 lines | 427 code | 55 blank | 22 comment | 123 complexity | 05aa48f502979276aec08c574a52119d MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-3.0, LGPL-2.0, 0BSD, Unlicense, GPL-2.0, AGPL-1.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  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. m_parent->m_dllAvCodec.av_parser_close(m_parser);
  45. m_parser = NULL;
  46. }
  47. if (m_context)
  48. {
  49. m_parent->m_dllAvCodec.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. if (!m_dllAvCodec.Load())
  105. {
  106. CLog::Log(LOGWARNING, "%s could not load ffmpeg", __FUNCTION__);
  107. return false;
  108. }
  109. Abort();
  110. // register codecs
  111. m_dllAvCodec.avcodec_register_all();
  112. m_pInput = pInput;
  113. if (!g_PVRClients->GetPlayingClient(m_pvrClient))
  114. return false;
  115. RequestStreams();
  116. return true;
  117. }
  118. void CDVDDemuxPVRClient::Dispose()
  119. {
  120. for (int i = 0; i < MAX_STREAMS; i++)
  121. {
  122. delete m_streams[i];
  123. m_streams[i] = NULL;
  124. }
  125. m_pInput = NULL;
  126. m_dllAvCodec.Unload();
  127. }
  128. void CDVDDemuxPVRClient::DisposeStream(int iStreamId)
  129. {
  130. if (iStreamId < 0 || iStreamId >= MAX_STREAMS)
  131. return;
  132. delete m_streams[iStreamId];
  133. m_streams[iStreamId] = NULL;
  134. }
  135. void CDVDDemuxPVRClient::Reset()
  136. {
  137. if(m_pInput && g_PVRManager.IsStarted())
  138. m_pvrClient->DemuxReset();
  139. CDVDInputStream* pInputStream = m_pInput;
  140. Dispose();
  141. Open(pInputStream);
  142. }
  143. void CDVDDemuxPVRClient::Abort()
  144. {
  145. if(m_pInput)
  146. m_pvrClient->DemuxAbort();
  147. }
  148. void CDVDDemuxPVRClient::Flush()
  149. {
  150. if(m_pInput && g_PVRManager.IsStarted())
  151. m_pvrClient->DemuxFlush();
  152. }
  153. void CDVDDemuxPVRClient::ParsePacket(DemuxPacket* pkt)
  154. {
  155. CDemuxStream* st = m_streams[pkt->iStreamId];
  156. if (st == NULL)
  157. return;
  158. if (st->ExtraSize)
  159. return;
  160. CDemuxStreamPVRInternal* pvr = dynamic_cast<CDemuxStreamPVRInternal*>(st);
  161. if(pvr == NULL
  162. || pvr->m_parser == NULL)
  163. return;
  164. if(pvr->m_context == NULL)
  165. {
  166. AVCodec *codec = m_dllAvCodec.avcodec_find_decoder(st->codec);
  167. if (codec == NULL)
  168. {
  169. CLog::Log(LOGERROR, "%s - can't find decoder", __FUNCTION__);
  170. pvr->DisposeParser();
  171. return;
  172. }
  173. pvr->m_context = m_dllAvCodec.avcodec_alloc_context3(codec);
  174. if(pvr->m_context == NULL)
  175. {
  176. CLog::Log(LOGERROR, "%s - can't allocate context", __FUNCTION__);
  177. pvr->DisposeParser();
  178. return;
  179. }
  180. pvr->m_context->time_base.num = 1;
  181. pvr->m_context->time_base.den = DVD_TIME_BASE;
  182. }
  183. if(pvr->m_parser_split && pvr->m_parser->parser->split)
  184. {
  185. int len = pvr->m_parser->parser->split(pvr->m_context, pkt->pData, pkt->iSize);
  186. if (len > 0 && len < FF_MAX_EXTRADATA_SIZE)
  187. {
  188. if (st->ExtraData)
  189. delete[] (uint8_t*)st->ExtraData;
  190. st->changes++;
  191. st->disabled = false;
  192. st->ExtraSize = len;
  193. st->ExtraData = new uint8_t[len+FF_INPUT_BUFFER_PADDING_SIZE];
  194. memcpy(st->ExtraData, pkt->pData, len);
  195. memset((uint8_t*)st->ExtraData + len, 0 , FF_INPUT_BUFFER_PADDING_SIZE);
  196. pvr->m_parser_split = false;
  197. }
  198. }
  199. uint8_t *outbuf = NULL;
  200. int outbuf_size = 0;
  201. int len = m_dllAvCodec.av_parser_parse2(pvr->m_parser
  202. , pvr->m_context, &outbuf, &outbuf_size
  203. , pkt->pData, pkt->iSize
  204. , (int64_t)(pkt->pts * DVD_TIME_BASE)
  205. , (int64_t)(pkt->dts * DVD_TIME_BASE)
  206. , 0);
  207. /* our parse is setup to parse complete frames, so we don't care about outbufs */
  208. if(len >= 0)
  209. {
  210. #define CHECK_UPDATE(st, trg, src, invalid) do { \
  211. if(src != invalid \
  212. && src != st->trg) { \
  213. CLog::Log(LOGDEBUG, "%s - {%d} " #trg " changed from %d to %d", __FUNCTION__, st->iId, st->trg, src); \
  214. st->trg = src; \
  215. st->changes++; \
  216. st->disabled = false; \
  217. } \
  218. } while(0)
  219. CHECK_UPDATE(st, profile, pvr->m_context->profile , FF_PROFILE_UNKNOWN);
  220. CHECK_UPDATE(st, level , pvr->m_context->level , 0);
  221. switch (st->type)
  222. {
  223. case STREAM_AUDIO: {
  224. CDemuxStreamAudioPVRClient* sta = static_cast<CDemuxStreamAudioPVRClient*>(st);
  225. CHECK_UPDATE(sta, iChannels , pvr->m_context->channels , 0);
  226. CHECK_UPDATE(sta, iSampleRate , pvr->m_context->sample_rate, 0);
  227. break;
  228. }
  229. case STREAM_VIDEO: {
  230. CDemuxStreamVideoPVRClient* stv = static_cast<CDemuxStreamVideoPVRClient*>(st);
  231. CHECK_UPDATE(stv, iWidth , pvr->m_context->width , 0);
  232. CHECK_UPDATE(stv, iHeight , pvr->m_context->height, 0);
  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
  295. || (st->codec != (AVCodecID)props.stream[i].iCodecId)
  296. || (st->iChannels != props.stream[i].iChannels))
  297. DisposeStream(i);
  298. }
  299. if (!m_streams[i])
  300. {
  301. st = new CDemuxStreamAudioPVRClient(this);
  302. st->m_parser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
  303. if(st->m_parser)
  304. st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
  305. }
  306. st->iChannels = props.stream[i].iChannels;
  307. st->iSampleRate = props.stream[i].iSampleRate;
  308. st->iBlockAlign = props.stream[i].iBlockAlign;
  309. st->iBitRate = props.stream[i].iBitRate;
  310. st->iBitsPerSample = props.stream[i].iBitsPerSample;
  311. m_streams[i] = st;
  312. st->m_parser_split = true;
  313. }
  314. else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_VIDEO)
  315. {
  316. CDemuxStreamVideoPVRClient* st = NULL;
  317. if (stm)
  318. {
  319. st = dynamic_cast<CDemuxStreamVideoPVRClient*>(stm);
  320. if (!st
  321. || (st->codec != (AVCodecID)props.stream[i].iCodecId)
  322. || (st->iWidth != props.stream[i].iWidth)
  323. || (st->iHeight != props.stream[i].iHeight))
  324. DisposeStream(i);
  325. }
  326. if (!m_streams[i])
  327. {
  328. st = new CDemuxStreamVideoPVRClient(this);
  329. st->m_parser = m_dllAvCodec.av_parser_init(props.stream[i].iCodecId);
  330. if(st->m_parser)
  331. st->m_parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;
  332. }
  333. st->iFpsScale = props.stream[i].iFPSScale;
  334. st->iFpsRate = props.stream[i].iFPSRate;
  335. st->iHeight = props.stream[i].iHeight;
  336. st->iWidth = props.stream[i].iWidth;
  337. st->fAspect = props.stream[i].fAspect;
  338. st->stereo_mode = "mono";
  339. m_streams[i] = st;
  340. st->m_parser_split = true;
  341. }
  342. else if (props.stream[i].iCodecId == AV_CODEC_ID_DVB_TELETEXT)
  343. {
  344. if (stm)
  345. {
  346. if (stm->codec != (AVCodecID)props.stream[i].iCodecId)
  347. DisposeStream(i);
  348. }
  349. if (!m_streams[i])
  350. m_streams[i] = new CDemuxStreamTeletext();
  351. }
  352. else if (props.stream[i].iCodecType == XBMC_CODEC_TYPE_SUBTITLE)
  353. {
  354. CDemuxStreamSubtitlePVRClient* st = NULL;
  355. if (stm)
  356. {
  357. st = dynamic_cast<CDemuxStreamSubtitlePVRClient*>(stm);
  358. if (!st || (st->codec != (AVCodecID)props.stream[i].iCodecId))
  359. DisposeStream(i);
  360. }
  361. if (!m_streams[i])
  362. {
  363. st = new CDemuxStreamSubtitlePVRClient(this);
  364. }
  365. if(props.stream[i].iIdentifier)
  366. {
  367. st->ExtraData = new uint8_t[4];
  368. st->ExtraSize = 4;
  369. ((uint16_t*)st->ExtraData)[0] = (props.stream[i].iIdentifier >> 0) & 0xFFFFu;
  370. ((uint16_t*)st->ExtraData)[1] = (props.stream[i].iIdentifier >> 4) & 0xFFFFu;
  371. }
  372. m_streams[i] = st;
  373. }
  374. else
  375. {
  376. if (m_streams[i])
  377. DisposeStream(i);
  378. m_streams[i] = new CDemuxStream();
  379. }
  380. m_streams[i]->codec = (AVCodecID)props.stream[i].iCodecId;
  381. m_streams[i]->iId = i;
  382. m_streams[i]->iPhysicalId = props.stream[i].iPhysicalId;
  383. m_streams[i]->language[0] = props.stream[i].strLanguage[0];
  384. m_streams[i]->language[1] = props.stream[i].strLanguage[1];
  385. m_streams[i]->language[2] = props.stream[i].strLanguage[2];
  386. m_streams[i]->language[3] = props.stream[i].strLanguage[3];
  387. CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): added/updated stream %d:%d with codec_id %d",
  388. m_streams[i]->iId,
  389. m_streams[i]->iPhysicalId,
  390. m_streams[i]->codec);
  391. }
  392. // check if we need to dispose any streams no longer in props
  393. for (unsigned int j = i; j < MAX_STREAMS; j++)
  394. {
  395. if (m_streams[j])
  396. {
  397. CLog::Log(LOGDEBUG,"CDVDDemuxPVRClient::RequestStreams(): disposed stream %d:%d with codec_id %d",
  398. m_streams[j]->iId,
  399. m_streams[j]->iPhysicalId,
  400. m_streams[j]->codec);
  401. DisposeStream(j);
  402. }
  403. }
  404. }
  405. int CDVDDemuxPVRClient::GetNrOfStreams()
  406. {
  407. int i = 0;
  408. while (i < MAX_STREAMS && m_streams[i]) i++;
  409. return i;
  410. }
  411. std::string CDVDDemuxPVRClient::GetFileName()
  412. {
  413. if(m_pInput)
  414. return m_pInput->GetFileName();
  415. else
  416. return "";
  417. }
  418. void CDVDDemuxPVRClient::GetStreamCodecName(int iStreamId, CStdString &strName)
  419. {
  420. CDemuxStream *stream = GetStream(iStreamId);
  421. if (stream)
  422. {
  423. if (stream->codec == AV_CODEC_ID_AC3)
  424. strName = "ac3";
  425. else if (stream->codec == AV_CODEC_ID_MP2)
  426. strName = "mp2";
  427. else if (stream->codec == AV_CODEC_ID_AAC)
  428. strName = "aac";
  429. else if (stream->codec == AV_CODEC_ID_DTS)
  430. strName = "dca";
  431. else if (stream->codec == AV_CODEC_ID_MPEG2VIDEO)
  432. strName = "mpeg2video";
  433. else if (stream->codec == AV_CODEC_ID_H264)
  434. strName = "h264";
  435. else if (stream->codec == AV_CODEC_ID_EAC3)
  436. strName = "eac3";
  437. }
  438. }
  439. bool CDVDDemuxPVRClient::SeekTime(int timems, bool backwards, double *startpts)
  440. {
  441. if (m_pInput)
  442. return m_pvrClient->SeekTime(timems, backwards, startpts);
  443. return false;
  444. }
  445. void CDVDDemuxPVRClient::SetSpeed ( int speed )
  446. {
  447. if (m_pInput)
  448. m_pvrClient->SetSpeed(speed);
  449. }