mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
220 lines
6.8 KiB
C
220 lines
6.8 KiB
C
/*
|
|
* pat.c: PAT section filter
|
|
*
|
|
* See the main source file 'vdr.c' for copyright information and
|
|
* how to reach the author.
|
|
*
|
|
* $Id: pat.c 1.1 2003/12/21 15:28:28 kls Exp $
|
|
*/
|
|
|
|
#include "pat.h"
|
|
#include <malloc.h>
|
|
#include "libsi/section.h"
|
|
#include "libsi/descriptor.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;
|
|
int length;
|
|
uchar *data;
|
|
public:
|
|
cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int ProviderId, int CaPid, int Length, const uchar *Data);
|
|
virtual ~cCaDescriptor();
|
|
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, int Length, const uchar *Data)
|
|
{
|
|
source = Source;
|
|
transponder = Transponder;
|
|
serviceId = ServiceId;
|
|
caSystem = CaSystem;
|
|
providerId = ProviderId;
|
|
caPid = CaPid;
|
|
length = Length + 6;
|
|
data = MALLOC(uchar, length);
|
|
data[0] = SI::CaDescriptorTag;
|
|
data[1] = length - 2;
|
|
data[2] = (caSystem >> 8) & 0xFF;
|
|
data[3] = caSystem & 0xFF;
|
|
data[4] = ((CaPid >> 8) & 0x1F) | 0xE0;
|
|
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 -", source, transponder, serviceId, caSystem, providerId, caPid);
|
|
for (int i = 0; i < length; i++)
|
|
q += sprintf(q, " %02X", data[i]);
|
|
dsyslog(buffer);
|
|
#endif
|
|
}
|
|
|
|
cCaDescriptor::~cCaDescriptor()
|
|
{
|
|
free(data);
|
|
}
|
|
|
|
// --- cCaDescriptors --------------------------------------------------------
|
|
|
|
class cCaDescriptors : public cList<cCaDescriptor> {
|
|
private:
|
|
cMutex mutex;
|
|
public:
|
|
void NewCaDescriptor(int Source, int Transponder, int ServiceId, SI::CaDescriptor *d);
|
|
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data);
|
|
};
|
|
|
|
void cCaDescriptors::NewCaDescriptor(int Source, int Transponder, int ServiceId, SI::CaDescriptor *d)
|
|
{
|
|
// 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;
|
|
}
|
|
|
|
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())
|
|
return;
|
|
}
|
|
Add(new cCaDescriptor(Source, Transponder, ServiceId, d->getCaType(), ProviderID, d->getCaPid(), Length, Data));
|
|
//XXX update???
|
|
}
|
|
|
|
int cCaDescriptors::GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data)
|
|
{
|
|
if (!CaSystemIds || !*CaSystemIds)
|
|
return 0;
|
|
if (BufSize > 0 && Data) {
|
|
cMutexLock MutexLock(&mutex);
|
|
int length = 0;
|
|
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) {
|
|
memcpy(Data + length, d->Data(), d->Length());
|
|
length += d->Length();
|
|
}
|
|
else
|
|
return -1;
|
|
}
|
|
} while (*++caids);
|
|
}
|
|
}
|
|
return length;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
cCaDescriptors CaDescriptors;
|
|
|
|
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data)
|
|
{
|
|
return CaDescriptors.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data);
|
|
}
|
|
|
|
// --- cPatFilter ------------------------------------------------------------
|
|
|
|
cPatFilter::cPatFilter(void)
|
|
{
|
|
pmtIndex = 0;
|
|
pmtPid = 0;
|
|
lastPmtScan = 0;
|
|
Set(0x00, 0x00); // PAT
|
|
}
|
|
|
|
void cPatFilter::SetStatus(bool On)
|
|
{
|
|
cFilter::SetStatus(On);
|
|
pmtIndex = 0;
|
|
pmtPid = 0;
|
|
lastPmtScan = 0;
|
|
}
|
|
|
|
void cPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
|
|
{
|
|
if (Pid == 0x00) {
|
|
if (Tid == 0x00) {
|
|
if (pmtPid && time(NULL) - lastPmtScan > PMT_SCAN_TIMEOUT) {
|
|
Del(pmtPid, 0x02);
|
|
pmtPid = 0;
|
|
pmtIndex++;
|
|
lastPmtScan = time(NULL);
|
|
}
|
|
if (!pmtPid) {
|
|
SI::PAT pat(Data, false);
|
|
if (!pat.CheckCRCAndParse())
|
|
return;
|
|
SI::PAT::Association assoc;
|
|
int Index = 0;
|
|
for (SI::Loop::Iterator it; pat.associationLoop.hasNext(it); ) {
|
|
assoc = pat.associationLoop.getNext(it);
|
|
if (!assoc.isNITPid()) {
|
|
if (Index++ == pmtIndex) {
|
|
pmtPid = assoc.getPid();
|
|
Add(pmtPid, 0x02);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!pmtPid)
|
|
pmtIndex = 0;
|
|
}
|
|
}
|
|
}
|
|
else if (Pid == pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) {
|
|
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);
|
|
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);
|
|
delete d;
|
|
}
|
|
}
|
|
lastPmtScan = 0; // this triggers the next scan
|
|
}
|
|
}
|