summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2002-08-04 14:57:29 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2002-08-04 14:57:29 +0200
commit15cc1733e0e7bf005362fad61a3ccbbefe1cbceb (patch)
tree7bab620fbfb760f31daa464445f791f3fc0cf322
parent61ccfd5fab3e009bb6feda0647cd958107258819 (diff)
downloadvdr-15cc1733e0e7bf005362fad61a3ccbbefe1cbceb.tar.gz
vdr-15cc1733e0e7bf005362fad61a3ccbbefe1cbceb.tar.bz2
Changed the cDevice class to allow plugins to implement their own devices
-rw-r--r--Makefile4
-rw-r--r--PLUGINS.html117
-rw-r--r--config.c6
-rw-r--r--device.c673
-rw-r--r--device.h205
-rw-r--r--dvbdevice.c615
-rw-r--r--dvbdevice.h97
-rw-r--r--dvbosd.c13
-rw-r--r--dvbosd.h7
-rw-r--r--eit.h4
-rw-r--r--eitscan.c3
-rw-r--r--menu.c4
-rw-r--r--osd.c4
-rw-r--r--receiver.c3
-rw-r--r--remux.h4
-rw-r--r--ringbuffer.h5
-rw-r--r--tools.c4
-rw-r--r--vdr.c11
18 files changed, 1135 insertions, 644 deletions
diff --git a/Makefile b/Makefile
index 59908382..3359aadb 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
# See the main source file 'vdr.c' for copyright information and
# how to reach the author.
#
-# $Id: Makefile 1.43 2002/07/28 13:24:58 kls Exp $
+# $Id: Makefile 1.44 2002/07/28 15:20:47 kls Exp $
.DELETE_ON_ERROR:
@@ -27,7 +27,7 @@ INCLUDES = -I$(DVBDIR)/ost/include
DTVLIB = $(DTVDIR)/libdtv.a
-OBJS = audio.o config.o cutter.o device.o dvbplayer.o dvbosd.o eit.o eitscan.o font.o i18n.o\
+OBJS = audio.o config.o cutter.o device.o dvbdevice.o dvbosd.o dvbplayer.o eit.o eitscan.o font.o i18n.o\
interface.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o receiver.o\
recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\
tools.o transfer.o vdr.o videodir.o
diff --git a/PLUGINS.html b/PLUGINS.html
index 2a66e88d..c9d6c542 100644
--- a/PLUGINS.html
+++ b/PLUGINS.html
@@ -1152,5 +1152,122 @@ of these functions, and VDR/osd.c to see how VDR opens the OSD and sets up
its windows and color depths).
<!--X1.1.5--></td></tr></table>
+<!--X1.1.6--><table width=100%><tr><td bgcolor=#FF0000>&nbsp;</td><td width=100%>
+<hr><h2>Devices</h2>
+
+<center><i><b>Expanding the possibilities</b></i></center><p>
+
+By default VDR is based on using DVB PCI cards that are supported by the
+LinuxDVB driver. However, a plugin can implement additional devices that
+can be used as sources of MPEG data for viewing or recording, and also
+as output devices for replaying. Such a device can be a physical card
+that is installed in the PC (like, for instance, an MPEG encoder card that
+allows the analog signal of a proprietary set-top box to be integrated
+into a VDR system; or an analog TV receiver card, which does the MPEG encoding
+"on the fly" - assuming your machine is fast enough), or just a software program that takes an MPEG data
+stream and displays it, for instance, on an existing graphics adapter.
+<p>
+To implement an additional device, a plugin must derive a class from cDevice:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+#include &lt;vdr/device.h&gt;
+
+class cMyDevice : public cDevice {
+ ...
+ };
+</pre></td></tr></table><p>
+
+The derived class must implement several virtual functions, according to
+the abilities this new class of devices can provide. See the comments in the
+file <tt>VDR/device.h</tt> for more information on the various functions,
+and also <tt>VDR/dvbdevice.[hc]</tt> for details on the implementation of
+the <tt>cDvbDevice</tt>, which is used to access the DVB PCI cards.
+<p>
+<b>Channel selection</b>
+<p>
+If the new device can receive, it most likely needs to provide a way of
+selecting which channel it shall tune to:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual bool SetChannelDevice(const cChannel *Channel);
+</pre></td></tr></table><p>
+
+This function will be called with the desired channel and shall return whether
+tuning to it was successful.
+<p>
+<b>Recording</b>
+<p>
+A device that can be used for recording must implement the functions
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
+virtual bool OpenDvr(void);
+virtual void CloseDvr(void);
+virtual int GetTSPacket(uchar *Data);
+</pre></td></tr></table><p>
+
+which allow VDR to set the PIDs that shall be recorded, set up the device fro
+recording (and shut it down again), and receive the MPEG data stream. The data
+must be delivered in the form of a Transport Stream (TS), which consists of
+packets that are all 188 bytes in size. Each call to <tt>GetTSPacket()</tt>
+must deliver exactly one such packet (if one is currently available).
+<p>
+If this device allows receiving several different data streams, it can
+implement
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual bool CanBeReUsed(int Frequency, int Vpid);
+</pre></td></tr></table><p>
+
+to indicate this to VDR.
+<p>
+<b>Replaying</b>
+<p>
+The functions to implement replaying capabilites are
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual bool HasDecoder(void) const;
+virtual int SetPlayMode(bool On);
+virtual void TrickSpeed(int Speed);
+virtual void Clear(void);
+virtual void Play(void);
+virtual void Freeze(void);
+virtual void Mute(void);
+virtual void StillPicture(const uchar *Data, int Length);
+virtual int PlayVideo(const uchar *Data, int Length);
+</pre></td></tr></table><p>
+
+In addition, the following functions may be implemented to provide further
+functionality:
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int Si
+virtual void SetVideoFormat(bool VideoFormat16_9);
+virtual void SetVolumeDevice(int Volume);
+</pre></td></tr></table><p>
+
+<b>Initializing new devices</b>
+<p>
+A derived cDevice class shall implement a static function
+
+<p><table><tr><td bgcolor=#F0F0F0><pre><br>
+static bool Initialize(void);
+</pre></td></tr></table><p>
+
+in which it determines whether the necessary hardware to run this sort of
+device is actually present in this machine (or whatever other prerequisites
+might be important), and then creates as many device objects as necessary.
+See <tt>VDR/dvbdevice.c</tt> for the implementation of the <tt>cDvbDevice</tt>
+initialize function.
+<p>
+A plugin that adds devices to a VDR instance shall call this initializing
+function from its <a href="#Getting started"><tt>Start()</tt></a> function.
+<p>
+Nothing needs to be done to shut down the devices. VDR will automatically
+shut down (delete) all devices when the program terminates. It is therefore
+important that the devices are created on the heap, using the <tt>new</tt>
+operator!
+<!--X1.1.6--></td></tr></table>
+
</body>
</html>
diff --git a/config.c b/config.c
index 6753ce8d..376985f0 100644
--- a/config.c
+++ b/config.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: config.c 1.102 2002/06/16 12:57:31 kls Exp $
+ * $Id: config.c 1.103 2002/08/04 12:03:11 kls Exp $
*/
#include "config.h"
@@ -301,7 +301,7 @@ bool cChannel::Switch(cDevice *Device, bool Log)
if (Log)
isyslog("switching to channel %d", number);
for (int i = 3; i--;) {
- switch (Device->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, tpid, ca, pnr)) {
+ switch (Device->SetChannel(this)) {
case scrOk: return true;
case scrNoTransfer: if (Interface)
Interface->Error(tr("Can't start Transfer Mode!"));
@@ -1018,7 +1018,7 @@ cSetup::cSetup(void)
DefaultLifetime = 50;
UseSubtitle = 1;
RecordingDirs = 1;
- VideoFormat = VIDEO_FORMAT_4_3;
+ VideoFormat = 0;
RecordDolbyDigital = 1;
ChannelInfoPos = 0;
OSDwidth = 52;
diff --git a/device.c b/device.c
index 9e707515..5b9fb6be 100644
--- a/device.c
+++ b/device.c
@@ -4,108 +4,42 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.c 1.6 2002/07/28 11:03:53 kls Exp $
+ * $Id: device.c 1.7 2002/08/04 12:32:49 kls Exp $
*/
#include "device.h"
#include <errno.h>
-extern "C" {
-#define HAVE_BOOLEAN
-#include <jpeglib.h>
-}
-#include <linux/videodev.h>
-#include <ost/sec.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include "eit.h"
#include "player.h"
#include "receiver.h"
#include "status.h"
#include "transfer.h"
-#define DEV_VIDEO "/dev/video"
-#define DEV_OST_OSD "/dev/ost/osd"
-#define DEV_OST_FRONTEND "/dev/ost/frontend"
-#define DEV_OST_SEC "/dev/ost/sec"
-#define DEV_OST_DVR "/dev/ost/dvr"
-#define DEV_OST_DEMUX "/dev/ost/demux"
-#define DEV_OST_VIDEO "/dev/ost/video"
-#define DEV_OST_AUDIO "/dev/ost/audio"
-
-// The default priority for non-primary DVB cards:
+// The default priority for non-primary devices:
#define DEFAULTPRIORITY -2
-#define TS_SIZE 188
-#define TS_SYNC_BYTE 0x47
-#define PID_MASK_HI 0x1F
-
// The maximum time we wait before assuming that a recorded video data stream
// is broken:
#define MAXBROKENTIMEOUT 30 // seconds
-static const char *OstName(const char *Name, int n)
-{
- static char buffer[_POSIX_PATH_MAX];
- snprintf(buffer, sizeof(buffer), "%s%d", Name, n);
- return buffer;
-}
-
-static int OstOpen(const char *Name, int n, int Mode, bool ReportError = false)
-{
- const char *FileName = OstName(Name, n);
- int fd = open(FileName, Mode);
- if (fd < 0 && ReportError)
- LOG_ERROR_STR(FileName);
- return fd;
-}
-
int cDevice::numDevices = 0;
int cDevice::useDevice = 0;
+int cDevice::nextCardIndex = 0;
cDevice *cDevice::device[MAXDEVICES] = { NULL };
cDevice *cDevice::primaryDevice = NULL;
-cDevice::cDevice(int n)
+cDevice::cDevice(void)
{
- frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
- siProcessor = NULL;
- cardIndex = n;
-
- // Devices that are present on all card types:
+ cardIndex = nextCardIndex++;
- fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR);
-
- // Devices that are only present on DVB-S cards:
-
- fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
-
- // Devices that are only present on cards with decoders:
-
- fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR);
- fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
- fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
-
- // Video format:
-
- SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
-
- // We only check the devices that must be present - the others will be checked before accessing them://XXX
-
- if (fd_frontend >= 0) {
- siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
- FrontendInfo feinfo;
- if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0)
- frontendType = feinfo.type;
- else
- LOG_ERROR;
- }
- else
- esyslog("ERROR: can't open video device %d", n);
+ SetVideoFormat(Setup.VideoFormat);
- dvrFileName = strdup(OstName(DEV_OST_DVR, CardIndex()));
active = false;
currentChannel = 0;
- frequency = 0;
mute = false;
volume = Setup.CurrentVolume;
@@ -115,17 +49,20 @@ cDevice::cDevice(int n)
for (int i = 0; i < MAXRECEIVERS; i++)
receiver[i] = NULL;
ca = -1;
+
+ if (numDevices < MAXDEVICES) {
+ device[numDevices++] = this;
+ SetCaCaps(cardIndex);
+ }
+ else
+ esyslog("ERROR: too many devices!");
}
cDevice::~cDevice()
{
- delete dvrFileName;
- delete siProcessor;
Detach(player);
for (int i = 0; i < MAXRECEIVERS; i++)
Detach(receiver[i]);
- // We're not explicitly closing any device files here, since this sometimes
- // caused segfaults. Besides, the program is about to terminate anyway...
}
void cDevice::SetUseDevice(int n)
@@ -134,15 +71,44 @@ void cDevice::SetUseDevice(int n)
useDevice |= (1 << n);
}
+int cDevice::NextCardIndex(int n)
+{
+ if (n > 0) {
+ nextCardIndex += n;
+ if (nextCardIndex >= MAXDEVICES)
+ esyslog("ERROR: nextCardIndex too big (%d)", nextCardIndex);
+ }
+ else if (n < 0)
+ esyslog("ERROR: illegal value in IncCardIndex(%d)", n);
+ return nextCardIndex;
+}
+
+void cDevice::MakePrimaryDevice(bool On)
+{
+}
+
bool cDevice::SetPrimaryDevice(int n)
{
n--;
if (0 <= n && n < numDevices && device[n]) {
isyslog("setting primary device to %d", n + 1);
+ if (primaryDevice)
+ primaryDevice->MakePrimaryDevice(false);
primaryDevice = device[n];
+ primaryDevice->MakePrimaryDevice(true);
return true;
}
- esyslog("invalid devive number: %d", n + 1);
+ esyslog("invalid device number: %d", n + 1);
+ return false;
+}
+
+bool cDevice::CanBeReUsed(int Frequency, int Vpid)
+{
+ return false;
+}
+
+bool cDevice::HasDecoder(void) const
+{
return false;
}
@@ -156,20 +122,7 @@ cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool
for (int i = 0; i < numDevices; i++) {
if ((Provides[i] = device[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job
//XXX+ dsyslog("GetDevice: %d %d %d %5d %5d", i, device[i]->HasDecoder(), device[i]->Receiving(), Frequency, device[i]->frequency);//XXX
- if ( (!device[i]->HasDecoder() // it's a "budget card" which can receive multiple channels...
- && device[i]->frequency == Frequency // ...and it is tuned to the requested frequency...
- && device[i]->Receiving() // ...and is already receiving
- // need not check priority - if a budget card is already receiving on the requested
- // frequency, we can attach another receiver regardless of priority
- )
- || (device[i]->HasDecoder() // it's a "full featured card" which can receive only one channel...
- && device[i]->frequency == Frequency // ...and it is tuned to the requested frequency...
- && device[i]->pidHandles[ptVideo].pid == Vpid // ...and the requested video PID...
- && device[i]->Receiving() // ...and is already receiving
- // need not check priority - if a full featured card is already receiving the requested
- // frequency and video PID, we can attach another receiver regardless of priority
- )
- ) {
+ if (device[i]->CanBeReUsed(Frequency, Vpid)) {
d = device[i];
if (ReUse)
*ReUse = true;
@@ -204,50 +157,14 @@ cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool
return d;
}
-void cDevice::SetCaCaps(void)
+void cDevice::SetCaCaps(int Index)
{
for (int d = 0; d < numDevices; d++) {
- for (int i = 0; i < MAXCACAPS; i++)
- device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][i];
- }
-}
-
-bool cDevice::Probe(const char *FileName)
-{
- if (access(FileName, F_OK) == 0) {
- dsyslog("probing %s", FileName);
- int f = open(FileName, O_RDONLY);
- if (f >= 0) {
- close(f);
- return true;
- }
- else if (errno != ENODEV && errno != EINVAL)
- LOG_ERROR_STR(FileName);
- }
- else if (errno != ENOENT)
- LOG_ERROR_STR(FileName);
- return false;
-}
-
-bool cDevice::Initialize(void)
-{
- numDevices = 0;
- for (int i = 0; i < MAXDEVICES; i++) {
- if (useDevice == 0 || (useDevice & (1 << i)) != 0) {
- if (Probe(OstName(DEV_OST_FRONTEND, i)))
- device[numDevices++] = new cDevice(i);
- else
- break;
+ if (Index < 0 || Index == device[d]->CardIndex()) {
+ for (int i = 0; i < MAXCACAPS; i++)
+ device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][i];
}
}
- primaryDevice = device[0];
- if (numDevices > 0) {
- isyslog("found %d video device%s", numDevices, numDevices > 1 ? "s" : "");
- SetCaCaps();
- }
- else
- esyslog("ERROR: no video device found, giving up!");
- return numDevices > 0;
}
void cDevice::Shutdown(void)
@@ -261,106 +178,13 @@ void cDevice::Shutdown(void)
bool cDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
{
- int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR, true);
- if (videoDev >= 0) {
- int result = 0;
- struct video_mbuf mbuf;
- result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
- if (result == 0) {
- int msize = mbuf.size;
- unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
- if (mem && mem != (unsigned char *)-1) {
- // set up the size and RGB
- struct video_capability vc;
- result |= ioctl(videoDev, VIDIOCGCAP, &vc);
- struct video_mmap vm;
- vm.frame = 0;
- if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
- (SizeY > 0) && (SizeY <= vc.maxheight)) {
- vm.width = SizeX;
- vm.height = SizeY;
- }
- else {
- vm.width = vc.maxwidth;
- vm.height = vc.maxheight;
- }
- vm.format = VIDEO_PALETTE_RGB24;
- result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
- result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
- // make RGB out of BGR:
- int memsize = vm.width * vm.height;
- unsigned char *mem1 = mem;
- for (int i = 0; i < memsize; i++) {
- unsigned char tmp = mem1[2];
- mem1[2] = mem1[0];
- mem1[0] = tmp;
- mem1 += 3;
- }
-
- if (Quality < 0)
- Quality = 255; //XXX is this 'best'???
-
- isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
- FILE *f = fopen(FileName, "wb");
- if (f) {
- if (Jpeg) {
- // write JPEG file:
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
- jpeg_stdio_dest(&cinfo, f);
- cinfo.image_width = vm.width;
- cinfo.image_height = vm.height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
-
- jpeg_set_defaults(&cinfo);
- jpeg_set_quality(&cinfo, Quality, true);
- jpeg_start_compress(&cinfo, true);
-
- int rs = vm.width * 3;
- JSAMPROW rp[vm.height];
- for (int k = 0; k < vm.height; k++)
- rp[k] = &mem[rs * k];
- jpeg_write_scanlines(&cinfo, rp, vm.height);
- jpeg_finish_compress(&cinfo);
- jpeg_destroy_compress(&cinfo);
- }
- else {
- // write PNM file:
- if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
- fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
- LOG_ERROR_STR(FileName);
- result |= 1;
- }
- }
- fclose(f);
- }
- else {
- LOG_ERROR_STR(FileName);
- result |= 1;
- }
- munmap(mem, msize);
- }
- else
- result |= 1;
- }
- close(videoDev);
- return result == 0;
- }
return false;
}
-void cDevice::SetVideoFormat(videoFormat_t Format)
+void cDevice::SetVideoFormat(bool VideoFormat16_9)
{
- if (HasDecoder())
- CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, Format));
}
-// ptVideo ptAudio ptTeletext ptDolby ptOther
-dmxPesType_t PesTypes[] = { DMX_PES_VIDEO, DMX_PES_AUDIO, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
-
//#define PRINTPIDS(s) { char b[500]; char *q = b; q += sprintf(q, "%d %s ", CardIndex(), s); for (int i = 0; i < MAXPIDHANDLES; i++) q += sprintf(q, " %s%4d %d", i == ptOther ? "* " : "", pidHandles[i].pid, pidHandles[i].used); dsyslog(b); } //XXX+
#define PRINTPIDS(s)
@@ -375,13 +199,12 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
else if (a < 0 && i >= ptOther && !pidHandles[i].used)
a = i;
}
- dmxPesType_t PesType = PesTypes[ptOther];
if (n >= 0) {
// The Pid is already in use
if (++pidHandles[n].used == 2 && n <= ptTeletext) {
- // It's a special PID that has to be switched into "tap" mode
+ // It's a special PID that may have to be switched into "tap" mode
PRINTPIDS("A");//XXX+
- return SetPid(pidHandles[n].fd, PesTypes[n], Pid, DMX_OUT_TS_TAP);
+ return SetPid(&pidHandles[n], n, true);
}
PRINTPIDS("a");//XXX+
return true;
@@ -389,8 +212,6 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
else if (PidType < ptOther) {
// The Pid is not yet in use and it is a special one
n = PidType;
- PesType = PesTypes[PidType];
- PRINTPIDS("B");//XXX+
}
else if (a >= 0) {
// The Pid is not yet in use and we have a free slot
@@ -400,217 +221,51 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
esyslog("ERROR: no free slot for PID %d", Pid);
if (n >= 0) {
pidHandles[n].pid = Pid;
- pidHandles[n].fd = OstOpen(DEV_OST_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
pidHandles[n].used = 1;
PRINTPIDS("C");//XXX+
- return SetPid(pidHandles[n].fd, PesType, Pid, PidType <= ptTeletext ? DMX_OUT_DECODER : DMX_OUT_TS_TAP);
+ return SetPid(&pidHandles[n], n, true);
}
}
return true;
}
-bool cDevice::DelPid(int Pid)
+void cDevice::DelPid(int Pid)
{
if (Pid) {
for (int i = 0; i < MAXPIDHANDLES; i++) {
if (pidHandles[i].pid == Pid) {
- switch (--pidHandles[i].used) {
- case 0: CHECK(ioctl(pidHandles[i].fd, DMX_STOP));//XXX+ is this necessary???
- close(pidHandles[i].fd);
- pidHandles[i].fd = -1;
- pidHandles[i].pid = 0;
- break;
- case 1: if (i <= ptTeletext)
- SetPid(pidHandles[i].fd, PesTypes[i], Pid, DMX_OUT_DECODER);
- break;
- }
+ if (--pidHandles[i].used < 2) {
+ SetPid(&pidHandles[i], i, false);
+ if (pidHandles[i].used == 0) {
+ pidHandles[i].handle = -1;
+ pidHandles[i].pid = 0;
+ }
+ }
PRINTPIDS("D");//XXX+
- return pidHandles[i].used;
}
}
}
- return false;
}
-bool cDevice::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output)
+bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
{
- if (Pid) {
- CHECK(ioctl(fd, DMX_STOP));
- if (Pid != 0x1FFF) {
- dmxPesFilterParams pesFilterParams;
- pesFilterParams.pid = Pid;
- pesFilterParams.input = DMX_IN_FRONTEND;
- pesFilterParams.output = Output;
- pesFilterParams.pesType = PesType;
- pesFilterParams.flags = DMX_IMMEDIATE_START;
- //XXX+ pesFilterParams.flags = DMX_CHECK_CRC;//XXX
- if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
- LOG_ERROR;
- return false;
- }
- //XXX+ CHECK(ioctl(fd, DMX_SET_BUFFER_SIZE, KILOBYTE(32)));//XXX
- //XXX+ CHECK(ioctl(fd, DMX_START));//XXX
- }
- }
- return true;
+ return false;
}
-eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr)
+eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
{
- StopReplay();
-
cStatus::MsgChannelSwitch(this, 0);
+ StopReplay();
+
// Must set this anyway to avoid getting stuck when switching through
// channels with 'Up' and 'Down' keys:
- currentChannel = ChannelNumber;
-
- // Avoid noise while switching:
-
- if (HasDecoder()) {
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
- CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
- CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
- CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
- }
-
- // Stop setting system time:
-
- if (siProcessor)
- siProcessor->SetCurrentTransponder(0);
+ currentChannel = Channel->number;
// If this card can't receive this channel, we must not actually switch
// the channel here, because that would irritate the driver when we
// start replaying in Transfer Mode immediately after switching the channel:
- bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Ca));
-
- if (!NeedsTransferMode) {
-
- // Turn off current PIDs:
-
- if (HasDecoder()) {
- DelPid(pidHandles[ptVideo].pid);
- DelPid(pidHandles[ptAudio].pid);
- DelPid(pidHandles[ptTeletext].pid);
- DelPid(pidHandles[ptDolby].pid);
- }
-
- FrontendParameters Frontend;
-
- switch (frontendType) {
- case FE_QPSK: { // DVB-S
-
- // Frequency offsets:
-
- unsigned int freq = Frequency;
- int tone = SEC_TONE_OFF;
-
- if (freq < (unsigned int)Setup.LnbSLOF) {
- freq -= Setup.LnbFrequLo;
- tone = SEC_TONE_OFF;
- }
- else {
- freq -= Setup.LnbFrequHi;
- tone = SEC_TONE_ON;
- }
-
- Frontend.Frequency = freq * 1000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.qpsk.SymbolRate = Srate * 1000UL;
- Frontend.u.qpsk.FEC_inner = FEC_AUTO;
-
- int volt = (Polarization == 'v' || Polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
-
- // DiseqC:
-
- secCommand scmd;
- scmd.type = 0;
- scmd.u.diseqc.addr = 0x10;
- scmd.u.diseqc.cmd = 0x38;
- scmd.u.diseqc.numParams = 1;
- scmd.u.diseqc.params[0] = 0xF0 | ((Diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0);
-
- secCmdSequence scmds;
- scmds.voltage = volt;
- scmds.miniCommand = SEC_MINI_NONE;
- scmds.continuousTone = tone;
- scmds.numCommands = Setup.DiSEqC ? 1 : 0;
- scmds.commands = &scmd;
-
- CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
- }
- break;
- case FE_QAM: { // DVB-C
-
- // Frequency and symbol rate:
-
- Frontend.Frequency = Frequency * 1000000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.qam.SymbolRate = Srate * 1000UL;
- Frontend.u.qam.FEC_inner = FEC_AUTO;
- Frontend.u.qam.QAM = QAM_64;
- }
- break;
- case FE_OFDM: { // DVB-T
-
- // Frequency and OFDM paramaters:
-
- Frontend.Frequency = Frequency * 1000UL;
- Frontend.Inversion = INVERSION_AUTO;
- Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ;
- Frontend.u.ofdm.HP_CodeRate=FEC_2_3;
- Frontend.u.ofdm.LP_CodeRate=FEC_1_2;
- Frontend.u.ofdm.Constellation=QAM_64;
- Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K;
- Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32;
- Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE;
- }
- break;
- default:
- esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
- return scrFailed;
- }
-
- // Tuning:
-
- CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
-
- // Wait for channel sync:
-
- if (cFile::FileReady(fd_frontend, 5000)) {
- FrontendEvent event;
- int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
- if (res >= 0) {
- if (event.type != FE_COMPLETION_EV) {
- esyslog("ERROR: channel %d not sync'ed on DVB card %d!", ChannelNumber, CardIndex() + 1);
- if (IsPrimaryDevice())
- cThread::RaisePanic();
- return scrFailed;
- }
- }
- else
- esyslog("ERROR %d in frontend get event (channel %d, card %d)", res, ChannelNumber, CardIndex() + 1);
- }
- else
- esyslog("ERROR: timeout while tuning");
-
- frequency = Frequency;
-
- // PID settings:
-
- if (HasDecoder()) {
- if (!(AddPid(Vpid, ptVideo) && AddPid(Apid, ptAudio))) {//XXX+ dolby Dpid1!!! (if audio plugins are attached)
- esyslog("ERROR: failed to set PIDs for channel %d", ChannelNumber);
- return scrFailed;
- }
- if (IsPrimaryDevice())
- AddPid(Tpid, ptTeletext);
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- }
- }
-
- if (IsPrimaryDevice() && siProcessor)
- siProcessor->SetCurrentServiceID(Pnr);
+ bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Channel->ca));
eSetChannelResult Result = scrOk;
@@ -618,28 +273,30 @@ eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Pol
// use the card that actually can receive it and transfer data from there:
if (NeedsTransferMode) {
- cDevice *CaDevice = GetDevice(Ca, 0);
- if (CaDevice && !CaDevice->Receiving()) {
- if ((Result = CaDevice->SetChannel(ChannelNumber, Frequency, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) == scrOk)
- cControl::Launch(new cTransferControl(CaDevice, Vpid, Apid, 0, 0, 0));//XXX+
- }
+ cDevice *CaDevice = GetDevice(Channel->ca, 0);
+ if (CaDevice && !CaDevice->Receiving() && CaDevice->SetChannel(Channel) == scrOk)
+ cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+
else
Result = scrNoTransfer;
}
+ else if (!SetChannelDevice(Channel))
+ Result = scrFailed;
- if (HasDecoder()) {
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
- CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
- }
+ if (IsPrimaryDevice())
+ cSIProcessor::SetCurrentServiceID(Channel->pnr);
- // Start setting system time:
+ cStatus::MsgChannelSwitch(this, Channel->number);
- if (Result == scrOk && siProcessor)
- siProcessor->SetCurrentTransponder(Frequency);
+ return Result;
+}
- cStatus::MsgChannelSwitch(this, ChannelNumber);
+bool cDevice::SetChannelDevice(const cChannel *Channel)
+{
+ return false;
+}
- return Result;
+void cDevice::SetVolumeDevice(int Volume)
+{
}
bool cDevice::ToggleMute(void)
@@ -653,78 +310,40 @@ bool cDevice::ToggleMute(void)
void cDevice::SetVolume(int Volume, bool Absolute)
{
- if (HasDecoder()) {
- volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
- audioMixer_t am;
- am.volume_left = am.volume_right = volume;
- CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
- cStatus::MsgSetVolume(volume, Absolute);
- if (volume > 0)
- mute = false;
- }
+ volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
+ SetVolumeDevice(volume);
+ cStatus::MsgSetVolume(volume, Absolute);
+ if (volume > 0)
+ mute = false;
+}
+
+int cDevice::SetPlayMode(bool On)
+{
+ return -1;
}
void cDevice::TrickSpeed(int Speed)
{
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
}
void cDevice::Clear(void)
{
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
- if (fd_audio >= 0)
- CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
}
void cDevice::Play(void)
{
- if (fd_audio >= 0)
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_CONTINUE));
}
void cDevice::Freeze(void)
{
- if (fd_audio >= 0)
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
- if (fd_video >= 0)
- CHECK(ioctl(fd_video, VIDEO_FREEZE));
}
void cDevice::Mute(void)
{
- if (fd_audio >= 0) {
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
- }
}
void cDevice::StillPicture(const uchar *Data, int Length)
{
- Mute();
-/* Using the VIDEO_STILLPICTURE ioctl call would be the
- correct way to display a still frame, but unfortunately this
- doesn't work with frames from VDR. So let's do pretty much the
- same here as in DVB/driver/dvb.c's play_iframe() - I have absolutely
- no idea why it works this way, but doesn't work with VIDEO_STILLPICTURE.
- If anybody ever finds out what could be changed so that VIDEO_STILLPICTURE
- could be used, please let me know!
- kls 2002-03-23
-*/
-//#define VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
-#ifdef VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
- videoDisplayStillPicture sp = { (char *)Data, Length };
- CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
-#else
-#define MIN_IFRAME 400000
- for (int i = MIN_IFRAME / Length + 1; i > 0; i--) {
- safe_write(fd_video, Data, Length);
- usleep(1); // allows the buffer to be displayed in case the progress display is active
- }
-#endif
}
bool cDevice::Replaying(void)
@@ -741,19 +360,9 @@ bool cDevice::AttachPlayer(cPlayer *Player)
if (HasDecoder()) {
if (player)
Detach(player);
-
- if (siProcessor)
- siProcessor->SetStatus(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, true));
- CHECK(ioctl(fd_audio, AUDIO_PLAY));
- CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
- CHECK(ioctl(fd_video, VIDEO_PLAY));
-
player = Player;
player->device = this;
- player->deviceFileHandle = fd_video;
+ player->deviceFileHandle = SetPlayMode(true);
player->Activate(true);
return true;
}
@@ -767,17 +376,7 @@ void cDevice::Detach(cPlayer *Player)
player->deviceFileHandle = -1;
player->device = NULL;
player = NULL;
-
- CHECK(ioctl(fd_video, VIDEO_STOP, true));
- CHECK(ioctl(fd_audio, AUDIO_STOP, true));
- CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
- CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
- CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
- CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
- CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
- CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
- if (siProcessor)
- siProcessor->SetStatus(true);
+ SetPlayMode(false);
}
}
@@ -802,14 +401,11 @@ void cDevice::StopReplay(void)
int cDevice::PlayVideo(const uchar *Data, int Length)
{
- if (fd_video >= 0)
- return write(fd_video, Data, Length);
return -1;
}
int cDevice::PlayAudio(const uchar *Data, int Length)
{
- //XXX+
return -1;
}
@@ -828,7 +424,7 @@ int cDevice::Priority(void)
int cDevice::CanShift(int Ca, int Priority, int UsedCards)
{
return -1;//XXX+ too complex with multiple recordings per device
- // Test whether a receiving on this DVB device can be shifted to another one
+ // Test whether a receiver on this device can be shifted to another one
// in order to perform a new receiving with the given Ca and Priority on this device:
int ShiftLevel = -1; // default means this device can't be shifted
if (UsedCards & (1 << CardIndex()) != 0)
@@ -892,51 +488,31 @@ void cDevice::Action(void)
{
dsyslog("receiver thread started on device %d (pid=%d)", CardIndex() + 1, getpid());
- int fd_dvr = open(dvrFileName, O_RDONLY | O_NONBLOCK);
- if (fd_dvr >= 0) {
- pollfd pfd;
- pfd.fd = fd_dvr;
- pfd.events = pfd.revents = POLLIN;
+ if (OpenDvr()) {
uchar b[TS_SIZE];
time_t t = time(NULL);
active = true;
for (; active;) {
-
// Read data from the DVR device:
-
- if (pfd.revents & POLLIN != 0) {
- int r = read(fd_dvr, b, sizeof(b));
- if (r == TS_SIZE) {
- if (*b == TS_SYNC_BYTE) {
- // We're locked on to a TS packet
- int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2];
- // Distribute the packet to all attached receivers:
- Lock();
- for (int i = 0; i < MAXRECEIVERS; i++) {
- if (receiver[i] && receiver[i]->WantsPid(Pid))
- receiver[i]->Receive(b, TS_SIZE);
- }
- Unlock();
- }
- t = time(NULL);
- }
- else if (r > 0)
- esyslog("ERROR: got incomplete TS packet (%d bytes)", r);//XXX+ TODO do we have to read the rest???
- else if (r < 0) {
- if (FATALERRNO) {
- if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library
- esyslog("ERROR: DVB driver buffer overflow on device %d", CardIndex() + 1);
- else {
- LOG_ERROR;
- break;
- }
- }
+ int r = GetTSPacket(b);
+ if (r == TS_SIZE) {
+ if (*b == TS_SYNC_BYTE) {
+ // We're locked on to a TS packet
+ int Pid = (((uint16_t)b[1] & PID_MASK_HI) << 8) | b[2];
+ // Distribute the packet to all attached receivers:
+ Lock();
+ for (int i = 0; i < MAXRECEIVERS; i++) {
+ if (receiver[i] && receiver[i]->WantsPid(Pid))
+ receiver[i]->Receive(b, TS_SIZE);
+ }
+ Unlock();
}
+ t = time(NULL);
}
-
- // Wait for more data to become available:
-
- poll(&pfd, 1, 100);
+ else if (r > 0)
+ esyslog("ERROR: got incomplete TS packet (%d bytes) on device %d", r, CardIndex() + 1);//XXX+ TODO do we have to read the rest???
+ else if (r < 0)
+ break;
//XXX+ put this into the recorder??? or give the receiver a flag whether it wants this?
if (time(NULL) - t > MAXBROKENTIMEOUT) {
@@ -945,14 +521,26 @@ void cDevice::Action(void)
t = time(NULL);
}
}
- close(fd_dvr);
+ CloseDvr();
}
- else
- LOG_ERROR_STR(dvrFileName);
dsyslog("receiver thread ended on device %d (pid=%d)", CardIndex() + 1, getpid());
}
+bool cDevice::OpenDvr(void)
+{
+ return false;
+}
+
+void cDevice::CloseDvr(void)
+{
+}
+
+int cDevice::GetTSPacket(uchar *Data)
+{
+ return -1;
+}
+
bool cDevice::AttachReceiver(cReceiver *Receiver)
{
//XXX+ check for same transponder???
@@ -963,7 +551,6 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
StopReplay();
for (int i = 0; i < MAXRECEIVERS; i++) {
if (!receiver[i]) {
- //siProcessor->SetStatus(false);//XXX+
for (int n = 0; n < MAXRECEIVEPIDS; n++)
AddPid(Receiver->pids[n]);//XXX+ retval!
Receiver->Activate(true);
diff --git a/device.h b/device.h
index 124dcdc3..4610988d 100644
--- a/device.h
+++ b/device.h
@@ -4,38 +4,33 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: device.h 1.4 2002/07/28 10:48:12 kls Exp $
+ * $Id: device.h 1.5 2002/08/04 14:02:19 kls Exp $
*/
#ifndef __DEVICE_H
#define __DEVICE_H
-#include <stdlib.h> // FIXME: this is apparently necessary for the ost/... header files
- // FIXME: shouldn't every header file include ALL the other header
- // FIXME: files it depends on? The sequence in which header files
- // FIXME: are included here should not matter - and it should NOT
- // FIXME: be necessary to include <stdlib.h> here!
-#include <ost/dmx.h>
-#include <ost/frontend.h>
-#include <ost/audio.h>
-#include <ost/video.h>
-#include "eit.h"
#include "thread.h"
+#include "tools.h"
-enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
-
-#define MAXDEVICES 4 // the maximum number of devices in the system
-#define MAXCACAPS 16 // the maximum number of different CA values per DVB device
-#define MAXPIDHANDLES 16 // the maximum number of different PIDs per DVB device
-#define MAXRECEIVERS 16 // the maximum number of receivers per DVB device
+#define MAXDEVICES 16 // the maximum number of devices in the system
+#define MAXCACAPS 16 // the maximum number of different CA values per device
+#define MAXPIDHANDLES 16 // the maximum number of different PIDs per device
+#define MAXRECEIVERS 16 // the maximum number of receivers per device
#define MAXVOLUME 255
#define VOLUMEDELTA 5 // used to increase/decrease the volume
+#define TS_SIZE 188
+#define TS_SYNC_BYTE 0x47
+#define PID_MASK_HI 0x1F
+
+enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
+
+class cChannel;
class cPlayer;
class cReceiver;
class cDevice : cThread {
- friend class cOsd;//XXX
private:
static int numDevices;
static int useDevice;
@@ -43,106 +38,142 @@ private:
static cDevice *primaryDevice;
public:
static int NumDevices(void) { return numDevices; }
- // Returns the total number of DVB devices.
+ // Returns the total number of devices.
static void SetUseDevice(int n);
- // Sets the 'useDevice' flag of the given DVB device.
- // If this function is not called before Initialize(), all DVB devices
+ // Sets the 'useDevice' flag of the given device.
+ // If this function is not called before initializing, all devices
// will be used.
+ static bool UseDevice(int n) { return useDevice == 0 || (useDevice & (1 << n)) != 0; }
+ // Tells whether the device with the given card index shall be used in
+ // this instance of VDR.
static bool SetPrimaryDevice(int n);
- // Sets the primary DVB device to 'n' (which must be in the range
+ // Sets the primary device to 'n' (which must be in the range
// 1...numDevices) and returns true if this was possible.
static cDevice *PrimaryDevice(void) { return primaryDevice; }
- // Returns the primary DVB device.
+ // Returns the primary device.
static cDevice *GetDevice(int Ca, int Priority, int Frequency = 0, int Vpid = 0, bool *ReUse = NULL);
- // Selects a free DVB device, avoiding the primaryDevice if possible.
+ // Selects a free device, avoiding the primaryDevice if possible.
// If Ca is not 0, the device with the given number will be returned
// in case Ca is <= MAXDEVICES, or the device that provides the given
// value in its caCaps.
- // If there is a device that is already tuned to the given Frequency,
- // and that device is able to receive multiple channels ("budget" cards),
- // that device will be returned. Else if a ("full featured") device is
- // tuned to Frequency and Vpid, that one will be returned.
- // If all DVB devices are currently receiving, the one receiving the
- // lowest priority timer (if any) that is lower than the given Priority
+ // If there is a device that is already receiving and can be re-used to
+ // receive another data stream, that device will be returned.
+ // If all devices are currently receiving, the one receiving with the
+ // lowest priority (if any) that is lower than the given Priority
// will be returned.
// If ReUse is given, the caller will be informed whether the device can be re-used
// for a new recording. If ReUse returns 'true', the caller must NOT switch the channel
// (the device is already properly tuned). Otherwise the caller MUST switch the channel.
- static void SetCaCaps(void);
- // Sets the CaCaps of all DVB devices according to the Setup data.
- static bool Probe(const char *FileName);
- // Probes for existing DVB devices.
- static bool Initialize(void);
- // Initializes the DVB devices.
- // Must be called before accessing any DVB functions.
+ static void SetCaCaps(int Index = -1);
+ // Sets the CaCaps of the given device according to the Setup data.
+ // By default the CaCaps of all devices are set.
static void Shutdown(void);
- // Closes down all DVB devices.
+ // Closes down all devices.
// Must be called at the end of the program.
private:
+ static int nextCardIndex;
int cardIndex;
int caCaps[MAXCACAPS];
- FrontendType frontendType;
- char *dvrFileName;
- bool active;
- int fd_osd, fd_frontend, fd_sec, fd_audio, fd_video;
- int OsdDeviceHandle(void) { return fd_osd; }
-public:
- cDevice(int n);
+protected:
+ cDevice(void);
virtual ~cDevice();
+ static int NextCardIndex(int n = 0);
+ // Each device in a given machine must have a unique card index, which
+ // will be used to identify the device for assigning Ca parameters and
+ // deciding whether to actually use that device in this particular
+ // instance of VDR. Every time a new cDevice is created, it will be
+ // given the current nextCardIndex, and then nextCardIndex will be
+ // automatically incremented by 1. A derived class can determine whether
+ // a given device shall be used by checking UseDevice(NextCardIndex()).
+ // If a device is skipped, or if there are possible device indexes left
+ // after a derived class has set up all its devices, NextCardIndex(n)
+ // must be called, where n is the number of card indexes to skip.
+ virtual void MakePrimaryDevice(bool On);
+ // Informs a device that it will be the primary device. If there is
+ // anything the device needs to set up when it becomes the primary
+ // device (On = true) or to shut down when it no longer is the primary
+ // device (On = false), it should do so in this function.
+public:
bool IsPrimaryDevice(void) const { return this == primaryDevice; }
int CardIndex(void) const { return cardIndex; }
// Returns the card index of this device (0 ... MAXDEVICES - 1).
int ProvidesCa(int Ca);
- // Checks whether this DVB device provides the given value in its
+ // Checks whether this device provides the given value in its
// caCaps. Returns 0 if the value is not provided, 1 if only this
// value is provided, and > 1 if this and other values are provided.
- // If the given value is equal to the number of this DVB device,
+ // If the given value is equal to the number of this device,
// 1 is returned. If it is 0 (FTA), 1 plus the number of other values
// in caCaps is returned.
- bool HasDecoder(void) const { return fd_video >= 0 && fd_audio >= 0; }
+ virtual bool CanBeReUsed(int Frequency, int Vpid);//XXX TODO make it more abstract
+ // Tells whether this device is already receiving and allows another
+ // receiver with the given settings to be attached to it.
+ virtual bool HasDecoder(void) const;
+ // Tells whether this device has an MPEG decoder.
// Channel facilities
-private:
+protected:
int currentChannel;
- int frequency;
public:
- eSetChannelResult SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr);
+ eSetChannelResult SetChannel(const cChannel *Channel);
+ // Sets the device to the given channel (general setup).
+ virtual bool SetChannelDevice(const cChannel *Channel);
+ // Sets the device to the given channel (actual physical setup).
static int CurrentChannel(void) { return primaryDevice ? primaryDevice->currentChannel : 0; }
+ // Returns the number of the current channel on the primary device.
int Channel(void) { return currentChannel; }
+ // Returns the number of the current channel on this device.
// PID handle facilities
private:
+ bool active;
+ virtual void Action(void);
+protected:
enum ePidType { ptVideo, ptAudio, ptTeletext, ptDolby, ptOther };
class cPidHandle {
public:
int pid;
- int fd;
+ int handle;
int used;
- cPidHandle(void) { pid = used = 0; fd = -1; }
+ cPidHandle(void) { pid = used = 0; handle = -1; }
};
cPidHandle pidHandles[MAXPIDHANDLES];
bool AddPid(int Pid, ePidType PidType = ptOther);
- bool DelPid(int Pid);
- bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output);
- virtual void Action(void);
+ // Adds a PID to the set of PIDs this device shall receive.
+ void DelPid(int Pid);
+ // Deletes a PID from the set of PIDs this device shall receive.
+ virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
+ // Does the actual PID setting on this device.
+ // On indicates whether the PID shall be added or deleted.
+ // Handle->handle can be used by the device to store information it
+ // needs to receive this PID (for instance a file handle).
+ // Handle->used indicated how many receivers are using this PID.
+ // Type indicates some special types of PIDs, which the device may
+ // need to set in a specific way.
// Image Grab facilities
public:
- bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
+ virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
+ // Grabs the currently visible screen image into the given file, with the
+ // given parameters.
// Video format facilities
public:
- virtual void SetVideoFormat(videoFormat_t Format);
+ virtual void SetVideoFormat(bool VideoFormat16_9);
+ // Sets the output video format to either 16:9 or 4:3 (only useful
+ // if this device has an MPEG decoder).
// Volume facilities
private:
bool mute;
int volume;
+protected:
+ virtual void SetVolumeDevice(int Volume);
+ // Sets the audio volume on this device (Volume = 0...255).
public:
bool IsMute(void) { return mute; }
bool ToggleMute(void);
@@ -152,30 +183,46 @@ public:
// the current volume.
static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
- // EIT facilities
-
-private:
- cSIProcessor *siProcessor;
-
// Player facilities
private:
cPlayer *player;
+protected:
+ virtual int SetPlayMode(bool On);
+ // Sets the device into play mode (On = true) or normal
+ // viewing mode (On = false). If On is true, it may return a file
+ // handle that a player can use to poll this device when replaying.
+ //XXX TODO should be implemented differently
public:
- void TrickSpeed(int Speed);
- void Clear(void);
- void Play(void);
- void Freeze(void);
- void Mute(void);
- void StillPicture(const uchar *Data, int Length);
+ virtual void TrickSpeed(int Speed);
+ // Sets the device into a mode where replay is done slower.
+ // Every single frame shall then be displayed the given number of
+ // times.
+ virtual void Clear(void);
+ // Clears all video and audio data from the device.
+ virtual void Play(void);
+ // Sets the device into play mode (after a previous trick
+ // mode).
+ virtual void Freeze(void);
+ // Puts the device into "freeze frame" mode.
+ virtual void Mute(void);
+ // Turns off audio while replaying.
+ virtual void StillPicture(const uchar *Data, int Length);
+ // Displays the given I-frame as a still picture.
+ virtual int PlayVideo(const uchar *Data, int Length);
+ // Actually plays the given data block as video. The data must be
+ // part of a PES (Packetized Elementary Stream) which can contain
+ // one video and one audio strem.
+ virtual int PlayAudio(const uchar *Data, int Length);
+ // Plays additional audio streams, like Dolby Digital.
bool Replaying(void);
// Returns true if we are currently replaying.
void StopReplay(void);
// Stops the current replay session (if any).
bool AttachPlayer(cPlayer *Player);
+ // Attaches the given player to this device.
void Detach(cPlayer *Player);
- virtual int PlayVideo(const uchar *Data, int Length);
- virtual int PlayAudio(const uchar *Data, int Length);
+ // Detaches the given player from this device.
// Receiver facilities
@@ -184,16 +231,30 @@ private:
int ca;
int Priority(void);
// Returns the priority of the current receiving session (0..MAXPRIORITY),
- // or -1 if no receiver is currently active. The primary DVB device will
+ // or -1 if no receiver is currently active. The primary device will
// always return at least Setup.PrimaryLimit-1.
int CanShift(int Ca, int Priority, int UsedCards = 0);
+protected:
+ virtual bool OpenDvr(void);
+ // Opens the DVR of this device and prepares it to deliver a Transport
+ // Stream for use in a cReceiver.
+ virtual void CloseDvr(void);
+ // Shuts down the DVR.
+ virtual int GetTSPacket(uchar *Data);
+ // Gets exactly one TS packet from the DVR of this device and copies it
+ // into the given memory area (which is exactly 188 bytes in size).
+ // Returns the number of bytes copied into Data (which must be 188).
+ // If there is currently no TS packet available, 0 should be returned.
+ // In case of a non recoverable error, returns -1.
public:
int Ca(void) { return ca; }
// Returns the ca of the current receiving session.
bool Receiving(void);
// Returns true if we are currently receiving.
bool AttachReceiver(cReceiver *Receiver);
+ // Attaches the given receiver to this device.
void Detach(cReceiver *Receiver);
+ // Detaches the given receiver from this device.
};
#endif //__DEVICE_H
diff --git a/dvbdevice.c b/dvbdevice.c
new file mode 100644
index 00000000..be765005
--- /dev/null
+++ b/dvbdevice.c
@@ -0,0 +1,615 @@
+/*
+ * dvbdevice.c: The DVB device interface
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: dvbdevice.c 1.1 2002/08/04 12:24:25 kls Exp $
+ */
+
+#include "dvbdevice.h"
+#include <errno.h>
+extern "C" {
+#ifdef boolean
+#define HAVE_BOOLEAN
+#endif
+#include <jpeglib.h>
+#undef boolean
+}
+#include <limits.h>
+#include <linux/videodev.h>
+#include <ost/audio.h>
+#include <ost/sec.h>
+#include <ost/video.h>
+#include <poll.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include "dvbosd.h"
+#include "player.h"
+#include "receiver.h"
+#include "status.h"
+#include "transfer.h"
+
+#define MAXDVBDEVICES 4
+
+#define DEV_VIDEO "/dev/video"
+#define DEV_OST_OSD "/dev/ost/osd"
+#define DEV_OST_FRONTEND "/dev/ost/frontend"
+#define DEV_OST_SEC "/dev/ost/sec"
+#define DEV_OST_DVR "/dev/ost/dvr"
+#define DEV_OST_DEMUX "/dev/ost/demux"
+#define DEV_OST_VIDEO "/dev/ost/video"
+#define DEV_OST_AUDIO "/dev/ost/audio"
+
+static const char *OstName(const char *Name, int n)
+{
+ static char buffer[PATH_MAX];
+ snprintf(buffer, sizeof(buffer), "%s%d", Name, n);
+ return buffer;
+}
+
+static int OstOpen(const char *Name, int n, int Mode, bool ReportError = false)
+{
+ const char *FileName = OstName(Name, n);
+ int fd = open(FileName, Mode);
+ if (fd < 0 && ReportError)
+ LOG_ERROR_STR(FileName);
+ return fd;
+}
+
+cDvbDevice::cDvbDevice(int n)
+{
+ frontendType = FrontendType(-1); // don't know how else to initialize this - there is no FE_UNKNOWN
+ siProcessor = NULL;
+
+ // Devices that are present on all card types:
+
+ fd_frontend = OstOpen(DEV_OST_FRONTEND, n, O_RDWR);
+
+ // Devices that are only present on DVB-S cards:
+
+ fd_sec = OstOpen(DEV_OST_SEC, n, O_RDWR);
+
+ // Devices that are only present on cards with decoders:
+
+ fd_osd = OstOpen(DEV_OST_OSD, n, O_RDWR);
+ fd_video = OstOpen(DEV_OST_VIDEO, n, O_RDWR | O_NONBLOCK);
+ fd_audio = OstOpen(DEV_OST_AUDIO, n, O_RDWR | O_NONBLOCK);
+
+ // The DVR device (will be opened and closed as needed):
+
+ fd_dvr = -1;
+
+ // Video format:
+
+ SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
+
+ // We only check the devices that must be present - the others will be checked before accessing them://XXX
+
+ if (fd_frontend >= 0) {
+ siProcessor = new cSIProcessor(OstName(DEV_OST_DEMUX, n));
+ FrontendInfo feinfo;
+ if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0)
+ frontendType = feinfo.type;
+ else
+ LOG_ERROR;
+ }
+ else
+ esyslog("ERROR: can't open DVB device %d", n);
+
+ frequency = 0;
+}
+
+cDvbDevice::~cDvbDevice()
+{
+ delete siProcessor;
+ // We're not explicitly closing any device files here, since this sometimes
+ // caused segfaults. Besides, the program is about to terminate anyway...
+}
+
+bool cDvbDevice::Probe(const char *FileName)
+{
+ if (access(FileName, F_OK) == 0) {
+ dsyslog("probing %s", FileName);
+ int f = open(FileName, O_RDONLY);
+ if (f >= 0) {
+ close(f);
+ return true;
+ }
+ else if (errno != ENODEV && errno != EINVAL)
+ LOG_ERROR_STR(FileName);
+ }
+ else if (errno != ENOENT)
+ LOG_ERROR_STR(FileName);
+ return false;
+}
+
+bool cDvbDevice::Initialize(void)
+{
+ int found = 0;
+ int i;
+ for (i = 0; i < MAXDVBDEVICES; i++) {
+ if (UseDevice(NextCardIndex())) {
+ if (Probe(OstName(DEV_OST_FRONTEND, i))) {
+ new cDvbDevice(i);
+ found++;
+ }
+ else
+ break;
+ }
+ else
+ NextCardIndex(1); // skips this one
+ }
+ NextCardIndex(MAXDVBDEVICES - i); // skips the rest
+ if (found > 0)
+ isyslog("found %d video device%s", found, found > 1 ? "s" : "");
+ else
+ isyslog("no DVB device found");
+ return found > 0;
+}
+
+void cDvbDevice::MakePrimaryDevice(bool On)
+{
+ cDvbOsd::SetDvbDevice(On ? this : NULL);
+}
+
+bool cDvbDevice::CanBeReUsed(int Frequency, int Vpid)
+{
+ return Receiving() // to be reused the DVB device must already be receiving...
+ && frequency == Frequency // ...and tuned to the requested frequency...
+ && (!HasDecoder() // ...and either be a "budget card" which can receive multiple channels...
+ || pidHandles[ptVideo].pid == Vpid // ...or be a "full featured card" that's already tuned to the requested video PID
+ );
+}
+
+bool cDvbDevice::HasDecoder(void) const
+{
+ return fd_video >= 0 && fd_audio >= 0;
+}
+
+bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int SizeX, int SizeY)
+{
+ int videoDev = OstOpen(DEV_VIDEO, CardIndex(), O_RDWR, true);
+ if (videoDev >= 0) {
+ int result = 0;
+ struct video_mbuf mbuf;
+ result |= ioctl(videoDev, VIDIOCGMBUF, &mbuf);
+ if (result == 0) {
+ int msize = mbuf.size;
+ unsigned char *mem = (unsigned char *)mmap(0, msize, PROT_READ | PROT_WRITE, MAP_SHARED, videoDev, 0);
+ if (mem && mem != (unsigned char *)-1) {
+ // set up the size and RGB
+ struct video_capability vc;
+ result |= ioctl(videoDev, VIDIOCGCAP, &vc);
+ struct video_mmap vm;
+ vm.frame = 0;
+ if ((SizeX > 0) && (SizeX <= vc.maxwidth) &&
+ (SizeY > 0) && (SizeY <= vc.maxheight)) {
+ vm.width = SizeX;
+ vm.height = SizeY;
+ }
+ else {
+ vm.width = vc.maxwidth;
+ vm.height = vc.maxheight;
+ }
+ vm.format = VIDEO_PALETTE_RGB24;
+ result |= ioctl(videoDev, VIDIOCMCAPTURE, &vm);
+ result |= ioctl(videoDev, VIDIOCSYNC, &vm.frame);
+ // make RGB out of BGR:
+ int memsize = vm.width * vm.height;
+ unsigned char *mem1 = mem;
+ for (int i = 0; i < memsize; i++) {
+ unsigned char tmp = mem1[2];
+ mem1[2] = mem1[0];
+ mem1[0] = tmp;
+ mem1 += 3;
+ }
+
+ if (Quality < 0)
+ Quality = 255; //XXX is this 'best'???
+
+ isyslog("grabbing to %s (%s %d %d %d)", FileName, Jpeg ? "JPEG" : "PNM", Quality, vm.width, vm.height);
+ FILE *f = fopen(FileName, "wb");
+ if (f) {
+ if (Jpeg) {
+ // write JPEG file:
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
+ jpeg_stdio_dest(&cinfo, f);
+ cinfo.image_width = vm.width;
+ cinfo.image_height = vm.height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
+
+ jpeg_set_defaults(&cinfo);
+ jpeg_set_quality(&cinfo, Quality, true);
+ jpeg_start_compress(&cinfo, true);
+
+ int rs = vm.width * 3;
+ JSAMPROW rp[vm.height];
+ for (int k = 0; k < vm.height; k++)
+ rp[k] = &mem[rs * k];
+ jpeg_write_scanlines(&cinfo, rp, vm.height);
+ jpeg_finish_compress(&cinfo);
+ jpeg_destroy_compress(&cinfo);
+ }
+ else {
+ // write PNM file:
+ if (fprintf(f, "P6\n%d\n%d\n255\n", vm.width, vm.height) < 0 ||
+ fwrite(mem, vm.width * vm.height * 3, 1, f) < 0) {
+ LOG_ERROR_STR(FileName);
+ result |= 1;
+ }
+ }
+ fclose(f);
+ }
+ else {
+ LOG_ERROR_STR(FileName);
+ result |= 1;
+ }
+ munmap(mem, msize);
+ }
+ else
+ result |= 1;
+ }
+ close(videoDev);
+ return result == 0;
+ }
+ return false;
+}
+
+void cDvbDevice::SetVideoFormat(bool VideoFormat16_9)
+{
+ if (HasDecoder())
+ CHECK(ioctl(fd_video, VIDEO_SET_FORMAT, VideoFormat16_9 ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3));
+}
+
+// ptVideo ptAudio ptTeletext ptDolby ptOther
+dmxPesType_t PesTypes[] = { DMX_PES_VIDEO, DMX_PES_AUDIO, DMX_PES_TELETEXT, DMX_PES_OTHER, DMX_PES_OTHER };
+
+bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
+{
+ if (Handle->pid) {
+ if (On) {
+ if (Handle->handle < 0) {
+ Handle->handle = OstOpen(DEV_OST_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
+ if (Handle->handle < 0)
+ return false;
+ }
+ }
+ else {
+ CHECK(ioctl(Handle->handle, DMX_STOP));
+ if (Handle->used == 0) {
+ close(Handle->handle);
+ Handle->handle = -1;
+ return true;
+ }
+ }
+
+ if (Handle->pid != 0x1FFF) {
+ dmxPesFilterParams pesFilterParams;
+ pesFilterParams.pid = Handle->pid;
+ pesFilterParams.input = DMX_IN_FRONTEND;
+ pesFilterParams.output = (Type <= ptTeletext && Handle->used <= 1) ? DMX_OUT_DECODER : DMX_OUT_TS_TAP;
+ pesFilterParams.pesType = PesTypes[Type < ptOther ? Type : ptOther];
+ pesFilterParams.flags = DMX_IMMEDIATE_START;
+ //XXX+ pesFilterParams.flags = DMX_CHECK_CRC;//XXX
+ if (ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+ LOG_ERROR;
+ return false;
+ }
+ //XXX+ CHECK(ioctl(Handle->handle, DMX_SET_BUFFER_SIZE, KILOBYTE(32)));//XXX
+ //XXX+ CHECK(ioctl(Handle->handle, DMX_START));//XXX
+ }
+ }
+ return true;
+}
+
+bool cDvbDevice::SetChannelDevice(const cChannel *Channel)
+{
+ // Avoid noise while switching:
+
+ if (HasDecoder()) {
+ CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
+ CHECK(ioctl(fd_video, VIDEO_SET_BLANK, true));
+ CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
+ CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
+ }
+
+ // Stop setting system time:
+
+ if (siProcessor)
+ siProcessor->SetCurrentTransponder(0);
+
+ // Turn off current PIDs:
+
+ if (HasDecoder()) {
+ DelPid(pidHandles[ptVideo].pid);
+ DelPid(pidHandles[ptAudio].pid);
+ DelPid(pidHandles[ptTeletext].pid);
+ DelPid(pidHandles[ptDolby].pid);
+ }
+
+ FrontendParameters Frontend;
+
+ switch (frontendType) {
+ case FE_QPSK: { // DVB-S
+
+ // Frequency offsets:
+
+ unsigned int freq = Channel->frequency;
+ int tone = SEC_TONE_OFF;
+
+ if (freq < (unsigned int)Setup.LnbSLOF) {
+ freq -= Setup.LnbFrequLo;
+ tone = SEC_TONE_OFF;
+ }
+ else {
+ freq -= Setup.LnbFrequHi;
+ tone = SEC_TONE_ON;
+ }
+
+ Frontend.Frequency = freq * 1000UL;
+ Frontend.Inversion = INVERSION_AUTO;
+ Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL;
+ Frontend.u.qpsk.FEC_inner = FEC_AUTO;
+
+ int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
+
+ // DiseqC:
+
+ secCommand scmd;
+ scmd.type = 0;
+ scmd.u.diseqc.addr = 0x10;
+ scmd.u.diseqc.cmd = 0x38;
+ scmd.u.diseqc.numParams = 1;
+ scmd.u.diseqc.params[0] = 0xF0 | ((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0);
+
+ secCmdSequence scmds;
+ scmds.voltage = volt;
+ scmds.miniCommand = SEC_MINI_NONE;
+ scmds.continuousTone = tone;
+ scmds.numCommands = Setup.DiSEqC ? 1 : 0;
+ scmds.commands = &scmd;
+
+ CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
+ }
+ break;
+ case FE_QAM: { // DVB-C
+
+ // Frequency and symbol rate:
+
+ Frontend.Frequency = Channel->frequency * 1000000UL;
+ Frontend.Inversion = INVERSION_AUTO;
+ Frontend.u.qam.SymbolRate = Channel->srate * 1000UL;
+ Frontend.u.qam.FEC_inner = FEC_AUTO;
+ Frontend.u.qam.QAM = QAM_64;
+ }
+ break;
+ case FE_OFDM: { // DVB-T
+
+ // Frequency and OFDM paramaters:
+
+ Frontend.Frequency = Channel->frequency * 1000UL;
+ Frontend.Inversion = INVERSION_AUTO;
+ Frontend.u.ofdm.bandWidth=BANDWIDTH_8_MHZ;
+ Frontend.u.ofdm.HP_CodeRate=FEC_2_3;
+ Frontend.u.ofdm.LP_CodeRate=FEC_1_2;
+ Frontend.u.ofdm.Constellation=QAM_64;
+ Frontend.u.ofdm.TransmissionMode=TRANSMISSION_MODE_2K;
+ Frontend.u.ofdm.guardInterval=GUARD_INTERVAL_1_32;
+ Frontend.u.ofdm.HierarchyInformation=HIERARCHY_NONE;
+ }
+ break;
+ default:
+ esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
+ return false;
+ }
+
+ // Tuning:
+
+ CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
+
+ // Wait for channel sync:
+
+ if (cFile::FileReady(fd_frontend, 5000)) {
+ FrontendEvent event;
+ int res = ioctl(fd_frontend, FE_GET_EVENT, &event);
+ if (res >= 0) {
+ if (event.type != FE_COMPLETION_EV) {
+ esyslog("ERROR: channel %d not sync'ed on DVB card %d!", Channel->number, CardIndex() + 1);
+ if (IsPrimaryDevice())
+ cThread::RaisePanic();
+ return false;
+ }
+ }
+ else
+ esyslog("ERROR %d in frontend get event (channel %d, card %d)", res, Channel->number, CardIndex() + 1);
+ }
+ else
+ esyslog("ERROR: timeout while tuning");
+
+ frequency = Channel->frequency;
+
+ // PID settings:
+
+ if (HasDecoder()) {
+ if (!(AddPid(Channel->vpid, ptVideo) && AddPid(Channel->apid1, ptAudio))) {//XXX+ dolby dpid1!!! (if audio plugins are attached)
+ esyslog("ERROR: failed to set PIDs for channel %d", Channel->number);
+ return false;
+ }
+ if (IsPrimaryDevice())
+ AddPid(Channel->tpid, ptTeletext);
+ CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
+ }
+
+ if (HasDecoder()) {
+ CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
+ CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
+ }
+
+ // Start setting system time:
+
+ if (siProcessor)
+ siProcessor->SetCurrentTransponder(Channel->frequency);
+
+ return true;
+}
+
+void cDvbDevice::SetVolumeDevice(int Volume)
+{
+ if (HasDecoder()) {
+ audioMixer_t am;
+ am.volume_left = am.volume_right = Volume;
+ CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
+ }
+}
+
+int cDvbDevice::SetPlayMode(bool On)
+{
+ if (On) {
+ if (siProcessor)
+ siProcessor->SetStatus(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, true));
+ CHECK(ioctl(fd_audio, AUDIO_PLAY));
+ CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_MEMORY));
+ CHECK(ioctl(fd_video, VIDEO_PLAY));
+ return fd_video;
+ }
+ else {
+ CHECK(ioctl(fd_video, VIDEO_STOP, true));
+ CHECK(ioctl(fd_audio, AUDIO_STOP, true));
+ CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
+ CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
+ CHECK(ioctl(fd_video, VIDEO_SELECT_SOURCE, VIDEO_SOURCE_DEMUX));
+ CHECK(ioctl(fd_audio, AUDIO_SELECT_SOURCE, AUDIO_SOURCE_DEMUX));
+ CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
+ CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
+ if (siProcessor)
+ siProcessor->SetStatus(true);
+ return -1;
+ }
+}
+
+void cDvbDevice::TrickSpeed(int Speed)
+{
+ if (fd_video >= 0)
+ CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
+}
+
+void cDvbDevice::Clear(void)
+{
+ if (fd_video >= 0)
+ CHECK(ioctl(fd_video, VIDEO_CLEAR_BUFFER));
+ if (fd_audio >= 0)
+ CHECK(ioctl(fd_audio, AUDIO_CLEAR_BUFFER));
+}
+
+void cDvbDevice::Play(void)
+{
+ if (fd_audio >= 0)
+ CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, true));
+ if (fd_video >= 0)
+ CHECK(ioctl(fd_video, VIDEO_CONTINUE));
+}
+
+void cDvbDevice::Freeze(void)
+{
+ if (fd_audio >= 0)
+ CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
+ if (fd_video >= 0)
+ CHECK(ioctl(fd_video, VIDEO_FREEZE));
+}
+
+void cDvbDevice::Mute(void)
+{
+ if (fd_audio >= 0) {
+ CHECK(ioctl(fd_audio, AUDIO_SET_AV_SYNC, false));
+ CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, true));
+ }
+}
+
+void cDvbDevice::StillPicture(const uchar *Data, int Length)
+{
+ Mute();
+/* Using the VIDEO_STILLPICTURE ioctl call would be the
+ correct way to display a still frame, but unfortunately this
+ doesn't work with frames from VDR. So let's do pretty much the
+ same here as in DVB/driver/dvb.c's play_iframe() - I have absolutely
+ no idea why it works this way, but doesn't work with VIDEO_STILLPICTURE.
+ If anybody ever finds out what could be changed so that VIDEO_STILLPICTURE
+ could be used, please let me know!
+ kls 2002-03-23
+*/
+//#define VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
+#ifdef VIDEO_STILLPICTURE_WORKS_WITH_VDR_FRAMES
+ videoDisplayStillPicture sp = { (char *)Data, Length };
+ CHECK(ioctl(fd_video, VIDEO_STILLPICTURE, &sp));
+#else
+#define MIN_IFRAME 400000
+ for (int i = MIN_IFRAME / Length + 1; i > 0; i--) {
+ safe_write(fd_video, Data, Length);
+ usleep(1); // allows the buffer to be displayed in case the progress display is active
+ }
+#endif
+}
+
+int cDvbDevice::PlayVideo(const uchar *Data, int Length)
+{
+ if (fd_video >= 0)
+ return write(fd_video, Data, Length);
+ return -1;
+}
+
+int cDvbDevice::PlayAudio(const uchar *Data, int Length)
+{
+ //XXX+
+ return -1;
+}
+
+bool cDvbDevice::OpenDvr(void)
+{
+ CloseDvr();
+ fd_dvr = OstOpen(DEV_OST_DVR, CardIndex(), O_RDONLY | O_NONBLOCK, true);
+ return fd_dvr >= 0;
+}
+
+void cDvbDevice::CloseDvr(void)
+{
+ if (fd_dvr >= 0) {
+ close(fd_dvr);
+ fd_dvr = -1;
+ }
+}
+
+int cDvbDevice::GetTSPacket(uchar *Data)
+{
+ if (fd_dvr >= 0) {
+ pollfd pfd;
+ pfd.fd = fd_dvr;
+ pfd.events = POLLIN;
+
+ poll(&pfd, 1, 100);
+
+ if (pfd.revents & POLLIN != 0) {
+ int r = read(fd_dvr, Data, TS_SIZE);
+ if (r >= 0)
+ return r;
+ else if (FATALERRNO) {
+ if (errno == EBUFFEROVERFLOW) // this error code is not defined in the library
+ esyslog("ERROR: DVB driver buffer overflow on device %d", CardIndex() + 1);
+ else {
+ LOG_ERROR;
+ return -1;
+ }
+ }
+ }
+ return 0;
+ }
+ else
+ return -1;
+}
diff --git a/dvbdevice.h b/dvbdevice.h
new file mode 100644
index 00000000..25777f06
--- /dev/null
+++ b/dvbdevice.h
@@ -0,0 +1,97 @@
+/*
+ * dvbdevice.h: The DVB device interface
+ *
+ * See the main source file 'vdr.c' for copyright information and
+ * how to reach the author.
+ *
+ * $Id: dvbdevice.h 1.1 2002/08/04 12:19:10 kls Exp $
+ */
+
+#ifndef __DVBDEVICE_H
+#define __DVBDEVICE_H
+
+#include <stdlib.h> // FIXME: this is apparently necessary for the ost/... header files
+ // FIXME: shouldn't every header file include ALL the other header
+ // FIXME: files it depends on? The sequence in which header files
+ // FIXME: are included here should not matter - and it should NOT
+ // FIXME: be necessary to include <stdlib.h> here!
+#include <ost/frontend.h>
+#include "device.h"
+#include "eit.h"
+
+class cDvbDevice : public cDevice {
+ friend class cDvbOsd;
+private:
+ static bool Probe(const char *FileName);
+ // Probes for existing DVB devices.
+public:
+ static bool Initialize(void);
+ // Initializes the DVB devices.
+ // Must be called before accessing any DVB functions.
+private:
+ FrontendType frontendType;
+ int fd_osd, fd_frontend, fd_sec, fd_audio, fd_video, fd_dvr;
+ int OsdDeviceHandle(void) const { return fd_osd; }
+protected:
+ virtual void MakePrimaryDevice(bool On);
+public:
+ cDvbDevice(int n);
+ virtual ~cDvbDevice();
+ virtual bool CanBeReUsed(int Frequency, int Vpid);
+ virtual bool HasDecoder(void) const;
+
+// Channel facilities
+
+private:
+ int frequency;
+public:
+ virtual bool SetChannelDevice(const cChannel *Channel);
+
+// PID handle facilities
+
+protected:
+ virtual bool SetPid(cPidHandle *Handle, int Type, bool On);
+
+// Image Grab facilities
+
+public:
+ virtual bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
+
+// Video format facilities
+
+public:
+ virtual void SetVideoFormat(bool VideoFormat16_9);
+
+// Volume facilities
+
+protected:
+ virtual void SetVolumeDevice(int Volume);
+
+// EIT facilities
+
+private:
+ cSIProcessor *siProcessor;
+
+// Player facilities
+
+protected:
+ virtual int SetPlayMode(bool On);
+public:
+ virtual void TrickSpeed(int Speed);
+ virtual void Clear(void);
+ virtual void Play(void);
+ virtual void Freeze(void);
+ virtual void Mute(void);
+ virtual void StillPicture(const uchar *Data, int Length);
+ virtual int PlayVideo(const uchar *Data, int Length);
+ virtual int PlayAudio(const uchar *Data, int Length);
+
+// Receiver facilities
+
+protected:
+ virtual bool OpenDvr(void);
+ virtual void CloseDvr(void);
+ virtual int GetTSPacket(uchar *Data);
+ };
+
+#endif //__DVBDEVICE_H
diff --git a/dvbosd.c b/dvbosd.c
index ad51966f..ca5cf490 100644
--- a/dvbosd.c
+++ b/dvbosd.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbosd.c 1.17 2002/05/18 13:39:02 kls Exp $
+ * $Id: dvbosd.c 1.18 2002/08/04 10:13:21 kls Exp $
*/
#include "dvbosd.h"
@@ -13,10 +13,12 @@
#include <sys/unistd.h>
#include "tools.h"
-cDvbOsd::cDvbOsd(int OsdDev, int x, int y)
+const cDvbDevice *cDvbOsd::dvbDevice = NULL;
+
+cDvbOsd::cDvbOsd(int x, int y)
:cOsdBase(x, y)
{
- osdDev = OsdDev;
+ osdDev = dvbDevice ? dvbDevice->OsdDeviceHandle() : -1;
if (osdDev < 0)
esyslog("ERROR: illegal OSD device handle (%d)!", osdDev);
}
@@ -27,6 +29,11 @@ cDvbOsd::~cDvbOsd()
CloseWindow(GetWindowNr(i));
}
+void cDvbOsd::SetDvbDevice(const cDvbDevice *DvbDevice)
+{
+ dvbDevice = DvbDevice;
+}
+
bool cDvbOsd::SetWindow(cWindow *Window)
{
if (Window) {
diff --git a/dvbosd.h b/dvbosd.h
index 0bc6079f..69838f6d 100644
--- a/dvbosd.h
+++ b/dvbosd.h
@@ -4,17 +4,19 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: dvbosd.h 1.13 2002/05/18 13:38:09 kls Exp $
+ * $Id: dvbosd.h 1.14 2002/08/04 10:12:14 kls Exp $
*/
#ifndef __DVBOSD_H
#define __DVBOSD_H
#include <ost/osd.h>
+#include "dvbdevice.h"
#include "osdbase.h"
class cDvbOsd : public cOsdBase {
private:
+ static const cDvbDevice *dvbDevice;
int osdDev;
bool SetWindow(cWindow *Window);
void Cmd(OSD_Command cmd, int color = 0, int x0 = 0, int y0 = 0, int x1 = 0, int y1 = 0, const void *data = NULL);
@@ -26,8 +28,9 @@ protected:
virtual void MoveWindow(cWindow *Window, int x, int y);
virtual void CloseWindow(cWindow *Window);
public:
- cDvbOsd(int OsdDev, int x, int y);
+ cDvbOsd(int x, int y);
virtual ~cDvbOsd();
+ static void SetDvbDevice(const cDvbDevice *DvbDevice);
};
#endif //__DVBOSD_H
diff --git a/eit.h b/eit.h
index 5221c403..981f4e59 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.16 2002/03/10 10:56:57 kls Exp $
+ * $Id: eit.h 1.17 2002/08/04 11:30:24 kls Exp $
***************************************************************************/
#ifndef __EIT_H
@@ -158,7 +158,7 @@ public:
static bool Read(FILE *f = NULL);
void SetStatus(bool On);
void SetCurrentTransponder(int CurrentTransponder);
- bool SetCurrentServiceID(unsigned short servid);
+ static bool SetCurrentServiceID(unsigned short servid);
};
#endif
diff --git a/eitscan.c b/eitscan.c
index a275abe0..08c91c61 100644
--- a/eitscan.c
+++ b/eitscan.c
@@ -4,10 +4,11 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: eitscan.c 1.3 2002/06/22 13:02:40 kls Exp $
+ * $Id: eitscan.c 1.4 2002/07/28 15:10:23 kls Exp $
*/
#include "eitscan.h"
+#include <stdlib.h>
cEITScanner::cEITScanner(void)
{
diff --git a/menu.c b/menu.c
index 0404b873..bb253859 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.202 2002/07/14 10:55:37 kls Exp $
+ * $Id: menu.c 1.203 2002/08/03 09:55:44 kls Exp $
*/
#include "menu.h"
@@ -1628,7 +1628,7 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
if (state == osBack && Key == kOk) {
if (Setup.PrimaryDVB != oldPrimaryDVB) {
state = osSwitchDvb;
- cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
+ cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat);
}
}
return state;
diff --git a/osd.c b/osd.c
index 6541560a..30eecae5 100644
--- a/osd.c
+++ b/osd.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: osd.c 1.31 2002/07/14 11:05:30 kls Exp $
+ * $Id: osd.c 1.32 2002/08/04 10:11:26 kls Exp $
*/
#include "osd.h"
@@ -73,7 +73,7 @@ cOsdBase *cOsd::OpenRaw(int x, int y)
#ifdef DEBUG_OSD
return NULL;
#else
- return osd ? NULL : new cDvbOsd(cDevice::PrimaryDevice()->OsdDeviceHandle(), x, y);
+ return osd ? NULL : new cDvbOsd(x, y);
#endif
}
diff --git a/receiver.c b/receiver.c
index 8f94c1a1..e9efac15 100644
--- a/receiver.c
+++ b/receiver.c
@@ -4,12 +4,13 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: receiver.c 1.2 2002/07/28 10:48:42 kls Exp $
+ * $Id: receiver.c 1.3 2002/07/28 15:14:49 kls Exp $
*/
#include <stdarg.h>
#include <stdio.h>
#include "receiver.h"
+#include "tools.h"
cReceiver::cReceiver(int Ca, int Priority, int NumPids, ...)
{
diff --git a/remux.h b/remux.h
index 792469e5..7d81ee03 100644
--- a/remux.h
+++ b/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 1.5 2001/06/23 14:06:59 kls Exp $
+ * $Id: remux.h 1.6 2002/08/04 10:27:07 kls Exp $
*/
#ifndef __REMUX_H
@@ -12,6 +12,7 @@
#include <time.h> //XXX FIXME: DVB/ost/include/ost/dmx.h should include <time.h> itself!!!
#include <ost/dmx.h>
+#include "tools.h"
// Picture types:
#define NO_PICTURE 0
@@ -24,7 +25,6 @@
#define RESULTBUFFERSIZE (MINVIDEODATA * 4)
-typedef unsigned char uchar;
class cTS2PES;
class cRemux {
diff --git a/ringbuffer.h b/ringbuffer.h
index 43176bde..660a08b0 100644
--- a/ringbuffer.h
+++ b/ringbuffer.h
@@ -4,15 +4,14 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ringbuffer.h 1.6 2002/06/16 11:30:07 kls Exp $
+ * $Id: ringbuffer.h 1.7 2002/08/04 10:27:30 kls Exp $
*/
#ifndef __RINGBUFFER_H
#define __RINGBUFFER_H
#include "thread.h"
-
-typedef unsigned char uchar;//XXX+
+#include "tools.h"
class cRingBuffer {
private:
diff --git a/tools.c b/tools.c
index 08aa8ae5..6449a1be 100644
--- a/tools.c
+++ b/tools.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: tools.c 1.67 2002/05/18 15:10:45 kls Exp $
+ * $Id: tools.c 1.68 2002/08/03 15:44:53 kls Exp $
*/
#include "tools.h"
@@ -407,7 +407,7 @@ bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
char *ReadLink(const char *FileName)
{
- char RealName[_POSIX_PATH_MAX];
+ char RealName[PATH_MAX];
const char *TargetName = NULL;
int n = readlink(FileName, RealName, sizeof(RealName) - 1);
if (n < 0) {
diff --git a/vdr.c b/vdr.c
index 10c54f74..fa7429c1 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.117 2002/06/23 11:23:34 kls Exp $
+ * $Id: vdr.c 1.118 2002/08/04 09:56:30 kls Exp $
*/
#include <getopt.h>
@@ -33,6 +33,7 @@
#include "config.h"
#include "cutter.h"
#include "device.h"
+#include "dvbdevice.h"
#include "eitscan.h"
#include "i18n.h"
#include "interface.h"
@@ -326,11 +327,9 @@ int main(int argc, char *argv[])
// DVB interfaces:
- if (!cDevice::Initialize())
+ if (!cDvbDevice::Initialize())
return 2;
- cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
-
cSIProcessor::Read();
// Start plugins:
@@ -338,6 +337,10 @@ int main(int argc, char *argv[])
if (!PluginManager.StartPlugins())
return 2;
+ // Primary device:
+
+ cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
+
// OSD:
cOsd::Initialize();