mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
CAMs are now sent a generated EIT packet that contains a single 'present event' for the current SID, in order to avoid any parental rating dialogs
This commit is contained in:
parent
7cfce2fffa
commit
073268bd45
5
HISTORY
5
HISTORY
@ -8990,3 +8990,8 @@ Video Disk Recorder Revision History
|
||||
- If 0 is given as the channel number in the SVDRP command LSTC, the data of the
|
||||
current channel is listed.
|
||||
- Fixed a possible crash when pulling the CAM while decrypting a channel with MTD.
|
||||
|
||||
2017-05-01: Version 2.3.5
|
||||
|
||||
- CAMs are now sent a generated EIT packet that contains a single 'present event' for
|
||||
the current SID, in order to avoid any parental rating dialogs.
|
||||
|
13
ci.c
13
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 4.13 2017/04/26 09:18:26 kls Exp $
|
||||
* $Id: ci.c 4.14 2017/05/01 09:26:12 kls Exp $
|
||||
*/
|
||||
|
||||
#include "ci.h"
|
||||
@ -2424,6 +2424,17 @@ uchar *cCamSlot::Decrypt(uchar *Data, int &Count)
|
||||
return Data;
|
||||
}
|
||||
|
||||
bool cCamSlot::Inject(uchar *Data, int Count)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void cCamSlot::InjectEit(int Sid)
|
||||
{
|
||||
cEitGenerator Eit(Sid);
|
||||
Inject(Eit.Data(), Eit.Length());
|
||||
}
|
||||
|
||||
// --- cCamSlots -------------------------------------------------------------
|
||||
|
||||
cCamSlots CamSlots;
|
||||
|
13
ci.h
13
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 4.6 2017/04/10 09:17:56 kls Exp $
|
||||
* $Id: ci.h 4.7 2017/05/01 09:21:22 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __CI_H
|
||||
@ -377,6 +377,17 @@ public:
|
||||
///< A derived class that implements this function will also need
|
||||
///< to set the WantsTsData parameter in the call to the base class
|
||||
///< constructor to true in order to receive the TS data.
|
||||
virtual bool Inject(uchar *Data, int Count);
|
||||
///< Sends all Count bytes of the given Data to the CAM, and returns true
|
||||
///< if this was possible. If the data can't be sent to the CAM completely,
|
||||
///< nothing shall be sent and the return value shall be false.
|
||||
///< No decrypted packet is returned by this function.
|
||||
virtual void InjectEit(int Sid);
|
||||
///< Injects a generated EIT with a "present event" for the given Sid into
|
||||
///< the TS data stream sent to the CAM. This only applies to CAM slots that
|
||||
///< have WantsTsData set to true in their constructor.
|
||||
///< The default implementation sends an EIT with the minimum event
|
||||
///< necessary to disable the CAMs parental rating prompt.
|
||||
};
|
||||
|
||||
class cCamSlots : public cList<cCamSlot> {
|
||||
|
10
config.h
10
config.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.h 4.8 2017/03/30 13:42:15 kls Exp $
|
||||
* $Id: config.h 4.9 2017/04/29 13:33:13 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
@ -22,13 +22,13 @@
|
||||
|
||||
// VDR's own version number:
|
||||
|
||||
#define VDRVERSION "2.3.4"
|
||||
#define VDRVERSNUM 20304 // Version * 10000 + Major * 100 + Minor
|
||||
#define VDRVERSION "2.3.5"
|
||||
#define VDRVERSNUM 20305 // Version * 10000 + Major * 100 + Minor
|
||||
|
||||
// The plugin API's version number:
|
||||
|
||||
#define APIVERSION "2.3.4"
|
||||
#define APIVERSNUM 20304 // Version * 10000 + Major * 100 + Minor
|
||||
#define APIVERSION "2.3.5"
|
||||
#define APIVERSNUM 20305 // Version * 10000 + Major * 100 + Minor
|
||||
|
||||
// When loading plugins, VDR searches them by their APIVERSION, which
|
||||
// may be smaller than VDRVERSION in case there have been no changes to
|
||||
|
19
device.c
19
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 4.15 2017/04/17 14:47:42 kls Exp $
|
||||
* $Id: device.c 4.16 2017/05/01 09:24:49 kls Exp $
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
@ -1652,6 +1652,7 @@ bool cDevice::Receiving(bool Dummy) const
|
||||
|
||||
#define TS_SCRAMBLING_TIMEOUT 3 // seconds to wait until a TS becomes unscrambled
|
||||
#define TS_SCRAMBLING_TIME_OK 10 // seconds before a Channel/CAM combination is marked as known to decrypt
|
||||
#define EIT_INJECTION_TIME 10 // seconds for which to inject EIT event
|
||||
|
||||
void cDevice::Action(void)
|
||||
{
|
||||
@ -1697,6 +1698,18 @@ void cDevice::Action(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Inject EIT event to avoid the CAMs parental rating prompt:
|
||||
if (Receiver->startEitInjection) {
|
||||
time_t Now = time(NULL);
|
||||
if (cCamSlot *cs = CamSlot()) {
|
||||
if (Now != Receiver->lastEitInjection) { // once per second
|
||||
cs->InjectEit(Receiver->ChannelID().Sid());
|
||||
Receiver->lastEitInjection = Now;
|
||||
}
|
||||
}
|
||||
if (Now - Receiver->startEitInjection > EIT_INJECTION_TIME)
|
||||
Receiver->startEitInjection = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock();
|
||||
@ -1755,6 +1768,10 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
|
||||
Unlock();
|
||||
if (camSlot && Receiver->priority > MINPRIORITY) { // priority check to avoid an infinite loop with the CAM slot's caPidReceiver
|
||||
camSlot->StartDecrypting();
|
||||
if (camSlot->WantsTsData()) {
|
||||
Receiver->lastEitInjection = 0;
|
||||
Receiver->startEitInjection = time(NULL);
|
||||
}
|
||||
if (CamSlots.NumReadyMasterSlots() > 1) { // don't try different CAMs if there is only one
|
||||
Receiver->startScrambleDetection = time(NULL);
|
||||
Receiver->scramblingTimeout = TS_SCRAMBLING_TIMEOUT;
|
||||
|
29
mtd.c
29
mtd.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: mtd.c 1.10 2017/04/26 08:33:54 kls Exp $
|
||||
* $Id: mtd.c 1.11 2017/05/01 09:19:52 kls Exp $
|
||||
*/
|
||||
|
||||
#include "mtd.h"
|
||||
@ -64,22 +64,20 @@ int cMtdHandler::Put(const uchar *Data, int Count)
|
||||
if (int Skipped = TS_SYNC(Data, Count))
|
||||
return Used + Skipped;
|
||||
int Pid = TsPid(Data);
|
||||
if (Pid != CATPID) { // the original CAT with mapped PIDs must be skipped here!
|
||||
#ifdef KEEPPIDS
|
||||
int Index = 0;
|
||||
int Index = 0;
|
||||
#else
|
||||
int Index = (Pid >> UNIQ_PID_SHIFT) - 1;
|
||||
int Index = (Pid >> UNIQ_PID_SHIFT) - 1;
|
||||
#endif // KEEPPIDS
|
||||
if (Index >= 0 && Index < camSlots.Size()) {
|
||||
int w = camSlots[Index]->PutData(Data, TS_SIZE);
|
||||
if (w == 0)
|
||||
break;
|
||||
else if (w != TS_SIZE)
|
||||
esyslog("ERROR: incomplete MTD packet written (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
|
||||
}
|
||||
else if (Index >= 0) // we silently ignore Index -1 (i.e. MTD number 0), since there are several hundred empty TS packets when switching to an encrypted channel for the first time since startup
|
||||
esyslog("ERROR: invalid MTD number (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
|
||||
if (Index >= 0 && Index < camSlots.Size()) {
|
||||
int w = camSlots[Index]->PutData(Data, TS_SIZE);
|
||||
if (w == 0)
|
||||
break;
|
||||
else if (w != TS_SIZE)
|
||||
esyslog("ERROR: incomplete MTD packet written (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
|
||||
}
|
||||
else if (Index >= 0) // anything with Index -1 (i.e. MTD number 0) is either garbage or an actual CAT or EIT, which need not be returned to the device
|
||||
esyslog("ERROR: invalid MTD number (%d) in PID %d (%04X)", Index + 1, Pid, Pid);
|
||||
Data += TS_SIZE;
|
||||
Count -= TS_SIZE;
|
||||
Used += TS_SIZE;
|
||||
@ -329,6 +327,11 @@ uchar *cMtdCamSlot::Decrypt(uchar *Data, int &Count)
|
||||
return d;
|
||||
}
|
||||
|
||||
void cMtdCamSlot::InjectEit(int Sid)
|
||||
{
|
||||
MasterSlot()->InjectEit(mtdMapper->RealToUniqSid(Sid));
|
||||
}
|
||||
|
||||
int cMtdCamSlot::PutData(const uchar *Data, int Count)
|
||||
{
|
||||
int Free = mtdBuffer->Free();
|
||||
|
3
mtd.h
3
mtd.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: mtd.h 1.7 2017/04/26 09:17:08 kls Exp $
|
||||
* $Id: mtd.h 1.8 2017/05/01 09:19:21 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __MTD_H
|
||||
@ -172,6 +172,7 @@ public:
|
||||
virtual void StartDecrypting(void);
|
||||
virtual void StopDecrypting(void);
|
||||
virtual uchar *Decrypt(uchar *Data, int &Count);
|
||||
virtual void InjectEit(int Sid);
|
||||
int PutData(const uchar *Data, int Count);
|
||||
int PutCat(const uchar *Data, int Count);
|
||||
// The following functions shall not be called for a cMtdCamSlot:
|
||||
|
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: receiver.c 4.3 2017/04/02 10:08:49 kls Exp $
|
||||
* $Id: receiver.c 4.4 2017/05/01 08:49:20 kls Exp $
|
||||
*/
|
||||
|
||||
#include "receiver.h"
|
||||
@ -19,6 +19,8 @@ cReceiver::cReceiver(const cChannel *Channel, int Priority)
|
||||
lastScrambledPacket = 0;
|
||||
startScrambleDetection = 0;
|
||||
scramblingTimeout = 0;
|
||||
startEitInjection = 0;
|
||||
lastEitInjection = 0;
|
||||
SetPids(Channel);
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: receiver.h 4.2 2017/04/02 10:08:49 kls Exp $
|
||||
* $Id: receiver.h 4.3 2017/05/01 08:48:34 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __RECEIVER_H
|
||||
@ -25,6 +25,8 @@ private:
|
||||
time_t lastScrambledPacket;
|
||||
time_t startScrambleDetection;
|
||||
int scramblingTimeout;
|
||||
time_t startEitInjection;
|
||||
time_t lastEitInjection;
|
||||
bool WantsPid(int Pid);
|
||||
protected:
|
||||
cDevice *Device(void) { return device; }
|
||||
|
89
remux.c
89
remux.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: remux.c 4.6 2017/04/24 14:59:39 kls Exp $
|
||||
* $Id: remux.c 4.7 2017/04/29 12:25:09 kls Exp $
|
||||
*/
|
||||
|
||||
#include "remux.h"
|
||||
@ -940,6 +940,93 @@ bool cPatPmtParser::GetVersions(int &PatVersion, int &PmtVersion) const
|
||||
return patVersion >= 0 && pmtVersion >= 0;
|
||||
}
|
||||
|
||||
// --- cEitGenerator ---------------------------------------------------------
|
||||
|
||||
cEitGenerator::cEitGenerator(int Sid)
|
||||
{
|
||||
counter = 0;
|
||||
version = 0;
|
||||
if (Sid)
|
||||
Generate(Sid);
|
||||
}
|
||||
|
||||
uint16_t cEitGenerator::YMDtoMJD(int Y, int M, int D)
|
||||
{
|
||||
int L = (M < 3) ? 1 : 0;
|
||||
return 14956 + D + int((Y - L) * 365.25) + int((M + 1 + L * 12) * 30.6001);
|
||||
}
|
||||
|
||||
uchar *cEitGenerator::AddParentalRatingDescriptor(uchar *p, uchar ParentalRating)
|
||||
{
|
||||
*p++ = SI::ParentalRatingDescriptorTag;
|
||||
*p++ = 0x04; // descriptor length
|
||||
*p++ = 'D'; // country code
|
||||
*p++ = 'E';
|
||||
*p++ = 'U';
|
||||
*p++ = ParentalRating;
|
||||
return p;
|
||||
}
|
||||
|
||||
uchar *cEitGenerator::Generate(int Sid)
|
||||
{
|
||||
uchar *PayloadStart;
|
||||
uchar *SectionStart;
|
||||
uchar *DescriptorsStart;
|
||||
memset(eit, 0xFF, sizeof(eit));
|
||||
struct tm tm_r;
|
||||
time_t t = time(NULL) - 3600; // let's have the event start one hour in the past
|
||||
tm *tm = localtime_r(&t, &tm_r);
|
||||
uint16_t MJD = YMDtoMJD(tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
|
||||
uchar *p = eit;
|
||||
// TS header:
|
||||
*p++ = TS_SYNC_BYTE;
|
||||
*p++ = TS_PAYLOAD_START;
|
||||
*p++ = EITPID;
|
||||
*p++ = 0x10 | (counter++ & 0x0F); // continuity counter
|
||||
*p++ = 0x00; // pointer field (payload unit start indicator is set)
|
||||
// payload:
|
||||
PayloadStart = p;
|
||||
*p++ = 0x4E; // TID present/following event on this transponder
|
||||
*p++ = 0xF0;
|
||||
*p++ = 0x00; // section length
|
||||
SectionStart = p;
|
||||
*p++ = Sid >> 8;
|
||||
*p++ = Sid & 0xFF;
|
||||
*p++ = 0xC1 | (version << 1);
|
||||
*p++ = 0x00; // section number
|
||||
*p++ = 0x00; // last section number
|
||||
*p++ = 0x00; // transport stream id
|
||||
*p++ = 0x00; // ...
|
||||
*p++ = 0x00; // original network id
|
||||
*p++ = 0x00; // ...
|
||||
*p++ = 0x00; // segment last section number
|
||||
*p++ = 0x4E; // last table id
|
||||
*p++ = 0x00; // event id
|
||||
*p++ = 0x01; // ...
|
||||
*p++ = MJD >> 8; // start time
|
||||
*p++ = MJD & 0xFF; // ...
|
||||
*p++ = tm->tm_hour; // ...
|
||||
*p++ = tm->tm_min; // ...
|
||||
*p++ = tm->tm_sec; // ...
|
||||
*p++ = 0x24; // duration (one day, should cover everything)
|
||||
*p++ = 0x00; // ...
|
||||
*p++ = 0x00; // ...
|
||||
*p++ = 0x90; // running status, free/CA mode
|
||||
*p++ = 0x00; // descriptors loop length
|
||||
DescriptorsStart = p;
|
||||
p = AddParentalRatingDescriptor(p);
|
||||
// fill in lengths:
|
||||
*(SectionStart - 1) = p - SectionStart + 4; // +4 = length of CRC
|
||||
*(DescriptorsStart - 1) = p - DescriptorsStart;
|
||||
// checksum
|
||||
int crc = SI::CRC32::crc32((char *)PayloadStart, p - PayloadStart, 0xFFFFFFFF);
|
||||
*p++ = crc >> 24;
|
||||
*p++ = crc >> 16;
|
||||
*p++ = crc >> 8;
|
||||
*p++ = crc;
|
||||
return eit;
|
||||
}
|
||||
|
||||
// --- cTsToPes --------------------------------------------------------------
|
||||
|
||||
cTsToPes::cTsToPes(void)
|
||||
|
19
remux.h
19
remux.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: remux.h 4.3 2017/03/26 13:06:37 kls Exp $
|
||||
* $Id: remux.h 4.4 2017/04/29 11:56:21 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __REMUX_H
|
||||
@ -51,6 +51,7 @@ public:
|
||||
|
||||
#define PATPID 0x0000 // PAT PID (constant 0)
|
||||
#define CATPID 0x0001 // CAT PID (constant 1)
|
||||
#define EITPID 0x0012 // EIT PID (constant 18)
|
||||
#define MAXPID 0x2000 // for arrays that use a PID as the index
|
||||
|
||||
#define PTSTICKS 90000 // number of PTS ticks per second
|
||||
@ -431,6 +432,22 @@ public:
|
||||
uint16_t AncillaryPageId(int i) const { return (0 <= i && i < MAXSPIDS) ? ancillaryPageIds[i] : uint16_t(0); }
|
||||
};
|
||||
|
||||
// EIT Generator:
|
||||
|
||||
class cEitGenerator {
|
||||
private:
|
||||
uchar eit[TS_SIZE];
|
||||
int counter;
|
||||
int version;
|
||||
uint16_t YMDtoMJD(int Y, int M, int D);
|
||||
uchar *AddParentalRatingDescriptor(uchar *p, uchar ParentalRating = 0);
|
||||
public:
|
||||
cEitGenerator(int Sid = 0);
|
||||
uchar *Generate(int Sid);
|
||||
uchar *Data(void) { return eit; }
|
||||
int Length(void) { return sizeof(eit); }
|
||||
};
|
||||
|
||||
// TS to PES converter:
|
||||
// Puts together the payload of several TS packets that form one PES
|
||||
// packet.
|
||||
|
Loading…
Reference in New Issue
Block a user