Added receiving Ca pids to cCamSlot

This commit is contained in:
Klaus Schmidinger 2014-01-01 12:37:22 +01:00
parent b95b85fee4
commit 566c6fa464
8 changed files with 135 additions and 16 deletions

View File

@ -8032,7 +8032,7 @@ Video Disk Recorder Revision History
the last replayed recording (if any) by pressing Ok repeatedly in the Recordings
menu.
2013-12-29: Version 2.1.3
2014-01-01: Version 2.1.3
- Changed the return value of cPositioner::HorizonLongitude() to 0 in case the
latitude of the antenna location is beyond +/-81 degrees.
@ -8091,7 +8091,10 @@ Video Disk Recorder Revision History
Skyttä).
- The new function cCamSlot::Decrypt() can be used by derived classes to implement a
CAM slot that can be freely assigned to any device, without being directly inserted
into the full TS data stream in hardware.
into the full TS data stream in hardware. A derived class that implements Decrypt()
will also need to set the new parameter ReceiveCaPids in the call to the cCamSlot
base class constructor to true, in order to receive the CA pid TS packets that
contain data necessary for decrypting.
- Many member functions of cCamSlot have been made virtual to allow for easier
implementation of derived classes.
- cTSBuffer now provides the number of available bytes in its Get() function.

36
ci.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ci.c 3.2 2013/12/29 15:51:08 kls Exp $
* $Id: ci.c 3.3 2014/01/01 12:33:27 kls Exp $
*/
#include "ci.h"
@ -19,6 +19,7 @@
#include <unistd.h>
#include "device.h"
#include "pat.h"
#include "receiver.h"
#include "tools.h"
// Set these to 'true' for debug output:
@ -102,6 +103,16 @@ static char *GetString(int &Length, const uint8_t **Data)
return NULL;
}
// --- cCaPidReceiver --------------------------------------------------------
// A dummy receiver, just used to make the device receive the CA pids.
class cCaPidReceiver : public cReceiver {
public:
virtual ~cCaPidReceiver() { Detach(); }
virtual void Receive(uchar *Data, int Length) {}
};
// --- cTPDU -----------------------------------------------------------------
#define MAX_TPDU_SIZE 2048
@ -570,7 +581,7 @@ bool cCiApplicationInformation::EnterMenu(void)
#define CPCI_QUERY 0x03
#define CPCI_NOT_SELECTED 0x04
class cCiCaPmt : public cListObject {
class cCiCaPmt {
friend class cCiConditionalAccessSupport;
private:
uint8_t cmdId;
@ -1553,9 +1564,10 @@ cCamSlots CamSlots;
#define MODULE_CHECK_INTERVAL 500 // ms
#define MODULE_RESET_TIMEOUT 2 // s
cCamSlot::cCamSlot(cCiAdapter *CiAdapter)
cCamSlot::cCamSlot(cCiAdapter *CiAdapter, bool ReceiveCaPids)
{
ciAdapter = CiAdapter;
caPidReceiver = ReceiveCaPids ? new cCaPidReceiver : NULL;
slotIndex = -1;
lastModuleStatus = msReset; // avoids initial reset log message
resetTime = 0;
@ -1572,6 +1584,7 @@ cCamSlot::cCamSlot(cCiAdapter *CiAdapter)
cCamSlot::~cCamSlot()
{
delete caPidReceiver;
CamSlots.Del(this, false);
DeleteAllConnections();
}
@ -1802,6 +1815,10 @@ void cCamSlot::SendCaPmt(uint8_t CmdId)
const int *CaSystemIds = cas->GetCaSystemIds();
if (CaSystemIds && *CaSystemIds) {
if (caProgramList.Count()) {
if (caPidReceiver && caPidReceiver->NumPids()) {
if (cDevice *d = Device())
d->Detach(caPidReceiver);
}
for (int Loop = 1; Loop <= 2; Loop++) {
for (cCiCaProgramData *p = caProgramList.First(); p; p = caProgramList.Next(p)) {
if (p->modified || resendPmt) {
@ -1814,6 +1831,15 @@ void cCamSlot::SendCaPmt(uint8_t CmdId)
}
}
if ((Loop == 1) != Active) { // first remove, then add
if (caPidReceiver) {
int CaPids[MAXRECEIVEPIDS + 1];
if (GetCaPids(source, transponder, p->programNumber, CaSystemIds, MAXRECEIVEPIDS + 1, CaPids) > 0) {
if (Loop == 1)
caPidReceiver->DelPids(CaPids);
else
caPidReceiver->AddPids(CaPids);
}
}
if (cas->RepliesToQuery())
CaPmt.SetListManagement(Active ? CPLM_ADD : CPLM_UPDATE);
if (Active || cas->RepliesToQuery())
@ -1823,6 +1849,10 @@ void cCamSlot::SendCaPmt(uint8_t CmdId)
}
}
}
if (caPidReceiver && caPidReceiver->NumPids()) {
if (cDevice *d = Device())
d->AttachReceiver(caPidReceiver);
}
resendPmt = false;
}
else {

12
ci.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: ci.h 3.1 2013/12/28 13:20:08 kls Exp $
* $Id: ci.h 3.2 2014/01/01 12:13:04 kls Exp $
*/
#ifndef __CI_H
@ -121,6 +121,7 @@ class cTPDU;
class cCiTransportConnection;
class cCiSession;
class cCiCaProgramData;
class cReceiver;
class cCamSlot : public cListObject {
friend class cCiAdapter;
@ -129,6 +130,7 @@ private:
cMutex mutex;
cCondVar processed;
cCiAdapter *ciAdapter;
cReceiver *caPidReceiver;
int slotIndex;
int slotNumber;
cCiTransportConnection *tc[MAX_CONNECTIONS_PER_CAM_SLOT + 1]; // connection numbering starts with 1
@ -147,10 +149,13 @@ private:
void Write(cTPDU *TPDU);
cCiSession *GetSessionByResourceId(uint32_t ResourceId);
public:
cCamSlot(cCiAdapter *CiAdapter);
cCamSlot(cCiAdapter *CiAdapter, bool ReceiveCaPids = false);
///< Creates a new CAM slot for the given CiAdapter.
///< The CiAdapter will take care of deleting the CAM slot,
///< so the caller must not delete it!
///< If ReceiveCaPids is true, the CAM slot will take care that the CA pids
///< of the selected programmes will be included in the TS data stream that
///< is presented to the Decrypt() function.
virtual ~cCamSlot();
bool Assign(cDevice *Device, bool Query = false);
///< Assigns this CAM slot to the given Device, if this is possible.
@ -243,6 +248,9 @@ public:
///< Data pointing to the TS packet immediately following the previous
///< one. However, it can not be assumed that a call to Decrypt() with
///< a Data pointer of P will be followed by a call with P + TS_SIZE.
///< A derived class that implements this function will also need
///< to set the ReceiveCaPids parameter in the call to the base class
///< constructor to true in order to receive the CA pid data.
};
class cCamSlots : public cList<cCamSlot> {};

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: device.c 3.5 2013/12/28 12:56:24 kls Exp $
* $Id: device.c 3.6 2014/01/01 11:51:17 kls Exp $
*/
#include "device.h"
@ -1666,7 +1666,7 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
Receiver->device = this;
receiver[i] = Receiver;
Unlock();
if (camSlot) {
if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
camSlot->StartDecrypting();
startScrambleDetection = time(NULL);
}
@ -1697,7 +1697,7 @@ void cDevice::Detach(cReceiver *Receiver)
else if (receiver[i])
receiversLeft = true;
}
if (camSlot)
if (camSlot && Receiver->priority > MINPRIORITY) // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
camSlot->StartDecrypting();
if (!receiversLeft)
Cancel(-1);

46
pat.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: pat.c 2.19 2012/11/25 14:12:21 kls Exp $
* $Id: pat.c 3.1 2014/01/01 12:02:39 kls Exp $
*/
#include "pat.h"
@ -21,6 +21,7 @@
class cCaDescriptor : public cListObject {
private:
int caSystem;
int caPid;
int esPid;
int length;
uchar *data;
@ -29,6 +30,7 @@ public:
virtual ~cCaDescriptor();
bool operator== (const cCaDescriptor &arg) const;
int CaSystem(void) { return caSystem; }
int CaPid(void) { return caPid; }
int EsPid(void) { return esPid; }
int Length(void) const { return length; }
const uchar *Data(void) const { return data; }
@ -37,6 +39,7 @@ public:
cCaDescriptor::cCaDescriptor(int CaSystem, int CaPid, int EsPid, int Length, const uchar *Data)
{
caSystem = CaSystem;
caPid = CaPid;
esPid = EsPid;
length = Length + 6;
data = MALLOC(uchar, length);
@ -79,6 +82,7 @@ public:
bool Empty(void) { return caDescriptors.Count() == 0; }
void AddCaDescriptor(SI::CaDescriptor *d, int EsPid);
int GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar *Data, int EsPid);
int GetCaPids(const int *CaSystemIds, int BufSize, int *Pids);
const int *CaIds(void) { return caIds; }
};
@ -179,6 +183,30 @@ int cCaDescriptors::GetCaDescriptors(const int *CaSystemIds, int BufSize, uchar
return -1;
}
int cCaDescriptors::GetCaPids(const int *CaSystemIds, int BufSize, int *Pids)
{
if (!CaSystemIds || !*CaSystemIds)
return 0;
if (BufSize > 0 && Pids) {
int numPids = 0;
for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
const int *caids = CaSystemIds;
do {
if (d->CaSystem() == *caids) {
if (numPids + 1 < BufSize) {
Pids[numPids++] = d->CaPid();
Pids[numPids] = 0;
}
else
return -1;
}
} while (*++caids);
}
return numPids;
}
return -1;
}
// --- cCaDescriptorHandler --------------------------------------------------
class cCaDescriptorHandler : public cList<cCaDescriptors> {
@ -190,6 +218,7 @@ public:
// 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 int *CaSystemIds, int BufSize, uchar *Data, int EsPid);
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids);
};
int cCaDescriptorHandler::AddCaDescriptors(cCaDescriptors *CaDescriptors)
@ -220,6 +249,16 @@ int cCaDescriptorHandler::GetCaDescriptors(int Source, int Transponder, int Serv
return 0;
}
int cCaDescriptorHandler::GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
{
cMutexLock MutexLock(&mutex);
for (cCaDescriptors *ca = First(); ca; ca = Next(ca)) {
if (ca->Is(Source, Transponder, ServiceId))
return ca->GetCaPids(CaSystemIds, BufSize, Pids);
}
return 0;
}
cCaDescriptorHandler CaDescriptorHandler;
int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, uchar *Data, int EsPid)
@ -227,6 +266,11 @@ int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSy
return CaDescriptorHandler.GetCaDescriptors(Source, Transponder, ServiceId, CaSystemIds, BufSize, Data, EsPid);
}
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids)
{
return CaDescriptorHandler.GetCaPids(Source, Transponder, ServiceId, CaSystemIds, BufSize, Pids);
}
// --- cPatFilter ------------------------------------------------------------
cPatFilter::cPatFilter(void)

12
pat.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: pat.h 2.3 2013/02/16 15:20:24 kls Exp $
* $Id: pat.h 3.1 2013/12/30 11:32:40 kls Exp $
*/
#ifndef __PAT_H
@ -39,7 +39,13 @@ int GetCaDescriptors(int Source, int Transponder, int ServiceId, const int *CaSy
///< are copied that match one of the given CA system IDs.
///< Returns the number of bytes copied into Data (0 if no CA descriptors are
///< available), or -1 if BufSize was too small to hold all CA descriptors.
///< The return value tells whether these CA descriptors are to be used
///< for the individual streams.
int GetCaPids(int Source, int Transponder, int ServiceId, const int *CaSystemIds, int BufSize, int *Pids);
///< Gets all CA pids for a given channel.
///< Copies all available CA pids from the CA descriptors for the given Source, Transponder and ServiceId
///< into the provided buffer at Pids (at most BufSize - 1 entries, the list will be zero-terminated).
///< Only the CA pids of those CA descriptors are copied that match one of the given CA system IDs.
///< Returns the number of pids copied into Pids (0 if no CA descriptors are
///< available), or -1 if BufSize was too small to hold all CA pids.
#endif //__PAT_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: receiver.c 2.7 2012/06/02 13:20:38 kls Exp $
* $Id: receiver.c 3.1 2014/01/01 12:03:00 kls Exp $
*/
#include "receiver.h"
@ -72,6 +72,28 @@ bool cReceiver::SetPids(const cChannel *Channel)
return true;
}
void cReceiver::DelPid(int Pid)
{
if (Pid) {
for (int i = 0; i < numPids; i++) {
if (pids[i] == Pid) {
for ( ; i < numPids; i++) // we also copy the terminating 0!
pids[i] = pids[i + 1];
numPids--;
return;
}
}
}
}
void cReceiver::DelPids(const int *Pids)
{
if (Pids) {
while (*Pids)
DelPid(*Pids++);
}
}
bool cReceiver::WantsPid(int Pid)
{
if (Pid) {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: receiver.h 2.9 2012/09/02 09:27:20 kls Exp $
* $Id: receiver.h 3.1 2014/01/01 11:45:09 kls Exp $
*/
#ifndef __RECEIVER_H
@ -64,7 +64,13 @@ public:
///< through ChannelID(). The ChannelID is necessary to allow the device
///< that will be used for this receiver to detect and store whether the
///< channel can be decrypted in case this is an encrypted channel.
void DelPid(int Pid);
///< Deletes the given Pid from the list of PIDs of this receiver.
void DelPids(const int *Pids);
///< Deletes the given zero terminated list of Pids from the list of PIDs of this
///< receiver.
tChannelID ChannelID(void) { return channelID; }
int NumPids(void) const { return numPids; }
bool IsAttached(void) { return device != NULL; }
///< Returns true if this receiver is (still) attached to a device.
///< A receiver may be automatically detached from its device in