Skip to content

Commit

Permalink
Re-add HLS recorder
Browse files Browse the repository at this point in the history
HLS recorder got removed following the IPTV branch merge a few months ago. Re-implement it using new framework
Construct it as a derivative of existing IPTV Stream Handler.
Extend IPTVChannel so it doesn't close immediately the stream handler. Instead we mark it for deletion and only delete it 5s later, re-use it if we attempt to use it again within that delay.
This is done to speed up startup as the HLS ring buffer can take a long time to start, and the signal monitor attempts to close the stream handler causing too much delay.
  • Loading branch information
jyavenard committed Jun 3, 2013
1 parent c227013 commit af0433b
Show file tree
Hide file tree
Showing 6 changed files with 349 additions and 31 deletions.
12 changes: 11 additions & 1 deletion mythtv/libs/libmythtv/iptvtuningdata.h
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 4 additions & 1 deletion mythtv/libs/libmythtv/libmythtv.pro
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
164 changes: 164 additions & 0 deletions 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();
}
47 changes: 47 additions & 0 deletions 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_

0 comments on commit af0433b

Please sign in to comment.