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(); } }
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(); } }
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(); } }
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(); } } }