Skip to content

Commit

Permalink
Sat>IP client -- Add recording of MPTS streams
Browse files Browse the repository at this point in the history
Add the capability to record a full transport stream, similar to how it is done for the HDHomeRun tuners.
Reduce the interval to wait before processing received RTP packets from 200 to 20 milliseconds.
This greatly reduces the number of missed RTP packets and the corresponding "Sequence number" error messages.

Refs #13121
  • Loading branch information
kmdewaal committed Aug 23, 2020
1 parent 083367b commit cf09ffe
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 33 deletions.
39 changes: 31 additions & 8 deletions mythtv/libs/libmythtv/recorders/satiprecorder.cpp
@@ -1,4 +1,9 @@
// C++ includes
#include <chrono>
#include <thread>

// MythTV includes
#include "tsstreamdata.h"
#include "satipstreamhandler.h"
#include "satiprecorder.h"
#include "satipchannel.h"
Expand All @@ -25,6 +30,15 @@ bool SatIPRecorder::Open(void)

ResetForNewFile();

if (m_channel->GetFormat().compare("MPTS") == 0)
{
// MPTS only. Use TSStreamData to write out unfiltered data.
LOG(VB_RECORD, LOG_INFO, LOC + "Using TSStreamData");
SetStreamData(new TSStreamData(m_inputId));
m_recordMptsOnly = true;
m_recordMpts = false;
}

m_streamHandler = SatIPStreamHandler::Get(m_channel->GetDevice(), m_inputId);

LOG(VB_RECORD, LOG_INFO, LOC + "SatIP opened successfully");
Expand All @@ -42,14 +56,17 @@ void SatIPRecorder::Close(void)

void SatIPRecorder::StartNewFile(void)
{
if (m_recordMpts)
if (!m_recordMptsOnly)
{
m_streamHandler->AddNamedOutputFile(m_ringBuffer->GetFilename());
}
if (m_recordMpts)
{
m_streamHandler->AddNamedOutputFile(m_ringBuffer->GetFilename());
}

// Make sure the first things in the file are a PAT & PMT
HandleSingleProgramPAT(m_streamData->PATSingleProgram(), true);
HandleSingleProgramPMT(m_streamData->PMTSingleProgram(), true);
// Make sure the first things in the file are a PAT & PMT
HandleSingleProgramPAT(m_streamData->PATSingleProgram(), true);
HandleSingleProgramPMT(m_streamData->PMTSingleProgram(), true);
}
}

void SatIPRecorder::run(void)
Expand All @@ -71,6 +88,12 @@ void SatIPRecorder::run(void)
m_recordingWait.wakeAll();
}

// Listen for time table on DVB standard streams
if (m_channel && (m_channel->GetSIStandard() == "dvb"))
m_streamData->AddListeningPID(DVB_TDT_PID);
if (m_recordMptsOnly)
m_streamData->AddListeningPID(0x2000);

StartNewFile();

m_streamData->AddAVListener(this);
Expand All @@ -95,11 +118,11 @@ void SatIPRecorder::run(void)
m_unpauseWait.wait(&m_pauseLock, 100);
}

if (!m_inputPmt)
if (!m_inputPmt && !m_recordMptsOnly)
{
LOG(VB_GENERAL, LOG_WARNING, LOC +
"Recording will not commence until a PMT is set.");
usleep(5000);
std::this_thread::sleep_for(std::chrono::milliseconds(5));
continue;
}

Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/recorders/satiprtsp.cpp
Expand Up @@ -489,7 +489,7 @@ SatIPRTSPWriteHelper::SatIPRTSPWriteHelper(SatIPRTSP* parent, SatIPStreamHandler
: m_parent(parent)
, m_streamHandler(handler)
{
m_timer = startTimer(200);
m_timer = startTimer(20);
}

void SatIPRTSPWriteHelper::timerEvent(QTimerEvent* /*event*/)
Expand Down
49 changes: 25 additions & 24 deletions mythtv/libs/libmythtv/recorders/satipstreamhandler.cpp
@@ -1,6 +1,7 @@
// -*- Mode: c++ -*-

// C+++ headers
// C++ headers
#include <chrono>
#include <thread>

// Qt headers
Expand Down Expand Up @@ -33,17 +34,14 @@ SatIPStreamHandler *SatIPStreamHandler::Get(const QString &devname, int inputid)

if (it == s_handlers.end())
{
LOG(VB_RECORD, LOG_INFO,
QString("SatIPSH[%1]: Creating new stream handler for %2")
.arg(inputid).arg(devname));

auto *newhandler = new SatIPStreamHandler(devname, inputid);
newhandler->Open();
s_handlers[devname] = newhandler;
s_handlersRefCnt[devname] = 1;

// SatIPRTSP per instance
newhandler->m_rtsp = new SatIPRTSP(newhandler);

LOG(VB_RECORD, LOG_INFO,
QString("SatIPSH[%1]: Creating new stream handler for %2")
.arg(inputid).arg(devname));
}
else
{
Expand All @@ -67,7 +65,11 @@ void SatIPStreamHandler::Return(SatIPStreamHandler * & ref, int inputid)

QMap<QString, uint>::iterator rit = s_handlersRefCnt.find(devname);
if (rit == s_handlersRefCnt.end())
{
LOG(VB_RECORD, LOG_ERR, QString("SatIPSH[%1]: Return(%2) not found")
.arg(inputid).arg(devname));
return;
}

LOG(VB_RECORD, LOG_INFO, QString("SatIPSH[%1]: Return(%2) has %3 handlers")
.arg(inputid).arg(devname).arg(*rit));
Expand All @@ -84,9 +86,8 @@ void SatIPStreamHandler::Return(SatIPStreamHandler * & ref, int inputid)
{
LOG(VB_RECORD, LOG_INFO, QString("SatIPSH[%1]: Closing handler for %2")
.arg(inputid).arg(devname));
ref->Stop();
ref->Close();
delete (*it)->m_rtsp;
(*it)->Stop();
(*it)->Close();
delete *it;
s_handlers.erase(it);
}
Expand All @@ -105,6 +106,7 @@ SatIPStreamHandler::SatIPStreamHandler(const QString &device, int inputid)
: StreamHandler(device, inputid)
, m_inputId(inputid)
, m_device(device)
, m_rtsp(new SatIPRTSP(this))
{
setObjectName("SatIPStreamHandler");

Expand All @@ -122,12 +124,18 @@ bool SatIPStreamHandler::UpdateFilters(void)

QStringList pids;

PIDInfoMap::const_iterator it = m_pidInfo.begin();
for (; it != m_pidInfo.end(); ++it)
if (m_pidInfo.contains(0x2000))
{
pids.append(QString("%1").arg(it.key()));
pids.append("all");
}
else
{
PIDInfoMap::const_iterator it = m_pidInfo.begin();
for (; it != m_pidInfo.end(); ++it)
{
pids.append(QString("%1").arg(it.key()));
}
}

#ifdef DEBUG_PID_FILTERS
QString msg = QString("PIDS: '%1'").arg(pids.join(","));
LOG(VB_RECORD, LOG_DEBUG, LOC + msg);
Expand Down Expand Up @@ -184,7 +192,7 @@ void SatIPStreamHandler::run(void)
}

// Delay to avoid busy wait loop
std::this_thread::sleep_for(std::chrono::milliseconds(40));
std::this_thread::sleep_for(std::chrono::milliseconds(20));

}
LOG(VB_RECORD, LOG_INFO, LOC + "RunTS(): " + "shutdown");
Expand All @@ -201,7 +209,6 @@ void SatIPStreamHandler::run(void)
}

SetRunning(false, false, false);

RunEpilog();
}

Expand All @@ -220,8 +227,6 @@ void SatIPStreamHandler::Tune(const DTVMultiplex &tuning)
qry.append(QString("sr=%1").arg(tuning.m_symbolRate / 1000)); // symbolrate in ksymb/s
qry.append("msys=dvbc");
qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));

// TODO: DVB-C2 parameters
}
else if (m_tunerType == DTVTunerType::kTunerTypeDVBT || m_tunerType == DTVTunerType::kTunerTypeDVBT2)
{
Expand All @@ -232,8 +237,6 @@ void SatIPStreamHandler::Tune(const DTVMultiplex &tuning)
qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
qry.append(QString("gi=%1").arg(SatIP::gi(tuning.m_guardInterval)));
qry.append(QString("fec=%1").arg(SatIP::fec(tuning.m_fec)));

// TODO: DVB-T2 parameters
}
else if (m_tunerType == DTVTunerType::kTunerTypeDVBS1 || m_tunerType == DTVTunerType::kTunerTypeDVBS2)
{
Expand All @@ -244,13 +247,11 @@ void SatIPStreamHandler::Tune(const DTVMultiplex &tuning)
qry.append(QString("mtype=%1").arg(SatIP::mtype(tuning.m_modulation)));
qry.append(QString("sr=%1").arg(tuning.m_symbolRate / 1000)); // symbolrate in ksymb/s
qry.append(QString("fec=%1").arg(SatIP::fec(tuning.m_fec)));

// TODO DVB-S2 parameters
qry.append(QString("plts=auto")); // pilot tones
}
else
{
LOG(VB_RECORD, LOG_INFO, LOC + QString("TODO unhandled m_tunerType %1 %2").arg(m_tunerType).arg(m_tunerType.toString()));
LOG(VB_RECORD, LOG_ERR, LOC + QString("Unhandled m_tunerType %1 %2").arg(m_tunerType).arg(m_tunerType.toString()));
}

QUrl url = QUrl(m_baseurl);
Expand Down

0 comments on commit cf09ffe

Please sign in to comment.