mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
VDR developer version 2.1.8 is now available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.1.8.tar.bz2 A 'diff' against the previous version is available at ftp://ftp.tvdr.de/vdr/Developer/vdr-2.1.7-2.1.8.diff MD5 checksums: 1d2751e87def9b18b448513f24e635e9 vdr-2.1.8.tar.bz2 0487e037278f6f6684a7933674910f05 vdr-2.1.7-2.1.8.diff WARNING: ======== This is a *developer* version. Even though *I* use it in my productive environment, I strongly recommend that you only use it under controlled conditions and for testing and debugging. From the HISTORY file: - Updated the Italian OSD texts (thanks to Diego Pierotto). - Fixed "warning: invalid suffix on literal" with GCC 4.8 and C++11 (thanks to Joerg Bornkessel). - Fixed the link to "svdrpsend (1)" in the vdr.1 man page (thanks to Chris Mayo). - Updated the Finnish OSD texts (thanks to Rolf Ahrenberg). - Updated the Romanian OSD texts (thanks to Lucian Muresan). - Added functionality based on the "jumpplay" patch from Torsten Kunkel and Thomas Günther: + The new option "Setup/Replay/Pause replay when jumping to a mark" can be used to turn off pausing replay when jumping to an editing mark with the '9' key. + The new option "Setup/Replay/Skip edited parts" can be used to automatically skip the edited parts of a recording during replay, without the need to actually cut the recording. + The new option "Setup/Replay/Pause replay at last mark" can be used to make replay go into Pause mode when it has reached the last "end" mark. + The '8' key for testing an edited sequence now also jumps to the next *end* mark if "Setup/Replay/Skip edited parts" is active. This allows for testing edits in recordings that have actually been cut, as well as recordings that have not been cut, in case "Skip edited parts" is enabled. - Added support for "Satellite Channel Routing" (SCR) according to EN50607, also known as "JESS" (thanks to Manfred Völkel and Frank Neumann). - The keys '1' and '3' can now be used in replay mode to position an editing mark in "binary" mode (based on a patch from Rolf Ahrenberg, with modifications by Helmut Auer). See MANUAL, section "Editing a Recording". - The Yellow button in the "Setup/CAM" menu can now be used to put the selected CAM into a mode where it remains assigned to a device that is tuned to the current channel until the smart card it contains is activated and the CAM thus starts to descramble (see MANUAL, section "Setup/CAM" for details). - Updated the Estonian OSD texts (thanks to Arthur Konovalov). - Added ARGSDIR to the ONEDIR section of Make.config.template (suggested by Derek Kelly). - Made cRecording::GetResume() public (suggested by Stefan Braun). - Fixed setting the read index in cDvbPlayer::Goto() in case Still is false. - The function cDvbPlayer::Goto() now automatically calls Play() if Still is false. - Added support for LCN (Logical Channel Numbers), which plugins may use to sort channels (thanks to Rolf Ahrenberg).
401 lines
22 KiB
C
401 lines
22 KiB
C
/*
|
|
* nit.c: NIT section filter
|
|
*
|
|
* See the main source file 'vdr.c' for copyright information and
|
|
* how to reach the author.
|
|
*
|
|
* $Id: nit.c 3.4 2015/02/01 13:46:00 kls Exp $
|
|
*/
|
|
|
|
#include "nit.h"
|
|
#include <linux/dvb/frontend.h>
|
|
#include "channels.h"
|
|
#include "dvbdevice.h"
|
|
#include "eitscan.h"
|
|
#include "libsi/section.h"
|
|
#include "libsi/descriptor.h"
|
|
#include "tools.h"
|
|
|
|
#define DVB_SYSTEM_1 0 // see also dvbdevice.c
|
|
#define DVB_SYSTEM_2 1
|
|
|
|
cNitFilter::cNitFilter(cSdtFilter *SdtFilter)
|
|
{
|
|
sdtFilter = SdtFilter;
|
|
numNits = 0;
|
|
networkId = 0;
|
|
Set(0x10, 0x40); // NIT
|
|
}
|
|
|
|
void cNitFilter::SetStatus(bool On)
|
|
{
|
|
cFilter::SetStatus(On);
|
|
numNits = 0;
|
|
networkId = 0;
|
|
sectionSyncer.Reset();
|
|
}
|
|
|
|
void cNitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
|
{
|
|
SI::NIT nit(Data, false);
|
|
if (!nit.CheckCRCAndParse())
|
|
return;
|
|
// Some broadcasters send more than one NIT, with no apparent way of telling which
|
|
// one is the right one to use. This is an attempt to find the NIT that contains
|
|
// the transponder it was transmitted on and use only that one:
|
|
int ThisNIT = -1;
|
|
if (!networkId) {
|
|
for (int i = 0; i < numNits; i++) {
|
|
if (nits[i].networkId == nit.getNetworkId()) {
|
|
if (nit.getSectionNumber() == 0) {
|
|
// all NITs have passed by
|
|
for (int j = 0; j < numNits; j++) {
|
|
if (nits[j].hasTransponder) {
|
|
networkId = nits[j].networkId;
|
|
//printf("taking NIT with network ID %d\n", networkId);
|
|
//XXX what if more than one NIT contains this transponder???
|
|
break;
|
|
}
|
|
}
|
|
if (!networkId) {
|
|
//printf("none of the NITs contains transponder %d\n", Transponder());
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
ThisNIT = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!networkId && ThisNIT < 0 && numNits < MAXNITS) {
|
|
if (nit.getSectionNumber() == 0) {
|
|
*nits[numNits].name = 0;
|
|
SI::Descriptor *d;
|
|
for (SI::Loop::Iterator it; (d = nit.commonDescriptors.getNext(it)); ) {
|
|
switch (d->getDescriptorTag()) {
|
|
case SI::NetworkNameDescriptorTag: {
|
|
SI::NetworkNameDescriptor *nnd = (SI::NetworkNameDescriptor *)d;
|
|
nnd->name.getText(nits[numNits].name, MAXNETWORKNAME);
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
delete d;
|
|
}
|
|
nits[numNits].networkId = nit.getNetworkId();
|
|
nits[numNits].hasTransponder = false;
|
|
//printf("NIT[%d] %5d '%s'\n", numNits, nits[numNits].networkId, nits[numNits].name);
|
|
ThisNIT = numNits;
|
|
numNits++;
|
|
}
|
|
}
|
|
}
|
|
else if (networkId != nit.getNetworkId())
|
|
return; // ignore all other NITs
|
|
else if (!sectionSyncer.Sync(nit.getVersionNumber(), nit.getSectionNumber(), nit.getLastSectionNumber()))
|
|
return;
|
|
if (!Channels.Lock(true, 10))
|
|
return;
|
|
SI::NIT::TransportStream ts;
|
|
for (SI::Loop::Iterator it; nit.transportStreamLoop.getNext(ts, it); ) {
|
|
SI::Descriptor *d;
|
|
|
|
SI::Loop::Iterator it2;
|
|
SI::FrequencyListDescriptor *fld = (SI::FrequencyListDescriptor *)ts.transportStreamDescriptors.getNext(it2, SI::FrequencyListDescriptorTag);
|
|
int NumFrequencies = fld ? fld->frequencies.getCount() + 1 : 1;
|
|
int Frequencies[NumFrequencies];
|
|
if (fld) {
|
|
int ct = fld->getCodingType();
|
|
if (ct > 0) {
|
|
int n = 1;
|
|
for (SI::Loop::Iterator it3; fld->frequencies.hasNext(it3); ) {
|
|
int f = fld->frequencies.getNext(it3);
|
|
switch (ct) {
|
|
case 1: f = BCD2INT(f) / 100; break;
|
|
case 2: f = BCD2INT(f) / 10; break;
|
|
case 3: f = f * 10; break;
|
|
default: ;
|
|
}
|
|
Frequencies[n++] = f;
|
|
}
|
|
}
|
|
else
|
|
NumFrequencies = 1;
|
|
}
|
|
delete fld;
|
|
|
|
for (SI::Loop::Iterator it2; (d = ts.transportStreamDescriptors.getNext(it2)); ) {
|
|
switch (d->getDescriptorTag()) {
|
|
case SI::SatelliteDeliverySystemDescriptorTag: {
|
|
SI::SatelliteDeliverySystemDescriptor *sd = (SI::SatelliteDeliverySystemDescriptor *)d;
|
|
cDvbTransponderParameters dtp;
|
|
int Source = cSource::FromData(cSource::stSat, BCD2INT(sd->getOrbitalPosition()), sd->getWestEastFlag());
|
|
int Frequency = Frequencies[0] = BCD2INT(sd->getFrequency()) / 100;
|
|
static char Polarizations[] = { 'H', 'V', 'L', 'R' };
|
|
dtp.SetPolarization(Polarizations[sd->getPolarization()]);
|
|
static int CodeRates[] = { FEC_NONE, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_8_9, FEC_3_5, FEC_4_5, FEC_9_10, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_NONE };
|
|
dtp.SetCoderateH(CodeRates[sd->getFecInner()]);
|
|
static int Modulations[] = { QAM_AUTO, QPSK, PSK_8, QAM_16 };
|
|
dtp.SetModulation(Modulations[sd->getModulationType()]);
|
|
dtp.SetSystem(sd->getModulationSystem() ? DVB_SYSTEM_2 : DVB_SYSTEM_1);
|
|
static int RollOffs[] = { ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_AUTO };
|
|
dtp.SetRollOff(sd->getModulationSystem() ? RollOffs[sd->getRollOff()] : ROLLOFF_AUTO);
|
|
int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10;
|
|
if (ThisNIT >= 0) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], dtp.Polarization()), Transponder())) {
|
|
nits[ThisNIT].hasTransponder = true;
|
|
//printf("has transponder %d\n", Transponder());
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (Setup.UpdateChannels >= 5) {
|
|
bool found = false;
|
|
bool forceTransponderUpdate = false;
|
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
|
if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
|
|
int transponder = Channel->Transponder();
|
|
found = true;
|
|
if (!ISTRANSPONDER(cChannel::Transponder(Frequency, dtp.Polarization()), transponder)) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
if (ISTRANSPONDER(cChannel::Transponder(Frequencies[n], dtp.Polarization()), transponder)) {
|
|
Frequency = Frequencies[n];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ISTRANSPONDER(cChannel::Transponder(Frequency, dtp.Polarization()), Transponder())) // only modify channels if we're actually receiving this transponder
|
|
Channel->SetTransponderData(Source, Frequency, SymbolRate, dtp.ToString('S'));
|
|
else if (Channel->Srate() != SymbolRate || strcmp(Channel->Parameters(), dtp.ToString('S')))
|
|
forceTransponderUpdate = true; // get us receiving this transponder
|
|
}
|
|
}
|
|
if (!found || forceTransponderUpdate) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
cChannel *Channel = new cChannel;
|
|
Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
|
|
if (Channel->SetTransponderData(Source, Frequencies[n], SymbolRate, dtp.ToString('S')))
|
|
EITScanner.AddTransponder(Channel);
|
|
else
|
|
delete Channel;
|
|
}
|
|
}
|
|
}
|
|
sdtFilter->Trigger(Source);
|
|
}
|
|
break;
|
|
case SI::S2SatelliteDeliverySystemDescriptorTag: {
|
|
if (Setup.UpdateChannels >= 5) {
|
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
|
if (!Channel->GroupSep() && cSource::IsSat(Channel->Source()) && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
|
|
SI::S2SatelliteDeliverySystemDescriptor *sd = (SI::S2SatelliteDeliverySystemDescriptor *)d;
|
|
cDvbTransponderParameters dtp(Channel->Parameters());
|
|
dtp.SetSystem(DVB_SYSTEM_2);
|
|
dtp.SetStreamId(sd->getInputStreamIdentifier());
|
|
Channel->SetTransponderData(Channel->Source(), Channel->Frequency(), Channel->Srate(), dtp.ToString('S'));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SI::CableDeliverySystemDescriptorTag: {
|
|
SI::CableDeliverySystemDescriptor *sd = (SI::CableDeliverySystemDescriptor *)d;
|
|
cDvbTransponderParameters dtp;
|
|
int Source = cSource::FromData(cSource::stCable);
|
|
int Frequency = Frequencies[0] = BCD2INT(sd->getFrequency()) / 10;
|
|
//XXX FEC_outer???
|
|
static int CodeRates[] = { FEC_NONE, FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_8_9, FEC_3_5, FEC_4_5, FEC_9_10, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_AUTO, FEC_NONE };
|
|
dtp.SetCoderateH(CodeRates[sd->getFecInner()]);
|
|
static int Modulations[] = { QPSK, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256, QAM_AUTO };
|
|
dtp.SetModulation(Modulations[min(sd->getModulation(), 6)]);
|
|
int SymbolRate = BCD2INT(sd->getSymbolRate()) / 10;
|
|
if (ThisNIT >= 0) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
if (ISTRANSPONDER(Frequencies[n] / 1000, Transponder())) {
|
|
nits[ThisNIT].hasTransponder = true;
|
|
//printf("has transponder %d\n", Transponder());
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (Setup.UpdateChannels >= 5) {
|
|
bool found = false;
|
|
bool forceTransponderUpdate = false;
|
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
|
if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
|
|
int transponder = Channel->Transponder();
|
|
found = true;
|
|
if (!ISTRANSPONDER(Frequency / 1000, transponder)) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
if (ISTRANSPONDER(Frequencies[n] / 1000, transponder)) {
|
|
Frequency = Frequencies[n];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ISTRANSPONDER(Frequency / 1000, Transponder())) // only modify channels if we're actually receiving this transponder
|
|
Channel->SetTransponderData(Source, Frequency, SymbolRate, dtp.ToString('C'));
|
|
else if (Channel->Srate() != SymbolRate || strcmp(Channel->Parameters(), dtp.ToString('C')))
|
|
forceTransponderUpdate = true; // get us receiving this transponder
|
|
}
|
|
}
|
|
if (!found || forceTransponderUpdate) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
cChannel *Channel = new cChannel;
|
|
Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
|
|
if (Channel->SetTransponderData(Source, Frequencies[n], SymbolRate, dtp.ToString('C')))
|
|
EITScanner.AddTransponder(Channel);
|
|
else
|
|
delete Channel;
|
|
}
|
|
}
|
|
}
|
|
sdtFilter->Trigger(Source);
|
|
}
|
|
break;
|
|
case SI::TerrestrialDeliverySystemDescriptorTag: {
|
|
SI::TerrestrialDeliverySystemDescriptor *sd = (SI::TerrestrialDeliverySystemDescriptor *)d;
|
|
cDvbTransponderParameters dtp;
|
|
int Source = cSource::FromData(cSource::stTerr);
|
|
int Frequency = Frequencies[0] = sd->getFrequency() * 10;
|
|
static int Bandwidths[] = { 8000000, 7000000, 6000000, 5000000, 0, 0, 0, 0 };
|
|
dtp.SetBandwidth(Bandwidths[sd->getBandwidth()]);
|
|
static int Constellations[] = { QPSK, QAM_16, QAM_64, QAM_AUTO };
|
|
dtp.SetModulation(Constellations[sd->getConstellation()]);
|
|
dtp.SetSystem(DVB_SYSTEM_1);
|
|
static int Hierarchies[] = { HIERARCHY_NONE, HIERARCHY_1, HIERARCHY_2, HIERARCHY_4, HIERARCHY_AUTO, HIERARCHY_AUTO, HIERARCHY_AUTO, HIERARCHY_AUTO };
|
|
dtp.SetHierarchy(Hierarchies[sd->getHierarchy()]);
|
|
static int CodeRates[] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_AUTO, FEC_AUTO, FEC_AUTO };
|
|
dtp.SetCoderateH(CodeRates[sd->getCodeRateHP()]);
|
|
dtp.SetCoderateL(CodeRates[sd->getCodeRateLP()]);
|
|
static int GuardIntervals[] = { GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_4 };
|
|
dtp.SetGuard(GuardIntervals[sd->getGuardInterval()]);
|
|
static int TransmissionModes[] = { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_4K, TRANSMISSION_MODE_AUTO };
|
|
dtp.SetTransmission(TransmissionModes[sd->getTransmissionMode()]);
|
|
if (ThisNIT >= 0) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
if (ISTRANSPONDER(Frequencies[n] / 1000000, Transponder())) {
|
|
nits[ThisNIT].hasTransponder = true;
|
|
//printf("has transponder %d\n", Transponder());
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if (Setup.UpdateChannels >= 5) {
|
|
bool found = false;
|
|
bool forceTransponderUpdate = false;
|
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
|
if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
|
|
int transponder = Channel->Transponder();
|
|
found = true;
|
|
if (!ISTRANSPONDER(Frequency / 1000000, transponder)) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
if (ISTRANSPONDER(Frequencies[n] / 1000000, transponder)) {
|
|
Frequency = Frequencies[n];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (ISTRANSPONDER(Frequency / 1000000, Transponder())) // only modify channels if we're actually receiving this transponder
|
|
Channel->SetTransponderData(Source, Frequency, 0, dtp.ToString('T'));
|
|
else if (strcmp(Channel->Parameters(), dtp.ToString('T')))
|
|
forceTransponderUpdate = true; // get us receiving this transponder
|
|
}
|
|
}
|
|
if (!found || forceTransponderUpdate) {
|
|
for (int n = 0; n < NumFrequencies; n++) {
|
|
cChannel *Channel = new cChannel;
|
|
Channel->SetId(ts.getOriginalNetworkId(), ts.getTransportStreamId(), 0, 0);
|
|
if (Channel->SetTransponderData(Source, Frequencies[n], 0, dtp.ToString('T')))
|
|
EITScanner.AddTransponder(Channel);
|
|
else
|
|
delete Channel;
|
|
}
|
|
}
|
|
}
|
|
sdtFilter->Trigger(Source);
|
|
}
|
|
break;
|
|
case SI::ExtensionDescriptorTag: {
|
|
SI::ExtensionDescriptor *sd = (SI::ExtensionDescriptor *)d;
|
|
switch (sd->getExtensionDescriptorTag()) {
|
|
case SI::T2DeliverySystemDescriptorTag: {
|
|
if (Setup.UpdateChannels >= 5) {
|
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
|
int Source = cSource::FromData(cSource::stTerr);
|
|
if (!Channel->GroupSep() && Channel->Source() == Source && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
|
|
SI::T2DeliverySystemDescriptor *td = (SI::T2DeliverySystemDescriptor *)d;
|
|
int Frequency = Channel->Frequency();
|
|
int SymbolRate = Channel->Srate();
|
|
cDvbTransponderParameters dtp(Channel->Parameters());
|
|
dtp.SetSystem(DVB_SYSTEM_2);
|
|
dtp.SetStreamId(td->getPlpId());
|
|
dtp.SetT2SystemId(td->getT2SystemId());
|
|
if (td->getExtendedDataFlag()) {
|
|
dtp.SetSisoMiso(td->getSisoMiso());
|
|
static int T2Bandwidths[] = { 8000000, 7000000, 6000000, 5000000, 10000000, 1712000, 0, 0 };
|
|
dtp.SetBandwidth(T2Bandwidths[td->getBandwidth()]);
|
|
static int T2GuardIntervals[] = { GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_4, GUARD_INTERVAL_1_128, GUARD_INTERVAL_19_128, GUARD_INTERVAL_19_256, 0 };
|
|
dtp.SetGuard(T2GuardIntervals[td->getGuardInterval()]);
|
|
static int T2TransmissionModes[] = { TRANSMISSION_MODE_2K, TRANSMISSION_MODE_8K, TRANSMISSION_MODE_4K, TRANSMISSION_MODE_1K, TRANSMISSION_MODE_16K, TRANSMISSION_MODE_32K, TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO };
|
|
dtp.SetTransmission(T2TransmissionModes[td->getTransmissionMode()]);
|
|
//TODO add parsing of frequencies
|
|
}
|
|
Channel->SetTransponderData(Source, Frequency, SymbolRate, dtp.ToString('T'));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
}
|
|
break;
|
|
case SI::LogicalChannelDescriptorTag: {
|
|
SI::LogicalChannelDescriptor *lcd = (SI::LogicalChannelDescriptor *)d;
|
|
SI::LogicalChannelDescriptor::LogicalChannel LogicalChannel;
|
|
for (SI::Loop::Iterator it4; lcd->logicalChannelLoop.getNext(LogicalChannel, it4); ) {
|
|
int lcn = LogicalChannel.getLogicalChannelNumber();
|
|
int sid = LogicalChannel.getServiceId();
|
|
if (LogicalChannel.getVisibleServiceFlag()) {
|
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
|
if (!Channel->GroupSep() && Channel->Sid() == sid && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
|
|
Channel->SetLcn(lcn);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case SI::HdSimulcastLogicalChannelDescriptorTag: {
|
|
SI::HdSimulcastLogicalChannelDescriptor *lcd = (SI::HdSimulcastLogicalChannelDescriptor *)d;
|
|
SI::HdSimulcastLogicalChannelDescriptor::HdSimulcastLogicalChannel HdSimulcastLogicalChannel;
|
|
for (SI::Loop::Iterator it4; lcd->hdSimulcastLogicalChannelLoop.getNext(HdSimulcastLogicalChannel, it4); ) {
|
|
int lcn = HdSimulcastLogicalChannel.getLogicalChannelNumber();
|
|
int sid = HdSimulcastLogicalChannel.getServiceId();
|
|
if (HdSimulcastLogicalChannel.getVisibleServiceFlag()) {
|
|
for (cChannel *Channel = Channels.First(); Channel; Channel = Channels.Next(Channel)) {
|
|
if (!Channel->GroupSep() && Channel->Sid() == sid && Channel->Nid() == ts.getOriginalNetworkId() && Channel->Tid() == ts.getTransportStreamId()) {
|
|
Channel->SetLcn(lcn);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default: ;
|
|
}
|
|
delete d;
|
|
}
|
|
}
|
|
Channels.Unlock();
|
|
}
|