summaryrefslogtreecommitdiff
path: root/dvbapi.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <kls (at) cadsoft (dot) de>2000-11-19 18:00:00 +0100
committerKlaus Schmidinger <kls (at) cadsoft (dot) de>2000-11-19 18:00:00 +0100
commit9aa2cda494d7af2733362de78234441a25959e86 (patch)
treea057edf79f3177b3ae1930e111df52cb90f95283 /dvbapi.c
parenta69b3211dc4f9b34eef440067d5ba304fbfbad94 (diff)
downloadvdr-patch-lnbsharing-9aa2cda494d7af2733362de78234441a25959e86.tar.gz
vdr-patch-lnbsharing-9aa2cda494d7af2733362de78234441a25959e86.tar.bz2
Version 0.68vdr-0.68
- Date and time in the title of an event info page are now always right adjusted. - The 'current channel' is now handled device specific (in case there is more than one DVB card). - The 'SetSystemTime' option in the "Setup" menu is now shown as "yes/no". - Implemented "internationalization" (see 'i18n.c' for information on how to add new languages). Thanks to Miha Setina for translating the OSD texts to the Slovenian language. - Fixed learning keys on the PC keyboard (display oscillated). - Fixed a timing problem with OSD refresh and SVDRP. - Avoiding multiple definitions of the same timer in the "Schedule" menu (this could happen when pressing the "Red" button while editing the timer). - There can now be a configuration file named 'commands.conf' that defines commands that can be executed through the "Main" menu's "Commands" option (see FORMATS for details on how to define these commands). - Added a 'fixed' font for use with the output of system commands. - The 'Priority' parameter of the timers is now also used to interrupt a low priority timer recording if a higher priority timer wants to record. - A timer recording on a DVB card with a CAM module will now be interrupted by a timer that needs to use this specific DVB card to record an encrypted channel, if the timer currently occupying this DVB card doesn't need the CAM module (and thus can continue recording on a different DVB card). - The "Yellow" button in the "What's on now/next?" menus now displays the schedule of the current channel from that menu. - All DVB cards in a multi-card system now write their EIT information into the same data structure. - If there is more than one DVB card in the system, the non-primary cards are now used to periodically scan through the channels in order to keep the EPG info up-to-date. Scanning kicks in after 60 seconds of user inactivity (timeout in order to keep user interactions instantaneously) and each channel that has the 'pnr' parameter defined in 'channels.conf' is switched to for 20 seconds. If there is only one DVB card in the system, that card will start scanning after 5 hours (configurable through the "Setup" menu) of user inactivity and will switch back to the channel it originally displayed at the first sign of user activity. Any scanning will only occur if that particular card is not currently recording or replaying. - Now shifting the 'Subtitle' info into the 'ExtendedDescription' on stations that don't send the EIT information correctly (like, e.g., 'VOX'). - Implemented a 10 seconds latency when removing files. - Fixed unwanted reaction on the "Green" and "Yellow" button in the "Event" display. - Implemented 'Transfer Mode' to display video data from the DVB card that actually can receive a certain channel on the primary interface. This is currently in an early state and may still cause some problems, but it appears to work nice already.
Diffstat (limited to 'dvbapi.c')
-rw-r--r--dvbapi.c210
1 files changed, 198 insertions, 12 deletions
diff --git a/dvbapi.c b/dvbapi.c
index cc246d2..5e4f2e6 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbapi.c 1.34 2000/11/01 09:19:27 kls Exp $
+ * $Id: dvbapi.c 1.40 2000/11/19 16:46:37 kls Exp $
*/
#include "dvbapi.h"
@@ -372,7 +372,9 @@ private:
int *inFile, *outFile;
protected:
int Free(void) { return ((tail >= head) ? size + head - tail : head - tail) - 1; }
+public:
int Available(void) { return (tail >= head) ? tail - head : size - head + tail; }
+protected:
int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap!
int Writeable(void) { return (tail >= head) ? tail - head : size - head; }
int Byte(int Offset);
@@ -1079,6 +1081,63 @@ int cReplayBuffer::Write(int Max)
return Written;
}
+// --- cTransferBuffer -------------------------------------------------------
+
+class cTransferBuffer : public cThread {
+private:
+ bool active;
+ int fromDevice, toDevice;
+protected:
+ virtual void Action(void);
+public:
+ cTransferBuffer(int FromDevice, int ToDevice);
+ virtual ~cTransferBuffer();
+ };
+
+cTransferBuffer::cTransferBuffer(int FromDevice, int ToDevice)
+{
+ fromDevice = FromDevice;
+ toDevice = ToDevice;
+ active = true;
+ Start();
+}
+
+cTransferBuffer::~cTransferBuffer()
+{
+ {
+ LOCK_THREAD;
+ active = false;
+ }
+ for (time_t t0 = time(NULL); time(NULL) - t0 < 3; ) {
+ LOCK_THREAD;
+ if (active)
+ break;
+ }
+}
+
+void cTransferBuffer::Action(void)
+{
+ dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid());
+ //XXX hack to make the video device go into 'replaying' mode:
+ char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode!
+ write(toDevice, dummy, strlen(dummy));
+ {
+ cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0);
+ while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start
+ Buffer.Read(); // initializes fromDevice for reading
+ usleep(1); // this keeps the CPU load low
+ }
+ for (; active;) {
+ if (Buffer.Read() < 0 || Buffer.Write() < 0)
+ break;
+ usleep(1); // this keeps the CPU load low
+ }
+ }
+ dsyslog(LOG_INFO, "data transfer thread stopped (pid=%d)", getpid());
+ LOCK_THREAD;
+ active = true;
+}
+
// --- cDvbApi ---------------------------------------------------------------
int cDvbApi::NumDvbApis = 0;
@@ -1091,6 +1150,10 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName)
pidRecord = pidReplay = 0;
fromRecord = toRecord = -1;
fromReplay = toReplay = -1;
+ ca = 0;
+ priority = -1;
+ transferBuffer = NULL;
+ transferringFromDvbApi = NULL;
videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK);
if (videoDev >= 0) {
siProcessor = new cSIProcessor(VbiFileName);
@@ -1130,6 +1193,7 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName)
#endif
lastProgress = lastTotal = -1;
replayTitle = NULL;
+ currentChannel = 1;
}
cDvbApi::~cDvbApi()
@@ -1139,7 +1203,9 @@ cDvbApi::~cDvbApi()
Close();
Stop();
StopRecord();
+ StopTransfer();
OvlO(false); //Overlay off!
+ //XXX the following call sometimes causes a segfault - driver problem?
close(videoDev);
}
#if defined(DEBUG_OSD) || defined(REMOTE_KBD)
@@ -1160,22 +1226,25 @@ bool cDvbApi::SetPrimaryDvbApi(int n)
return false;
}
-cDvbApi *cDvbApi::GetDvbApi(int Ca)
+cDvbApi *cDvbApi::GetDvbApi(int Ca, int Priority)
{
cDvbApi *d = NULL;
- Ca--;
+ int index = Ca - 1;
for (int i = MAXDVBAPI; --i >= 0; ) {
- if (dvbApi[i] && !dvbApi[i]->Recording()) {
- if (i == Ca)
- return dvbApi[i];
- if (Ca < 0) {
+ if (dvbApi[i]) {
+ if (i == index) { // means we need exactly _this_ device
d = dvbApi[i];
- if (d != PrimaryDvbApi)
+ break;
+ }
+ else if (Ca == 0) { // means any device would be acceptable
+ if (!d || !dvbApi[i]->Recording() || (d->Recording() && d->Priority() > dvbApi[i]->Priority()))
+ d = dvbApi[i];
+ if (d && d != PrimaryDvbApi && !d->Recording()) // avoids the PrimaryDvbApi if possible
break;
}
}
}
- return d;
+ return (d && (!d->Recording() || d->Priority() < Priority || (!d->Ca() && Ca))) ? d : NULL;
}
int cDvbApi::Index(void)
@@ -1616,6 +1685,24 @@ int cDvbApi::Width(unsigned char c)
#endif
}
+int cDvbApi::WidthInCells(const char *s)
+{
+#ifdef DEBUG_OSD
+ return strlen(s);
+#else
+ return (osd->Width(s) + charWidth - 1) / charWidth;
+#endif
+}
+
+eDvbFont cDvbApi::SetFont(eDvbFont Font)
+{
+#ifdef DEBUG_OSD
+ return Font;
+#else
+ return osd->SetFont(Font);
+#endif
+}
+
void cDvbApi::Text(int x, int y, const char *s, eDvbColor colorFg, eDvbColor colorBg)
{
if (x < 0) x = cols + x;
@@ -1689,9 +1776,15 @@ bool cDvbApi::ShowProgress(bool Initial)
return false;
}
-bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr)
+bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr)
{
if (videoDev >= 0) {
+ StopTransfer();
+ if (transferringFromDvbApi) {
+ transferringFromDvbApi->StopTransfer();
+ transferringFromDvbApi = NULL;
+ }
+ SetReplayMode(VID_PLAY_RESET);
struct frontend front;
ioctl(videoDev, VIDIOCGFRONTEND, &front);
unsigned int freq = FrequencyMHz;
@@ -1712,8 +1805,20 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr
front.AFC = 1;
ioctl(videoDev, VIDIOCSFRONTEND, &front);
if (front.sync & 0x1F == 0x1F) {
- if (siProcessor)
+ if (this == PrimaryDvbApi && siProcessor)
siProcessor->SetCurrentServiceID(Pnr);
+ currentChannel = ChannelNumber;
+ // If this DVB card can't receive this channel, let's see if we can
+ // use the card that actually can receive it and transfer data from there:
+ if (Ca && Ca != Index() + 1) {
+ cDvbApi *CaDvbApi = GetDvbApi(Ca, 0);
+ if (CaDvbApi) {
+ if (!CaDvbApi->Recording()) {
+ if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Ca, Pnr))
+ transferringFromDvbApi = CaDvbApi->StartTransfer(videoDev);
+ }
+ }
+ }
return true;
}
esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync);
@@ -1721,6 +1826,27 @@ bool cDvbApi::SetChannel(int FrequencyMHz, char Polarization, int Diseqc, int Sr
return false;
}
+bool cDvbApi::Transferring(void)
+{
+ return transferBuffer;
+}
+
+cDvbApi *cDvbApi::StartTransfer(int TransferToVideoDev)
+{
+ StopTransfer();
+ transferBuffer = new cTransferBuffer(videoDev, TransferToVideoDev);
+ return this;
+}
+
+void cDvbApi::StopTransfer(void)
+{
+ if (transferBuffer) {
+ delete transferBuffer;
+ transferBuffer = NULL;
+ SetReplayMode(VID_PLAY_RESET);
+ }
+}
+
bool cDvbApi::Recording(void)
{
if (pidRecord && !CheckProcess(pidRecord))
@@ -1735,7 +1861,7 @@ bool cDvbApi::Replaying(void)
return pidReplay;
}
-bool cDvbApi::StartRecord(const char *FileName)
+bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority)
{
if (Recording()) {
esyslog(LOG_ERR, "ERROR: StartRecord() called while recording - ignored!");
@@ -1743,6 +1869,8 @@ bool cDvbApi::StartRecord(const char *FileName)
}
if (videoDev >= 0) {
+ StopTransfer();
+
Stop(); // TODO: remove this if the driver is able to do record and replay at the same time
// Check FileName:
@@ -1832,6 +1960,9 @@ bool cDvbApi::StartRecord(const char *FileName)
fromRecord = fromRecordPipe[0];
toRecord = toRecordPipe[1];
+
+ ca = Ca;
+ priority = Priority;
return true;
}
return false;
@@ -1846,6 +1977,8 @@ void cDvbApi::StopRecord(void)
toRecord = fromRecord = -1;
KillProcess(pidRecord);
pidRecord = 0;
+ ca = 0;
+ priority = -1;
SetReplayMode(VID_PLAY_RESET); //XXX
}
}
@@ -1865,6 +1998,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title)
esyslog(LOG_ERR, "ERROR: StartReplay() called while recording - ignored!");
return false;
}
+ StopTransfer();
Stop();
if (videoDev >= 0) {
@@ -2086,3 +2220,55 @@ bool cDvbApi::GetIndex(int *Current, int *Total)
return false;
}
+// --- cEITScanner -----------------------------------------------------------
+
+cEITScanner::cEITScanner(void)
+{
+ lastScan = lastActivity = time(NULL);
+ currentChannel = 0;
+ lastChannel = 1;
+}
+
+void cEITScanner::Activity(void)
+{
+ if (currentChannel) {
+ Channels.SwitchTo(currentChannel);
+ currentChannel = 0;
+ }
+ lastActivity = time(NULL);
+}
+
+void cEITScanner::Process(void)
+{
+ if (Channels.MaxNumber() > 1) {
+ time_t now = time(NULL);
+ if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
+ for (int i = 0; i < cDvbApi::NumDvbApis; i++) {
+ cDvbApi *DvbApi = cDvbApi::GetDvbApi(i, 0);
+ if (DvbApi) {
+ if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
+ if (!(DvbApi->Recording() || DvbApi->Replaying() || DvbApi->Transferring())) {
+ int oldCh = lastChannel;
+ int ch = oldCh + 1;
+ while (ch != oldCh) {
+ if (ch > Channels.MaxNumber())
+ ch = 1;
+ cChannel *Channel = Channels.GetByNumber(ch);
+ if (Channel && Channel->pnr) {
+ if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel)
+ currentChannel = DvbApi->Channel();
+ Channel->Switch(DvbApi, false);
+ lastChannel = ch;
+ break;
+ }
+ ch++;
+ }
+ }
+ }
+ }
+ }
+ lastScan = time(NULL);
+ }
+ }
+}
+