Skip to content

Commit

Permalink
DVB HD Simulcast logical channel numbers
Browse files Browse the repository at this point in the history
Move processing of the DVB logical channel numbers including
the HD Simulcast logical channel numbers from scanning to
postprocessing.
Processing the HD simulcast logical channel numbers requires
access to all multiplexes. When scanning there is only access
to the current mulitplex.
Processing the logical channel number offset, defined in database
table video source, now also happens during postprocessing.
The feature to redo the postprocessing based on the data
from a previously stored scan does require that the logical
channel numbers are stored somewhere in the database.
Therefore the database schema has been changed.
  • Loading branch information
kmdewaal committed Jul 10, 2024
1 parent 115ebdb commit 8f6c474
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 40 deletions.
2 changes: 1 addition & 1 deletion mythtv/bindings/perl/MythTV.pm
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ package MythTV;
# schema version supported in the main code. We need to check that the schema
# version in the database is as expected by the bindings, which are expected
# to be kept in sync with the main code.
our $SCHEMA_VERSION = "1379";
our $SCHEMA_VERSION = "1380";

# NUMPROGRAMLINES is defined in mythtv/libs/libmythtv/programinfo.h and is
# the number of items in a ProgramInfo QStringList group used by
Expand Down
2 changes: 1 addition & 1 deletion mythtv/bindings/python/MythTV/_versions.py.in
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The file MythTV/_versions.py is usually generated by ./configure.
"""

OWN_VERSION = @MYTHTV_PYTHON_OWN_VERSION@
SCHEMA_VERSION = 1379
SCHEMA_VERSION = 1380
NVSCHEMA_VERSION = 1007
MUSICSCHEMA_VERSION = 1025
PROTO_VERSION = '91'
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythbase/mythversion.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ static constexpr const char* MYTH_PROTO_TOKEN { "BuzzOff" };
* mythtv/bindings/php/MythBackend.php
*/

static constexpr const char* MYTH_DATABASE_VERSION { "1379" };
static constexpr const char* MYTH_DATABASE_VERSION { "1380" };

MBASE_PUBLIC const char *GetMythSourceVersion();
MBASE_PUBLIC const char *GetMythSourcePath();
Expand Down
6 changes: 4 additions & 2 deletions mythtv/libs/libmythtv/channelinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ bool ChannelInsertInfo::SaveScan(uint scanid, uint transportid) const
" in_nit, in_sdt, is_encrypted, "
" is_data_service, is_audio_service, is_opencable, "
" could_be_opencable, decryption_status, default_authority, "
" service_type "
" service_type, logical_channel, simulcast_channel "
" ) "
"VALUES "
" ( :SCANID, :TRANSPORTID, "
Expand All @@ -324,7 +324,7 @@ bool ChannelInsertInfo::SaveScan(uint scanid, uint transportid) const
" :IN_NIT, :IN_SDT, :IS_ENCRYPTED, "
" :IS_DATA_SERVICE, :IS_AUDIO_SERVICE, :IS_OPENCABLE, "
" :COULD_BE_OPENCABLE,:DECRYPTION_STATUS, :DEFAULT_AUTHORITY, "
" :SERVICE_TYPE "
" :SERVICE_TYPE, :LOGICAL_CHANNEL, :SIMULCAST_CHANNEL "
" );");

query.bindValue(":SCANID", scanid);
Expand Down Expand Up @@ -366,6 +366,8 @@ bool ChannelInsertInfo::SaveScan(uint scanid, uint transportid) const
query.bindValue(":DECRYPTION_STATUS", m_decryptionStatus);
query.bindValueNoNull(":DEFAULT_AUTHORITY", m_defaultAuthority);
query.bindValue(":SERVICE_TYPE", m_serviceType);
query.bindValue(":LOGICAL_CHANNEL", m_logicalChannel);
query.bindValue(":SIMULCAST_CHANNEL", m_simulcastChannel);

if (!query.exec())
{
Expand Down
9 changes: 7 additions & 2 deletions mythtv/libs/libmythtv/channelinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ class MTV_PUBLIC ChannelInsertInfo
bool _is_encrypted, bool _is_data_service,
bool _is_audio_service, bool _is_opencable,
bool _could_be_opencable, int _decryption_status,
QString _default_authority, uint _service_type) :
QString _default_authority, uint _service_type,
uint _logical_channel, uint _simulcast_channel ) :
m_dbMplexId(_db_mplexid),
m_sourceId(_source_id),
m_channelId(_channel_id),
Expand Down Expand Up @@ -198,7 +199,9 @@ class MTV_PUBLIC ChannelInsertInfo
m_isAudioService(_is_audio_service),
m_isOpencable(_is_opencable),
m_couldBeOpencable(_could_be_opencable),
m_decryptionStatus(_decryption_status) {}
m_decryptionStatus(_decryption_status),
m_logicalChannel(_logical_channel),
m_simulcastChannel(_simulcast_channel) {}

ChannelInsertInfo(const ChannelInsertInfo &other) { (*this = other); }
ChannelInsertInfo &operator=(const ChannelInsertInfo&) = default;
Expand Down Expand Up @@ -250,6 +253,8 @@ class MTV_PUBLIC ChannelInsertInfo
bool m_isOpencable {false};
bool m_couldBeOpencable {false};
int m_decryptionStatus {0};
uint m_logicalChannel {0};
uint m_simulcastChannel {0};

// Service relocated descriptor
uint m_oldOrigNetId {0};
Expand Down
128 changes: 128 additions & 0 deletions mythtv/libs/libmythtv/channelscan/channelimporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,31 @@ static void channum_not_empty(ChannelInsertInfo &chan)
}
}

static uint getLcnOffset(int sourceid)
{
uint lcnOffset = 0;

MSqlQuery query(MSqlQuery::InitCon());
query.prepare(
"SELECT lcnoffset "
"FROM videosource "
"WHERE videosource.sourceid = :SOURCEID");
query.bindValue(":SOURCEID", sourceid);
if (!query.exec() || !query.isActive())
{
MythDB::DBError("ChannelImporter", query);
}
else if (query.next())
{
lcnOffset = query.value(0).toUInt();
}

LOG(VB_CHANSCAN, LOG_INFO, LOC +
QString("Logical Channel Number offset:%1")
.arg(lcnOffset));

return lcnOffset;
}

ChannelImporter::ChannelImporter(bool gui, bool interactive,
bool _delete, bool insert, bool save,
Expand Down Expand Up @@ -76,6 +101,8 @@ ChannelImporter::ChannelImporter(bool gui, bool interactive,
void ChannelImporter::Process(const ScanDTVTransportList &_transports,
int sourceid)
{
m_lcnOffset = getLcnOffset(sourceid);

if (_transports.empty())
{
if (m_useGui)
Expand Down Expand Up @@ -173,6 +200,12 @@ void ChannelImporter::Process(const ScanDTVTransportList &_transports,
}
}

// Process Logical Channel Numbers
if (m_doLcn)
{
ChannelNumbers(transports);
}

// Remove the channels that do not pass various criteria.
FilterServices(transports);

Expand Down Expand Up @@ -1152,6 +1185,101 @@ void ChannelImporter::FilterRelocatedServices(ScanDTVTransportList &transports)
}
}

// Process DVB Channel Numbers
void ChannelImporter::ChannelNumbers(ScanDTVTransportList &transports) const
{
QMap<qlonglong, uint> map_sid_scn; // HD Simulcast channel numbers, service ID is key
QMap<qlonglong, uint> map_sid_lcn; // Logical channel numbers, service ID is key
QMap<uint, qlonglong> map_lcn_sid; // Logical channel numbers, channel number is key

LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Process DVB Channel Numbers"));
for (auto & transport : transports)
{
for (auto & channel : transport.m_channels)
{
LOG(VB_CHANSCAN, LOG_DEBUG, LOC + QString("Channel onid:%1 sid:%2 lcn:%3 scn:%4")
.arg(channel.m_origNetId).arg(channel.m_serviceId).arg(channel.m_logicalChannel)
.arg(channel.m_simulcastChannel));
qlonglong key = ((qlonglong)channel.m_origNetId<<32) | channel.m_serviceId;
if (channel.m_logicalChannel > 0)
{
map_sid_lcn[key] = channel.m_logicalChannel;
map_lcn_sid[channel.m_logicalChannel] = key;
}
if (channel.m_simulcastChannel > 0)
{
map_sid_scn[key] = channel.m_simulcastChannel;
}
}
}

// Process the HD Simulcast Channel Numbers
//
// For each channel with a HD Simulcast Channel Number, do use that
// number as the Logical Channel Number; the SD channel that now has
// this LCN does get the original LCN of the HD Simulcast channel.
// If this is not selected then the Logical Channel Numbers are used
// without the override from the HD Simulcast channel numbers.
// This usually means that channel numbers 1, 2, 3 etc are used for SD channels
// while the corresponding HD channels do have higher channel numbers.
// When the HD Simulcast channel numbers are enabled then channel numbers 1, 2, 3 etc are
// used for the HD channels and the corresponding SD channels use the high channel numbers.
if (m_doScn)
{
LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Process Simulcast Channel Numbers"));

QMap<qlonglong, uint>::iterator it;
for (it = map_sid_scn.begin(); it != map_sid_scn.end(); ++it)
{
// Exchange LCN between the SD channel and the HD simulcast channel
qlonglong key_hd = it.key(); // Key of HD channel
uint scn_hd = *it; // SCN of the HD channel
uint lcn_sd = scn_hd; // Old LCN of the SD channel
uint lcn_hd = map_sid_lcn[key_hd]; // Old LCN of the HD channel

qlonglong key_sd = map_lcn_sid[lcn_sd]; // Key of the SD channel

map_sid_lcn[key_sd] = lcn_hd; // SD channel gets old LCN of HD channel
map_sid_lcn[key_hd] = lcn_sd; // HD channel gets old LCN of SD channel
map_lcn_sid[lcn_hd] = key_sd; // SD channel gets key of SD channel
map_lcn_sid[lcn_sd] = key_hd; // HD channel gets key of SD channel
}
}

// Update channels with the resulting Logical Channel Numbers
LOG(VB_CHANSCAN, LOG_INFO, LOC + QString("Process Logical Channel Numbers"));
for (auto & transport : transports)
{
for (auto & channel : transport.m_channels)
{
if (channel.m_chanNum.isEmpty())
{
qlonglong key = ((qlonglong)channel.m_origNetId<<32) | channel.m_serviceId;
QMap<qlonglong, uint>::const_iterator it = map_sid_lcn.constFind(key);
if (it != map_sid_lcn.cend())
{
channel.m_chanNum = QString::number(*it + m_lcnOffset);
LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
QString("Final channel sid:%1 channel %2")
.arg(channel.m_serviceId).arg(channel.m_chanNum));
}
else
{
LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
QString("Final channel sid:%1 NO channel number")
.arg(channel.m_serviceId));
}
}
else
{
LOG(VB_CHANSCAN, LOG_DEBUG, LOC +
QString("Final channel sid:%1 has already channel number %2")
.arg(channel.m_serviceId).arg(channel.m_chanNum));
}
}
}
}

/** \fn ChannelImporter::GetDBTransports(uint,ScanDTVTransportList&) const
* \brief Adds found channel info to transports list,
* returns channels in DB which were not found in scan
Expand Down
4 changes: 4 additions & 0 deletions mythtv/libs/libmythtv/channelscan/channelimporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class MTV_PUBLIC ChannelImporter : public QObject
static void RemoveDuplicates(ScanDTVTransportList &transports, ScanDTVTransportList &duplicates);
void FilterServices(ScanDTVTransportList &transports) const;
static void FilterRelocatedServices(ScanDTVTransportList &transports);
void ChannelNumbers(ScanDTVTransportList &transports) const;

ScanDTVTransportList GetDBTransports(
uint sourceid, ScanDTVTransportList &transports) const;
Expand Down Expand Up @@ -248,13 +249,16 @@ class MTV_PUBLIC ChannelImporter : public QObject
bool m_doDelete;
bool m_doInsert;
bool m_doSave;
bool m_doLcn {true}; // Use Logical Channel Numbers
bool m_doScn {true}; // Use HD Simulcast logical channel numbers
bool m_ftaOnly {true}; // Only FreeToAir (non-encrypted) channels desired post scan?
bool m_lcnOnly {false}; // Only services with logical channel numbers desired post scan?
bool m_completeOnly {true}; // Only services with complete scandata desired post scan?
bool m_keepChannelNumbers {true}; // Keep existing channel numbers on channel update
bool m_fullChannelSearch {false}; // Full search for old channels across transports in database
bool m_removeDuplicates {false}; // Remove duplicate transports and channels in scan
bool m_success {false}; // To pass information IPTV channel scan succeeded
int m_lcnOffset {0}; // Read from database table videosource
int m_functorRetval {0};
ChannelScannerWeb * m_pWeb {nullptr};

Expand Down
44 changes: 14 additions & 30 deletions mythtv/libs/libmythtv/channelscan/channelscan_sm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1710,9 +1710,8 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
dbchan_it != pnum_to_dbchan.end(); ++dbchan_it)
{
ChannelInsertInfo &info = *dbchan_it;

if (!info.m_chanNum.isEmpty())
continue;
qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
QMap<qlonglong, uint>::const_iterator it;

// DVB HD Simulcast channel numbers
//
Expand All @@ -1721,45 +1720,30 @@ ChannelScanSM::GetChannelList(transport_scan_items_it_t trans_info,
// and the receiver is capable of receiving the HD signal.
// The latter is assumed correct for a MythTV system.
//
if (info.m_chanNum.isEmpty())
it = scnChanNums.constFind(key);
if (it != scnChanNums.constEnd())
{
qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
QMap<qlonglong, uint>::const_iterator it = scnChanNums.constFind(key);

if (it != scnChanNums.constEnd())
{
info.m_chanNum = QString::number(*it + m_lcnOffset);
}
info.m_simulcastChannel = *it;
}

// DVB Logical Channel Numbers (a.k.a. UK channel numbers)
if (info.m_chanNum.isEmpty())
it = ukChanNums.constFind(key);
if (it != ukChanNums.constEnd())
{
qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
QMap<qlonglong, uint>::const_iterator it = ukChanNums.constFind(key);

if (it != ukChanNums.constEnd())
{
info.m_chanNum = QString::number(*it + m_lcnOffset);
}
info.m_logicalChannel = *it;
}

// Freesat and Sky channel numbers
if (info.m_chanNum.isEmpty())
it = sid_lcn.constFind(key);
if (it != sid_lcn.constEnd())
{
qlonglong key = ((qlonglong)info.m_origNetId<<32) | info.m_serviceId;
QMap<qlonglong, uint>::const_iterator it = sid_lcn.constFind(key);

if (it != sid_lcn.constEnd())
{
info.m_chanNum = QString::number(*it + m_lcnOffset);
}
info.m_logicalChannel = *it;
}

LOG(VB_CHANSCAN, LOG_INFO, LOC +
QString("GetChannelList: service %1 (0x%2) chan_num '%3' callsign '%4'")
QString("service %1 (0x%2) lcn:%3 scn:%4 callsign '%5'")
.arg(info.m_serviceId).arg(info.m_serviceId,4,16,QChar('0'))
.arg(info.m_chanNum, info.m_callSign));
.arg(info.m_logicalChannel).arg(info.m_simulcastChannel).arg(info.m_callSign));
}

// Get QAM/SCTE/MPEG channel numbers
Expand Down Expand Up @@ -1990,7 +1974,7 @@ void ChannelScanSM::StartScanner(void)
}

/** \fn ChannelScanSM::run(void)
* \brief This runs the event loop for ChannelScanSM until 'threadExit' is true.
* \brief This runs the event loop for ChannelScanSM until 'm_threadExit' is true.
*/
void ChannelScanSM::run(void)
{
Expand Down
6 changes: 4 additions & 2 deletions mythtv/libs/libmythtv/channelscan/scaninfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ ScanDTVTransportList LoadScan(uint scanid)
" in_nit, in_sdt, is_encrypted, " // 27, 28, 29
" is_data_service, is_audio_service, is_opencable, " // 30, 31, 32
" could_be_opencable, decryption_status, default_authority, " // 33, 34, 35
" service_type " // 36
" service_type, logical_channel, simulcast_channel " // 36, 37, 38
"FROM channelscan_channel "
"WHERE transportid = :TRANSPORTID");
query2.bindValue(":TRANSPORTID", query.value(15).toUInt());
Expand Down Expand Up @@ -187,7 +187,9 @@ ScanDTVTransportList LoadScan(uint scanid)
query2.value(33).toBool(), // could_be_opencable
query2.value(34).toInt(), // decryption_status
query2.value(35).toString(), // default_authority
query2.value(36).toUInt()); // service_type
query2.value(36).toUInt(), // service_type
query2.value(37).toUInt(), // logical_channel
query2.value(38).toUInt()); // simulcast_channel
mux.m_channels.push_back(chan);
}

Expand Down
11 changes: 11 additions & 0 deletions mythtv/libs/libmythtv/dbcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4055,6 +4055,17 @@ static bool doUpgradeTVDatabaseSchema(void)
return false;
}

if (dbver == "1379")
{
DBUpdates updates {
"ALTER TABLE channelscan_channel ADD COLUMN logical_channel INT UNSIGNED NOT NULL DEFAULT 0 AFTER service_type;"
"ALTER TABLE channelscan_channel ADD COLUMN simulcast_channel INT UNSIGNED NOT NULL DEFAULT 0 AFTER logical_channel;"
};
if (!performActualUpdate("MythTV", "DBSchemaVer",
updates, "1380", dbver))
return false;
}

return true;
}

Expand Down
4 changes: 3 additions & 1 deletion mythtv/libs/libmythtv/dtvmultiplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -692,7 +692,9 @@ bool ScanDTVTransport::FillFromDB(DTVTunerType type, uint mplexid)
false, false, false, false,
false, false, false, 0,
query.value(17).toString(), /* default_authority */
query.value(18).toUInt()); /* service_type */
query.value(18).toUInt(), /* service_type */
0, /* logical_channel */
0); /* simulcast_channel */

m_channels.push_back(chan);
}
Expand Down

0 comments on commit 8f6c474

Please sign in to comment.