mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Changed the cDevice class to allow plugins to implement their own devices
This commit is contained in:
parent
61ccfd5fab
commit
15cc1733e0
4
Makefile
4
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
|
||||
|
117
PLUGINS.html
117
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> </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 <vdr/device.h>
|
||||
|
||||
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>
|
||||
|
6
config.c
6
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;
|
||||
|
633
device.c
633
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;
|
||||
cardIndex = nextCardIndex++;
|
||||
|
||||
// Devices that are present on all card types:
|
||||
SetVideoFormat(Setup.VideoFormat);
|
||||
|
||||
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);
|
||||
|
||||
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++) {
|
||||
if (Index < 0 || Index == device[d]->CardIndex()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (--pidHandles[i].used < 2) {
|
||||
SetPid(&pidHandles[i], i, false);
|
||||
if (pidHandles[i].used == 0) {
|
||||
pidHandles[i].handle = -1;
|
||||
pidHandles[i].pid = 0;
|
||||
break;
|
||||
case 1: if (i <= ptTeletext)
|
||||
SetPid(pidHandles[i].fd, PesTypes[i], Pid, DMX_OUT_DECODER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
PRINTPIDS("D");//XXX+
|
||||
return pidHandles[i].used;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDevice::SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output)
|
||||
eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
eSetChannelResult cDevice::SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr)
|
||||
{
|
||||
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,30 +273,32 @@ 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:
|
||||
|
||||
if (Result == scrOk && siProcessor)
|
||||
siProcessor->SetCurrentTransponder(Frequency);
|
||||
|
||||
cStatus::MsgChannelSwitch(this, ChannelNumber);
|
||||
cStatus::MsgChannelSwitch(this, Channel->number);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool cDevice::SetChannelDevice(const cChannel *Channel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void cDevice::SetVolumeDevice(int Volume)
|
||||
{
|
||||
}
|
||||
|
||||
bool cDevice::ToggleMute(void)
|
||||
{
|
||||
int OldVolume = volume;
|
||||
@ -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));
|
||||
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,20 +488,13 @@ 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));
|
||||
int r = GetTSPacket(b);
|
||||
if (r == TS_SIZE) {
|
||||
if (*b == TS_SYNC_BYTE) {
|
||||
// We're locked on to a TS packet
|
||||
@ -921,22 +510,9 @@ void cDevice::Action(void)
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for more data to become available:
|
||||
|
||||
poll(&pfd, 1, 100);
|
||||
|
||||
//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);
|
||||
|
205
device.h
205
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
|
||||
|
615
dvbdevice.c
Normal file
615
dvbdevice.c
Normal file
@ -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;
|
||||
}
|
97
dvbdevice.h
Normal file
97
dvbdevice.h
Normal file
@ -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
|
13
dvbosd.c
13
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) {
|
||||
|
7
dvbosd.h
7
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
|
||||
|
4
eit.h
4
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
|
||||
|
@ -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)
|
||||
{
|
||||
|
4
menu.c
4
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;
|
||||
|
4
osd.c
4
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
|
||||
}
|
||||
|
||||
|
@ -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, ...)
|
||||
{
|
||||
|
4
remux.h
4
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 {
|
||||
|
@ -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:
|
||||
|
4
tools.c
4
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) {
|
||||
|
11
vdr.c
11
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();
|
||||
|
Loading…
Reference in New Issue
Block a user