summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY7
-rw-r--r--ci.c36
-rw-r--r--ci.h12
-rw-r--r--device.c6
-rw-r--r--pat.c46
-rw-r--r--pat.h12
-rw-r--r--receiver.c24
-rw-r--r--receiver.h8
8 files changed, 135 insertions, 16 deletions
diff --git a/HISTORY b/HISTORY
index 89dffaab..a5aa6526 100644
--- a/HISTORY
+++ b/HISTORY
@@ -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.
diff --git a/ci.c b/ci.c
index 92aaf722..2d9735e5 100644
--- a/ci.c
+++ b/ci.c
@@ -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 {
diff --git a/ci.h b/ci.h
index f41c0dae..1d6f5d1f 100644
--- a/ci.h
+++ b/ci.h
@@ -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> {};
diff --git a/device.c b/device.c
index c9a70173..4db3ddd7 100644
--- a/device.c
+++ b/device.c
@@ -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);
diff --git a/pat.c b/pat.c
index a7791e2a..9f5f12de 100644
--- a/pat.c
+++ b/pat.c
@@ -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)
diff --git a/pat.h b/pat.h
index 08da051f..b45e720e 100644
--- a/pat.h
+++ b/pat.h
@@ -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
diff --git a/receiver.c b/receiver.c
index bde60e46..de5d0aea 100644
--- a/receiver.c
+++ b/receiver.c
@@ -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) {
diff --git a/receiver.h b/receiver.h
index 775dabdf..8d6fee66 100644
--- a/receiver.h
+++ b/receiver.h
@@ -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