Пример #1
0
DvbStream::DvbStream( Device *d, const QString &charset, EventTable *et )
{
	dvbDevice = d;
	isRunning = false;
	timeShifting = false;
	waitPause = 0;
	delOut = 0;
	fdFrontend = fdDvr = 0;
	ndmx = 0;
	currentTransponder = Transponder();
	frontendName = QString("/dev/dvb/adapter%1/frontend%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner );
	dvrName = QString("/dev/dvb/adapter%1/dvr%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner );
	demuxName = QString("/dev/dvb/adapter%1/demux%2").arg( dvbDevice->adapter ).arg( dvbDevice->tuner );

	out.setAutoDelete( true );

	QString deviceType="NONE";
	switch ( dvbDevice->type ) {
		case FE_QPSK: deviceType = "DVBS"; break;
		case FE_OFDM: deviceType = "DVBT"; break;
		case FE_QAM: deviceType = "DVBC"; break;
		case FE_ATSC: deviceType = "DVBA"; break;
	}
	dvbEvents = new DVBevents( deviceType, dvbDevice->adapter, dvbDevice->tuner, charset, et );

	camProbed = false;
	cam = NULL;
	plug = NULL;

	connect( &statusTimer, SIGNAL(timeout()), this, SLOT(checkStatus()) );
}
Пример #2
0
void cEitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
  switch (Pid) {
    case 0x12: {
         cSchedulesLock SchedulesLock(true, 10);
         cSchedules *Schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock);
         if (Schedules)
            cEIT EIT(Schedules, Source(), Tid, Data);
         else {
            // If we don't get a write lock, let's at least get a read lock, so
            // that we can set the running status and 'seen' timestamp (well, actually
            // with a read lock we shouldn't be doing that, but it's only integers that
            // get changed, so it should be ok)
            cSchedulesLock SchedulesLock(false, 50);
            cSchedules *Schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock);
            if (Schedules)
               cEIT EIT(Schedules, Source(), Tid, Data, true);
            }
         }
         break;
    case 0x14: {
         if (Setup.SetSystemTime && Setup.TimeTransponder && ISTRANSPONDER(Transponder(), Setup.TimeTransponder))
            cTDT TDT(Data);
         }
         break;
    }
}
Пример #3
0
int cScanData::Compare(const cListObject &ListObject) const
{
  const cScanData *sd = (const cScanData *)&ListObject;
  int r = Source() - sd->Source();
  if (r == 0)
     r = Transponder() - sd->Transponder();
  return r;
}
Пример #4
0
int cChannel::Transponder(void) const
{
  int tf = frequency;
  while (tf > 20000)
        tf /= 1000;
  if (IsSat())
     tf = Transponder(tf, polarization);
  return tf;
}
Пример #5
0
int cChannel::Transponder(void) const
{
  int tf = frequency;
  while (tf > 20000)
        tf /= 1000;
  if (IsSat()) {
     const char *p = strpbrk(parameters, "HVLRhvlr"); // lowercase for backwards compatibility
     if (p)
        tf = Transponder(tf, *p);
     }
  return tf;
}
Пример #6
0
bool DvbStream::closeFe()
{
	if ( !fdFrontend )
		return true;
	if ( close( fdFrontend )<0 ) {
		perror("closeFe: ");
		return false;
	}
	fprintf(stderr,"Frontend closed\n");
	fdFrontend = 0;
	currentTransponder = Transponder();
	return true;
}
Пример #7
0
void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
  if (Pid == 0x00)
  {
    if (Tid == 0x00)
    {
      SI::PAT pat(Data, false);
      if (!pat.CheckCRCAndParse())
        return;
      SI::PAT::Association assoc;
      for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); )
      {
        if (!assoc.isNITPid())
        {
          const cChannel *Channel =  Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
          if (Channel && (Channel == m_Channel))
          {
            int prevPmtPid = m_pmtPid;
            if (0 != (m_pmtPid = assoc.getPid()))
            {
              if (m_pmtPid != prevPmtPid)
              {
                m_pmtSid = assoc.getServiceId();
                Add(m_pmtPid, 0x02);
                m_pmtVersion = -1;
                break;
              }
              return;
            }
          }
        }
      }
    }
  }
  else if (Pid == m_pmtPid && Tid == SI::TableIdPMT && Source() && Transponder())
  {
    SI::PMT pmt(Data, false);
    if (!pmt.CheckCRCAndParse())
      return;
    if (pmt.getServiceId() != m_pmtSid)
      return; // skip broken PMT records
    if (m_pmtVersion != -1)
    {
      if (m_pmtVersion != pmt.getVersionNumber())
      {
        cFilter::Del(m_pmtPid, 0x02);
        m_pmtPid = 0; // this triggers PAT scan
      }
      return;
    }
    m_pmtVersion = pmt.getVersionNumber();

    cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId());
    if (Channel) {
       // Scan the stream-specific loop:
       SI::PMT::Stream stream;
       int Vpid = 0;
       int Ppid = 0;
       int Vtype = 0;
       int Apids[MAXAPIDS + 1] = { 0 }; // these lists are zero-terminated
       int Atypes[MAXAPIDS + 1] = { 0 };
       int Dpids[MAXDPIDS + 1] = { 0 };
       int Dtypes[MAXDPIDS + 1] = { 0 };
       int Spids[MAXSPIDS + 1] = { 0 };
       uchar SubtitlingTypes[MAXSPIDS + 1] = { 0 };
       uint16_t CompositionPageIds[MAXSPIDS + 1] = { 0 };
       uint16_t AncillaryPageIds[MAXSPIDS + 1] = { 0 };
       char ALangs[MAXAPIDS][MAXLANGCODE2] = { "" };
       char DLangs[MAXDPIDS][MAXLANGCODE2] = { "" };
       char SLangs[MAXSPIDS][MAXLANGCODE2] = { "" };
       int Tpid = 0;
       int NumApids = 0;
       int NumDpids = 0;
       int NumSpids = 0;
       for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); ) {
           bool ProcessCaDescriptors = false;
           int esPid = stream.getPid();
           switch (stream.getStreamType()) {
             case 1: // STREAMTYPE_11172_VIDEO
             case 2: // STREAMTYPE_13818_VIDEO
             case 0x1B: // MPEG4
                     Vpid = esPid;
                     Ppid = pmt.getPCRPid();
                     Vtype = stream.getStreamType();
                     ProcessCaDescriptors = true;
                     break;
             case 3: // STREAMTYPE_11172_AUDIO
             case 4: // STREAMTYPE_13818_AUDIO
             case 0x0F: // ISO/IEC 13818-7 Audio with ADTS transport syntax
             case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
                     {
                     if (NumApids < MAXAPIDS) {
                        Apids[NumApids] = esPid;
                        Atypes[NumApids] = stream.getStreamType();
                        SI::Descriptor *d;
                        for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
                            switch (d->getDescriptorTag()) {
                              case SI::ISO639LanguageDescriptorTag: {
                                   SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
                                   SI::ISO639LanguageDescriptor::Language l;
                                   char *s = ALangs[NumApids];
                                   int n = 0;
                                   for (SI::Loop::Iterator it; ld->languageLoop.getNext(l, it); ) {
                                       if (*ld->languageCode != '-') { // some use "---" to indicate "none"
                                          if (n > 0)
                                             *s++ = '+';
                                          strn0cpy(s, I18nNormalizeLanguageCode(l.languageCode), MAXLANGCODE1);
                                          s += strlen(s);
                                          if (n++ > 1)
                                             break;
                                          }
                                       }
                                   }
                                   break;
                              default: ;
                              }
                            delete d;
                            }
                        NumApids++;
                        }
                     ProcessCaDescriptors = true;
                     }
                     break;
             case 5: // STREAMTYPE_13818_PRIVATE
             case 6: // STREAMTYPE_13818_PES_PRIVATE
             //XXX case 8: // STREAMTYPE_13818_DSMCC
                     {
                     int dpid = 0;
                     int dtype = 0;
                     char lang[MAXLANGCODE1] = { 0 };
                     SI::Descriptor *d;
                     for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
                         switch (d->getDescriptorTag()) {
                           case SI::AC3DescriptorTag:
                           case SI::EnhancedAC3DescriptorTag:
                                dpid = esPid;
                                dtype = d->getDescriptorTag();
                                ProcessCaDescriptors = true;
                                break;
                           case SI::SubtitlingDescriptorTag:
                                if (NumSpids < MAXSPIDS) {
                                   Spids[NumSpids] = esPid;
                                   SI::SubtitlingDescriptor *sd = (SI::SubtitlingDescriptor *)d;
                                   SI::SubtitlingDescriptor::Subtitling sub;
                                   char *s = SLangs[NumSpids];
                                   int n = 0;
                                   for (SI::Loop::Iterator it; sd->subtitlingLoop.getNext(sub, it); ) {
                                       if (sub.languageCode[0]) {
                                          SubtitlingTypes[NumSpids] = sub.getSubtitlingType();
                                          CompositionPageIds[NumSpids] = sub.getCompositionPageId();
                                          AncillaryPageIds[NumSpids] = sub.getAncillaryPageId();
                                          if (n > 0)
                                             *s++ = '+';
                                          strn0cpy(s, I18nNormalizeLanguageCode(sub.languageCode), MAXLANGCODE1);
                                          s += strlen(s);
                                          if (n++ > 1)
                                             break;
                                          }
                                       }
                                   NumSpids++;
                                   }
                                break;
                           case SI::TeletextDescriptorTag:
                                Tpid = esPid;
                                break;
                           case SI::ISO639LanguageDescriptorTag: {
                                SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
                                strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
                                }
                                break;
                           default: ;
                           }
                         delete d;
                         }
                     if (dpid) {
                        if (NumDpids < MAXDPIDS) {
                           Dpids[NumDpids] = dpid;
                           Dtypes[NumDpids] = dtype;
                           strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
                           NumDpids++;
                           }
                        }
                     }
                     break;
             case 0x80: // STREAMTYPE_USER_PRIVATE
#if APIVERSNUM >= 10728
                     if (Setup.StandardCompliance == STANDARD_ANSISCTE)
#endif
                     { // DigiCipher II VIDEO (ANSI/SCTE 57)
                        Vpid = esPid;
                        Ppid = pmt.getPCRPid();
                        Vtype = 0x02; // compression based upon MPEG-2
                        ProcessCaDescriptors = true;
                        break;
                        }
                     // fall through
             case 0x81: // STREAMTYPE_USER_PRIVATE
#if APIVERSNUM >= 10728
                     if (Setup.StandardCompliance == STANDARD_ANSISCTE)
#endif
                     { // ATSC A/53 AUDIO (ANSI/SCTE 57)
                        char lang[MAXLANGCODE1] = { 0 };
                        SI::Descriptor *d;
                        for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
                            switch (d->getDescriptorTag()) {
                              case SI::ISO639LanguageDescriptorTag: {
                                   SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
                                   strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
                                   }
                                   break;
                              default: ;
                              }
                           delete d;
                           }
                        if (NumDpids < MAXDPIDS) {
                           Dpids[NumDpids] = esPid;
                           Dtypes[NumDpids] = SI::AC3DescriptorTag;
                           strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
                           NumDpids++;
                           }
                        ProcessCaDescriptors = true;
                        break;
                        }
                     // fall through
             case 0x82: // STREAMTYPE_USER_PRIVATE
#if APIVERSNUM >= 10728
                     if (Setup.StandardCompliance == STANDARD_ANSISCTE)
#endif
                     { // STANDARD SUBTITLE (ANSI/SCTE 27)
                        //TODO
                        break;
                        }
                     // fall through
             case 0x83 ... 0xFF: // STREAMTYPE_USER_PRIVATE
                     {
                     char lang[MAXLANGCODE1] = { 0 };
                     bool IsAc3 = false;
                     SI::Descriptor *d;
                     for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
                         switch (d->getDescriptorTag()) {
                           case SI::RegistrationDescriptorTag: {
                                SI::RegistrationDescriptor *rd = (SI::RegistrationDescriptor *)d;
                                // http://www.smpte-ra.org/mpegreg/mpegreg.html
                                switch (rd->getFormatIdentifier()) {
                                  case 0x41432D33: // 'AC-3'
                                       IsAc3 = true;
                                       break;
                                  default:
                                       //printf("Format identifier: 0x%08X (pid: %d)\n", rd->getFormatIdentifier(), esPid);
                                       break;
                                  }
                                }
                                break;
                           case SI::ISO639LanguageDescriptorTag: {
                                SI::ISO639LanguageDescriptor *ld = (SI::ISO639LanguageDescriptor *)d;
                                strn0cpy(lang, I18nNormalizeLanguageCode(ld->languageCode), MAXLANGCODE1);
                                }
                                break;
                           default: ;
                           }
                        delete d;
                        }
                     if (IsAc3) {
                        if (NumDpids < MAXDPIDS) {
                           Dpids[NumDpids] = esPid;
                           Dtypes[NumDpids] = SI::AC3DescriptorTag;
                           strn0cpy(DLangs[NumDpids], lang, MAXLANGCODE1);
                           NumDpids++;
                           }
                        ProcessCaDescriptors = true;
                        }
                     }
                     break;
             default: ;//printf("PID: %5d %5d %2d %3d %3d\n", pmt.getServiceId(), stream.getPid(), stream.getStreamType(), pmt.getVersionNumber(), Channel->Number());
             }
           }
       cChannel pmtChannel(*Channel);
       pmtChannel.SetPids(Vpid, Ppid, Vtype, Apids, Atypes, ALangs, Dpids, Dtypes, DLangs, Spids, SLangs, Tpid);
       pmtChannel.SetSubtitlingDescriptors(SubtitlingTypes, CompositionPageIds, AncillaryPageIds);
       m_Streamer->SetTpid(Tpid);
       cPatPmtGenerator patPmtGenerator(&pmtChannel);
       m_Streamer->m_bufferLock.Lock();
       m_Streamer->Put(patPmtGenerator.GetPat(), TS_SIZE);
       int Index = 0;
       while (uchar *pmt = patPmtGenerator.GetPmt(Index))
         m_Streamer->Put(pmt, TS_SIZE);
       m_Streamer->m_bufferLock.Unlock();
       }
  }
Пример #8
0
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;
#ifdef USE_PROVIDERCHARSET
                      nnd->name.getText(nits[numNits].name, MAXNETWORKNAME, NULL);
#else
                      nnd->name.getText(nits[numNits].name, MAXNETWORKNAME);
#endif
                      }
                      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() ? SYS_DVBS2 : SYS_DVBS);
                 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;
                           }
                       }
                    }
                 }
                 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;
                           }
                       }
                    }
                 }
                 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, 0, 0, 0, 0, 0 };
                 dtp.SetBandwidth(Bandwidths[sd->getBandwidth()]);
                 static int Constellations[] = { QPSK, QAM_16, QAM_64, QAM_AUTO };
                 dtp.SetModulation(Constellations[sd->getConstellation()]);
                 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_AUTO, 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;
                           }
                        }
                    }
                 }
                 break;
            default: ;
            }
          delete d;
          }
      }
  Channels.Unlock();
}
Пример #9
0
void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
  if (Pid == 0x00 && Tid == 0x00)
  {
    SI::PAT pat(Data, false);
    if (!pat.CheckCRCAndParse())
      return;

    SI::PAT::Association assoc;
    for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); )
    {
      if (!assoc.isNITPid())
      {
    	XVDRChannels.Lock(false);
        const cChannel *Channel =  XVDRChannels.Get()->GetByServiceID(Source(), Transponder(), assoc.getServiceId());

        if (Channel && (Channel == m_Channel))
        {
          int prevPmtPid = m_pmtPid;
          if (0 != (m_pmtPid = assoc.getPid()))
          {
            m_pmtSid = assoc.getServiceId();
            if (m_pmtPid != prevPmtPid)
            {
              Add(m_pmtPid, 0x02);
              m_pmtVersion = -1;
            }
            XVDRChannels.Unlock();
            return;
          }
        }

        XVDRChannels.Unlock();
      }
    }
  }
  else if (Pid == m_pmtPid && Tid == SI::TableIdPMT && Source() && Transponder())
  {
    SI::PMT pmt(Data, false);
    if (!pmt.CheckCRCAndParse() || pmt.getServiceId() != m_pmtSid)
      return;

    if (m_pmtVersion != -1)
    {
      if (m_pmtVersion != pmt.getVersionNumber())
      {
        cFilter::Del(m_pmtPid, 0x02);
        m_pmtPid = 0; // this triggers PAT scan
      }
      return;
    }
    m_pmtVersion = pmt.getVersionNumber();

    // get cached channel data
    if(m_ChannelCache.size() == 0)
      m_ChannelCache = cChannelCache::GetFromCache(CreateChannelUID(m_Channel));

    // get all streams and check if there are new (currently unknown) streams
    SI::PMT::Stream stream;
    cChannelCache cache;
    for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); )
    {
      cStreamInfo info;
      if (GetStreamInfo(stream, info) && cache.size() < MAXRECEIVEPIDS) {
        info.SetContent();
        cache.AddStream(info);
      }
    }

    // no new streams found -> exit
    if (m_ChannelCache.ismetaof(cache))
      return;

    m_Streamer->m_FilterMutex.Lock();

    // create new stream demuxers
    m_Streamer->Detach();
    cache.CreateDemuxers(m_Streamer);

    m_Streamer->m_ready = false;
    INFOLOG("Currently unknown new streams found, requesting stream change");

    m_Streamer->RequestStreamChange();

    // write changed data back to the cache
    m_ChannelCache = cache;
    cChannelCache::AddToCache(CreateChannelUID(m_Channel), m_ChannelCache);

    // try to attach receiver
    int c = 0;
    for(; c < 3 && !m_Streamer->Attach(); c++) {
      INFOLOG("Unable to attach receiver, retrying ...");
      usleep(100 * 1000);
    }

    // unable to attach receiver
    if(c == 3) {
      ERRORLOG("failed to attach receiver, sending detach ...");
      m_Streamer->sendDetach();
    }

    m_Streamer->m_FilterMutex.Unlock();
  }
}
Пример #10
0
void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
  if (Pid == 0x00 && Tid == 0x00)
  {
    SI::PAT pat(Data, false);
    if (!pat.CheckCRCAndParse())
      return;

    SI::PAT::Association assoc;
    for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); )
    {
      if (!assoc.isNITPid())
      {
        const cChannel *Channel =  Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
        if (Channel && (Channel == m_Channel))
        {
          int prevPmtPid = m_pmtPid;
          if (0 != (m_pmtPid = assoc.getPid()))
          {
            m_pmtSid = assoc.getServiceId();
            if (m_pmtPid != prevPmtPid)
            {
              Add(m_pmtPid, 0x02);
              m_pmtVersion = -1;
            }
            return;
          }
        }
      }
    }
  }
  else if (Pid == m_pmtPid && Tid == SI::TableIdPMT && Source() && Transponder())
  {
    SI::PMT pmt(Data, false);
    if (!pmt.CheckCRCAndParse() || pmt.getServiceId() != m_pmtSid)
      return;

    if (m_pmtVersion != -1)
    {
      if (m_pmtVersion != pmt.getVersionNumber())
      {
        cFilter::Del(m_pmtPid, 0x02);
        m_pmtPid = 0; // this triggers PAT scan
      }
      return;
    }
    m_pmtVersion = pmt.getVersionNumber();

    // get cached channel data
    if(m_ChannelCache.size() == 0)
      m_ChannelCache = cChannelCache::GetFromCache(CreateChannelUID(m_Channel));

    // get all streams and check if there are new (currently unknown) streams
    SI::PMT::Stream stream;
    cChannelCache cache;
    for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); )
    {
      struct StreamInfo info;
      if (GetStreamInfo(stream, info) && cache.size() < MAXRECEIVEPIDS)
        cache.AddStream(info);
    }

    // no new streams found -> exit
    if (cache == m_ChannelCache)
      return;

    m_Streamer->m_FilterMutex.Lock();

    // create new stream demuxers
    cache.CreateDemuxers(m_Streamer);

    INFOLOG("Currently unknown new streams found, requesting stream change");

    // write changed data back to the cache
    m_ChannelCache = cache;
    cChannelCache::AddToCache(CreateChannelUID(m_Channel), m_ChannelCache);

    m_Streamer->RequestStreamChange();
    m_Streamer->m_FilterMutex.Unlock();
  }
}
Пример #11
0
void cEitFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
  switch (Pid) {
    case 0x12: {
         cSchedulesLock SchedulesLock(true, 10);
         cSchedules *Schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock);
         if (Schedules)
            cEIT EIT(Schedules, Source(), Tid, Data);
         else {
            // If we don't get a write lock, let's at least get a read lock, so
            // that we can set the running status and 'seen' timestamp (well, actually
            // with a read lock we shouldn't be doing that, but it's only integers that
            // get changed, so it should be ok)
            cSchedulesLock SchedulesLock;
            cSchedules *Schedules = (cSchedules *)cSchedules::Schedules(SchedulesLock);
            if (Schedules)
               cEIT EIT(Schedules, Source(), Tid, Data, true);
            }
         }
         break;
    case 0x14: {
         /* TB: (time(NULL) < 31536000*2) 
          * always get the time if the system time has never been set
          * regardless of the transponder */
         if ((time(NULL) < VALID_TIME) || ((Setup.SetSystemTime && Setup.TimeTransponder) && ISTRANSPONDER(Transponder(), Setup.TimeTransponder)))
            cTDT TDT(Data);
         }
         break;
    }
}
Пример #12
0
void cSdtFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
  if (!(Source() && Transponder()))
     return;
  SI::SDT sdt(Data, false);
  if (!sdt.CheckCRCAndParse())
     return;
  if (!sectionSyncer.Sync(sdt.getVersionNumber(), sdt.getSectionNumber(), sdt.getLastSectionNumber()))
     return;
  if (!Channels.Lock(true, 10))
     return;
  SI::SDT::Service SiSdtService;
  for (SI::Loop::Iterator it; sdt.serviceLoop.getNext(SiSdtService, it); ) {
      cChannel *channel = Channels.GetByChannelID(tChannelID(Source(), sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId()));
      if (!channel)
         channel = Channels.GetByChannelID(tChannelID(Source(), 0, Transponder(), SiSdtService.getServiceId()));

      cLinkChannels *LinkChannels = NULL;
      SI::Descriptor *d;
      for (SI::Loop::Iterator it2; (d = SiSdtService.serviceDescriptors.getNext(it2)); ) {
          switch (d->getDescriptorTag()) {
            case SI::ServiceDescriptorTag: {
                 SI::ServiceDescriptor *sd = (SI::ServiceDescriptor *)d;
                 switch (sd->getServiceType()) {
                   case 0x01: // digital television service
                   case 0x02: // digital radio sound service
                   case 0x04: // NVOD reference service
                   case 0x05: // NVOD time-shifted service
                        {
                        char NameBuf[1024];
                        char ShortNameBuf[1024];
                        char ProviderNameBuf[1024];
                        sd->serviceName.getText(NameBuf, ShortNameBuf, sizeof(NameBuf), sizeof(ShortNameBuf));
                        char *pn = compactspace(NameBuf);
                        char *ps = compactspace(ShortNameBuf);
                        if (!*ps && cSource::IsCable(Source())) {
                           // Some cable providers don't mark short channel names according to the
                           // standard, but rather go their own way and use "name>short name" or
                           // "name, short name":
                           char *p = strchr(pn, '>'); // fix for UPC Wien
                           if (!p)
                              p = strchr(pn, ','); // fix for "Kabel Deutschland"
                           if (p && p > pn) {
                              *p++ = 0;
                              strcpy(ShortNameBuf, skipspace(p));
                              }
                           }
                        sd->providerName.getText(ProviderNameBuf, sizeof(ProviderNameBuf));
                        char *pp = compactspace(ProviderNameBuf);
                        if (channel) {
                           channel->SetId(sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
                           if (Setup.UpdateChannels == 1 || Setup.UpdateChannels >= 3)
                              channel->SetName(pn, ps, pp);
                           // Using SiSdtService.getFreeCaMode() is no good, because some
                           // tv stations set this flag even for non-encrypted channels :-(
                           // The special value 0xFFFF was supposed to mean "unknown encryption"
                           // and would have been overwritten with real CA values later:
                           // channel->SetCa(SiSdtService.getFreeCaMode() ? 0xFFFF : 0);
                           }
                        else if (*pn && Setup.UpdateChannels >= 4) {
                           channel = Channels.NewChannel(Channel(), pn, ps, pp, sdt.getOriginalNetworkId(), sdt.getTransportStreamId(), SiSdtService.getServiceId());
                           patFilter->Trigger();
                           }
                        }
                   }
                 }
                 break;
            // Using the CaIdentifierDescriptor is no good, because some tv stations
            // just don't use it. The actual CA values are collected in pat.c:
            /*
            case SI::CaIdentifierDescriptorTag: {
                 SI::CaIdentifierDescriptor *cid = (SI::CaIdentifierDescriptor *)d;
                 if (channel) {
                    for (SI::Loop::Iterator it; cid->identifiers.hasNext(it); )
                        channel->SetCa(cid->identifiers.getNext(it));
                    }
                 }
                 break;
            */
            case SI::NVODReferenceDescriptorTag: {
                 SI::NVODReferenceDescriptor *nrd = (SI::NVODReferenceDescriptor *)d;
                 SI::NVODReferenceDescriptor::Service Service;
                 for (SI::Loop::Iterator it; nrd->serviceLoop.getNext(Service, it); ) {
                     cChannel *link = Channels.GetByChannelID(tChannelID(Source(), Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId()));
                     if (!link && Setup.UpdateChannels >= 4) {
                        link = Channels.NewChannel(Channel(), "NVOD", "", "", Service.getOriginalNetworkId(), Service.getTransportStream(), Service.getServiceId());
                        patFilter->Trigger();
                        }
                     if (link) {
                        if (!LinkChannels)
                           LinkChannels = new cLinkChannels;
                        LinkChannels->Add(new cLinkChannel(link));
                        }
                     }
                 }
                 break;
            default: ;
            }
          delete d;
          }
      if (LinkChannels) {
         if (channel)
            channel->SetLinkChannels(LinkChannels);
         else
            delete LinkChannels;
         }
      }
  Channels.Unlock();
}
Пример #13
0
void cLivePatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
{
  if (Pid == 0x00)
  {
    if (Tid == 0x00)
    {
      SI::PAT pat(Data, false);
      if (!pat.CheckCRCAndParse())
        return;
      SI::PAT::Association assoc;
      for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); )
      {
        if (!assoc.isNITPid())
        {
          const cChannel *Channel =  Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
          if (Channel && (Channel == m_Channel))
          {
            int prevPmtPid = m_pmtPid;
            if (0 != (m_pmtPid = assoc.getPid()))
            {
              m_pmtSid = assoc.getServiceId();
              if (m_pmtPid != prevPmtPid)
              {
                Add(m_pmtPid, 0x02);
                m_pmtVersion = -1;
              }
              return;
            }
          }
        }
      }
    }
  }
  else if (Pid == m_pmtPid && Tid == SI::TableIdPMT && Source() && Transponder())
  {
    SI::PMT pmt(Data, false);
    if (!pmt.CheckCRCAndParse())
      return;
    if (pmt.getServiceId() != m_pmtSid)
      return; // skip broken PMT records
    if (m_pmtVersion != -1)
    {
      if (m_pmtVersion != pmt.getVersionNumber())
      {
//        printf("cStreamdevPatFilter: PMT version changed, detaching all pids\n");
        cFilter::Del(m_pmtPid, 0x02);
        m_pmtPid = 0; // this triggers PAT scan
      }
      return;
    }
    m_pmtVersion = pmt.getVersionNumber();

    SI::PMT::Stream stream;
    int         pids[MAXRECEIVEPIDS + 1];
    eStreamType types[MAXRECEIVEPIDS + 1];
    char        langs[MAXRECEIVEPIDS + 1][MAXLANGCODE2];
    int         subtitlingType[MAXRECEIVEPIDS + 1];
    int         compositionPageId[MAXRECEIVEPIDS + 1];
    int         ancillaryPageId[MAXRECEIVEPIDS + 1];
    int         streams = 0;
    for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); )
    {
      eStreamType type;
      int pid = GetPid(stream, &type, langs[streams], &subtitlingType[streams], &compositionPageId[streams], &ancillaryPageId[streams]);
      if (0 != pid && streams < MAXRECEIVEPIDS)
      {
        pids[streams]   = pid;
        types[streams]  = type;
        streams++;
      }
    }
    pids[streams] = 0;

    int newstreams = 0;
    for (int i = 0; i < streams; i++)
    {
      if (m_Streamer->HaveStreamDemuxer(pids[i], types[i]) == -1)
        newstreams++;
    }

    if (newstreams > 0)
    {
      m_Streamer->m_FilterMutex.Lock();
      if (m_Streamer->m_Receiver)
      {
        DEBUGLOG("Detaching Live Receiver");
        m_Streamer->m_Device->Detach(m_Streamer->m_Receiver);
        DELETENULL(m_Streamer->m_Receiver);
      }

      for (int idx = 0; idx < MAXRECEIVEPIDS; ++idx)
      {
        if (m_Streamer->m_Streams[idx])
        {
          DELETENULL(m_Streamer->m_Streams[idx]);
          m_Streamer->m_Pids[idx] = 0;
        }
      }
      m_Streamer->m_NumStreams  = 0;
      m_Streamer->m_streamReady = false;
      m_Streamer->m_IFrameSeen  = false;

      for (int i = 0; i < streams; i++)
      {
        switch (types[i])
        {
          case stMPEG2AUDIO:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stMPEG2AUDIO, pids[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetLanguage(langs[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stMPEG2VIDEO:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stMPEG2VIDEO, pids[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stH264:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stH264, pids[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stAC3:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stAC3, pids[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetLanguage(langs[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stEAC3:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stEAC3, pids[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetLanguage(langs[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stDTS:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stDTS, pids[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetLanguage(langs[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stAAC:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stAAC, pids[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetLanguage(langs[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stLATM:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stLATM, pids[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetLanguage(langs[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stDVBSUB:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stDVBSUB, pids[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetLanguage(langs[i]);
            m_Streamer->m_Streams[m_Streamer->m_NumStreams]->SetSubtitlingDescriptor(subtitlingType[i], compositionPageId[i], ancillaryPageId[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          case stTELETEXT:
          {
            m_Streamer->m_Streams[m_Streamer->m_NumStreams] = new cTSDemuxer(m_Streamer, stTELETEXT, pids[i]);
            m_Streamer->m_Pids[m_Streamer->m_NumStreams] = pids[i];
            m_Streamer->m_NumStreams++;
            break;
          }
          default:
            break;
        }
      }

      m_Streamer->m_Receiver  = new cLiveReceiver(m_Streamer, m_Channel->GetChannelID(), m_Streamer->m_Priority, m_Streamer->m_Pids);
      m_Streamer->m_Device->AttachReceiver(m_Streamer->m_Receiver);
      INFOLOG("Currently unknown new streams found, requesting stream change");
      m_Streamer->RequestStreamChange();
      m_Streamer->m_FilterMutex.Unlock();
    }
  }
}