PageRenderTime 27ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/xbmc/cores/VideoPlayer/DVDInputStreams/DVDInputStreamPVRManager.cpp

https://gitlab.com/sloshedpuppie/LetsGoRetro
C++ | 699 lines | 557 code | 98 blank | 44 comment | 112 complexity | 54cd24b033addc03259b7c0ae540db44 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 "DVDFactoryInputStream.h"
  21. #include "DVDInputStreamPVRManager.h"
  22. #include "DVDDemuxers/DVDDemuxPacket.h"
  23. #include "URL.h"
  24. #include "pvr/PVRManager.h"
  25. #include "pvr/channels/PVRChannel.h"
  26. #include "utils/log.h"
  27. #include "utils/StringUtils.h"
  28. #include "pvr/addons/PVRClients.h"
  29. #include "pvr/channels/PVRChannelGroupsContainer.h"
  30. #include "pvr/recordings/PVRRecordingsPath.h"
  31. #include "settings/Settings.h"
  32. #include "cores/VideoPlayer/DVDDemuxers/DVDDemux.h"
  33. #include <assert.h>
  34. using namespace XFILE;
  35. using namespace PVR;
  36. /************************************************************************
  37. * Description: Class constructor, initialize member variables
  38. * public class is CDVDInputStream
  39. */
  40. CDVDInputStreamPVRManager::CDVDInputStreamPVRManager(IVideoPlayer* pPlayer, const CFileItem& fileitem)
  41. : CDVDInputStream(DVDSTREAM_TYPE_PVRMANAGER, fileitem)
  42. {
  43. m_pPlayer = pPlayer;
  44. m_pOtherStream = nullptr;
  45. m_eof = true;
  46. m_ScanTimeout.Set(0);
  47. m_isOtherStreamHack = false;
  48. m_demuxActive = false;
  49. m_StreamProps = new PVR_STREAM_PROPERTIES;
  50. }
  51. /************************************************************************
  52. * Description: Class destructor
  53. */
  54. CDVDInputStreamPVRManager::~CDVDInputStreamPVRManager()
  55. {
  56. Close();
  57. m_streamMap.clear();
  58. delete m_StreamProps;
  59. }
  60. void CDVDInputStreamPVRManager::ResetScanTimeout(unsigned int iTimeoutMs)
  61. {
  62. m_ScanTimeout.Set(iTimeoutMs);
  63. }
  64. bool CDVDInputStreamPVRManager::IsEOF()
  65. {
  66. // don't mark as eof while within the scan timeout
  67. if (!m_ScanTimeout.IsTimePast())
  68. return false;
  69. if (m_pOtherStream)
  70. return m_pOtherStream->IsEOF();
  71. else
  72. return m_eof;
  73. }
  74. bool CDVDInputStreamPVRManager::Open()
  75. {
  76. if (!CDVDInputStream::Open())
  77. return false;
  78. CURL url(m_item.GetPath());
  79. std::string strURL = url.Get();
  80. if (StringUtils::StartsWith(strURL, "pvr://channels/tv/") ||
  81. StringUtils::StartsWith(strURL, "pvr://channels/radio/"))
  82. {
  83. CFileItemPtr tag = g_PVRChannelGroups->GetByPath(strURL);
  84. if (tag && tag->HasPVRChannelInfoTag())
  85. {
  86. if (!g_PVRManager.OpenLiveStream(*tag))
  87. return false;
  88. m_isRecording = false;
  89. CLog::Log(LOGDEBUG, "CDVDInputStreamPVRManager - %s - playback has started on filename %s", __FUNCTION__, strURL.c_str());
  90. }
  91. else
  92. {
  93. CLog::Log(LOGERROR, "CDVDInputStreamPVRManager - %s - channel not found with filename %s", __FUNCTION__, strURL.c_str());
  94. return false;
  95. }
  96. }
  97. else if (CPVRRecordingsPath(strURL).IsActive())
  98. {
  99. CFileItemPtr tag = g_PVRRecordings->GetByPath(strURL);
  100. if (tag && tag->HasPVRRecordingInfoTag())
  101. {
  102. if (!g_PVRManager.OpenRecordedStream(tag->GetPVRRecordingInfoTag()))
  103. return false;
  104. m_isRecording = true;
  105. CLog::Log(LOGDEBUG, "%s - playback has started on recording %s (%s)", __FUNCTION__, strURL.c_str(), tag->GetPVRRecordingInfoTag()->m_strIconPath.c_str());
  106. }
  107. else
  108. {
  109. CLog::Log(LOGERROR, "CDVDInputStreamPVRManager - Recording not found with filename %s", strURL.c_str());
  110. return false;
  111. }
  112. }
  113. else if (CPVRRecordingsPath(strURL).IsDeleted())
  114. {
  115. CLog::Log(LOGNOTICE, "CDVDInputStreamPVRManager - Playback of deleted recordings is not possible (%s)", strURL.c_str());
  116. return false;
  117. }
  118. else
  119. {
  120. CLog::Log(LOGERROR, "%s - invalid path specified %s", __FUNCTION__, strURL.c_str());
  121. return false;
  122. }
  123. m_eof = false;
  124. /*
  125. * Translate the "pvr://....." entry.
  126. * The PVR Client can use http or whatever else is supported by VideoPlayer.
  127. * to access streams.
  128. * If after translation the file protocol is still "pvr://" use this class
  129. * to read the stream data over the CPVRFile class and the PVR Library itself.
  130. * Otherwise call CreateInputStream again with the translated filename and looks again
  131. * for the right protocol stream handler and swap every call to this input stream
  132. * handler.
  133. */
  134. m_isOtherStreamHack = false;
  135. std::string transFile = ThisIsAHack(m_item.GetPath());
  136. if(transFile.substr(0, 6) != "pvr://")
  137. {
  138. m_isOtherStreamHack = true;
  139. m_item.SetPath(transFile);
  140. m_item.SetMimeTypeForInternetFile();
  141. m_pOtherStream = CDVDFactoryInputStream::CreateInputStream(m_pPlayer, m_item);
  142. if (!m_pOtherStream)
  143. {
  144. CLog::Log(LOGERROR, "CDVDInputStreamPVRManager::Open - unable to create input stream for [%s]", CURL::GetRedacted(transFile).c_str());
  145. return false;
  146. }
  147. if (!m_pOtherStream->Open())
  148. {
  149. CLog::Log(LOGERROR, "CDVDInputStreamPVRManager::Open - error opening [%s]", CURL::GetRedacted(transFile).c_str());
  150. delete m_pOtherStream;
  151. m_pOtherStream = NULL;
  152. return false;
  153. }
  154. }
  155. else
  156. {
  157. if (URIUtils::IsPVRChannel(url.Get()))
  158. {
  159. std::shared_ptr<CPVRClient> client;
  160. if (g_PVRClients->GetPlayingClient(client) &&
  161. client->HandlesDemuxing())
  162. m_demuxActive = true;
  163. }
  164. }
  165. ResetScanTimeout((unsigned int) CSettings::GetInstance().GetInt(CSettings::SETTING_PVRPLAYBACK_SCANTIME) * 1000);
  166. CLog::Log(LOGDEBUG, "CDVDInputStreamPVRManager::Open - stream opened: %s", CURL::GetRedacted(transFile).c_str());
  167. m_StreamProps->iStreamCount = 0;
  168. return true;
  169. }
  170. std::string CDVDInputStreamPVRManager::ThisIsAHack(const std::string& pathFile)
  171. {
  172. std::string FileName = pathFile;
  173. if (FileName.substr(0, 14) == "pvr://channels")
  174. {
  175. CFileItemPtr channel = g_PVRChannelGroups->GetByPath(FileName);
  176. if (channel && channel->HasPVRChannelInfoTag())
  177. {
  178. std::string stream = channel->GetPVRChannelInfoTag()->StreamURL();
  179. if(!stream.empty())
  180. {
  181. if (stream.compare(6, 7, "stream/") == 0)
  182. {
  183. // pvr://stream
  184. // This function was added to retrieve the stream URL for this item
  185. // Is is used for the MediaPortal (ffmpeg) PVR addon
  186. // see PVRManager.cpp
  187. return g_PVRClients->GetStreamURL(channel->GetPVRChannelInfoTag());
  188. }
  189. else
  190. {
  191. return stream;
  192. }
  193. }
  194. }
  195. }
  196. return FileName;
  197. }
  198. // close file and reset everything
  199. void CDVDInputStreamPVRManager::Close()
  200. {
  201. if (m_pOtherStream)
  202. {
  203. m_pOtherStream->Close();
  204. delete m_pOtherStream;
  205. }
  206. g_PVRManager.CloseStream();
  207. CDVDInputStream::Close();
  208. m_pPlayer = NULL;
  209. m_pOtherStream = NULL;
  210. m_eof = true;
  211. CLog::Log(LOGDEBUG, "CDVDInputStreamPVRManager::Close - stream closed");
  212. }
  213. int CDVDInputStreamPVRManager::Read(uint8_t* buf, int buf_size)
  214. {
  215. if (m_pOtherStream)
  216. {
  217. return m_pOtherStream->Read(buf, buf_size);
  218. }
  219. else
  220. {
  221. int ret = g_PVRClients->ReadStream((BYTE*)buf, buf_size);
  222. if (ret < 0)
  223. ret = -1;
  224. /* we currently don't support non completing reads */
  225. if( ret == 0 )
  226. m_eof = true;
  227. return ret;
  228. }
  229. }
  230. int64_t CDVDInputStreamPVRManager::Seek(int64_t offset, int whence)
  231. {
  232. if (m_pOtherStream)
  233. {
  234. return m_pOtherStream->Seek(offset, whence);
  235. }
  236. else
  237. {
  238. if (whence == SEEK_POSSIBLE)
  239. {
  240. if (g_PVRClients->CanSeekStream())
  241. return 1;
  242. else
  243. return 0;
  244. }
  245. int64_t ret = g_PVRClients->SeekStream(offset, whence);
  246. // if we succeed, we are not eof anymore
  247. if( ret >= 0 )
  248. m_eof = false;
  249. return ret;
  250. }
  251. }
  252. int64_t CDVDInputStreamPVRManager::GetLength()
  253. {
  254. if (m_pOtherStream)
  255. return m_pOtherStream->GetLength();
  256. else
  257. return g_PVRClients->GetStreamLength();
  258. }
  259. int CDVDInputStreamPVRManager::GetTotalTime()
  260. {
  261. if (!m_isRecording)
  262. return g_PVRManager.GetTotalTime();
  263. return 0;
  264. }
  265. int CDVDInputStreamPVRManager::GetTime()
  266. {
  267. if (!m_isRecording)
  268. return g_PVRManager.GetStartTime();
  269. return 0;
  270. }
  271. bool CDVDInputStreamPVRManager::NextChannel(bool preview/* = false*/)
  272. {
  273. PVR_CLIENT client;
  274. unsigned int newchannel;
  275. if (!preview && IsOtherStreamHack())
  276. {
  277. CPVRChannelPtr channel(g_PVRManager.GetCurrentChannel());
  278. CFileItemPtr item(g_PVRChannelGroups->Get(channel->IsRadio())->GetSelectedGroup()->GetByChannelUp(channel));
  279. if (item)
  280. return CloseAndOpen(item->GetPath().c_str());
  281. }
  282. else if (!m_isRecording)
  283. return g_PVRManager.ChannelUp(&newchannel, preview);
  284. return false;
  285. }
  286. bool CDVDInputStreamPVRManager::PrevChannel(bool preview/* = false*/)
  287. {
  288. PVR_CLIENT client;
  289. unsigned int newchannel;
  290. if (!preview && IsOtherStreamHack())
  291. {
  292. CPVRChannelPtr channel(g_PVRManager.GetCurrentChannel());
  293. CFileItemPtr item(g_PVRChannelGroups->Get(channel->IsRadio())->GetSelectedGroup()->GetByChannelDown(channel));
  294. if (item)
  295. return CloseAndOpen(item->GetPath().c_str());
  296. }
  297. else if (!m_isRecording)
  298. return g_PVRManager.ChannelDown(&newchannel, preview);
  299. return false;
  300. }
  301. bool CDVDInputStreamPVRManager::SelectChannelByNumber(unsigned int iChannelNumber)
  302. {
  303. PVR_CLIENT client;
  304. CPVRChannelPtr currentChannel(g_PVRManager.GetCurrentChannel());
  305. CFileItemPtr item(g_PVRChannelGroups->Get(currentChannel->IsRadio())->GetSelectedGroup()->GetByChannelNumber(iChannelNumber));
  306. if (!item)
  307. return false;
  308. if (IsOtherStreamHack())
  309. {
  310. return CloseAndOpen(item->GetPath().c_str());
  311. }
  312. else if (!m_isRecording)
  313. {
  314. if (item->HasPVRChannelInfoTag())
  315. return g_PVRManager.ChannelSwitchById(item->GetPVRChannelInfoTag()->ChannelID());
  316. }
  317. return false;
  318. }
  319. bool CDVDInputStreamPVRManager::SelectChannel(const CPVRChannelPtr &channel)
  320. {
  321. assert(channel.get());
  322. PVR_CLIENT client;
  323. if (IsOtherStreamHack())
  324. {
  325. CFileItem item(channel);
  326. return CloseAndOpen(item.GetPath().c_str());
  327. }
  328. else if (!m_isRecording)
  329. {
  330. return g_PVRManager.ChannelSwitchById(channel->ChannelID());
  331. }
  332. return false;
  333. }
  334. CPVRChannelPtr CDVDInputStreamPVRManager::GetSelectedChannel()
  335. {
  336. return g_PVRManager.GetCurrentChannel();
  337. }
  338. bool CDVDInputStreamPVRManager::UpdateItem(CFileItem& item)
  339. {
  340. return g_PVRManager.UpdateItem(item);
  341. }
  342. CDVDInputStream::ENextStream CDVDInputStreamPVRManager::NextStream()
  343. {
  344. m_eof = IsEOF();
  345. CDVDInputStream::ENextStream next;
  346. if (m_pOtherStream && ((next = m_pOtherStream->NextStream()) != NEXTSTREAM_NONE))
  347. return next;
  348. else if(!m_isRecording)
  349. {
  350. if (m_eof)
  351. return NEXTSTREAM_OPEN;
  352. else
  353. return NEXTSTREAM_RETRY;
  354. }
  355. return NEXTSTREAM_NONE;
  356. }
  357. bool CDVDInputStreamPVRManager::CanRecord()
  358. {
  359. if (!m_isRecording)
  360. return g_PVRClients->CanRecordInstantly();
  361. return false;
  362. }
  363. bool CDVDInputStreamPVRManager::IsRecording()
  364. {
  365. return g_PVRClients->IsRecordingOnPlayingChannel();
  366. }
  367. bool CDVDInputStreamPVRManager::Record(bool bOnOff)
  368. {
  369. return g_PVRManager.StartRecordingOnPlayingChannel(bOnOff);
  370. }
  371. bool CDVDInputStreamPVRManager::CanPause()
  372. {
  373. return g_PVRClients->CanPauseStream();
  374. }
  375. bool CDVDInputStreamPVRManager::CanSeek()
  376. {
  377. return g_PVRClients->CanSeekStream();
  378. }
  379. void CDVDInputStreamPVRManager::Pause(bool bPaused)
  380. {
  381. g_PVRClients->PauseStream(bPaused);
  382. }
  383. std::string CDVDInputStreamPVRManager::GetInputFormat()
  384. {
  385. if (!m_pOtherStream)
  386. return g_PVRClients->GetCurrentInputFormat();
  387. return "";
  388. }
  389. bool CDVDInputStreamPVRManager::CloseAndOpen(const char* strFile)
  390. {
  391. Close();
  392. m_item.SetPath(strFile);
  393. if (Open())
  394. {
  395. return true;
  396. }
  397. return false;
  398. }
  399. bool CDVDInputStreamPVRManager::IsOtherStreamHack(void)
  400. {
  401. return m_isOtherStreamHack;
  402. }
  403. bool CDVDInputStreamPVRManager::IsRealtime()
  404. {
  405. return g_PVRClients->IsRealTimeStream();
  406. }
  407. inline CDVDInputStream::IDemux* CDVDInputStreamPVRManager::GetIDemux()
  408. {
  409. if (m_demuxActive)
  410. return this;
  411. else
  412. return nullptr;
  413. }
  414. bool CDVDInputStreamPVRManager::OpenDemux()
  415. {
  416. PVR_CLIENT client;
  417. if (!g_PVRClients->GetPlayingClient(client))
  418. {
  419. return false;
  420. }
  421. client->GetStreamProperties(m_StreamProps);
  422. UpdateStreamMap();
  423. return true;
  424. }
  425. DemuxPacket* CDVDInputStreamPVRManager::ReadDemux()
  426. {
  427. PVR_CLIENT client;
  428. if (!g_PVRClients->GetPlayingClient(client))
  429. {
  430. return nullptr;
  431. }
  432. DemuxPacket* pPacket = client->DemuxRead();
  433. if (!pPacket)
  434. {
  435. return nullptr;
  436. }
  437. else if (pPacket->iStreamId == DMX_SPECIALID_STREAMINFO)
  438. {
  439. client->GetStreamProperties(m_StreamProps);
  440. return pPacket;
  441. }
  442. else if (pPacket->iStreamId == DMX_SPECIALID_STREAMCHANGE)
  443. {
  444. client->GetStreamProperties(m_StreamProps);
  445. UpdateStreamMap();
  446. }
  447. return pPacket;
  448. }
  449. CDemuxStream* CDVDInputStreamPVRManager::GetStream(int iStreamId) const
  450. {
  451. auto stream = m_streamMap.find(iStreamId);
  452. if (stream != m_streamMap.end())
  453. {
  454. return stream->second.get();
  455. }
  456. else
  457. return nullptr;
  458. }
  459. std::vector<CDemuxStream*> CDVDInputStreamPVRManager::GetStreams() const
  460. {
  461. std::vector<CDemuxStream*> streams;
  462. for (auto& st : m_streamMap)
  463. {
  464. streams.push_back(st.second.get());
  465. }
  466. return streams;
  467. }
  468. int CDVDInputStreamPVRManager::GetNrOfStreams() const
  469. {
  470. return m_StreamProps->iStreamCount;
  471. }
  472. void CDVDInputStreamPVRManager::SetSpeed(int Speed)
  473. {
  474. PVR_CLIENT client;
  475. if (g_PVRClients->GetPlayingClient(client))
  476. {
  477. client->SetSpeed(Speed);
  478. }
  479. }
  480. bool CDVDInputStreamPVRManager::SeekTime(int timems, bool backwards, double *startpts)
  481. {
  482. PVR_CLIENT client;
  483. if (g_PVRClients->GetPlayingClient(client))
  484. {
  485. return client->SeekTime(timems, backwards, startpts);
  486. }
  487. return false;
  488. }
  489. void CDVDInputStreamPVRManager::AbortDemux()
  490. {
  491. PVR_CLIENT client;
  492. if (g_PVRClients->GetPlayingClient(client))
  493. {
  494. client->DemuxAbort();
  495. }
  496. }
  497. void CDVDInputStreamPVRManager::FlushDemux()
  498. {
  499. PVR_CLIENT client;
  500. if (g_PVRClients->GetPlayingClient(client))
  501. {
  502. client->DemuxFlush();
  503. }
  504. }
  505. std::shared_ptr<CDemuxStream> CDVDInputStreamPVRManager::GetStreamInternal(int iStreamId)
  506. {
  507. auto stream = m_streamMap.find(iStreamId);
  508. if (stream != m_streamMap.end())
  509. {
  510. return stream->second;
  511. }
  512. else
  513. return nullptr;
  514. }
  515. void CDVDInputStreamPVRManager::UpdateStreamMap()
  516. {
  517. std::map<int, std::shared_ptr<CDemuxStream>> m_newStreamMap;
  518. int num = GetNrOfStreams();
  519. for (int i = 0; i < num; ++i)
  520. {
  521. PVR_STREAM_PROPERTIES::PVR_STREAM stream = m_StreamProps->stream[i];
  522. std::shared_ptr<CDemuxStream> dStream = GetStreamInternal(stream.iPID);
  523. if (stream.iCodecType == XBMC_CODEC_TYPE_AUDIO)
  524. {
  525. std::shared_ptr<CDemuxStreamAudio> streamAudio;
  526. if (dStream)
  527. streamAudio = std::dynamic_pointer_cast<CDemuxStreamAudio>(dStream);
  528. if (!streamAudio)
  529. streamAudio = std::make_shared<CDemuxStreamAudio>();
  530. streamAudio->iChannels = stream.iChannels;
  531. streamAudio->iSampleRate = stream.iSampleRate;
  532. streamAudio->iBlockAlign = stream.iBlockAlign;
  533. streamAudio->iBitRate = stream.iBitRate;
  534. streamAudio->iBitsPerSample = stream.iBitsPerSample;
  535. dStream = streamAudio;
  536. }
  537. else if (stream.iCodecType == XBMC_CODEC_TYPE_VIDEO)
  538. {
  539. std::shared_ptr<CDemuxStreamVideo> streamVideo;
  540. if (dStream)
  541. streamVideo = std::dynamic_pointer_cast<CDemuxStreamVideo>(dStream);
  542. if (!streamVideo)
  543. streamVideo = std::make_shared<CDemuxStreamVideo>();
  544. streamVideo->iFpsScale = stream.iFPSScale;
  545. streamVideo->iFpsRate = stream.iFPSRate;
  546. streamVideo->iHeight = stream.iHeight;
  547. streamVideo->iWidth = stream.iWidth;
  548. streamVideo->fAspect = stream.fAspect;
  549. streamVideo->stereo_mode = "mono";
  550. dStream = streamVideo;
  551. }
  552. else if (stream.iCodecId == AV_CODEC_ID_DVB_TELETEXT)
  553. {
  554. std::shared_ptr<CDemuxStreamTeletext> streamTeletext;
  555. if (dStream)
  556. streamTeletext = std::dynamic_pointer_cast<CDemuxStreamTeletext>(dStream);
  557. if (!streamTeletext)
  558. streamTeletext = std::make_shared<CDemuxStreamTeletext>();
  559. dStream = streamTeletext;
  560. }
  561. else if (stream.iCodecType == XBMC_CODEC_TYPE_SUBTITLE)
  562. {
  563. std::shared_ptr<CDemuxStreamSubtitle> streamSubtitle;
  564. if (dStream)
  565. streamSubtitle = std::dynamic_pointer_cast<CDemuxStreamSubtitle>(dStream);
  566. if (!streamSubtitle)
  567. streamSubtitle = std::make_shared<CDemuxStreamSubtitle>();
  568. if (stream.iSubtitleInfo)
  569. {
  570. streamSubtitle->ExtraData = new uint8_t[4];
  571. streamSubtitle->ExtraSize = 4;
  572. streamSubtitle->ExtraData[0] = (stream.iSubtitleInfo >> 8) & 0xff;
  573. streamSubtitle->ExtraData[1] = (stream.iSubtitleInfo >> 0) & 0xff;
  574. streamSubtitle->ExtraData[2] = (stream.iSubtitleInfo >> 24) & 0xff;
  575. streamSubtitle->ExtraData[3] = (stream.iSubtitleInfo >> 16) & 0xff;
  576. }
  577. dStream = streamSubtitle;
  578. }
  579. else if (stream.iCodecType == XBMC_CODEC_TYPE_RDS &&
  580. CSettings::GetInstance().GetBool("pvrplayback.enableradiords"))
  581. {
  582. std::shared_ptr<CDemuxStreamRadioRDS> streamRadioRDS;
  583. if (dStream)
  584. streamRadioRDS = std::dynamic_pointer_cast<CDemuxStreamRadioRDS>(dStream);
  585. if (!streamRadioRDS)
  586. streamRadioRDS = std::make_shared<CDemuxStreamRadioRDS>();
  587. dStream = streamRadioRDS;
  588. }
  589. else
  590. dStream = std::make_shared<CDemuxStream>();
  591. dStream->codec = (AVCodecID)stream.iCodecId;
  592. dStream->uniqueId = stream.iPID;
  593. dStream->language[0] = stream.strLanguage[0];
  594. dStream->language[1] = stream.strLanguage[1];
  595. dStream->language[2] = stream.strLanguage[2];
  596. dStream->language[3] = stream.strLanguage[3];
  597. dStream->realtime = true;
  598. m_newStreamMap[stream.iPID] = dStream;
  599. }
  600. m_streamMap = m_newStreamMap;
  601. }