summaryrefslogtreecommitdiff
path: root/pat.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2004-01-04 12:30:00 +0100
committerKlaus Schmidinger <vdr@tvdr.de>2004-01-04 12:30:00 +0100
commit8976ebcec5ca1ac03c54209b7cc12e9d14915c6b (patch)
tree8562202f489ee585c1252b2cb4a9e61b3e200efe /pat.c
parent3a1058fe1fca6d10cea42786aa54abf3d0bd0b94 (diff)
downloadvdr-8976ebcec5ca1ac03c54209b7cc12e9d14915c6b.tar.gz
vdr-8976ebcec5ca1ac03c54209b7cc12e9d14915c6b.tar.bz2
Implemented automatic PID switching and channel detection
Diffstat (limited to 'pat.c')
-rw-r--r--pat.c332
1 files changed, 242 insertions, 90 deletions
diff --git a/pat.c b/pat.c
index 07980147..3fa6848c 100644
--- a/pat.c
+++ b/pat.c
@@ -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();
}
}