Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- diff --git a/mythtv/libs/libmythtv/iptvtuningdata.h b/mythtv/libs/libmythtv/iptvtuningdata.h
- index d8d9cc5..0ebe2ff 100644
- --- a/mythtv/libs/libmythtv/iptvtuningdata.h
- +++ b/mythtv/libs/libmythtv/iptvtuningdata.h
- @@ -74,6 +74,8 @@ class MTV_PUBLIC IPTVTuningData
- QString GetDeviceKey(void) const
- {
- const QUrl u = GetDataURL();
- + if (IsHLS())
- + return u.toString();
- return QString("%1:%2:%3")
- .arg(u.host()).arg(u.userInfo()).arg(u.port()).toLower();
- }
- @@ -131,7 +133,15 @@ class MTV_PUBLIC IPTVTuningData
- uint GetURLCount(void) const { return 3; }
- - bool IsValid(void) const { return m_data_url.port() != -1; }
- + bool IsHLS(void) const
- + {
- + return m_data_url.scheme().startsWith("http") && m_data_url.isValid();
- + }
- +
- + bool IsValid(void) const
- + {
- + return IsHLS() || m_data_url.port() != -1;
- + }
- public:
- QUrl m_data_url;
- diff --git a/mythtv/libs/libmythtv/libmythtv.pro b/mythtv/libs/libmythtv/libmythtv.pro
- index fcf1170..de19f69 100644
- --- a/mythtv/libs/libmythtv/libmythtv.pro
- +++ b/mythtv/libs/libmythtv/libmythtv.pro
- @@ -29,7 +29,6 @@ DEPENDPATH += ../libmythdvdnav/
- DEPENDPATH += ./mpeg ./channelscan ./visualisations
- DEPENDPATH += ./recorders
- DEPENDPATH += ./recorders/dvbdev
- -DEPENDPATH += ./recorders/HLS
- DEPENDPATH += ./recorders/rtp
- DEPENDPATH += ./recorders/vbitext
- DEPENDPATH += ../libmythlivemedia/BasicUsageEnvironment/include
- @@ -651,6 +650,10 @@ using_backend {
- SOURCES += recorders/rtp/packetbuffer.cpp
- SOURCES += recorders/rtp/rtppacketbuffer.cpp
- + # Suppport for HLS recorder
- + HEADERS += recorders/hlsstreamhandler.h
- + SOURCES += recorders/hlsstreamhandler.cpp
- +
- DEFINES += USING_IPTV
- # Support for HDHomeRun box
- diff --git a/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp
- new file mode 100644
- index 0000000..3d908cf
- --- /dev/null
- +++ b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.cpp
- @@ -0,0 +1,164 @@
- +/** -*- Mode: c++ -*-
- + * HLSStreamHandler
- + * Copyright (c) 2013 Bubblestuff Pty Ltd
- + * based on IPTVStreamHandler
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +// MythTV headers
- +#include "hlsstreamhandler.h"
- +#include "mythlogging.h"
- +#include "HLS/httplivestreambuffer.h"
- +
- +#define LOC QString("HLSSH(%1): ").arg(_device)
- +
- +// BUFFER_SIZE is a multiple of TS_SIZE
- +#define TS_SIZE 188
- +#define BUFFER_SIZE (128 * TS_SIZE)
- +
- +QMap<QString,HLSStreamHandler*> HLSStreamHandler::s_handlers;
- +QMap<QString,uint> HLSStreamHandler::s_handlers_refcnt;
- +QMutex HLSStreamHandler::s_handlers_lock;
- +
- +HLSStreamHandler* HLSStreamHandler::Get(const IPTVTuningData& tuning)
- +{
- + QMutexLocker locker(&s_handlers_lock);
- +
- + QString devkey = tuning.GetDeviceKey();
- +
- + QMap<QString,HLSStreamHandler*>::iterator it = s_handlers.find(devkey);
- +
- + if (it == s_handlers.end())
- + {
- + HLSStreamHandler* newhandler = new HLSStreamHandler(tuning);
- + newhandler->Start();
- + s_handlers[devkey] = newhandler;
- + s_handlers_refcnt[devkey] = 1;
- +
- + LOG(VB_RECORD, LOG_INFO,
- + QString("HLSSH: Creating new stream handler %1 for %2")
- + .arg(devkey).arg(tuning.GetDeviceName()));
- + }
- + else
- + {
- + s_handlers_refcnt[devkey]++;
- + uint rcount = s_handlers_refcnt[devkey];
- + LOG(VB_RECORD, LOG_INFO,
- + QString("HLSSH: Using existing stream handler %1 for %2")
- + .arg(devkey).arg(tuning.GetDeviceName()) +
- + QString(" (%1 in use)").arg(rcount));
- + }
- +
- + return s_handlers[devkey];
- +}
- +
- +void HLSStreamHandler::Return(HLSStreamHandler* & ref)
- +{
- + QMutexLocker locker(&s_handlers_lock);
- +
- + QString devname = ref->_device;
- +
- + QMap<QString,uint>::iterator rit = s_handlers_refcnt.find(devname);
- + if (rit == s_handlers_refcnt.end())
- + return;
- +
- + LOG(VB_RECORD, LOG_INFO, QString("HLSSH: Return(%1) has %2 handlers")
- + .arg(devname).arg(*rit));
- +
- + if (*rit > 1)
- + {
- + ref = NULL;
- + (*rit)--;
- + return;
- + }
- +
- + QMap<QString,HLSStreamHandler*>::iterator it = s_handlers.find(devname);
- + if ((it != s_handlers.end()) && (*it == ref))
- + {
- + LOG(VB_RECORD, LOG_INFO, QString("HLSSH: Closing handler for %1")
- + .arg(devname));
- + ref->Stop();
- + LOG(VB_RECORD, LOG_DEBUG, QString("HLSSH: handler for %1 stopped")
- + .arg(devname));
- + delete *it;
- + s_handlers.erase(it);
- + }
- + else
- + {
- + LOG(VB_GENERAL, LOG_ERR,
- + QString("HLSSH Error: Couldn't find handler for %1")
- + .arg(devname));
- + }
- +
- + s_handlers_refcnt.erase(rit);
- + ref = NULL;
- +}
- +
- +HLSStreamHandler::HLSStreamHandler(const IPTVTuningData& tuning) :
- + IPTVStreamHandler(tuning),
- + m_tuning(tuning)
- +{
- + m_hls = new HLSRingBuffer(m_tuning.GetURL(0).toString(), false);
- + m_buffer = new uint8_t[BUFFER_SIZE];
- +}
- +
- +HLSStreamHandler::~HLSStreamHandler(void)
- +{
- + Stop();
- + m_hls->Interrupt();
- + delete m_hls;
- + delete[] m_buffer;
- +}
- +
- +void HLSStreamHandler::run(void)
- +{
- + RunProlog();
- +
- + LOG(VB_GENERAL, LOG_INFO, LOC + "run()");
- +
- + SetRunning(true, false, false);
- +
- + // TODO Error handling..
- +
- + if (!m_hls->IsOpen())
- + {
- + m_hls->OpenFile(m_tuning.GetURL(0).toString());
- + }
- +
- + while (m_hls->IsOpen() && _running_desired)
- + {
- + int size = m_hls->Read((void*)m_buffer, BUFFER_SIZE);
- +
- + if (size < 0)
- + {
- + break; // error
- + }
- + if (m_buffer[0] != 0x47)
- + {
- + LOG(VB_RECORD, LOG_INFO, LOC +
- + QString("Packet not starting with SYNC Byte (got 0x%1)")
- + .arg((char)m_buffer[0], 2, QLatin1Char('0')));
- + }
- +
- + int remainder = 0;
- + {
- + QMutexLocker locker(&_listener_lock);
- + HLSStreamHandler::StreamDataList::const_iterator sit;
- + sit = _stream_data_list.begin();
- + for (; sit != _stream_data_list.end(); ++sit)
- + {
- + remainder = sit.key()->ProcessData(m_buffer, size);
- + }
- + }
- +
- + if (remainder != 0)
- + {
- + LOG(VB_RECORD, LOG_INFO, LOC +
- + QString("data_length = %1 remainder = %2")
- + .arg(size).arg(remainder));
- + }
- + }
- +
- + SetRunning(false, false, false);
- + RunEpilog();
- +}
- diff --git a/mythtv/libs/libmythtv/recorders/hlsstreamhandler.h b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.h
- new file mode 100644
- index 0000000..6593fb6
- --- /dev/null
- +++ b/mythtv/libs/libmythtv/recorders/hlsstreamhandler.h
- @@ -0,0 +1,47 @@
- +/** -*- Mode: c++ -*-
- + * HLSStreamHandler
- + * Copyright (c) 2013 Bubblestuff Pty Ltd
- + * based on IPTVStreamHandler
- + * Distributed as part of MythTV under GPL v2 and later.
- + */
- +
- +#ifndef _HLSSTREAMHANDLER_H_
- +#define _HLSSTREAMHANDLER_H_
- +
- +#include <vector>
- +using namespace std;
- +
- +#include <QString>
- +#include <QMutex>
- +#include <QMap>
- +
- +#include "channelutil.h"
- +#include "iptvstreamhandler.h"
- +
- +class MPEGStreamData;
- +class HLSRingBuffer;
- +
- +class HLSStreamHandler : public IPTVStreamHandler
- +{
- + public:
- + static HLSStreamHandler* Get(const IPTVTuningData& tuning);
- + static void Return(HLSStreamHandler* & ref);
- +
- + protected:
- + HLSStreamHandler(const IPTVTuningData &tuning);
- + virtual ~HLSStreamHandler(void);
- +
- + virtual void run(void); // MThread
- +
- + protected:
- + IPTVTuningData m_tuning;
- + HLSRingBuffer* m_hls;
- + uint8_t* m_buffer;
- +
- + // for implementing Get & Return
- + static QMutex s_handlers_lock;
- + static QMap<QString, HLSStreamHandler*> s_handlers;
- + static QMap<QString, uint> s_handlers_refcnt;
- +};
- +
- +#endif // _HLSSTREAMHANDLER_H_
- diff --git a/mythtv/libs/libmythtv/recorders/iptvchannel.cpp b/mythtv/libs/libmythtv/recorders/iptvchannel.cpp
- index 941aa6e..7fc1bf0 100644
- --- a/mythtv/libs/libmythtv/recorders/iptvchannel.cpp
- +++ b/mythtv/libs/libmythtv/recorders/iptvchannel.cpp
- @@ -11,6 +11,7 @@
- // MythTV headers
- #include "iptvstreamhandler.h"
- +#include "hlsstreamhandler.h"
- #include "iptvrecorder.h"
- #include "iptvchannel.h"
- #include "mythlogging.h"
- @@ -19,16 +20,25 @@
- #define LOC QString("IPTVChan[%1]: ").arg(GetCardID())
- IPTVChannel::IPTVChannel(TVRec *rec, const QString&) :
- - DTVChannel(rec), m_open(false),
- - m_stream_handler(NULL), m_stream_data(NULL)
- + DTVChannel(rec), m_open(false), m_firsttune(true),
- + m_stream_handler(NULL), m_stream_data(NULL), m_timer(0)
- {
- LOG(VB_CHANNEL, LOG_INFO, LOC + "ctor");
- }
- +void IPTVChannel::KillTimer(void)
- +{
- + if (m_timer)
- + {
- + killTimer(m_timer);
- + m_timer = 0;
- + }
- +}
- +
- IPTVChannel::~IPTVChannel()
- {
- LOG(VB_CHANNEL, LOG_INFO, LOC + "dtor");
- - m_stream_data = NULL;
- + Close();
- }
- bool IPTVChannel::Open(void)
- @@ -38,16 +48,21 @@ bool IPTVChannel::Open(void)
- if (IsOpen())
- return true;
- - QMutexLocker locker(&m_lock);
- + m_lock.lock();
- if (!InitializeInputs())
- {
- + m_lock.unlock();
- Close();
- return false;
- }
- if (m_stream_data)
- - SetStreamDataInternal(m_stream_data);
- + SetStreamDataInternal(m_stream_data, true);
- +
- + m_open = true;
- +
- + m_lock.unlock();
- return true;
- }
- @@ -55,63 +70,115 @@ bool IPTVChannel::Open(void)
- void IPTVChannel::SetStreamData(MPEGStreamData *sd)
- {
- QMutexLocker locker(&m_lock);
- - SetStreamDataInternal(sd);
- + SetStreamDataInternal(sd, false);
- }
- -void IPTVChannel::SetStreamDataInternal(MPEGStreamData *sd)
- +void IPTVChannel::SetStreamDataInternal(MPEGStreamData *sd, bool closeimmediately)
- {
- - LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetStreamData(0x%1)")
- - .arg((intptr_t)sd,0,16));
- + LOG(VB_CHANNEL, LOG_INFO, LOC + QString("SetStreamData(0x%1) StreamHandler(0x%2) Close(%3)")
- + .arg((intptr_t)sd,0,16).arg((intptr_t)m_stream_handler,0,16).arg(closeimmediately));
- if (m_stream_data == sd)
- return;
- - if (m_stream_data)
- + if (m_stream_handler)
- {
- - if (sd)
- + KillTimer();
- +
- + if (m_stream_data)
- {
- m_stream_handler->RemoveListener(m_stream_data);
- + }
- + if (sd)
- + {
- m_stream_handler->AddListener(sd);
- }
- else
- {
- - m_stream_handler->RemoveListener(m_stream_data);
- - IPTVStreamHandler::Return(m_stream_handler);
- + if (!closeimmediately)
- + {
- + // streamdata is zero
- + // mark stream handler for deletion in 5s
- + // so we can re-use it shortly if need be
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC +
- + QString("Scheduling for deletion: StreamHandler(0x%1)")
- + .arg((intptr_t)m_stream_handler,0,16));
- + m_timer = startTimer(5000);
- + }
- + else
- + {
- + CloseStreamHandler();
- + }
- }
- }
- else
- {
- - assert(m_stream_handler == NULL);
- - if (m_stream_handler)
- - IPTVStreamHandler::Return(m_stream_handler);
- -
- if (sd)
- {
- - if (m_last_tuning.IsValid())
- - m_stream_handler = IPTVStreamHandler::Get(m_last_tuning);
- - if (m_stream_handler)
- - m_stream_handler->AddListener(sd);
- + OpenStreamHandler();
- + m_stream_handler->AddListener(sd);
- }
- }
- m_stream_data = sd;
- }
- +void IPTVChannel::timerEvent(QTimerEvent*)
- +{
- + LOG(VB_CHANNEL, LOG_INFO, LOC + "timerEvent()");
- +
- + CloseStreamHandler();
- +}
- +
- void IPTVChannel::Close(void)
- {
- LOG(VB_CHANNEL, LOG_INFO, LOC + "Close()");
- QMutexLocker locker(&m_lock);
- +
- + CloseStreamHandler();
- +
- + m_open = false;
- +}
- +
- +void IPTVChannel::OpenStreamHandler(void)
- +{
- + if (m_last_tuning.IsHLS())
- + {
- + m_stream_handler = HLSStreamHandler::Get(m_last_tuning);
- + }
- + else
- + {
- + m_stream_handler = IPTVStreamHandler::Get(m_last_tuning);
- + }
- +}
- +
- +void IPTVChannel::CloseStreamHandler(void)
- +{
- + KillTimer();
- +
- if (m_stream_handler)
- {
- if (m_stream_data)
- m_stream_handler->RemoveListener(m_stream_data);
- - IPTVStreamHandler::Return(m_stream_handler);
- +
- + HLSStreamHandler* hsh = dynamic_cast<HLSStreamHandler*>(m_stream_handler);
- + if (hsh)
- + {
- + HLSStreamHandler::Return(hsh);
- + m_stream_handler = hsh;
- + }
- + else
- + {
- + IPTVStreamHandler::Return(m_stream_handler);
- + }
- }
- }
- bool IPTVChannel::IsOpen(void) const
- {
- QMutexLocker locker(&m_lock);
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("IsOpen(%1)")
- + .arg(m_last_tuning.GetDeviceName()));
- return m_open;
- }
- @@ -135,17 +202,34 @@ bool IPTVChannel::Tune(const IPTVTuningData &tuning)
- }
- if (m_last_tuning == tuning)
- + {
- + LOG(VB_CHANNEL, LOG_DEBUG, LOC + QString("Already tuned to %1")
- + .arg(tuning.GetDeviceName()));
- return true;
- + }
- m_last_tuning = tuning;
- - if (m_stream_data)
- + if (!m_firsttune) // for historical reason, an initial tune is requested at startup
- + // so don't open the stream handler just yet
- + // it will be opened after the next Tune or SetStreamData)
- {
- MPEGStreamData *tmp = m_stream_data;
- - SetStreamDataInternal(NULL);
- - SetStreamDataInternal(tmp);
- +
- + CloseStreamHandler();
- +
- + if (tmp)
- + {
- + SetStreamDataInternal(tmp, true);
- + }
- + else
- + {
- + OpenStreamHandler();
- + }
- }
- + m_firsttune = false;
- +
- return true;
- }
- diff --git a/mythtv/libs/libmythtv/recorders/iptvchannel.h b/mythtv/libs/libmythtv/recorders/iptvchannel.h
- index 69ee1f2..60013e5 100644
- --- a/mythtv/libs/libmythtv/recorders/iptvchannel.h
- +++ b/mythtv/libs/libmythtv/recorders/iptvchannel.h
- @@ -18,16 +18,19 @@
- class IPTVStreamHandler;
- class IPTVTuningData;
- class IPTVRecorder;
- +class MPEGStreamData;
- -class IPTVChannel : public DTVChannel
- +class IPTVChannel : QObject, public DTVChannel
- {
- + Q_OBJECT
- +
- public:
- IPTVChannel(TVRec*, const QString&);
- ~IPTVChannel();
- // Commands
- virtual bool Open(void);
- - virtual void Close(void);
- + virtual void Close(void);
- using DTVChannel::Tune;
- virtual bool Tune(const IPTVTuningData&);
- @@ -41,14 +44,19 @@ class IPTVChannel : public DTVChannel
- virtual bool IsIPTV(void) const { return true; } // DTVChannel
- private:
- - void SetStreamDataInternal(MPEGStreamData*);
- + void SetStreamDataInternal(MPEGStreamData*, bool closeimmediately);
- + void timerEvent(QTimerEvent*);
- + void KillTimer(void);
- + void OpenStreamHandler(void);
- + void CloseStreamHandler(void);
- private:
- mutable QMutex m_lock;
- - volatile bool m_open;
- + volatile bool m_open, m_firsttune;
- IPTVTuningData m_last_tuning;
- IPTVStreamHandler *m_stream_handler;
- MPEGStreamData *m_stream_data;
- + int m_timer;
- };
- #endif // _IPTV_CHANNEL_H_
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement