summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY20
-rw-r--r--MANUAL18
-rw-r--r--channels.conf2
-rw-r--r--ci.c61
-rw-r--r--ci.h11
-rw-r--r--config.h4
-rw-r--r--dvbdevice.c66
-rw-r--r--eit.c91
-rw-r--r--eit.h14
-rw-r--r--i18n.c18
-rw-r--r--menu.c31
-rw-r--r--menu.h3
-rw-r--r--osd.h3
-rw-r--r--vdr.c35
15 files changed, 240 insertions, 138 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index fad8e0b..d05b928 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -196,6 +196,7 @@ Andreas Schultz <aschultz@warp10.net>
for pointing out some unnecessary #includes in eit.c and a problem with
cMenuRecordings::Del(), which caused warnings with gcc-3.2
for suggesting a Make.config file
+ for making EIT filtering use masks to reduce the number of filters
Aaron Holtzman
for writing 'ac3dec'
diff --git a/HISTORY b/HISTORY
index 7e69524..439e064 100644
--- a/HISTORY
+++ b/HISTORY
@@ -2033,3 +2033,23 @@ Video Disk Recorder Revision History
applies to the RCU remote control in case of errors during startup.
- Fixed handling of Ca parameters with values <= MAXDEVICES, which don't indicate
an actual encrypted channel (thanks to Stefan Huelswitt for reporting this one).
+
+2003-04-21: Version 1.1.28
+
+- Using masks in EIT filtering to reduce the number of filters (thanks to Andreas
+ Schultz).
+- Fixed handling Ca descriptors (thanks to Stefan Huelswitt).
+- Now only those Ca descriptors are sent to a CAM that are actually understood
+ by that CAM.
+- Re-enabled CAM communication during replay and on non-Ca channels. This requires
+ a DVB driver with firmware version 2613 or later.
+- It is now possible to do simultaneous recording and replay with a single DVB
+ card, even with encrypted channels. This requires the use of the Link Layer
+ firmware, version 2613 or higher; the -icam firmware is still limited to live
+ encrypted channels only. Finally we have time shift for encrypted channels on
+ single card systems!
+- Enhanced detection of pending user I/O from CAMs to avoid sluggish reaction
+ to remote control keypresses.
+- Implemented "pause live video". You can now press "Menu/Yellow" or "Pause" on
+ your remote control while watching live video to start an instant recording
+ of the current programme and immediately start replaying that recording.
diff --git a/MANUAL b/MANUAL
index b5f00d1..be9ac52 100644
--- a/MANUAL
+++ b/MANUAL
@@ -19,7 +19,7 @@ Video Disk Recorder User's Manual
Back - Menu off VDR menu VDR menu Discard VDR menu Recordings menu
Red - Record Edit Edit ABC/abc Play/Commands(2) Jump
Green - Language New New Ins/Ovr Rewind Skip -60s
- Yellow - - Delete Delete Delete Delete Skip +60s
+ Yellow - Pause live Delete Delete Delete Delete Skip +60s
Blue - Stop/Resume Mark On/Off(1) - Summary Stop
0..9 Ch select - - - Numeric inp. Exec cmd(2) Editing
@@ -31,7 +31,7 @@ Video Disk Recorder User's Manual
following functions:
Play resume normal replay
- Pause pause replay
+ Pause pause replay or live video
Stop stop replay
Record instant recording
FastFwd fast forward
@@ -191,6 +191,20 @@ Video Disk Recorder User's Manual
Stop instant recording by pressing the "Menu" button and selecting
"Stop Recording", or by disabling the timer.
+* Pausing live video
+
+ If you want to pause the live programme you are just watching, simple press
+ "Menu/Yellow" or "Pause" on your remote control. VDR will start an instant
+ recording of the current channel (just as if you had pressed "Menu/Red" or
+ "Record") and immediately begin replaying that recording. Replay will be
+ put into "pause" mode, so you can attend to whatever it was that disturbed
+ your live viewing session. Once you're back, simply press the "Up" or "Play"
+ button and you'll be watching the current channel in time shift mode, right
+ from the point where you left off. The instant recording VDR has started
+ will use the same parameters for priority, lifetime and recording duration
+ as any other instant recording, so by default it will record 3 hours (which
+ should be enough for any normal broadcast).
+
* Replaying a Recording
All recordings are listed in the "Recordings" menu. Browse through the
diff --git a/channels.conf b/channels.conf
index 2f0c7eb..13bc7e7 100644
--- a/channels.conf
+++ b/channels.conf
@@ -59,7 +59,7 @@ Studio Universal:12071:h:S19.2E:27500:2047:2048:0:101:36:0:0:0
Premiere Serie:12031:h:S19.2E:27500:1023:1024:0:101:16:0:0:0
Disney Channel:11758:h:S19.2E:27500:2559:2560:0:101:34:0:0:0
Premiere Nostalgie:12031:h:S19.2E:27500:2559:2560:0:101:516:0:0:0
-Discovery Channel:12031:h:S19.2E:27500:1791:1792:0:101:14:0:0:0
+Discovery Channel:11758:h:S19.2E:27500:1023:1024:8181:101:14:0:0:0
Planet:12090:v:S19.2E:27500:1279:1280:0:101:13:0:0:0
Fox Kids:11758:h:S19.2E:27500:1279:1280:0:101:28:0:0:0
Junior:11758:h:S19.2E:27500:255:256:0:101:19:0:0:0
diff --git a/ci.c b/ci.c
index a3d64df..91d9ede 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 1.9 2003/03/23 15:18:40 kls Exp $
+ * $Id: ci.c 1.14 2003/04/20 09:52:45 kls Exp $
*/
/* XXX TODO
@@ -625,6 +625,7 @@ public:
const cCiTransportConnection *Tc(void) { return tc; }
int SessionId(void) { return sessionId; }
int ResourceId(void) { return resourceId; }
+ virtual bool HasUserIO(void) { return false; }
virtual bool Process(int Length = 0, const uint8_t *Data = NULL);
};
@@ -769,7 +770,7 @@ public:
cCiApplicationInformation::cCiApplicationInformation(int SessionId, cCiTransportConnection *Tc)
:cCiSession(SessionId, RI_APPLICATION_INFORMATION, Tc)
{
- dbgprotocol("New Aplication Information (session id %d)\n", SessionId);
+ dbgprotocol("New Application Information (session id %d)\n", SessionId);
state = 0;
creationTime = time(NULL);
menuString = NULL;
@@ -827,12 +828,17 @@ bool cCiApplicationInformation::EnterMenu(void)
// --- cCiConditionalAccessSupport -------------------------------------------
+#define MAXCASYSTEMIDS 16
+
class cCiConditionalAccessSupport : public cCiSession {
private:
int state;
+ int numCaSystemIds;
+ unsigned short caSystemIds[MAXCASYSTEMIDS + 1]; // list is zero terminated!
public:
cCiConditionalAccessSupport(int SessionId, cCiTransportConnection *Tc);
virtual bool Process(int Length = 0, const uint8_t *Data = NULL);
+ const unsigned short *GetCaSystemIds(void) { return caSystemIds; }
bool SendPMT(cCiCaPmt &CaPmt);
};
@@ -841,6 +847,7 @@ cCiConditionalAccessSupport::cCiConditionalAccessSupport(int SessionId, cCiTrans
{
dbgprotocol("New Conditional Access Support (session id %d)\n", SessionId);
state = 0;
+ caSystemIds[numCaSystemIds = 0] = 0;
}
bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
@@ -853,9 +860,16 @@ bool cCiConditionalAccessSupport::Process(int Length, const uint8_t *Data)
int l = 0;
const uint8_t *d = GetData(Data, l);
while (l > 1) {
- dbgprotocol(" %04X", ((unsigned int)(*d) << 8) | *(d + 1));
+ unsigned short id = ((unsigned short)(*d) << 8) | *(d + 1);
+ dbgprotocol(" %04X", id);
d += 2;
l -= 2;
+ if (numCaSystemIds < MAXCASYSTEMIDS) {
+ caSystemIds[numCaSystemIds++] = id;
+ caSystemIds[numCaSystemIds] = 0;
+ }
+ else
+ esyslog("ERROR: too many CA system IDs!");
}
dbgprotocol("\n");
}
@@ -996,6 +1010,7 @@ public:
cCiMMI(int SessionId, cCiTransportConnection *Tc);
virtual ~cCiMMI();
virtual bool Process(int Length = 0, const uint8_t *Data = NULL);
+ virtual bool HasUserIO(void) { return menu || enquiry; }
cCiMenu *Menu(void);
cCiEnquiry *Enquiry(void);
bool SendMenuAnswer(uint8_t Selection);
@@ -1273,7 +1288,8 @@ void cCiCaPmt::AddCaDescriptor(int Length, uint8_t *Data)
cCiHandler::cCiHandler(int Fd, int NumSlots)
{
numSlots = NumSlots;
- enabled = true;
+ newCaSupport = false;
+ hasUserIO = false;
for (int i = 0; i < MAX_CI_SESSION; i++)
sessions[i] = NULL;
tpl = new cCiTransportLayer(Fd, numSlots);
@@ -1299,12 +1315,14 @@ cCiHandler *cCiHandler::CreateCiHandler(const char *FileName)
if (Caps.slot_type == CA_CI_LINK)
return new cCiHandler(fd_ca, NumSlots);
else
- esyslog("ERROR: CAM doesn't support link layer interface");
+ isyslog("CAM doesn't support link layer interface");
}
- esyslog("ERROR: no CAM slots found");
+ else
+ esyslog("ERROR: no CAM slots found");
}
else
LOG_ERROR_STR(FileName);
+ close(fd_ca);
}
return NULL;
}
@@ -1358,7 +1376,8 @@ cCiSession *cCiHandler::CreateSession(int ResourceId)
switch (ResourceId) {
case RI_RESOURCE_MANAGER: return sessions[i] = new cCiResourceManager(i + 1, tc);
case RI_APPLICATION_INFORMATION: return sessions[i] = new cCiApplicationInformation(i + 1, tc);
- case RI_CONDITIONAL_ACCESS_SUPPORT: return sessions[i] = new cCiConditionalAccessSupport(i + 1, tc);
+ case RI_CONDITIONAL_ACCESS_SUPPORT: newCaSupport = true;
+ return sessions[i] = new cCiConditionalAccessSupport(i + 1, tc);
case RI_HOST_CONTROL: break; //XXX
case RI_DATE_TIME: return sessions[i] = new cCiDateTime(i + 1, tc);
case RI_MMI: return sessions[i] = new cCiMMI(i + 1, tc);
@@ -1426,8 +1445,6 @@ int cCiHandler::CloseAllSessions(int Slot)
bool cCiHandler::Process(void)
{
- if (!enabled)
- return false;
bool result = true;
cMutexLock MutexLock(&mutex);
for (int Slot = 0; Slot < numSlots; Slot++) {
@@ -1466,10 +1483,14 @@ bool cCiHandler::Process(void)
tpl->NewConnection(Slot);
}
}
+ bool UserIO = false;
for (int i = 0; i < MAX_CI_SESSION; i++) {
- if (sessions[i])
- sessions[i]->Process();
+ if (sessions[i] && sessions[i]->Process())
+ UserIO |= sessions[i]->HasUserIO();
}
+ hasUserIO = UserIO;
+ if (newCaSupport)
+ newCaSupport = result = false; // triggers new SetCaPmt at caller!
return result;
}
@@ -1502,16 +1523,18 @@ cCiEnquiry *cCiHandler::GetEnquiry(void)
return NULL;
}
-bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt)
+const unsigned short *cCiHandler::GetCaSystemIds(int Slot)
{
cMutexLock MutexLock(&mutex);
- bool result = false;
- for (int Slot = 0; Slot < numSlots; Slot++) {
- cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
- if (cas)
- result |= cas->SendPMT(CaPmt);
- }
- return result;
+ cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
+ return cas ? cas->GetCaSystemIds() : NULL;
+}
+
+bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt, int Slot)
+{
+ cMutexLock MutexLock(&mutex);
+ cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot);
+ return cas && cas->SendPMT(CaPmt);
}
bool cCiHandler::Reset(int Slot)
diff --git a/ci.h b/ci.h
index a9f27f1..79ed62f 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 1.4 2003/03/23 15:18:40 kls Exp $
+ * $Id: ci.h 1.7 2003/04/20 09:21:23 kls Exp $
*/
#ifndef __CI_H
@@ -80,7 +80,8 @@ class cCiHandler {
private:
cMutex mutex;
int numSlots;
- bool enabled;
+ bool newCaSupport;
+ bool hasUserIO;
cCiSession *sessions[MAX_CI_SESSION];
cCiTransportLayer *tpl;
cCiTransportConnection *tc;
@@ -96,12 +97,14 @@ private:
public:
~cCiHandler();
static cCiHandler *CreateCiHandler(const char *FileName);
- void SetEnabled(bool Enabled) { enabled = Enabled; }
+ int NumSlots(void) { return numSlots; }
bool Process(void);
+ bool HasUserIO(void) { return hasUserIO; }
bool EnterMenu(int Slot);
cCiMenu *GetMenu(void);
cCiEnquiry *GetEnquiry(void);
- bool SetCaPmt(cCiCaPmt &CaPmt);
+ const unsigned short *GetCaSystemIds(int Slot);
+ bool SetCaPmt(cCiCaPmt &CaPmt, int Slot);
bool Reset(int Slot);
};
diff --git a/config.h b/config.h
index ac40ff4..94bdcd7 100644
--- a/config.h
+++ b/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 1.152 2003/04/12 09:35:50 kls Exp $
+ * $Id: config.h 1.153 2003/04/13 14:02:02 kls Exp $
*/
#ifndef __CONFIG_H
@@ -19,7 +19,7 @@
#include "device.h"
#include "tools.h"
-#define VDRVERSION "1.1.27"
+#define VDRVERSION "1.1.28"
#define MAXPRIORITY 99
#define MAXLIFETIME 99
diff --git a/dvbdevice.c b/dvbdevice.c
index 9bbac2d..c25ebef 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbdevice.c 1.51 2003/04/12 15:06:11 kls Exp $
+ * $Id: dvbdevice.c 1.54 2003/04/19 14:24:25 kls Exp $
*/
#include "dvbdevice.h"
@@ -116,13 +116,14 @@ bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
void cDvbTuner::Set(const cChannel *Channel, bool Tune)
{
cMutexLock MutexLock(&mutex);
- channel = *Channel;
+ bool CaChange = !(Channel->GetChannelID() == channel.GetChannelID());
if (Tune)
tunerStatus = tsSet;
- else if (tunerStatus == tsCam)
+ else if (tunerStatus == tsCam && CaChange)
tunerStatus = tsTuned;
- if (Channel->Ca())
+ if (Channel->Ca() && CaChange)
startTime = time(NULL);
+ channel = *Channel;
newSet.Broadcast();
}
@@ -264,27 +265,29 @@ void cDvbTuner::Action(void)
}
}
if (tunerStatus >= tsLocked) {
- if (ciHandler && channel.Ca()) {
+ if (ciHandler) {
if (ciHandler->Process()) {
if (tunerStatus != tsCam) {//XXX TODO update in case the CA descriptors have changed
- uchar buffer[2048];
- int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer);
- if (length > 0) {
- cCiCaPmt CaPmt(channel.Sid());
- CaPmt.AddCaDescriptor(length, buffer);
- if (channel.Vpid())
- CaPmt.AddPid(channel.Vpid());
- if (channel.Apid1())
- CaPmt.AddPid(channel.Apid1());
- if (channel.Apid2())
- CaPmt.AddPid(channel.Apid2());
- if (channel.Dpid1())
- CaPmt.AddPid(channel.Dpid1());
- if (ciHandler->SetCaPmt(CaPmt)) {
- tunerStatus = tsCam;
- startTime = 0;
- }
- }
+ for (int Slot = 0; Slot < ciHandler->NumSlots(); Slot++) {
+ uchar buffer[2048];
+ int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), ciHandler->GetCaSystemIds(Slot), sizeof(buffer), buffer);
+ if (length > 0) {
+ cCiCaPmt CaPmt(channel.Sid());
+ CaPmt.AddCaDescriptor(length, buffer);
+ if (channel.Vpid())
+ CaPmt.AddPid(channel.Vpid());
+ if (channel.Apid1())
+ CaPmt.AddPid(channel.Apid1());
+ if (channel.Apid2())
+ CaPmt.AddPid(channel.Apid2());
+ if (channel.Dpid1())
+ CaPmt.AddPid(channel.Dpid1());
+ if (ciHandler->SetCaPmt(CaPmt, Slot)) {
+ tunerStatus = tsCam;
+ startTime = 0;
+ }
+ }
+ }
}
}
else
@@ -588,7 +591,8 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
if (!HasPid(Channel->Vpid())) {
#ifdef DO_MULTIPLE_RECORDINGS
if (Channel->Ca() > CACONFBASE)
- needsDetachReceivers = true;
+ needsDetachReceivers = !ciHandler // only LL-firmware can do non-live CA channels
+ || Ca() != Channel->Ca();
else if (!IsPrimaryDevice())
result = true;
#ifdef DO_REC_AND_PLAY_ON_PRIMARY_DEVICE
@@ -609,7 +613,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
{
- bool IsEncrypted = Channel->Ca() > CACONFBASE;
+ bool IsEncrypted = Channel->Ca() > CACONFBASE && !ciHandler; // only LL-firmware can do non-live CA channels
bool DoTune = !dvbTuner->IsTunedTo(Channel);
@@ -714,7 +718,7 @@ int cDvbDevice::NumAudioTracksDevice(void) const
int n = 0;
if (aPid1)
n++;
- if (Ca() <= MAXDEVICES && aPid2 && aPid1 != aPid2) // a Ca recording session blocks switching live audio tracks
+ if (Ca() <= MAXDEVICES && aPid2 && aPid1 != aPid2) // a CA recording session blocks switching live audio tracks
n++;
return n;
}
@@ -746,7 +750,7 @@ bool cDvbDevice::CanReplay(void) const
if (Receiving())
return false;
#endif
- return cDevice::CanReplay() && Ca() <= MAXDEVICES; // we can only replay if there is no Ca recording going on
+ return cDevice::CanReplay() && (Ca() <= MAXDEVICES || ciHandler); // with non-LL-firmware we can only replay if there is no CA recording going on
}
bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
@@ -775,15 +779,11 @@ bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
if (siProcessor)
siProcessor->SetStatus(true);
- if (ciHandler)
- ciHandler->SetEnabled(true);
break;
case pmAudioVideo:
case pmAudioOnlyBlack:
if (siProcessor)
siProcessor->SetStatus(false);
- if (ciHandler)
- ciHandler->SetEnabled(false);
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_MEMORY));
CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, PlayMode == pmAudioVideo));
@@ -794,8 +794,6 @@ bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
case pmAudioOnly:
if (siProcessor)
siProcessor->SetStatus(false);
- if (ciHandler)
- ciHandler->SetEnabled(false);
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
CHECK(ioctl(fd_audio, AUDIO_STOP, true));
CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
@@ -807,8 +805,6 @@ bool cDvbDevice::SetPlayMode(ePlayMode PlayMode)
case pmExtern_THIS_SHOULD_BE_AVOIDED:
if (siProcessor)
siProcessor->SetStatus(false);
- if (ciHandler)
- ciHandler->SetEnabled(false);
close(fd_video);
close(fd_audio);
fd_video = fd_audio = -1;
diff --git a/eit.c b/eit.c
index ff5dd42..2bab1a5 100644
--- a/eit.c
+++ b/eit.c
@@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.c 1.68 2003/04/12 11:27:31 kls Exp $
+ * $Id: eit.c 1.72 2003/04/21 13:21:54 kls Exp $
***************************************************************************/
#include "eit.h"
@@ -1002,34 +1002,38 @@ bool cEIT::IsPresentFollowing()
// --- cCaDescriptor ---------------------------------------------------------
class cCaDescriptor : public cListObject {
- friend class cCaDescriptors;
+ friend class cSIProcessor;
private:
int source;
int transponder;
int serviceId;
int caSystem;
+ unsigned int providerId;
+ int caPid;
int length;
uchar *data;
public:
- cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, int CaPid, int Length, uchar *Data);
+ cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, unsigned int ProviderId, int CaPid, int Length, 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 CaPid, int Length, uchar *Data)
+cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaSystem, unsigned int ProviderId, int CaPid, int Length, uchar *Data)
{
source = Source;
transponder = Transponder;
serviceId = ServiceId;
caSystem = CaSystem;
+ providerId = ProviderId;
+ caPid = CaPid;
length = Length + 6;
data = MALLOC(uchar, length);
data[0] = DESCR_CA;
data[1] = length - 2;
data[2] = (caSystem >> 8) & 0xFF;
data[3] = caSystem & 0xFF;
- data[4] = ((CaPid >> 8) & 0xFF) | 0xE0;
+ data[4] = ((CaPid >> 8) & 0x1F) | 0xE0;
data[5] = CaPid & 0xFF;
if (Length)
memcpy(&data[6], Data, Length);
@@ -1037,7 +1041,7 @@ cCaDescriptor::cCaDescriptor(int Source, int Transponder, int ServiceId, int CaS
#ifdef DEBUG_CA_DESCRIPTORS
char buffer[1024];
char *q = buffer;
- q += sprintf(q, "CAM: %04X %5d %4d", source, transponder, serviceId);
+ 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);
@@ -1049,26 +1053,6 @@ cCaDescriptor::~cCaDescriptor()
free(data);
}
-// --- cCaDescriptors --------------------------------------------------------
-
-class cCaDescriptors : public cList<cCaDescriptor> {
-public:
- const cCaDescriptor *Get(int Source, int Transponder, int ServiceId, int CaSystem);
- };
-
-const cCaDescriptor *cCaDescriptors::Get(int Source, int Transponder, int ServiceId, int CaSystem)
-{
- for (cCaDescriptor *ca = First(); ca; ca = Next(ca)) {
- if (ca->source == Source && ca->transponder == Transponder && ca->serviceId == ServiceId) {
- if (CaSystem == -1 || ca->caSystem == CaSystem)
- return ca;
- if (CaSystem < 0)
- CaSystem++;
- }
- }
- return NULL;
-}
-
// --- cSIProcessor ----------------------------------------------------------
#define MAX_FILTERS 20
@@ -1077,7 +1061,7 @@ const cCaDescriptor *cCaDescriptors::Get(int Source, int Transponder, int Servic
int cSIProcessor::numSIProcessors = 0;
cSchedules *cSIProcessor::schedules = NULL;
cMutex cSIProcessor::schedulesMutex;
-cCaDescriptors *cSIProcessor::caDescriptors = NULL;
+cList<cCaDescriptor> cSIProcessor::caDescriptors;
cMutex cSIProcessor::caDescriptorsMutex;
const char *cSIProcessor::epgDataFileName = EPGDATAFILENAME;
time_t cSIProcessor::lastDump = time(NULL);
@@ -1094,7 +1078,6 @@ cSIProcessor::cSIProcessor(const char *FileName)
filters = NULL;
if (!numSIProcessors++) { // the first one creates them
schedules = new cSchedules;
- caDescriptors = new cCaDescriptors;
}
filters = (SIP_FILTER *)calloc(MAX_FILTERS, sizeof(SIP_FILTER));
SetStatus(true);
@@ -1111,7 +1094,6 @@ cSIProcessor::~cSIProcessor()
free(filters);
if (!--numSIProcessors) { // the last one deletes them
delete schedules;
- delete caDescriptors;
}
free(fileName);
}
@@ -1176,12 +1158,9 @@ void cSIProcessor::SetStatus(bool On)
AddFilter(0x00, 0x00); // PAT
AddFilter(0x14, 0x70); // TDT
AddFilter(0x14, 0x73); // TOT
- AddFilter(0x12, 0x4e); // event info, actual TS, present/following
- AddFilter(0x12, 0x4f); // event info, other TS, present/following
- AddFilter(0x12, 0x50); // event info, actual TS, schedule
- AddFilter(0x12, 0x60); // event info, other TS, schedule
- AddFilter(0x12, 0x51); // event info, actual TS, schedule for another 4 days
- AddFilter(0x12, 0x61); // event info, other TS, schedule for another 4 days
+ AddFilter(0x12, 0x4e, 0xfe); // event info, actual(0x4e)/other(0x4f) TS, present/following
+ AddFilter(0x12, 0x50, 0xfe); // event info, actual TS, schedule(0x50)/schedule for another 4 days(0x51)
+ AddFilter(0x12, 0x60, 0xfe); // event info, other TS, schedule(0x60)/schedule for another 4 days(0x61)
}
}
@@ -1351,7 +1330,7 @@ void cSIProcessor::Action()
/** Add a filter with packet identifier pid and
table identifer tid */
-bool cSIProcessor::AddFilter(unsigned short pid, u_char tid)
+bool cSIProcessor::AddFilter(unsigned short pid, u_char tid, u_char mask)
{
dmx_sct_filter_params sctFilterParams;
memset(&sctFilterParams, 0, sizeof(sctFilterParams));
@@ -1359,7 +1338,7 @@ bool cSIProcessor::AddFilter(unsigned short pid, u_char tid)
sctFilterParams.timeout = 0;
sctFilterParams.flags = DMX_IMMEDIATE_START;
sctFilterParams.filter.filter[0] = tid;
- sctFilterParams.filter.mask[0] = 0xFF;
+ sctFilterParams.filter.mask[0] = mask;
for (int a = 0; a < MAX_FILTERS; a++)
{
@@ -1443,36 +1422,40 @@ void cSIProcessor::TriggerDump(void)
lastDump = 0;
}
-void cSIProcessor::NewCaDescriptor(struct Descriptor *d, int ProgramID)
+void cSIProcessor::NewCaDescriptor(struct Descriptor *d, int ServiceId)
{
if (DescriptorTag(d) == DESCR_CA) {
struct CaDescriptor *cd = (struct CaDescriptor *)d;
- if (!caDescriptors->Get(currentSource, currentTransponder, ProgramID, cd->CA_type)) {
- cMutexLock MutexLock(&caDescriptorsMutex);
- caDescriptors->Add(new cCaDescriptor(currentSource, currentTransponder, ProgramID, cd->CA_type, cd->CA_PID, cd->DataLength, cd->Data));
- }
+ cMutexLock MutexLock(&caDescriptorsMutex);
+
+ for (cCaDescriptor *ca = caDescriptors.First(); ca; ca = caDescriptors.Next(ca)) {
+ if (ca->source == currentSource && ca->transponder == currentTransponder && ca->serviceId == ServiceId && ca->caSystem == cd->CA_type && ca->providerId == cd->ProviderID && ca->caPid == cd->CA_PID)
+ return;
+ }
+ caDescriptors.Add(new cCaDescriptor(currentSource, currentTransponder, ServiceId, cd->CA_type, cd->ProviderID, cd->CA_PID, cd->DataLength, cd->Data));
//XXX update???
}
}
-int cSIProcessor::GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data)
+int cSIProcessor::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(&caDescriptorsMutex);
int length = 0;
- for (int i = -1; ; i--) {
- const cCaDescriptor *d = caDescriptors->Get(Source, Transponder, ServiceId, i);
- if (d) {
- if (length + d->Length() <= BufSize) {
- memcpy(Data + length, d->Data(), d->Length());
- length += d->Length();
+ do {
+ for (cCaDescriptor *d = caDescriptors.First(); d; d = caDescriptors.Next(d)) {
+ if (d->source == Source && d->transponder == Transponder && d->serviceId == ServiceId && d->caSystem == *CaSystemIds) {
+ if (length + d->Length() <= BufSize) {
+ memcpy(Data + length, d->Data(), d->Length());
+ length += d->Length();
+ }
+ else
+ return -1;
}
- else
- return -1;
}
- else
- break;
- }
+ } while (*++CaSystemIds);
return length;
}
return -1;
diff --git a/eit.h b/eit.h
index e956b01..3773334 100644
--- a/eit.h
+++ b/eit.h
@@ -16,7 +16,7 @@
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
- * $Id: eit.h 1.25 2003/04/12 10:59:26 kls Exp $
+ * $Id: eit.h 1.28 2003/04/21 13:22:06 kls Exp $
***************************************************************************/
#ifndef __EIT_H
@@ -135,14 +135,13 @@ typedef struct sip_filter {
}SIP_FILTER;
class cCaDescriptor;
-class cCaDescriptors;
class cSIProcessor : public cThread {
private:
static int numSIProcessors;
static cSchedules *schedules;
static cMutex schedulesMutex;
- static cCaDescriptors *caDescriptors;
+ static cList<cCaDescriptor> caDescriptors;
static cMutex caDescriptorsMutex;
static const char *epgDataFileName;
static time_t lastDump;
@@ -155,10 +154,10 @@ private:
char *fileName;
bool active;
void Action(void);
- bool AddFilter(unsigned short pid, u_char tid);
+ bool AddFilter(unsigned short pid, u_char tid, u_char mask = 0xFF);
bool DelFilter(unsigned short pid, u_char tid);
bool ShutDownFilters(void);
- void NewCaDescriptor(struct Descriptor *d, int ProgramID);
+ void NewCaDescriptor(struct Descriptor *d, int ServiceId);
public:
cSIProcessor(const char *FileName);
~cSIProcessor();
@@ -168,10 +167,11 @@ public:
// Caller must provide a cMutexLock which has to survive the entire
// time the returned cSchedules is accessed. Once the cSchedules is no
// longer used, the cMutexLock must be destroyed.
- static int GetCaDescriptors(int Source, int Transponder, int ServiceId, int BufSize, uchar *Data);
+ static int GetCaDescriptors(int Source, int Transponder, int ServiceId, const unsigned short *CaSystemIds, int BufSize, uchar *Data);
///< Gets all CA descriptors for a given channel.
///< Copies all available CA descriptors for the given Source, Transponder and ServiceId
- ///< into the provided buffer at Data (at most BufSize bytes).
+ ///< into the provided buffer at Data (at most BufSize bytes). Only those CA descriptors
+ ///< are copied that match one of the given CA system IDs.
///< \return 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.
static bool Read(FILE *f = NULL);
diff --git a/i18n.c b/i18n.c
index 506e0a5..efeb869 100644
--- a/i18n.c
+++ b/i18n.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: i18n.c 1.105 2003/04/12 09:39:35 kls Exp $
+ * $Id: i18n.c 1.106 2003/04/21 14:05:17 kls Exp $
*
* Translations provided by:
*
@@ -3411,6 +3411,22 @@ const tI18nPhrase Phrases[] = {
"Caut inregistrari...",
"Felvett adások böngészése...",
},
+ { "Pausing live video...",
+ "Live-Signal wird angehalten...",
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ "",// TODO
+ },
{ "This plugin has no setup parameters!",
"Dieses Plugin hat keine Setup-Parameter!",
"",// TODO
diff --git a/menu.c b/menu.c
index e63d707..4b7136b 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.235 2003/04/12 09:40:48 kls Exp $
+ * $Id: menu.c 1.237 2003/04/21 14:57:13 kls Exp $
*/
#include "menu.h"
@@ -1636,7 +1636,7 @@ cOsdObject *CamControl(void)
cDevice *Device = cDevice::GetDevice(d);
if (Device) {
cCiHandler *CiHandler = Device->CiHandler();
- if (CiHandler) {
+ if (CiHandler && CiHandler->HasUserIO()) {
cCiMenu *CiMenu = CiHandler->GetMenu();
if (CiMenu)
return new cMenuCam(CiMenu);
@@ -2488,7 +2488,7 @@ void cMenuMain::Set(const char *Plugin)
// Color buttons:
- SetHelp(tr("Record"), cDevice::PrimaryDevice()->NumAudioTracks() > 1 ? tr("Language") : NULL, NULL, replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
+ SetHelp(tr("Record"), cDevice::PrimaryDevice()->NumAudioTracks() > 1 ? tr("Language") : NULL, replaying ? NULL : tr("Pause"), replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
Display();
lastActivity = time(NULL);
}
@@ -2560,6 +2560,9 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
}
}
break;
+ case kYellow: if (!HasSubMenu())
+ state = osPause;
+ break;
case kBlue: if (!HasSubMenu())
state = replaying ? osStopReplay : cReplayControl::LastReplayed() ? osReplay : osContinue;
break;
@@ -2936,6 +2939,8 @@ cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer)
if (device->AttachReceiver(recorder)) {
Recording.WriteSummary();
cStatus::MsgRecording(device, Recording.Name());
+ if (!Timer && !cReplayControl::LastReplayed()) // an instant recording, maybe from cRecordControls::PauseLiveVideo()
+ cReplayControl::SetRecording(fileName, Recording.Name());
}
else
DELETENULL(recorder);
@@ -3073,6 +3078,26 @@ bool cRecordControls::StopPrimary(bool DoIt)
return false;
}
+bool cRecordControls::PauseLiveVideo(void)
+{
+ Interface->Open(Setup.OSDwidth, -1);
+ Interface->Status(tr("Pausing live video..."));
+ Interface->Flush();
+ cReplayControl::SetRecording(NULL, NULL); // make sure the new cRecordControl will set cReplayControl::LastReplayed()
+ if (Start()) {
+ sleep(2); // allow recorded file to fill up enough to start replaying
+ cReplayControl *rc = new cReplayControl;
+ cControl::Launch(rc);
+ cControl::Attach();
+ sleep(1); // allow device to replay some frames, so we have a picture
+ Interface->Close();
+ rc->ProcessKey(kPause); // pause, allowing replay mode display
+ return true;
+ }
+ Interface->Close();
+ return false;
+}
+
const char *cRecordControls::GetInstantId(const char *LastInstantId)
{
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
diff --git a/menu.h b/menu.h
index 43a0d8f..fab74a7 100644
--- a/menu.h
+++ b/menu.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.h 1.53 2003/01/12 14:54:05 kls Exp $
+ * $Id: menu.h 1.54 2003/04/21 13:40:45 kls Exp $
*/
#ifndef __MENU_H
@@ -135,6 +135,7 @@ public:
static void Stop(const char *InstantId);
static void Stop(cDevice *Device);
static bool StopPrimary(bool DoIt = false);
+ static bool PauseLiveVideo(void);
static const char *GetInstantId(const char *LastInstantId);
static cRecordControl *GetRecordControl(const char *FileName);
static void Process(time_t t);
diff --git a/osd.h b/osd.h
index 5f1ec96..ffce583 100644
--- a/osd.h
+++ b/osd.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.h 1.38 2002/12/08 12:21:26 kls Exp $
+ * $Id: osd.h 1.39 2003/04/21 10:27:41 kls Exp $
*/
#ifndef __OSD_H
@@ -30,6 +30,7 @@ enum eOSState { osUnknown,
osPlugin,
osSetup,
osCommands,
+ osPause,
osRecord,
osReplay,
osStopRecord,
diff --git a/vdr.c b/vdr.c
index 3f0a7f0..a160e4c 100644
--- a/vdr.c
+++ b/vdr.c
@@ -22,7 +22,7 @@
*
* The project's page is at http://www.cadsoft.de/people/kls/vdr
*
- * $Id: vdr.c 1.149 2003/04/12 13:57:45 kls Exp $
+ * $Id: vdr.c 1.150 2003/04/21 14:41:41 kls Exp $
*/
#include <getopt.h>
@@ -553,6 +553,26 @@ int main(int argc, char *argv[])
cDisplayVolume::Process(key);
key = kNone; // nobody else needs to see these keys
break;
+ // Pausing live video:
+ case kPause:
+ if (!cControl::Control()) {
+ DELETENULL(Menu);
+ Temp = NULL;
+ if (!cRecordControls::PauseLiveVideo())
+ Interface->Error(tr("No free DVB device to record!"));
+ key = kNone; // nobody else needs to see this key
+ }
+ break;
+ // Instant recording:
+ case kRecord:
+ if (!cControl::Control()) {
+ if (cRecordControls::Start())
+ ;//XXX Interface->Info(tr("Recording"));
+ else
+ Interface->Error(tr("No free DVB device to record!"));
+ key = kNone; // nobody else needs to see this key
+ }
+ break;
// Power off:
case kPower: isyslog("Power button pressed");
DELETENULL(Menu);
@@ -577,6 +597,12 @@ int main(int argc, char *argv[])
if (state == osUnknown && ISMODELESSKEY(key) && cControl::Control() && Interact != cControl::Control())
state = cControl::Control()->ProcessKey(key);
switch (state) {
+ case osPause: DELETENULL(Menu);
+ cControl::Shutdown(); // just in case
+ Temp = NULL;
+ if (!cRecordControls::PauseLiveVideo())
+ Interface->Error(tr("No free DVB device to record!"));
+ break;
case osRecord: DELETENULL(Menu);
Temp = NULL;
if (cRecordControls::Start())
@@ -652,13 +678,6 @@ int main(int argc, char *argv[])
break;
// Viewing Control:
case kOk: LastChannel = -1; break; // forces channel display
- // Instant recording:
- case kRecord:
- if (cRecordControls::Start())
- ;//XXX Interface->Info(tr("Recording"));
- else
- Interface->Error(tr("No free DVB device to record!"));
- break;
// Key macros:
case kRed:
case kGreen: