Advertisement
jyavenard

Untitled

Jun 3rd, 2013
154
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.65 KB | None | 0 0
  1. diff --git a/mythtv/libs/libmythtv/iptvtuningdata.h b/mythtv/libs/libmythtv/iptvtuningdata.h
  2. index d8d9cc5..0ebe2ff 100644
  3. --- a/mythtv/libs/libmythtv/iptvtuningdata.h
  4. +++ b/mythtv/libs/libmythtv/iptvtuningdata.h
  5. @@ -74,6 +74,8 @@ class MTV_PUBLIC IPTVTuningData
  6. QString GetDeviceKey(void) const
  7. {
  8. const QUrl u = GetDataURL();
  9. + if (IsHLS())
  10. + return u.toString();
  11. return QString("%1:%2:%3")
  12. .arg(u.host()).arg(u.userInfo()).arg(u.port()).toLower();
  13. }
  14. @@ -131,7 +133,15 @@ class MTV_PUBLIC IPTVTuningData
  15.  
  16. uint GetURLCount(void) const { return 3; }
  17.  
  18. - bool IsValid(void) const { return m_data_url.port() != -1; }
  19. + bool IsHLS(void) const
  20. + {
  21. + return m_data_url.scheme().startsWith("http") && m_data_url.isValid();
  22. + }
  23. +
  24. + bool IsValid(void) const
  25. + {
  26. + return IsHLS() || m_data_url.port() != -1;
  27. + }
  28.  
  29. public:
  30. QUrl m_data_url;
  31. diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro
  32. index fcf1170..de19f69 100644
  33. --- a/mythtv/libs/libmythtv/libmythtv.pro
  34. +++ b/mythtv/libs/libmythtv/libmythtv.pro
  35. @@ -29,7 +29,6 @@ DEPENDPATH += ../libmythdvdnav/
  36. DEPENDPATH += ./mpeg ./channelscan ./visualisations
  37. DEPENDPATH += ./recorders
  38. DEPENDPATH += ./recorders/dvbdev
  39. -DEPENDPATH += ./recorders/HLS
  40. DEPENDPATH += ./recorders/rtp
  41. DEPENDPATH += ./recorders/vbitext
  42. DEPENDPATH += ../libmythlivemedia/BasicUsageEnvironment/include
  43. @@ -651,6 +650,10 @@ using_backend {
  44. SOURCES += recorders/rtp/packetbuffer.cpp
  45. SOURCES += recorders/rtp/rtppacketbuffer.cpp
  46.  
  47. + # Suppport for HLS recorder
  48. + HEADERS += recorders/hlsstreamhandler.h
  49. + SOURCES += recorders/hlsstreamhandler.cpp
  50. +
  51. DEFINES += USING_IPTV
  52.  
  53. # Support for HDHomeRun box
  54. diff --git a/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp
  55. new file mode 100644
  56. index 0000000..3d908cf
  57. --- /dev/null
  58. +++ b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp
  59. @@ -0,0 +1,164 @@
  60. +/** -*- Mode: c++ -*-
  61. + * HLSStreamHandler
  62. + * Copyright (c) 2013 Bubblestuff Pty Ltd
  63. + * based on IPTVStreamHandler
  64. + * Distributed as part of MythTV under GPL v2 and later.
  65. + */
  66. +
  67. +// MythTV headers
  68. +#include "hlsstreamhandler.h"
  69. +#include "mythlogging.h"
  70. +#include "HLS/httplivestreambuffer.h"
  71. +
  72. +#define LOC QString("HLSSH(%1): ").arg(_device)
  73. +
  74. +// BUFFER_SIZE is a multiple of TS_SIZE
  75. +#define TS_SIZE 188
  76. +#define BUFFER_SIZE (128 * TS_SIZE)
  77. +
  78. +QMap<QString,HLSStreamHandler*> HLSStreamHandler::s_handlers;
  79. +QMap<QString,uint> HLSStreamHandler::s_handlers_refcnt;
  80. +QMutex HLSStreamHandler::s_handlers_lock;
  81. +
  82. +HLSStreamHandler* HLSStreamHandler::Get(const IPTVTuningData& tuning)
  83. +{
  84. + QMutexLocker locker(&s_handlers_lock);
  85. +
  86. + QString devkey = tuning.GetDeviceKey();
  87. +
  88. + QMap<QString,HLSStreamHandler*>::iterator it = s_handlers.find(devkey);
  89. +
  90. + if (it == s_handlers.end())
  91. + {
  92. + HLSStreamHandler* newhandler = new HLSStreamHandler(tuning);
  93. + newhandler->Start();
  94. + s_handlers[devkey] = newhandler;
  95. + s_handlers_refcnt[devkey] = 1;
  96. +
  97. + LOG(VB_RECORD, LOG_INFO,
  98. + QString("HLSSH: Creating new stream handler %1 for %2")
  99. + .arg(devkey).arg(tuning.GetDeviceName()));
  100. + }
  101. + else
  102. + {
  103. + s_handlers_refcnt[devkey]++;
  104. + uint rcount = s_handlers_refcnt[devkey];
  105. + LOG(VB_RECORD, LOG_INFO,
  106. + QString("HLSSH: Using existing stream handler %1 for %2")
  107. + .arg(devkey).arg(tuning.GetDeviceName()) +
  108. + QString(" (%1 in use)").arg(rcount));
  109. + }
  110. +
  111. + return s_handlers[devkey];
  112. +}
  113. +
  114. +void HLSStreamHandler::Return(HLSStreamHandler* & ref)
  115. +{
  116. + QMutexLocker locker(&s_handlers_lock);
  117. +
  118. + QString devname = ref->_device;
  119. +
  120. + QMap<QString,uint>::iterator rit = s_handlers_refcnt.find(devname);
  121. + if (rit == s_handlers_refcnt.end())
  122. + return;
  123. +
  124. + LOG(VB_RECORD, LOG_INFO, QString("HLSSH: Return(%1) has %2 handlers")
  125. + .arg(devname).arg(*rit));
  126. +
  127. + if (*rit > 1)
  128. + {
  129. + ref = NULL;
  130. + (*rit)--;
  131. + return;
  132. + }
  133. +
  134. + QMap<QString,HLSStreamHandler*>::iterator it = s_handlers.find(devname);
  135. + if ((it != s_handlers.end()) && (*it == ref))
  136. + {
  137. + LOG(VB_RECORD, LOG_INFO, QString("HLSSH: Closing handler for %1")
  138. + .arg(devname));
  139. + ref->Stop();
  140. + LOG(VB_RECORD, LOG_DEBUG, QString("HLSSH: handler for %1 stopped")
  141. + .arg(devname));
  142. + delete *it;
  143. + s_handlers.erase(it);
  144. + }
  145. + else
  146. + {
  147. + LOG(VB_GENERAL, LOG_ERR,
  148. + QString("HLSSH Error: Couldn't find handler for %1")
  149. + .arg(devname));
  150. + }
  151. +
  152. + s_handlers_refcnt.erase(rit);
  153. + ref = NULL;
  154. +}
  155. +
  156. +HLSStreamHandler::HLSStreamHandler(const IPTVTuningData& tuning) :
  157. + IPTVStreamHandler(tuning),
  158. + m_tuning(tuning)
  159. +{
  160. + m_hls = new HLSRingBuffer(m_tuning.GetURL(0).toString(), false);
  161. + m_buffer = new uint8_t[BUFFER_SIZE];
  162. +}
  163. +
  164. +HLSStreamHandler::~HLSStreamHandler(void)
  165. +{
  166. + Stop();
  167. + m_hls->Interrupt();
  168. + delete m_hls;
  169. + delete[] m_buffer;
  170. +}
  171. +
  172. +void HLSStreamHandler::run(void)
  173. +{
  174. + RunProlog();
  175. +
  176. + LOG(VB_GENERAL, LOG_INFO, LOC + "run()");
  177. +
  178. + SetRunning(true, false, false);
  179. +
  180. + // TODO Error handling..
  181. +
  182. + if (!m_hls->IsOpen())
  183. + {
  184. + m_hls->OpenFile(m_tuning.GetURL(0).toString());
  185. + }
  186. +
  187. + while (m_hls->IsOpen() && _running_desired)
  188. + {
  189. + int size = m_hls->Read((void*)m_buffer, BUFFER_SIZE);
  190. +
  191. + if (size < 0)
  192. + {
  193. + break; // error
  194. + }
  195. + if (m_buffer[0] != 0x47)
  196. + {
  197. + LOG(VB_RECORD, LOG_INFO, LOC +
  198. + QString("Packet not starting with SYNC Byte (got 0x%1)")
  199. + .arg((char)m_buffer[0], 2, QLatin1Char('0')));
  200. + }
  201. +
  202. + int remainder = 0;
  203. + {
  204. + QMutexLocker locker(&_listener_lock);
  205. + HLSStreamHandler::StreamDataList::const_iterator sit;
  206. + sit = _stream_data_list.begin();
  207. + for (; sit != _stream_data_list.end(); ++sit)
  208. + {
  209. + remainder = sit.key()->ProcessData(m_buffer, size);
  210. + }
  211. + }
  212. +
  213. + if (remainder != 0)
  214. + {
  215. + LOG(VB_RECORD, LOG_INFO, LOC +
  216. + QString("data_length = %1 remainder = %2")
  217. + .arg(size).arg(remainder));
  218. + }
  219. + }
  220. +
  221. + SetRunning(false, false, false);
  222. + RunEpilog();
  223. +}
  224. diff --git a/mythtv/libs/libmythtv/recorders/hlsstreamhandler.h b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.h
  225. new file mode 100644
  226. index 0000000..6593fb6
  227. --- /dev/null
  228. +++ b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.h
  229. @@ -0,0 +1,47 @@
  230. +/** -*- Mode: c++ -*-
  231. + * HLSStreamHandler
  232. + * Copyright (c) 2013 Bubblestuff Pty Ltd
  233. + * based on IPTVStreamHandler
  234. + * Distributed as part of MythTV under GPL v2 and later.
  235. + */
  236. +
  237. +#ifndef _HLSSTREAMHANDLER_H_
  238. +#define _HLSSTREAMHANDLER_H_
  239. +
  240. +#include <vector>
  241. +using namespace std;
  242. +
  243. +#include <QString>
  244. +#include <QMutex>
  245. +#include <QMap>
  246. +
  247. +#include "channelutil.h"
  248. +#include "iptvstreamhandler.h"
  249. +
  250. +class MPEGStreamData;
  251. +class HLSRingBuffer;
  252. +
  253. +class HLSStreamHandler : public IPTVStreamHandler
  254. +{
  255. + public:
  256. + static HLSStreamHandler* Get(const IPTVTuningData& tuning);
  257. + static void Return(HLSStreamHandler* & ref);
  258. +
  259. + protected:
  260. + HLSStreamHandler(const IPTVTuningData &tuning);
  261. + virtual ~HLSStreamHandler(void);
  262. +
  263. + virtual void run(void); // MThread
  264. +
  265. + protected:
  266. + IPTVTuningData m_tuning;
  267. + HLSRingBuffer* m_hls;
  268. + uint8_t* m_buffer;
  269. +
  270. + // for implementing Get & Return
  271. + static QMutex s_handlers_lock;
  272. + static QMap<QString, HLSStreamHandler*> s_handlers;
  273. + static QMap<QString, uint> s_handlers_refcnt;
  274. +};
  275. +
  276. +#endif // _HLSSTREAMHANDLER_H_
  277. diff --git a/mythtv/libs/libmythtv/recorders/iptvchannel.cpp b/mythtv/libs/libmythtv/recorders/iptvchannel.cpp
  278. index 941aa6e..7fc1bf0 100644
  279. --- a/mythtv/libs/libmythtv/recorders/iptvchannel.cpp
  280. +++ b/mythtv/libs/libmythtv/recorders/iptvchannel.cpp
  281. @@ -11,6 +11,7 @@
  282.  
  283. // MythTV headers
  284. #include "iptvstreamhandler.h"
  285. +#include "hlsstreamhandler.h"
  286. #include "iptvrecorder.h"
  287. #include "iptvchannel.h"
  288. #include "mythlogging.h"
  289. @@ -19,16 +20,25 @@
  290. #define LOC QString("IPTVChan[%1]: ").arg(GetCardID())
  291.  
  292. IPTVChannel::IPTVChannel(TVRec *rec, const QString&) :
  293. - DTVChannel(rec), m_open(false),
  294. - m_stream_handler(NULL), m_stream_data(NULL)
  295. + DTVChannel(rec), m_open(false), m_firsttune(true),
  296. + m_stream_handler(NULL), m_stream_data(NULL), m_timer(0)
  297. {
  298. LOG(VB_CHANNEL, LOG_INFO, LOC + "ctor");
  299. }
  300.  
  301. +void IPTVChannel::KillTimer(void)
  302. +{
  303. + if (m_timer)
  304. + {
  305. + killTimer(m_timer);
  306. + m_timer = 0;
  307. + }
  308. +}
  309. +
  310. IPTVChannel::~IPTVChannel()
  311. {
  312. LOG(VB_CHANNEL, LOG_INFO, LOC + "dtor");
  313. - m_stream_data = NULL;
  314. + Close();
  315. }
  316.  
  317. bool IPTVChannel::Open(void)
  318. @@ -38,16 +48,21 @@ bool IPTVChannel::Open(void)
  319. if (IsOpen())
  320. return true;
  321.  
  322. - QMutexLocker locker(&m_lock);
  323. + m_lock.lock();
  324.  
  325. if (!InitializeInputs())
  326. {
  327. + m_lock.unlock();
  328. Close();
  329. return false;
  330. }
  331.  
  332. if (m_stream_data)
  333. - SetStreamDataInternal(m_stream_data);
  334. + SetStreamDataInternal(m_stream_data, true);
  335. +
  336. + m_open = true;
  337. +
  338. + m_lock.unlock();
  339.  
  340. return true;
  341. }
  342. @@ -55,63 +70,115 @@ bool IPTVChannel::Open(void)
  343. void IPTVChannel::SetStreamData(MPEGStreamData *sd)
  344. {
  345. QMutexLocker locker(&m_lock);
  346. - SetStreamDataInternal(sd);
  347. + SetStreamDataInternal(sd, false);
  348. }
  349.  
  350. -void IPTVChannel::SetStreamDataInternal(MPEGStreamData *sd)
  351. +void IPTVChannel::SetStreamDataInternal(MPEGStreamData *sd, bool closeimmediately)
  352. {
  353. - LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetStreamData(0x%1)")
  354. - .arg((intptr_t)sd,0,16));
  355. + LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetStreamData(0x%1) StreamHandler(0x%2) Close(%3)")
  356. + .arg((intptr_t)sd,0,16).arg((intptr_t)m_stream_handler,0,16).arg(closeimmediately));
  357.  
  358. if (m_stream_data == sd)
  359. return;
  360.  
  361. - if (m_stream_data)
  362. + if (m_stream_handler)
  363. {
  364. - if (sd)
  365. + KillTimer();
  366. +
  367. + if (m_stream_data)
  368. {
  369. m_stream_handler->RemoveListener(m_stream_data);
  370. + }
  371. + if (sd)
  372. + {
  373. m_stream_handler->AddListener(sd);
  374. }
  375. else
  376. {
  377. - m_stream_handler->RemoveListener(m_stream_data);
  378. - IPTVStreamHandler::Return(m_stream_handler);
  379. + if (!closeimmediately)
  380. + {
  381. + // streamdata is zero
  382. + // mark stream handler for deletion in 5s
  383. + // so we can re-use it shortly if need be
  384. + LOG(VB_CHANNEL, LOG_DEBUG, LOC +
  385. + QString("Scheduling for deletion: StreamHandler(0x%1)")
  386. + .arg((intptr_t)m_stream_handler,0,16));
  387. + m_timer = startTimer(5000);
  388. + }
  389. + else
  390. + {
  391. + CloseStreamHandler();
  392. + }
  393. }
  394. }
  395. else
  396. {
  397. - assert(m_stream_handler == NULL);
  398. - if (m_stream_handler)
  399. - IPTVStreamHandler::Return(m_stream_handler);
  400. -
  401. if (sd)
  402. {
  403. - if (m_last_tuning.IsValid())
  404. - m_stream_handler = IPTVStreamHandler::Get(m_last_tuning);
  405. - if (m_stream_handler)
  406. - m_stream_handler->AddListener(sd);
  407. + OpenStreamHandler();
  408. + m_stream_handler->AddListener(sd);
  409. }
  410. }
  411.  
  412. m_stream_data = sd;
  413. }
  414.  
  415. +void IPTVChannel::timerEvent(QTimerEvent*)
  416. +{
  417. + LOG(VB_CHANNEL, LOG_INFO, LOC + "timerEvent()");
  418. +
  419. + CloseStreamHandler();
  420. +}
  421. +
  422. void IPTVChannel::Close(void)
  423. {
  424. LOG(VB_CHANNEL, LOG_INFO, LOC + "Close()");
  425. QMutexLocker locker(&m_lock);
  426. +
  427. + CloseStreamHandler();
  428. +
  429. + m_open = false;
  430. +}
  431. +
  432. +void IPTVChannel::OpenStreamHandler(void)
  433. +{
  434. + if (m_last_tuning.IsHLS())
  435. + {
  436. + m_stream_handler = HLSStreamHandler::Get(m_last_tuning);
  437. + }
  438. + else
  439. + {
  440. + m_stream_handler = IPTVStreamHandler::Get(m_last_tuning);
  441. + }
  442. +}
  443. +
  444. +void IPTVChannel::CloseStreamHandler(void)
  445. +{
  446. + KillTimer();
  447. +
  448. if (m_stream_handler)
  449. {
  450. if (m_stream_data)
  451. m_stream_handler->RemoveListener(m_stream_data);
  452. - IPTVStreamHandler::Return(m_stream_handler);
  453. +
  454. + HLSStreamHandler* hsh = dynamic_cast<HLSStreamHandler*>(m_stream_handler);
  455. + if (hsh)
  456. + {
  457. + HLSStreamHandler::Return(hsh);
  458. + m_stream_handler = hsh;
  459. + }
  460. + else
  461. + {
  462. + IPTVStreamHandler::Return(m_stream_handler);
  463. + }
  464. }
  465. }
  466.  
  467. bool IPTVChannel::IsOpen(void) const
  468. {
  469. QMutexLocker locker(&m_lock);
  470. + LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("IsOpen(%1)")
  471. + .arg(m_last_tuning.GetDeviceName()));
  472. return m_open;
  473. }
  474.  
  475. @@ -135,17 +202,34 @@ bool IPTVChannel::Tune(const IPTVTuningData &tuning)
  476. }
  477.  
  478. if (m_last_tuning == tuning)
  479. + {
  480. + LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("Already tuned to %1")
  481. + .arg(tuning.GetDeviceName()));
  482. return true;
  483. + }
  484.  
  485. m_last_tuning = tuning;
  486.  
  487. - if (m_stream_data)
  488. + if (!m_firsttune) // for historical reason, an initial tune is requested at startup
  489. + // so don't open the stream handler just yet
  490. + // it will be opened after the next Tune or SetStreamData)
  491. {
  492. MPEGStreamData *tmp = m_stream_data;
  493. - SetStreamDataInternal(NULL);
  494. - SetStreamDataInternal(tmp);
  495. +
  496. + CloseStreamHandler();
  497. +
  498. + if (tmp)
  499. + {
  500. + SetStreamDataInternal(tmp, true);
  501. + }
  502. + else
  503. + {
  504. + OpenStreamHandler();
  505. + }
  506. }
  507.  
  508. + m_firsttune = false;
  509. +
  510. return true;
  511. }
  512.  
  513. diff --git a/mythtv/libs/libmythtv/recorders/iptvchannel.h b/mythtv/libs/libmythtv/recorders/iptvchannel.h
  514. index 69ee1f2..60013e5 100644
  515. --- a/mythtv/libs/libmythtv/recorders/iptvchannel.h
  516. +++ b/mythtv/libs/libmythtv/recorders/iptvchannel.h
  517. @@ -18,16 +18,19 @@
  518. class IPTVStreamHandler;
  519. class IPTVTuningData;
  520. class IPTVRecorder;
  521. +class MPEGStreamData;
  522.  
  523. -class IPTVChannel : public DTVChannel
  524. +class IPTVChannel : QObject, public DTVChannel
  525. {
  526. + Q_OBJECT
  527. +
  528. public:
  529. IPTVChannel(TVRec*, const QString&);
  530. ~IPTVChannel();
  531.  
  532. // Commands
  533. virtual bool Open(void);
  534. - virtual void Close(void);
  535. + virtual void Close(void);
  536.  
  537. using DTVChannel::Tune;
  538. virtual bool Tune(const IPTVTuningData&);
  539. @@ -41,14 +44,19 @@ class IPTVChannel : public DTVChannel
  540. virtual bool IsIPTV(void) const { return true; } // DTVChannel
  541.  
  542. private:
  543. - void SetStreamDataInternal(MPEGStreamData*);
  544. + void SetStreamDataInternal(MPEGStreamData*, bool closeimmediately);
  545. + void timerEvent(QTimerEvent*);
  546. + void KillTimer(void);
  547. + void OpenStreamHandler(void);
  548. + void CloseStreamHandler(void);
  549.  
  550. private:
  551. mutable QMutex m_lock;
  552. - volatile bool m_open;
  553. + volatile bool m_open, m_firsttune;
  554. IPTVTuningData m_last_tuning;
  555. IPTVStreamHandler *m_stream_handler;
  556. MPEGStreamData *m_stream_data;
  557. + int m_timer;
  558. };
  559.  
  560. #endif // _IPTV_CHANNEL_H_
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement