diff options
author | Klaus Schmidinger <vdr@tvdr.de> | 2004-01-04 12:30:00 +0100 |
---|---|---|
committer | Klaus Schmidinger <vdr@tvdr.de> | 2004-01-04 12:30:00 +0100 |
commit | 8976ebcec5ca1ac03c54209b7cc12e9d14915c6b (patch) | |
tree | 8562202f489ee585c1252b2cb4a9e61b3e200efe /pat.c | |
parent | 3a1058fe1fca6d10cea42786aa54abf3d0bd0b94 (diff) | |
download | vdr-8976ebcec5ca1ac03c54209b7cc12e9d14915c6b.tar.gz vdr-8976ebcec5ca1ac03c54209b7cc12e9d14915c6b.tar.bz2 |
Implemented automatic PID switching and channel detection
Diffstat (limited to 'pat.c')
-rw-r--r-- | pat.c | 332 |
1 files changed, 242 insertions, 90 deletions
@@ -4,45 +4,39 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: pat.c 1.2 2003/12/24 10:23:33 kls Exp $ + * $Id: pat.c 1.3 2004/01/04 12:27:06 kls Exp $ */ #include "pat.h" #include <malloc.h> +#include "channels.h" #include "libsi/section.h" #include "libsi/descriptor.h" +#include "thread.h" #define PMT_SCAN_TIMEOUT 10 // seconds // --- cCaDescriptor --------------------------------------------------------- class cCaDescriptor : public cListObject { - friend class cCaDescriptors; private: - int source; - int transponder; - int serviceId; int caSystem; - int providerId; - int caPid; bool stream; int length; uchar *data; public: - cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int ProviderId, int CaPid, bool Stream, int Length, const uchar *Data); + cCaDescriptor(int CaSystem, int CaPid, bool Stream, int Length, const uchar *Data); virtual ~cCaDescriptor(); + bool operator== (const cCaDescriptor &arg) const; + int CaSystem(void) { return caSystem; } + int Stream(void) { return stream; } int Length(void) const { return length; } const uchar *Data(void) const { return data; } }; -cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int ProviderId, int CaPid, bool Stream, int Length, const uchar *Data) +cCaDescriptor::cCaDescriptor(int CaSystem, int CaPid, bool Stream, int Length, const uchar *Data) { - source = Source; - transponder = Transponder; - serviceId = ServiceId; caSystem = CaSystem; - providerId = ProviderId; - caPid = CaPid; stream = Stream; length = Length + 6; data = MALLOC(uchar, length); @@ -54,15 +48,6 @@ cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaS data[5] = CaPid & 0xFF; if (Length) memcpy(&data[6], Data, Length); -//#define DEBUG_CA_DESCRIPTORS 1 -#ifdef DEBUG_CA_DESCRIPTORS - char buffer[1024]; - char *q = buffer; - q += sprintf(q, "CAM: %04X %5d %5d %04X %6X %04X %d -", source, transponder, serviceId, caSystem, providerId, caPid, stream); - for (int i = 0; i < length; i++) - q += sprintf(q, " %02X", data[i]); - dsyslog(buffer); -#endif } cCaDescriptor::~cCaDescriptor() @@ -70,75 +55,121 @@ cCaDescriptor::~cCaDescriptor() free(data); } +bool cCaDescriptor::operator== (const cCaDescriptor &arg) const +{ + return length == arg.length && memcmp(data, arg.data, length) == 0; +} + // --- cCaDescriptors -------------------------------------------------------- -class cCaDescriptors : public cList<cCaDescriptor> { +class cCaDescriptors : public cListObject { private: - cMutex mutex; + int source; + int transponder; + int serviceId; + int numCaIds; + int caIds[MAXCAIDS + 1]; + cList<cCaDescriptor> caDescriptors; + void AddCaId(int CaId); public: - void NewCaDescriptor(int Source, int Transponder, int ServiceId, SI::CaDescriptor *d, bool Stream); - int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag); + cCaDescriptors(int Source, int Transponder, int ServiceId); + bool operator== (const cCaDescriptors &arg) const; + bool Is(int Source, int Transponder, int ServiceId); + bool Is(cCaDescriptors * CaDescriptors); + bool Empty(void) { return caDescriptors.Count() == 0; } + void AddCaDescriptor(SI::CaDescriptor *d, bool Stream); + int GetCaDescriptors(const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag); + const int *CaIds(void) { return caIds; } }; -void cCaDescriptors::NewCaDescriptor(int Source, int Transponder, int ServiceId, SI::CaDescriptor *d, bool Stream) -{ - // The code for determining the ProviderID was taken from 'libdtv' - // written by Rolf Hakenes <hakenes@hippomi.de>. - - const uchar *Data = d->privateData.getData(); - int Length = d->privateData.getLength(); - int ProviderID = 0; - - switch (d->getCaType() >> 8) { - case 0x01: // SECA - ProviderID = (Data[0] << 8) | Data[1]; - break; - case 0x05: // Viaccess ? (France Telecom) - for (int i = 0; i < Length; i++) { - if (Data[i] == 0x14 && Data[i + 1] == 0x03) { - ProviderID = (Data[i + 2] << 16) | - (Data[i + 3] << 8) | - (Data[i + 4] & 0xf0); - break; - } - } - break; +cCaDescriptors::cCaDescriptors(int Source, int Transponder, int ServiceId) +{ + source = Source; + transponder = Transponder; + serviceId = ServiceId; + numCaIds = 0; + caIds[0] = 0; +} + +bool cCaDescriptors::operator== (const cCaDescriptors &arg) const +{ + cCaDescriptor *ca1 = caDescriptors.First(); + cCaDescriptor *ca2 = arg.caDescriptors.First(); + while (ca1 && ca2) { + if (!(*ca1 == *ca2)) + return false; + ca1 = caDescriptors.Next(ca1); + ca2 = arg.caDescriptors.Next(ca2); + } + return !ca1 && !ca2; +} + +bool cCaDescriptors::Is(int Source, int Transponder, int ServiceId) +{ + return source == Source && transponder == Transponder && serviceId == ServiceId; +} + +bool cCaDescriptors::Is(cCaDescriptors * CaDescriptors) +{ + return Is(CaDescriptors->source, CaDescriptors->transponder, CaDescriptors->serviceId); +} + +void cCaDescriptors::AddCaId(int CaId) +{ + if (numCaIds < MAXCAIDS) { + for (int i = 0; i < numCaIds; i++) { + if (caIds[i] == CaId) + return; + } + caIds[numCaIds++] = CaId; + caIds[numCaIds] = 0; } +} - cMutexLock MutexLock(&mutex); - for (cCaDescriptor *ca = First(); ca; ca = Next(ca)) { - if (ca->source == Source && ca->transponder == Transponder && ca->serviceId == ServiceId && ca->caSystem == d->getCaType() && ca->providerId == ProviderID && ca->caPid == d->getCaPid()) +void cCaDescriptors::AddCaDescriptor(SI::CaDescriptor *d, bool Stream) +{ + cCaDescriptor *nca = new cCaDescriptor(d->getCaType(), d->getCaPid(), Stream, d->privateData.getLength(), d->privateData.getData()); + for (cCaDescriptor *ca = caDescriptors.First(); ca; ca = caDescriptors.Next(ca)) { + if (*ca == *nca) { + delete nca; return; + } } - Add(new cCaDescriptor(Source, Transponder, ServiceId, d->getCaType(), ProviderID, d->getCaPid(), Stream, Length, Data)); - //XXX update??? + AddCaId(nca->CaSystem()); + caDescriptors.Add(nca); +//#define DEBUG_CA_DESCRIPTORS 1 +#ifdef DEBUG_CA_DESCRIPTORS + char buffer[1024]; + char *q = buffer; + q += sprintf(q, "CAM: %04X %5d %5d %04X %d -", source, transponder, serviceId, d->getCaType(), Stream); + for (int i = 0; i < nca->Length(); i++) + q += sprintf(q, " %02X", nca->Data()[i]); + dsyslog(buffer); +#endif } -int cCaDescriptors::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag) +int cCaDescriptors::GetCaDescriptors(const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag) { if (!CaSystemIds || !*CaSystemIds) return 0; if (BufSize > 0 && Data) { - cMutexLock MutexLock(&mutex); int length = 0; int IsStream = -1; - for (cCaDescriptor *d = First(); d; d = Next(d)) { - if (d->source == Source && d->transponder == Transponder && d->serviceId == ServiceId) { - const unsigned short *caids = CaSystemIds; - do { - if (d->caSystem == *caids) { - if (length + d->Length() <= BufSize) { - if (IsStream >= 0 && IsStream != d->stream) - dsyslog("CAM: different stream flag in CA descriptors"); - IsStream = d->stream; - memcpy(Data + length, d->Data(), d->Length()); - length += d->Length(); - } - else - return -1; + for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) { + const unsigned short *caids = CaSystemIds; + do { + if (d->CaSystem() == *caids) { + if (length + d->Length() <= BufSize) { + if (IsStream >= 0 && IsStream != d->Stream()) + dsyslog("CAM: different stream flag in CA descriptors"); + IsStream = d->Stream(); + memcpy(Data + length, d->Data(), d->Length()); + length += d->Length(); } - } while (*++caids); - } + else + return -1; + } + } while (*++caids); } StreamFlag = IsStream == 1; return length; @@ -146,11 +177,52 @@ int cCaDescriptors::GetCaDescriptors(int Source, int Transponder, int ServiceId, return -1; } -cCaDescriptors CaDescriptors; +// --- cCaDescriptorHandler -------------------------------------------------- + +class cCaDescriptorHandler : public cList<cCaDescriptors> { +private: + cMutex mutex; +public: + int AddCaDescriptors(cCaDescriptors *CaDescriptors); + // Returns 0 if this is an already known descriptor, + // 1 if it is an all new descriptor with actual contents, + // and 2 if an existing descriptor was changed. + int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag); + }; + +int cCaDescriptorHandler::AddCaDescriptors(cCaDescriptors *CaDescriptors) +{ + cMutexLock MutexLock(&mutex); + for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) { + if (ca->Is(CaDescriptors)) { + if (*ca == *CaDescriptors) { + delete CaDescriptors; + return 0; + } + Del(ca); + Add(CaDescriptors); + return 2; + } + } + Add(CaDescriptors); + return CaDescriptors->Empty() ? 0 : 1; +} + +int cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag) +{ + cMutexLock MutexLock(&mutex); + for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) { + if (ca->Is(Source, Transponder, ServiceId)) + return ca->GetCaDescriptors(CaSystemIds, BufSize, Data, StreamFlag); + } + return 0; +} + +cCaDescriptorHandler CaDescriptorHandler; int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data, bool &StreamFlag) { - return CaDescriptors.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, StreamFlag); + return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, StreamFlag); } // --- cPatFilter ------------------------------------------------------------ @@ -160,6 +232,7 @@ cPatFilter::cPatFilter(void) pmtIndex = 0; pmtPid = 0; lastPmtScan = 0; + numPmtEntries = 0; Set(0x00, 0x00); // PAT } @@ -169,6 +242,28 @@ void cPatFilter::SetStatus(bool On) pmtIndex = 0; pmtPid = 0; lastPmtScan = 0; + numPmtEntries = 0; +} + +void cPatFilter::Trigger(void) +{ + numPmtEntries = 0; +} + +bool cPatFilter::PmtVersionChanged(int PmtPid, int Version) +{ + Version <<= 16; + for (int i = 0; i < numPmtEntries; i++) { + if ((pmtVersion[i] & 0x0000FFFF) == PmtPid) { + bool Changed = (pmtVersion[i] & 0x00FF0000) != Version; + if (Changed) + pmtVersion[i] = PmtPid | Version; + return Changed; + } + } + if (numPmtEntries < MAXPMTENTRIES) + pmtVersion[numPmtEntries++] = PmtPid | Version; + return true; } void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length) @@ -206,21 +301,78 @@ void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length SI::PMT pmt(Data, false); if (!pmt.CheckCRCAndParse()) return; - SI::CaDescriptor *d; - // Scan the common loop: - for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)pmt.commonDescriptors.getNext(it, SI::CaDescriptorTag)); ) { - CaDescriptors.NewCaDescriptor(Source(), Transponder(), pmt.getServiceId(), d, false); - delete d; - } - // Scan the stream-specific loop: - SI::PMT::Stream stream; - for (SI::Loop::Iterator it; pmt.streamLoop.hasNext(it); ) { - stream = pmt.streamLoop.getNext(it); - for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)stream.streamDescriptors.getNext(it, SI::CaDescriptorTag)); ) { - CaDescriptors.NewCaDescriptor(Source(), Transponder(), pmt.getServiceId(), d, true); - delete d; - } - } + if (!PmtVersionChanged(pmtPid, pmt.getVersionNumber())) { + lastPmtScan = 0; // this triggers the next scan + return; + } + if (!Channels.Lock(true, 10)) { + numPmtEntries = 0; // to make sure we try again + return; + } + cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), pmt.getServiceId()); + if (Channel) { + SI::CaDescriptor *d; + cCaDescriptors *CaDescriptors = new cCaDescriptors(Channel->Source(), Channel->Transponder(), Channel->Sid()); + // Scan the common loop: + for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)pmt.commonDescriptors.getNext(it, SI::CaDescriptorTag)); ) { + CaDescriptors->AddCaDescriptor(d, false); + delete d; + } + // Scan the stream-specific loop: + SI::PMT::Stream stream; + int Vpid = 0; + int Ppid = pmt.getPCRPid(); + int Apids[MAXAPIDS] = { 0 }; + int Dpids[MAXAPIDS] = { 0 }; + int Tpid = 0; + int NumApids = 0; + int NumDpids = 0; + for (SI::Loop::Iterator it; pmt.streamLoop.hasNext(it); ) { + stream = pmt.streamLoop.getNext(it); + switch (stream.getStreamType()) { + case 1: // STREAMTYPE_11172_VIDEO + case 2: // STREAMTYPE_13818_VIDEO + Vpid = stream.getPid(); + break; + case 3: // STREAMTYPE_11172_AUDIO + case 4: // STREAMTYPE_13818_AUDIO + { + if (NumApids < MAXAPIDS) + Apids[NumApids++] = stream.getPid(); + } + break; + case 5: // STREAMTYPE_13818_PRIVATE + case 6: // STREAMTYPE_13818_PES_PRIVATE + //XXX case 8: // STREAMTYPE_13818_DSMCC + { + SI::Descriptor *d; + for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) { + switch (d->getDescriptorTag()) { + case SI::AC3DescriptorTag: + if (NumDpids < MAXAPIDS) + Dpids[NumDpids++] = stream.getPid(); + break; + case SI::TeletextDescriptorTag: + Tpid = stream.getPid(); + break; + default: ; + } + delete d; + } + } + break; + //default: printf("PID: %5d %5d %2d %3d %3d\n", pmt.getServiceId(), stream.getPid(), stream.getStreamType(), pmt.getVersionNumber(), Channel->Number());//XXX + } + for (SI::Loop::Iterator it; (d = (SI::CaDescriptor*)stream.streamDescriptors.getNext(it, SI::CaDescriptorTag)); ) { + CaDescriptors->AddCaDescriptor(d, true); + delete d; + } + } + Channel->SetPids(Vpid, Ppid, Apids[0], Apids[1], Dpids[0], Dpids[1], Tpid); + Channel->SetCaIds(CaDescriptors->CaIds()); + Channel->SetCaDescriptors(CaDescriptorHandler.AddCaDescriptors(CaDescriptors)); + } lastPmtScan = 0; // this triggers the next scan + Channels.Unlock(); } } |