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
|
# See the main source file 'vdr.c' for copyright information and
|
||||||
# how to reach the author.
|
# 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:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ INCLUDES = -I$(DVBDIR)/ost/include
|
|||||||
|
|
||||||
DTVLIB = $(DTVDIR)/libdtv.a
|
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\
|
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\
|
recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\
|
||||||
tools.o transfer.o vdr.o videodir.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).
|
its windows and color depths).
|
||||||
<!--X1.1.5--></td></tr></table>
|
<!--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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
6
config.c
6
config.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "config.h"
|
||||||
@ -301,7 +301,7 @@ bool cChannel::Switch(cDevice *Device, bool Log)
|
|||||||
if (Log)
|
if (Log)
|
||||||
isyslog("switching to channel %d", number);
|
isyslog("switching to channel %d", number);
|
||||||
for (int i = 3; i--;) {
|
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 scrOk: return true;
|
||||||
case scrNoTransfer: if (Interface)
|
case scrNoTransfer: if (Interface)
|
||||||
Interface->Error(tr("Can't start Transfer Mode!"));
|
Interface->Error(tr("Can't start Transfer Mode!"));
|
||||||
@ -1018,7 +1018,7 @@ cSetup::cSetup(void)
|
|||||||
DefaultLifetime = 50;
|
DefaultLifetime = 50;
|
||||||
UseSubtitle = 1;
|
UseSubtitle = 1;
|
||||||
RecordingDirs = 1;
|
RecordingDirs = 1;
|
||||||
VideoFormat = VIDEO_FORMAT_4_3;
|
VideoFormat = 0;
|
||||||
RecordDolbyDigital = 1;
|
RecordDolbyDigital = 1;
|
||||||
ChannelInfoPos = 0;
|
ChannelInfoPos = 0;
|
||||||
OSDwidth = 52;
|
OSDwidth = 52;
|
||||||
|
635
device.c
635
device.c
@ -4,108 +4,42 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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 "device.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
extern "C" {
|
|
||||||
#define HAVE_BOOLEAN
|
|
||||||
#include <jpeglib.h>
|
|
||||||
}
|
|
||||||
#include <linux/videodev.h>
|
|
||||||
#include <ost/sec.h>
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include "eit.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include "receiver.h"
|
#include "receiver.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
#include "transfer.h"
|
#include "transfer.h"
|
||||||
|
|
||||||
#define DEV_VIDEO "/dev/video"
|
// The default priority for non-primary devices:
|
||||||
#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:
|
|
||||||
#define DEFAULTPRIORITY -2
|
#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
|
// The maximum time we wait before assuming that a recorded video data stream
|
||||||
// is broken:
|
// is broken:
|
||||||
#define MAXBROKENTIMEOUT 30 // seconds
|
#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::numDevices = 0;
|
||||||
int cDevice::useDevice = 0;
|
int cDevice::useDevice = 0;
|
||||||
|
int cDevice::nextCardIndex = 0;
|
||||||
cDevice *cDevice::device[MAXDEVICES] = { NULL };
|
cDevice *cDevice::device[MAXDEVICES] = { NULL };
|
||||||
cDevice *cDevice::primaryDevice = 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
|
cardIndex = nextCardIndex++;
|
||||||
siProcessor = NULL;
|
|
||||||
cardIndex = n;
|
|
||||||
|
|
||||||
// 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;
|
active = false;
|
||||||
|
|
||||||
currentChannel = 0;
|
currentChannel = 0;
|
||||||
frequency = 0;
|
|
||||||
|
|
||||||
mute = false;
|
mute = false;
|
||||||
volume = Setup.CurrentVolume;
|
volume = Setup.CurrentVolume;
|
||||||
@ -115,17 +49,20 @@ cDevice::cDevice(int n)
|
|||||||
for (int i = 0; i < MAXRECEIVERS; i++)
|
for (int i = 0; i < MAXRECEIVERS; i++)
|
||||||
receiver[i] = NULL;
|
receiver[i] = NULL;
|
||||||
ca = -1;
|
ca = -1;
|
||||||
|
|
||||||
|
if (numDevices < MAXDEVICES) {
|
||||||
|
device[numDevices++] = this;
|
||||||
|
SetCaCaps(cardIndex);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: too many devices!");
|
||||||
}
|
}
|
||||||
|
|
||||||
cDevice::~cDevice()
|
cDevice::~cDevice()
|
||||||
{
|
{
|
||||||
delete dvrFileName;
|
|
||||||
delete siProcessor;
|
|
||||||
Detach(player);
|
Detach(player);
|
||||||
for (int i = 0; i < MAXRECEIVERS; i++)
|
for (int i = 0; i < MAXRECEIVERS; i++)
|
||||||
Detach(receiver[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)
|
void cDevice::SetUseDevice(int n)
|
||||||
@ -134,15 +71,44 @@ void cDevice::SetUseDevice(int n)
|
|||||||
useDevice |= (1 << 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)
|
bool cDevice::SetPrimaryDevice(int n)
|
||||||
{
|
{
|
||||||
n--;
|
n--;
|
||||||
if (0 <= n && n < numDevices && device[n]) {
|
if (0 <= n && n < numDevices && device[n]) {
|
||||||
isyslog("setting primary device to %d", n + 1);
|
isyslog("setting primary device to %d", n + 1);
|
||||||
|
if (primaryDevice)
|
||||||
|
primaryDevice->MakePrimaryDevice(false);
|
||||||
primaryDevice = device[n];
|
primaryDevice = device[n];
|
||||||
|
primaryDevice->MakePrimaryDevice(true);
|
||||||
return 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;
|
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++) {
|
for (int i = 0; i < numDevices; i++) {
|
||||||
if ((Provides[i] = device[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job
|
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
|
//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...
|
if (device[i]->CanBeReUsed(Frequency, Vpid)) {
|
||||||
&& 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
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
d = device[i];
|
d = device[i];
|
||||||
if (ReUse)
|
if (ReUse)
|
||||||
*ReUse = true;
|
*ReUse = true;
|
||||||
@ -204,50 +157,14 @@ cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool
|
|||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDevice::SetCaCaps(void)
|
void cDevice::SetCaCaps(int Index)
|
||||||
{
|
{
|
||||||
for (int d = 0; d < numDevices; d++) {
|
for (int d = 0; d < numDevices; d++) {
|
||||||
|
if (Index < 0 || Index == device[d]->CardIndex()) {
|
||||||
for (int i = 0; i < MAXCACAPS; i++)
|
for (int i = 0; i < MAXCACAPS; i++)
|
||||||
device[d]->caCaps[i] = Setup.CaCaps[device[d]->CardIndex()][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)
|
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)
|
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;
|
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) { 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)
|
#define PRINTPIDS(s)
|
||||||
|
|
||||||
@ -375,13 +199,12 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
|
|||||||
else if (a < 0 && i >= ptOther && !pidHandles[i].used)
|
else if (a < 0 && i >= ptOther && !pidHandles[i].used)
|
||||||
a = i;
|
a = i;
|
||||||
}
|
}
|
||||||
dmxPesType_t PesType = PesTypes[ptOther];
|
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
// The Pid is already in use
|
// The Pid is already in use
|
||||||
if (++pidHandles[n].used == 2 && n <= ptTeletext) {
|
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+
|
PRINTPIDS("A");//XXX+
|
||||||
return SetPid(pidHandles[n].fd, PesTypes[n], Pid, DMX_OUT_TS_TAP);
|
return SetPid(&pidHandles[n], n, true);
|
||||||
}
|
}
|
||||||
PRINTPIDS("a");//XXX+
|
PRINTPIDS("a");//XXX+
|
||||||
return true;
|
return true;
|
||||||
@ -389,8 +212,6 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
|
|||||||
else if (PidType < ptOther) {
|
else if (PidType < ptOther) {
|
||||||
// The Pid is not yet in use and it is a special one
|
// The Pid is not yet in use and it is a special one
|
||||||
n = PidType;
|
n = PidType;
|
||||||
PesType = PesTypes[PidType];
|
|
||||||
PRINTPIDS("B");//XXX+
|
|
||||||
}
|
}
|
||||||
else if (a >= 0) {
|
else if (a >= 0) {
|
||||||
// The Pid is not yet in use and we have a free slot
|
// 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);
|
esyslog("ERROR: no free slot for PID %d", Pid);
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
pidHandles[n].pid = Pid;
|
pidHandles[n].pid = Pid;
|
||||||
pidHandles[n].fd = OstOpen(DEV_OST_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true);
|
|
||||||
pidHandles[n].used = 1;
|
pidHandles[n].used = 1;
|
||||||
PRINTPIDS("C");//XXX+
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDevice::DelPid(int Pid)
|
void cDevice::DelPid(int Pid)
|
||||||
{
|
{
|
||||||
if (Pid) {
|
if (Pid) {
|
||||||
for (int i = 0; i < MAXPIDHANDLES; i++) {
|
for (int i = 0; i < MAXPIDHANDLES; i++) {
|
||||||
if (pidHandles[i].pid == Pid) {
|
if (pidHandles[i].pid == Pid) {
|
||||||
switch (--pidHandles[i].used) {
|
if (--pidHandles[i].used < 2) {
|
||||||
case 0: CHECK(ioctl(pidHandles[i].fd, DMX_STOP));//XXX+ is this necessary???
|
SetPid(&pidHandles[i], i, false);
|
||||||
close(pidHandles[i].fd);
|
if (pidHandles[i].used == 0) {
|
||||||
pidHandles[i].fd = -1;
|
pidHandles[i].handle = -1;
|
||||||
pidHandles[i].pid = 0;
|
pidHandles[i].pid = 0;
|
||||||
break;
|
}
|
||||||
case 1: if (i <= ptTeletext)
|
|
||||||
SetPid(pidHandles[i].fd, PesTypes[i], Pid, DMX_OUT_DECODER);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
PRINTPIDS("D");//XXX+
|
PRINTPIDS("D");//XXX+
|
||||||
return pidHandles[i].used;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
||||||
|
{
|
||||||
return false;
|
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);
|
cStatus::MsgChannelSwitch(this, 0);
|
||||||
|
|
||||||
|
StopReplay();
|
||||||
|
|
||||||
// Must set this anyway to avoid getting stuck when switching through
|
// Must set this anyway to avoid getting stuck when switching through
|
||||||
// channels with 'Up' and 'Down' keys:
|
// channels with 'Up' and 'Down' keys:
|
||||||
currentChannel = ChannelNumber;
|
currentChannel = Channel->number;
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// If this card can't receive this channel, we must not actually switch
|
// If this card can't receive this channel, we must not actually switch
|
||||||
// the channel here, because that would irritate the driver when we
|
// the channel here, because that would irritate the driver when we
|
||||||
// start replaying in Transfer Mode immediately after switching the channel:
|
// start replaying in Transfer Mode immediately after switching the channel:
|
||||||
bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Ca));
|
bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Channel->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);
|
|
||||||
|
|
||||||
eSetChannelResult Result = scrOk;
|
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:
|
// use the card that actually can receive it and transfer data from there:
|
||||||
|
|
||||||
if (NeedsTransferMode) {
|
if (NeedsTransferMode) {
|
||||||
cDevice *CaDevice = GetDevice(Ca, 0);
|
cDevice *CaDevice = GetDevice(Channel->ca, 0);
|
||||||
if (CaDevice && !CaDevice->Receiving()) {
|
if (CaDevice && !CaDevice->Receiving() && CaDevice->SetChannel(Channel) == scrOk)
|
||||||
if ((Result = CaDevice->SetChannel(ChannelNumber, Frequency, Polarization, Diseqc, Srate, Vpid, Apid, Tpid, Ca, Pnr)) == scrOk)
|
cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+
|
||||||
cControl::Launch(new cTransferControl(CaDevice, Vpid, Apid, 0, 0, 0));//XXX+
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
Result = scrNoTransfer;
|
Result = scrNoTransfer;
|
||||||
}
|
}
|
||||||
|
else if (!SetChannelDevice(Channel))
|
||||||
|
Result = scrFailed;
|
||||||
|
|
||||||
if (HasDecoder()) {
|
if (IsPrimaryDevice())
|
||||||
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
|
cSIProcessor::SetCurrentServiceID(Channel->pnr);
|
||||||
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start setting system time:
|
cStatus::MsgChannelSwitch(this, Channel->number);
|
||||||
|
|
||||||
if (Result == scrOk && siProcessor)
|
|
||||||
siProcessor->SetCurrentTransponder(Frequency);
|
|
||||||
|
|
||||||
cStatus::MsgChannelSwitch(this, ChannelNumber);
|
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cDevice::SetChannelDevice(const cChannel *Channel)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDevice::SetVolumeDevice(int Volume)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
bool cDevice::ToggleMute(void)
|
bool cDevice::ToggleMute(void)
|
||||||
{
|
{
|
||||||
int OldVolume = volume;
|
int OldVolume = volume;
|
||||||
@ -653,78 +310,40 @@ bool cDevice::ToggleMute(void)
|
|||||||
|
|
||||||
void cDevice::SetVolume(int Volume, bool Absolute)
|
void cDevice::SetVolume(int Volume, bool Absolute)
|
||||||
{
|
{
|
||||||
if (HasDecoder()) {
|
|
||||||
volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
|
volume = min(max(Absolute ? Volume : volume + Volume, 0), MAXVOLUME);
|
||||||
audioMixer_t am;
|
SetVolumeDevice(volume);
|
||||||
am.volume_left = am.volume_right = volume;
|
|
||||||
CHECK(ioctl(fd_audio, AUDIO_SET_MIXER, &am));
|
|
||||||
cStatus::MsgSetVolume(volume, Absolute);
|
cStatus::MsgSetVolume(volume, Absolute);
|
||||||
if (volume > 0)
|
if (volume > 0)
|
||||||
mute = false;
|
mute = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cDevice::SetPlayMode(bool On)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDevice::TrickSpeed(int Speed)
|
void cDevice::TrickSpeed(int Speed)
|
||||||
{
|
{
|
||||||
if (fd_video >= 0)
|
|
||||||
CHECK(ioctl(fd_video, VIDEO_SLOWMOTION, Speed));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDevice::Clear(void)
|
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)
|
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)
|
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)
|
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)
|
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)
|
bool cDevice::Replaying(void)
|
||||||
@ -741,19 +360,9 @@ bool cDevice::AttachPlayer(cPlayer *Player)
|
|||||||
if (HasDecoder()) {
|
if (HasDecoder()) {
|
||||||
if (player)
|
if (player)
|
||||||
Detach(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 = Player;
|
||||||
player->device = this;
|
player->device = this;
|
||||||
player->deviceFileHandle = fd_video;
|
player->deviceFileHandle = SetPlayMode(true);
|
||||||
player->Activate(true);
|
player->Activate(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -767,17 +376,7 @@ void cDevice::Detach(cPlayer *Player)
|
|||||||
player->deviceFileHandle = -1;
|
player->deviceFileHandle = -1;
|
||||||
player->device = NULL;
|
player->device = NULL;
|
||||||
player = NULL;
|
player = NULL;
|
||||||
|
SetPlayMode(false);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -802,14 +401,11 @@ void cDevice::StopReplay(void)
|
|||||||
|
|
||||||
int cDevice::PlayVideo(const uchar *Data, int Length)
|
int cDevice::PlayVideo(const uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
if (fd_video >= 0)
|
|
||||||
return write(fd_video, Data, Length);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cDevice::PlayAudio(const uchar *Data, int Length)
|
int cDevice::PlayAudio(const uchar *Data, int Length)
|
||||||
{
|
{
|
||||||
//XXX+
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,7 +424,7 @@ int cDevice::Priority(void)
|
|||||||
int cDevice::CanShift(int Ca, int Priority, int UsedCards)
|
int cDevice::CanShift(int Ca, int Priority, int UsedCards)
|
||||||
{
|
{
|
||||||
return -1;//XXX+ too complex with multiple recordings per device
|
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:
|
// 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
|
int ShiftLevel = -1; // default means this device can't be shifted
|
||||||
if (UsedCards & (1 << CardIndex()) != 0)
|
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());
|
dsyslog("receiver thread started on device %d (pid=%d)", CardIndex() + 1, getpid());
|
||||||
|
|
||||||
int fd_dvr = open(dvrFileName, O_RDONLY | O_NONBLOCK);
|
if (OpenDvr()) {
|
||||||
if (fd_dvr >= 0) {
|
|
||||||
pollfd pfd;
|
|
||||||
pfd.fd = fd_dvr;
|
|
||||||
pfd.events = pfd.revents = POLLIN;
|
|
||||||
uchar b[TS_SIZE];
|
uchar b[TS_SIZE];
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
active = true;
|
active = true;
|
||||||
for (; active;) {
|
for (; active;) {
|
||||||
|
|
||||||
// Read data from the DVR device:
|
// Read data from the DVR device:
|
||||||
|
int r = GetTSPacket(b);
|
||||||
if (pfd.revents & POLLIN != 0) {
|
|
||||||
int r = read(fd_dvr, b, sizeof(b));
|
|
||||||
if (r == TS_SIZE) {
|
if (r == TS_SIZE) {
|
||||||
if (*b == TS_SYNC_BYTE) {
|
if (*b == TS_SYNC_BYTE) {
|
||||||
// We're locked on to a TS packet
|
// We're locked on to a TS packet
|
||||||
@ -921,22 +510,9 @@ void cDevice::Action(void)
|
|||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
}
|
}
|
||||||
else if (r > 0)
|
else if (r > 0)
|
||||||
esyslog("ERROR: got incomplete TS packet (%d bytes)", r);//XXX+ TODO do we have to read the rest???
|
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) {
|
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;
|
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?
|
//XXX+ put this into the recorder??? or give the receiver a flag whether it wants this?
|
||||||
if (time(NULL) - t > MAXBROKENTIMEOUT) {
|
if (time(NULL) - t > MAXBROKENTIMEOUT) {
|
||||||
@ -945,14 +521,26 @@ void cDevice::Action(void)
|
|||||||
t = time(NULL);
|
t = time(NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(fd_dvr);
|
CloseDvr();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
LOG_ERROR_STR(dvrFileName);
|
|
||||||
|
|
||||||
dsyslog("receiver thread ended on device %d (pid=%d)", CardIndex() + 1, getpid());
|
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)
|
bool cDevice::AttachReceiver(cReceiver *Receiver)
|
||||||
{
|
{
|
||||||
//XXX+ check for same transponder???
|
//XXX+ check for same transponder???
|
||||||
@ -963,7 +551,6 @@ bool cDevice::AttachReceiver(cReceiver *Receiver)
|
|||||||
StopReplay();
|
StopReplay();
|
||||||
for (int i = 0; i < MAXRECEIVERS; i++) {
|
for (int i = 0; i < MAXRECEIVERS; i++) {
|
||||||
if (!receiver[i]) {
|
if (!receiver[i]) {
|
||||||
//siProcessor->SetStatus(false);//XXX+
|
|
||||||
for (int n = 0; n < MAXRECEIVEPIDS; n++)
|
for (int n = 0; n < MAXRECEIVEPIDS; n++)
|
||||||
AddPid(Receiver->pids[n]);//XXX+ retval!
|
AddPid(Receiver->pids[n]);//XXX+ retval!
|
||||||
Receiver->Activate(true);
|
Receiver->Activate(true);
|
||||||
|
205
device.h
205
device.h
@ -4,38 +4,33 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __DEVICE_H
|
||||||
#define __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 "thread.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
|
#define MAXDEVICES 16 // the maximum number of devices in the system
|
||||||
|
#define MAXCACAPS 16 // the maximum number of different CA values per device
|
||||||
#define MAXDEVICES 4 // the maximum number of devices in the system
|
#define MAXPIDHANDLES 16 // the maximum number of different PIDs per device
|
||||||
#define MAXCACAPS 16 // the maximum number of different CA values per DVB device
|
#define MAXRECEIVERS 16 // the maximum number of receivers per 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 MAXVOLUME 255
|
#define MAXVOLUME 255
|
||||||
#define VOLUMEDELTA 5 // used to increase/decrease the volume
|
#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 cPlayer;
|
||||||
class cReceiver;
|
class cReceiver;
|
||||||
|
|
||||||
class cDevice : cThread {
|
class cDevice : cThread {
|
||||||
friend class cOsd;//XXX
|
|
||||||
private:
|
private:
|
||||||
static int numDevices;
|
static int numDevices;
|
||||||
static int useDevice;
|
static int useDevice;
|
||||||
@ -43,106 +38,142 @@ private:
|
|||||||
static cDevice *primaryDevice;
|
static cDevice *primaryDevice;
|
||||||
public:
|
public:
|
||||||
static int NumDevices(void) { return numDevices; }
|
static int NumDevices(void) { return numDevices; }
|
||||||
// Returns the total number of DVB devices.
|
// Returns the total number of devices.
|
||||||
static void SetUseDevice(int n);
|
static void SetUseDevice(int n);
|
||||||
// Sets the 'useDevice' flag of the given DVB device.
|
// Sets the 'useDevice' flag of the given device.
|
||||||
// If this function is not called before Initialize(), all DVB devices
|
// If this function is not called before initializing, all devices
|
||||||
// will be used.
|
// 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);
|
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.
|
// 1...numDevices) and returns true if this was possible.
|
||||||
static cDevice *PrimaryDevice(void) { return primaryDevice; }
|
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);
|
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
|
// 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
|
// in case Ca is <= MAXDEVICES, or the device that provides the given
|
||||||
// value in its caCaps.
|
// value in its caCaps.
|
||||||
// If there is a device that is already tuned to the given Frequency,
|
// If there is a device that is already receiving and can be re-used to
|
||||||
// and that device is able to receive multiple channels ("budget" cards),
|
// receive another data stream, that device will be returned.
|
||||||
// that device will be returned. Else if a ("full featured") device is
|
// If all devices are currently receiving, the one receiving with the
|
||||||
// tuned to Frequency and Vpid, that one will be returned.
|
// lowest priority (if any) that is lower than the given Priority
|
||||||
// If all DVB devices are currently receiving, the one receiving the
|
|
||||||
// lowest priority timer (if any) that is lower than the given Priority
|
|
||||||
// will be returned.
|
// will be returned.
|
||||||
// If ReUse is given, the caller will be informed whether the device can be re-used
|
// 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
|
// 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.
|
// (the device is already properly tuned). Otherwise the caller MUST switch the channel.
|
||||||
static void SetCaCaps(void);
|
static void SetCaCaps(int Index = -1);
|
||||||
// Sets the CaCaps of all DVB devices according to the Setup data.
|
// Sets the CaCaps of the given device according to the Setup data.
|
||||||
static bool Probe(const char *FileName);
|
// By default the CaCaps of all devices are set.
|
||||||
// Probes for existing DVB devices.
|
|
||||||
static bool Initialize(void);
|
|
||||||
// Initializes the DVB devices.
|
|
||||||
// Must be called before accessing any DVB functions.
|
|
||||||
static void Shutdown(void);
|
static void Shutdown(void);
|
||||||
// Closes down all DVB devices.
|
// Closes down all devices.
|
||||||
// Must be called at the end of the program.
|
// Must be called at the end of the program.
|
||||||
private:
|
private:
|
||||||
|
static int nextCardIndex;
|
||||||
int cardIndex;
|
int cardIndex;
|
||||||
int caCaps[MAXCACAPS];
|
int caCaps[MAXCACAPS];
|
||||||
FrontendType frontendType;
|
protected:
|
||||||
char *dvrFileName;
|
cDevice(void);
|
||||||
bool active;
|
|
||||||
int fd_osd, fd_frontend, fd_sec, fd_audio, fd_video;
|
|
||||||
int OsdDeviceHandle(void) { return fd_osd; }
|
|
||||||
public:
|
|
||||||
cDevice(int n);
|
|
||||||
virtual ~cDevice();
|
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; }
|
bool IsPrimaryDevice(void) const { return this == primaryDevice; }
|
||||||
int CardIndex(void) const { return cardIndex; }
|
int CardIndex(void) const { return cardIndex; }
|
||||||
// Returns the card index of this device (0 ... MAXDEVICES - 1).
|
// Returns the card index of this device (0 ... MAXDEVICES - 1).
|
||||||
int ProvidesCa(int Ca);
|
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
|
// 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.
|
// 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
|
// 1 is returned. If it is 0 (FTA), 1 plus the number of other values
|
||||||
// in caCaps is returned.
|
// 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
|
// Channel facilities
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
int currentChannel;
|
int currentChannel;
|
||||||
int frequency;
|
|
||||||
public:
|
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; }
|
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; }
|
int Channel(void) { return currentChannel; }
|
||||||
|
// Returns the number of the current channel on this device.
|
||||||
|
|
||||||
// PID handle facilities
|
// PID handle facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool active;
|
||||||
|
virtual void Action(void);
|
||||||
|
protected:
|
||||||
enum ePidType { ptVideo, ptAudio, ptTeletext, ptDolby, ptOther };
|
enum ePidType { ptVideo, ptAudio, ptTeletext, ptDolby, ptOther };
|
||||||
class cPidHandle {
|
class cPidHandle {
|
||||||
public:
|
public:
|
||||||
int pid;
|
int pid;
|
||||||
int fd;
|
int handle;
|
||||||
int used;
|
int used;
|
||||||
cPidHandle(void) { pid = used = 0; fd = -1; }
|
cPidHandle(void) { pid = used = 0; handle = -1; }
|
||||||
};
|
};
|
||||||
cPidHandle pidHandles[MAXPIDHANDLES];
|
cPidHandle pidHandles[MAXPIDHANDLES];
|
||||||
bool AddPid(int Pid, ePidType PidType = ptOther);
|
bool AddPid(int Pid, ePidType PidType = ptOther);
|
||||||
bool DelPid(int Pid);
|
// Adds a PID to the set of PIDs this device shall receive.
|
||||||
bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output);
|
void DelPid(int Pid);
|
||||||
virtual void Action(void);
|
// 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
|
// Image Grab facilities
|
||||||
|
|
||||||
public:
|
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
|
// Video format facilities
|
||||||
|
|
||||||
public:
|
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
|
// Volume facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mute;
|
bool mute;
|
||||||
int volume;
|
int volume;
|
||||||
|
protected:
|
||||||
|
virtual void SetVolumeDevice(int Volume);
|
||||||
|
// Sets the audio volume on this device (Volume = 0...255).
|
||||||
public:
|
public:
|
||||||
bool IsMute(void) { return mute; }
|
bool IsMute(void) { return mute; }
|
||||||
bool ToggleMute(void);
|
bool ToggleMute(void);
|
||||||
@ -152,30 +183,46 @@ public:
|
|||||||
// the current volume.
|
// the current volume.
|
||||||
static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
|
static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
|
||||||
|
|
||||||
// EIT facilities
|
|
||||||
|
|
||||||
private:
|
|
||||||
cSIProcessor *siProcessor;
|
|
||||||
|
|
||||||
// Player facilities
|
// Player facilities
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cPlayer *player;
|
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:
|
public:
|
||||||
void TrickSpeed(int Speed);
|
virtual void TrickSpeed(int Speed);
|
||||||
void Clear(void);
|
// Sets the device into a mode where replay is done slower.
|
||||||
void Play(void);
|
// Every single frame shall then be displayed the given number of
|
||||||
void Freeze(void);
|
// times.
|
||||||
void Mute(void);
|
virtual void Clear(void);
|
||||||
void StillPicture(const uchar *Data, int Length);
|
// 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);
|
bool Replaying(void);
|
||||||
// Returns true if we are currently replaying.
|
// Returns true if we are currently replaying.
|
||||||
void StopReplay(void);
|
void StopReplay(void);
|
||||||
// Stops the current replay session (if any).
|
// Stops the current replay session (if any).
|
||||||
bool AttachPlayer(cPlayer *Player);
|
bool AttachPlayer(cPlayer *Player);
|
||||||
|
// Attaches the given player to this device.
|
||||||
void Detach(cPlayer *Player);
|
void Detach(cPlayer *Player);
|
||||||
virtual int PlayVideo(const uchar *Data, int Length);
|
// Detaches the given player from this device.
|
||||||
virtual int PlayAudio(const uchar *Data, int Length);
|
|
||||||
|
|
||||||
// Receiver facilities
|
// Receiver facilities
|
||||||
|
|
||||||
@ -184,16 +231,30 @@ private:
|
|||||||
int ca;
|
int ca;
|
||||||
int Priority(void);
|
int Priority(void);
|
||||||
// Returns the priority of the current receiving session (0..MAXPRIORITY),
|
// 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.
|
// always return at least Setup.PrimaryLimit-1.
|
||||||
int CanShift(int Ca, int Priority, int UsedCards = 0);
|
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:
|
public:
|
||||||
int Ca(void) { return ca; }
|
int Ca(void) { return ca; }
|
||||||
// Returns the ca of the current receiving session.
|
// Returns the ca of the current receiving session.
|
||||||
bool Receiving(void);
|
bool Receiving(void);
|
||||||
// Returns true if we are currently receiving.
|
// Returns true if we are currently receiving.
|
||||||
bool AttachReceiver(cReceiver *Receiver);
|
bool AttachReceiver(cReceiver *Receiver);
|
||||||
|
// Attaches the given receiver to this device.
|
||||||
void Detach(cReceiver *Receiver);
|
void Detach(cReceiver *Receiver);
|
||||||
|
// Detaches the given receiver from this device.
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__DEVICE_H
|
#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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "dvbosd.h"
|
||||||
@ -13,10 +13,12 @@
|
|||||||
#include <sys/unistd.h>
|
#include <sys/unistd.h>
|
||||||
#include "tools.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)
|
:cOsdBase(x, y)
|
||||||
{
|
{
|
||||||
osdDev = OsdDev;
|
osdDev = dvbDevice ? dvbDevice->OsdDeviceHandle() : -1;
|
||||||
if (osdDev < 0)
|
if (osdDev < 0)
|
||||||
esyslog("ERROR: illegal OSD device handle (%d)!", osdDev);
|
esyslog("ERROR: illegal OSD device handle (%d)!", osdDev);
|
||||||
}
|
}
|
||||||
@ -27,6 +29,11 @@ cDvbOsd::~cDvbOsd()
|
|||||||
CloseWindow(GetWindowNr(i));
|
CloseWindow(GetWindowNr(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cDvbOsd::SetDvbDevice(const cDvbDevice *DvbDevice)
|
||||||
|
{
|
||||||
|
dvbDevice = DvbDevice;
|
||||||
|
}
|
||||||
|
|
||||||
bool cDvbOsd::SetWindow(cWindow *Window)
|
bool cDvbOsd::SetWindow(cWindow *Window)
|
||||||
{
|
{
|
||||||
if (Window) {
|
if (Window) {
|
||||||
|
7
dvbosd.h
7
dvbosd.h
@ -4,17 +4,19 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __DVBOSD_H
|
||||||
#define __DVBOSD_H
|
#define __DVBOSD_H
|
||||||
|
|
||||||
#include <ost/osd.h>
|
#include <ost/osd.h>
|
||||||
|
#include "dvbdevice.h"
|
||||||
#include "osdbase.h"
|
#include "osdbase.h"
|
||||||
|
|
||||||
class cDvbOsd : public cOsdBase {
|
class cDvbOsd : public cOsdBase {
|
||||||
private:
|
private:
|
||||||
|
static const cDvbDevice *dvbDevice;
|
||||||
int osdDev;
|
int osdDev;
|
||||||
bool SetWindow(cWindow *Window);
|
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);
|
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 MoveWindow(cWindow *Window, int x, int y);
|
||||||
virtual void CloseWindow(cWindow *Window);
|
virtual void CloseWindow(cWindow *Window);
|
||||||
public:
|
public:
|
||||||
cDvbOsd(int OsdDev, int x, int y);
|
cDvbOsd(int x, int y);
|
||||||
virtual ~cDvbOsd();
|
virtual ~cDvbOsd();
|
||||||
|
static void SetDvbDevice(const cDvbDevice *DvbDevice);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //__DVBOSD_H
|
#endif //__DVBOSD_H
|
||||||
|
4
eit.h
4
eit.h
@ -16,7 +16,7 @@
|
|||||||
* the Free Software Foundation; either version 2 of the License, or *
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
* (at your option) any later version. *
|
* (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
|
#ifndef __EIT_H
|
||||||
@ -158,7 +158,7 @@ public:
|
|||||||
static bool Read(FILE *f = NULL);
|
static bool Read(FILE *f = NULL);
|
||||||
void SetStatus(bool On);
|
void SetStatus(bool On);
|
||||||
void SetCurrentTransponder(int CurrentTransponder);
|
void SetCurrentTransponder(int CurrentTransponder);
|
||||||
bool SetCurrentServiceID(unsigned short servid);
|
static bool SetCurrentServiceID(unsigned short servid);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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 "eitscan.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
cEITScanner::cEITScanner(void)
|
cEITScanner::cEITScanner(void)
|
||||||
{
|
{
|
||||||
|
4
menu.c
4
menu.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "menu.h"
|
||||||
@ -1628,7 +1628,7 @@ eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
|
|||||||
if (state == osBack && Key == kOk) {
|
if (state == osBack && Key == kOk) {
|
||||||
if (Setup.PrimaryDVB != oldPrimaryDVB) {
|
if (Setup.PrimaryDVB != oldPrimaryDVB) {
|
||||||
state = osSwitchDvb;
|
state = osSwitchDvb;
|
||||||
cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
|
cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
|
4
osd.c
4
osd.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "osd.h"
|
||||||
@ -73,7 +73,7 @@ cOsdBase *cOsd::OpenRaw(int x, int y)
|
|||||||
#ifdef DEBUG_OSD
|
#ifdef DEBUG_OSD
|
||||||
return NULL;
|
return NULL;
|
||||||
#else
|
#else
|
||||||
return osd ? NULL : new cDvbOsd(cDevice::PrimaryDevice()->OsdDeviceHandle(), x, y);
|
return osd ? NULL : new cDvbOsd(x, y);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,13 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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 <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "receiver.h"
|
#include "receiver.h"
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
cReceiver::cReceiver(int Ca, int Priority, int NumPids, ...)
|
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
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __REMUX_H
|
||||||
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <time.h> //XXX FIXME: DVB/ost/include/ost/dmx.h should include <time.h> itself!!!
|
#include <time.h> //XXX FIXME: DVB/ost/include/ost/dmx.h should include <time.h> itself!!!
|
||||||
#include <ost/dmx.h>
|
#include <ost/dmx.h>
|
||||||
|
#include "tools.h"
|
||||||
|
|
||||||
// Picture types:
|
// Picture types:
|
||||||
#define NO_PICTURE 0
|
#define NO_PICTURE 0
|
||||||
@ -24,7 +25,6 @@
|
|||||||
|
|
||||||
#define RESULTBUFFERSIZE (MINVIDEODATA * 4)
|
#define RESULTBUFFERSIZE (MINVIDEODATA * 4)
|
||||||
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
class cTS2PES;
|
class cTS2PES;
|
||||||
|
|
||||||
class cRemux {
|
class cRemux {
|
||||||
|
@ -4,15 +4,14 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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
|
#ifndef __RINGBUFFER_H
|
||||||
#define __RINGBUFFER_H
|
#define __RINGBUFFER_H
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "tools.h"
|
||||||
typedef unsigned char uchar;//XXX+
|
|
||||||
|
|
||||||
class cRingBuffer {
|
class cRingBuffer {
|
||||||
private:
|
private:
|
||||||
|
4
tools.c
4
tools.c
@ -4,7 +4,7 @@
|
|||||||
* See the main source file 'vdr.c' for copyright information and
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
* how to reach the author.
|
* 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"
|
#include "tools.h"
|
||||||
@ -407,7 +407,7 @@ bool RemoveEmptyDirectories(const char *DirName, bool RemoveThis)
|
|||||||
|
|
||||||
char *ReadLink(const char *FileName)
|
char *ReadLink(const char *FileName)
|
||||||
{
|
{
|
||||||
char RealName[_POSIX_PATH_MAX];
|
char RealName[PATH_MAX];
|
||||||
const char *TargetName = NULL;
|
const char *TargetName = NULL;
|
||||||
int n = readlink(FileName, RealName, sizeof(RealName) - 1);
|
int n = readlink(FileName, RealName, sizeof(RealName) - 1);
|
||||||
if (n < 0) {
|
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
|
* 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>
|
#include <getopt.h>
|
||||||
@ -33,6 +33,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "cutter.h"
|
#include "cutter.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "dvbdevice.h"
|
||||||
#include "eitscan.h"
|
#include "eitscan.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
@ -326,11 +327,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// DVB interfaces:
|
// DVB interfaces:
|
||||||
|
|
||||||
if (!cDevice::Initialize())
|
if (!cDvbDevice::Initialize())
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
|
|
||||||
|
|
||||||
cSIProcessor::Read();
|
cSIProcessor::Read();
|
||||||
|
|
||||||
// Start plugins:
|
// Start plugins:
|
||||||
@ -338,6 +337,10 @@ int main(int argc, char *argv[])
|
|||||||
if (!PluginManager.StartPlugins())
|
if (!PluginManager.StartPlugins())
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
|
// Primary device:
|
||||||
|
|
||||||
|
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
|
||||||
|
|
||||||
// OSD:
|
// OSD:
|
||||||
|
|
||||||
cOsd::Initialize();
|
cOsd::Initialize();
|
||||||
|
Loading…
Reference in New Issue
Block a user