mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Implemented recording and replaying with a single DVB card
This commit is contained in:
parent
1967d0cd3d
commit
3e58bc64fe
9
HISTORY
9
HISTORY
@ -1431,9 +1431,16 @@ Video Disk Recorder Revision History
|
||||
time changed into the future (thanks to Matthias Schniedermeyer for reporting
|
||||
this one).
|
||||
|
||||
2002-08-28: Version 1.1.9
|
||||
2002-09-04: Version 1.1.9
|
||||
|
||||
- Fixed the 'newplugin' script to make it name the target for creating the
|
||||
distribution package 'dist', as stated in the PLUGINS.html documentation.
|
||||
If you have already created a plugin source directory and Makefile you may
|
||||
want to check it and replace the 'package' target with 'dist' if necessary.
|
||||
- Changed device handling for being able to do simultaneous recording and
|
||||
replay on the same device (Time Shifting). In order for this to work you need
|
||||
to use a driver with a firmware version that has this feature implemented.
|
||||
- cDevice::ProvidesCa() is no longer virtual. The new function
|
||||
cDevice::ProvidesChannel() is now used to determine whether a device can
|
||||
receive a given channel, and by default this function returns false. So a
|
||||
device that is a pure replaying device doesn't need to do anything here.
|
||||
|
46
PLUGINS.html
46
PLUGINS.html
@ -21,18 +21,18 @@ VDR program and present itself to the user.
|
||||
The <i>inside</i> interface provides the plugin code access to VDR's internal data
|
||||
structures and allows it to hook itself into specific areas to perform special actions.
|
||||
<p>
|
||||
<!--X1.1.5--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
|
||||
Important modifications introduced in version 1.1.5 are marked like this.
|
||||
<!--X1.1.5--></td></tr></table>
|
||||
<!--X1.1.6--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
|
||||
<!--X1.1.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
|
||||
Important modifications introduced in version 1.1.6 are marked like this.
|
||||
<!--X1.1.6--></td></tr></table>
|
||||
<!--X1.1.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||
<!--X1.1.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
|
||||
Important modifications introduced in version 1.1.7 are marked like this.
|
||||
<!--X1.1.7--></td></tr></table>
|
||||
<!--X1.1.8--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||
<!--X1.1.8--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||
Important modifications introduced in version 1.1.8 are marked like this.
|
||||
<!--X1.1.8--></td></tr></table>
|
||||
<!--X1.1.9--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||
Important modifications introduced in version 1.1.9 are marked like this.
|
||||
<!--X1.1.9--></td></tr></table>
|
||||
|
||||
<a name="Part I - The Outside Interface"><hr><center><h1>Part I - The Outside Interface</h1></center>
|
||||
|
||||
@ -352,20 +352,20 @@ these values inside the plugin. Here's an example:
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
bool cPluginHello::ProcessArgs(int argc, char *argv[])
|
||||
{
|
||||
{
|
||||
// Implement command line argument processing here if applicable.
|
||||
static struct option long_options[] = {
|
||||
{ "aaa", required_argument, NULL, 'a' },
|
||||
{ "bbb", no_argument, NULL, 'b' },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 'a': option_a = optarg;
|
||||
break;
|
||||
case 'b': option_b = true;
|
||||
case 'b': option_b = true;
|
||||
break;
|
||||
default: return false;
|
||||
}
|
||||
@ -609,7 +609,7 @@ public:
|
||||
};
|
||||
|
||||
cMenuSetupHello::cMenuSetupHello(void)
|
||||
{
|
||||
{
|
||||
newGreetingTime = GreetingTime;
|
||||
newUseAlternateGreeting = UseAlternateGreeting;
|
||||
Add(new cMenuEditIntItem( tr("Greeting time (s)"), &newGreetingTime));
|
||||
@ -617,7 +617,7 @@ cMenuSetupHello::cMenuSetupHello(void)
|
||||
}
|
||||
|
||||
void cMenuSetupHello::Store(void)
|
||||
{
|
||||
{
|
||||
SetupStore("GreetingTime", GreetingTime = newGreetingTime);
|
||||
SetupStore("UseAlternateGreeting", UseAlternateGreeting = newUseAlternateGreeting);
|
||||
}
|
||||
@ -957,7 +957,7 @@ stream. There are no prerequisites regarding the length or alignment of an
|
||||
individual block of data. The sum of all blocks must simply result in the
|
||||
desired video data stream, and it must be delivered fast enough so that the
|
||||
DVB device doesn't run out of data.
|
||||
<!--X1.1.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||
<!--X1.1.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
|
||||
To avoid busy loops the player should call its member function
|
||||
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
@ -1034,7 +1034,7 @@ void DeviceStillPicture(const uchar *Data, int Length);
|
||||
|
||||
which can be called to display a still picture. VDR uses this function when handling
|
||||
its editing marks. A special case of a "player" might use this function to implement
|
||||
a "picture viewer".
|
||||
a "picture viewer".
|
||||
<p>
|
||||
For detailed information on how to implement your own player, please take a look
|
||||
at VDR's <tt>cDvbPlayer</tt> and <tt>cDvbPlayerControl</tt> classes.
|
||||
@ -1065,7 +1065,7 @@ enjoy additional players, since they will be able to control them with actions
|
||||
that they already know. If you absolutely want to do things differently, just go
|
||||
ahead - it's your show...
|
||||
|
||||
<!--X1.1.6--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
|
||||
<!--X1.1.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
|
||||
<hr><h2>Receivers</h2>
|
||||
|
||||
<center><i><b>Tapping into the stream...</b></i></center><p>
|
||||
@ -1121,7 +1121,6 @@ If the <tt>cReceiver</tt> isn't needed any more, it may simply be <i>deleted</i>
|
||||
and will automatically detach itself from the <tt>cDevice</tt>.
|
||||
<!--X1.1.6--></td></tr></table>
|
||||
|
||||
<!--X1.1.5--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
|
||||
<hr><h2>The On Screen Display</h2>
|
||||
|
||||
<center><i><b>Express yourself</b></i></center><p>
|
||||
@ -1151,9 +1150,8 @@ MyOsd->Create(...);
|
||||
to define an actual OSD drawing area (see VDR/osdbase.h for the declarations
|
||||
of these functions, and VDR/osd.c to see how VDR opens the OSD and sets up
|
||||
its windows and color depths).
|
||||
<!--X1.1.5--></td></tr></table>
|
||||
|
||||
<!--X1.1.6--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
|
||||
<!--X1.1.6--><table width=100%><tr><td bgcolor=#0000AA> </td><td width=100%>
|
||||
<hr><h2>Devices</h2>
|
||||
|
||||
<center><i><b>Expanding the possibilities</b></i></center><p>
|
||||
@ -1189,12 +1187,16 @@ the <tt>cDvbDevice</tt>, which is used to access the DVB PCI cards.
|
||||
If the new device can receive, it most likely needs to provide a way of
|
||||
selecting which channel it shall tune to:
|
||||
|
||||
<!--X1.1.9--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
virtual bool SetChannelDevice(const cChannel *Channel);
|
||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL);
|
||||
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
This function will be called with the desired channel and shall return whether
|
||||
tuning to it was successful.
|
||||
These functions will be called with the desired channel and shall return whether
|
||||
this device can provide the requested channel and whether tuning to it was successful,
|
||||
repectively.
|
||||
<!--X1.1.9--></td></tr></table>
|
||||
<p>
|
||||
<b>Recording</b>
|
||||
<p>
|
||||
@ -1226,7 +1228,7 @@ to indicate this to VDR.
|
||||
<p>
|
||||
The functions to implement replaying capabilites are
|
||||
|
||||
<!--X1.1.7--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||
<!--X1.1.7--><table width=100%><tr><td bgcolor=#00AA00> </td><td width=100%>
|
||||
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
|
||||
virtual bool HasDecoder(void) const;
|
||||
virtual bool SetPlayMode(ePlayMode PlayMode);
|
||||
@ -1250,7 +1252,7 @@ virtual void SetVideoFormat(bool VideoFormat16_9);
|
||||
virtual void SetVolumeDevice(int Volume);
|
||||
</pre></td></tr></table><p>
|
||||
|
||||
<!--X1.1.8--><table width=100%><tr><td bgcolor=#FF0000> </td><td width=100%>
|
||||
<!--X1.1.8--><table width=100%><tr><td bgcolor=#AA0000> </td><td width=100%>
|
||||
<p>
|
||||
<b>On Screen Display</b>
|
||||
<p>
|
||||
|
32
config.c
32
config.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.c 1.104 2002/08/11 11:35:18 kls Exp $
|
||||
* $Id: config.c 1.105 2002/09/04 13:45:56 kls Exp $
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
@ -293,30 +293,6 @@ bool cChannel::Save(FILE *f)
|
||||
return fprintf(f, ToText()) > 0;
|
||||
}
|
||||
|
||||
bool cChannel::Switch(cDevice *Device, bool Log)
|
||||
{
|
||||
if (!Device)
|
||||
Device = cDevice::PrimaryDevice();
|
||||
if (!(Device->IsPrimaryDevice() && Device->Receiving()) && !groupSep) {
|
||||
if (Log)
|
||||
isyslog("switching to channel %d", number);
|
||||
for (int i = 3; i--;) {
|
||||
switch (Device->SetChannel(this)) {
|
||||
case scrOk: return true;
|
||||
case scrNoTransfer: if (Interface)
|
||||
Interface->Error(tr("Can't start Transfer Mode!"));
|
||||
return false;
|
||||
case scrFailed: break; // loop will retry
|
||||
}
|
||||
esyslog("retrying");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (Device->IsPrimaryDevice() && Device->Receiving())
|
||||
Interface->Error(tr("Channel locked (recording)!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// -- cTimer -----------------------------------------------------------------
|
||||
|
||||
char *cTimer::buffer = NULL;
|
||||
@ -836,10 +812,10 @@ cChannel *cChannels::GetByServiceID(unsigned short ServiceId)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool cChannels::SwitchTo(int Number, cDevice *Device)
|
||||
bool cChannels::SwitchTo(int Number)
|
||||
{
|
||||
cChannel *channel = GetByNumber(Number);
|
||||
return channel && channel->Switch(Device);
|
||||
return channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true);
|
||||
}
|
||||
|
||||
const char *cChannels::GetChannelNameByNumber(int Number)
|
||||
@ -944,7 +920,7 @@ bool cSetupLine::operator< (const cListObject &ListObject)
|
||||
{
|
||||
const cSetupLine *sl = (cSetupLine *)&ListObject;
|
||||
if (!plugin && !sl->plugin)
|
||||
return strcasecmp(name, sl->name) < 0;
|
||||
return strcasecmp(name, sl->name) < 0;
|
||||
if (!plugin)
|
||||
return true;
|
||||
if (!sl->plugin)
|
||||
|
7
config.h
7
config.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: config.h 1.125 2002/08/28 19:26:56 kls Exp $
|
||||
* $Id: config.h 1.126 2002/09/04 11:04:55 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
@ -119,7 +119,6 @@ public:
|
||||
const char *ToText(void);
|
||||
bool Parse(const char *s);
|
||||
bool Save(FILE *f);
|
||||
bool Switch(cDevice *Device = NULL, bool Log = true);
|
||||
};
|
||||
|
||||
enum eTimerActive { taInactive = 0,
|
||||
@ -198,6 +197,8 @@ public:
|
||||
bool Accepts(in_addr_t Address);
|
||||
};
|
||||
|
||||
#define CACONFBASE 100
|
||||
|
||||
class cCaDefinition : public cListObject {
|
||||
private:
|
||||
int number;
|
||||
@ -296,7 +297,7 @@ public:
|
||||
cChannel *GetByNumber(int Number);
|
||||
cChannel *GetByServiceID(unsigned short ServiceId);
|
||||
const char *GetChannelNameByNumber(int Number);
|
||||
bool SwitchTo(int Number, cDevice *Device = NULL);
|
||||
bool SwitchTo(int Number);
|
||||
int MaxNumber(void) { return maxNumber; }
|
||||
};
|
||||
|
||||
|
128
device.c
128
device.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: device.c 1.13 2002/08/25 09:16:51 kls Exp $
|
||||
* $Id: device.c 1.14 2002/09/04 17:26:02 kls Exp $
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
@ -12,6 +12,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include "eit.h"
|
||||
#include "i18n.h"
|
||||
#include "player.h"
|
||||
#include "receiver.h"
|
||||
#include "status.h"
|
||||
@ -101,11 +102,6 @@ bool cDevice::SetPrimaryDevice(int n)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDevice::CanBeReUsed(int Frequency, int Vpid)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDevice::HasDecoder(void) const
|
||||
{
|
||||
return false;
|
||||
@ -116,31 +112,26 @@ cOsdBase *cDevice::NewOsd(int x, int y)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cDevice *cDevice::GetDevice(int Ca, int Priority, int Frequency, int Vpid, bool *ReUse)
|
||||
cDevice *cDevice::GetDevice(int Index)
|
||||
{
|
||||
return (0 <= Index && Index < numDevices) ? device[Index] : NULL;
|
||||
}
|
||||
|
||||
cDevice *cDevice::GetDevice(const cChannel *Channel, int Priority, bool *NeedsSwitchChannel)
|
||||
{
|
||||
if (ReUse)
|
||||
*ReUse = false;
|
||||
cDevice *d = NULL;
|
||||
int Provides[MAXDEVICES];
|
||||
// Check which devices provide Ca:
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
if ((Provides[i] = device[i]->ProvidesCa(Ca)) != 0) { // this device is basicly able to do the job
|
||||
//XXX+ dsyslog("GetDevice: %d %d %d %5d %5d", i, device[i]->HasDecoder(), device[i]->Receiving(), Frequency, device[i]->frequency);//XXX
|
||||
if (device[i]->CanBeReUsed(Frequency, Vpid)) {
|
||||
d = device[i];
|
||||
if (ReUse)
|
||||
*ReUse = true;
|
||||
break;
|
||||
}
|
||||
if (Priority > device[i]->Priority() // Priority is high enough to use this device
|
||||
&& (!d // we don't have a device yet, or...
|
||||
|| device[i]->Priority() < d->Priority() // ...this one has an even lower Priority
|
||||
|| (device[i]->Priority() == d->Priority() // ...same Priority...
|
||||
&& Provides[i] < Provides[d->CardIndex()] // ...but this one provides fewer Ca values
|
||||
)
|
||||
)
|
||||
bool nsc;
|
||||
if (device[i]->ProvidesChannel(Channel, Priority, &nsc) // this device is basicly able to do the job
|
||||
&& (!d // we don't have a device yet, or...
|
||||
|| device[i]->Priority() < d->Priority() // ...this one has an even lower Priority, or...
|
||||
|| device[i]->Priority() == d->Priority() // ...same Priority...
|
||||
&& device[i]->ProvidesCa(Channel->ca) < d->ProvidesCa(Channel->ca) // ...but this one provides fewer Ca values
|
||||
)
|
||||
d = device[i];
|
||||
) {
|
||||
d = device[i];
|
||||
if (NeedsSwitchChannel)
|
||||
*NeedsSwitchChannel = nsc;
|
||||
}
|
||||
}
|
||||
/*XXX+ too complex with multiple recordings per device
|
||||
@ -189,9 +180,18 @@ void cDevice::SetVideoFormat(bool VideoFormat16_9)
|
||||
{
|
||||
}
|
||||
|
||||
//#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); }
|
||||
#define PRINTPIDS(s)
|
||||
|
||||
bool cDevice::HasPid(int Pid)
|
||||
{
|
||||
for (int i = 0; i < MAXPIDHANDLES; i++) {
|
||||
if (pidHandles[i].pid == Pid)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDevice::AddPid(int Pid, ePidType PidType)
|
||||
{
|
||||
if (Pid) {
|
||||
@ -207,10 +207,10 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
|
||||
// The Pid is already in use
|
||||
if (++pidHandles[n].used == 2 && n <= ptTeletext) {
|
||||
// It's a special PID that may have to be switched into "tap" mode
|
||||
PRINTPIDS("A");//XXX+
|
||||
PRINTPIDS("A");
|
||||
return SetPid(&pidHandles[n], n, true);
|
||||
}
|
||||
PRINTPIDS("a");//XXX+
|
||||
PRINTPIDS("a");
|
||||
return true;
|
||||
}
|
||||
else if (PidType < ptOther) {
|
||||
@ -226,7 +226,7 @@ bool cDevice::AddPid(int Pid, ePidType PidType)
|
||||
if (n >= 0) {
|
||||
pidHandles[n].pid = Pid;
|
||||
pidHandles[n].used = 1;
|
||||
PRINTPIDS("C");//XXX+
|
||||
PRINTPIDS("C");
|
||||
return SetPid(&pidHandles[n], n, true);
|
||||
}
|
||||
}
|
||||
@ -238,14 +238,15 @@ void cDevice::DelPid(int Pid)
|
||||
if (Pid) {
|
||||
for (int i = 0; i < MAXPIDHANDLES; i++) {
|
||||
if (pidHandles[i].pid == Pid) {
|
||||
PRINTPIDS("D");
|
||||
if (--pidHandles[i].used < 2) {
|
||||
SetPid(&pidHandles[i], i, false);
|
||||
if (pidHandles[i].used == 0) {
|
||||
pidHandles[i].handle = -1;
|
||||
pidHandles[i].pid = 0;
|
||||
}
|
||||
pidHandles[i].handle = -1;
|
||||
pidHandles[i].pid = 0;
|
||||
}
|
||||
}
|
||||
PRINTPIDS("D");//XXX+
|
||||
PRINTPIDS("E");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -256,11 +257,35 @@ bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
||||
return false;
|
||||
}
|
||||
|
||||
eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
|
||||
bool cDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsSwitchChannel)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cDevice::SwitchChannel(const cChannel *Channel, bool LiveView)
|
||||
{
|
||||
if (LiveView)
|
||||
isyslog("switching to channel %d", Channel->number);
|
||||
for (int i = 3; i--;) {
|
||||
switch (SetChannel(Channel, LiveView)) {
|
||||
case scrOk: return true;
|
||||
case scrNotAvailable: return false;
|
||||
case scrNoTransfer: if (Interface)
|
||||
Interface->Error(tr("Can't start Transfer Mode!"));
|
||||
return false;
|
||||
case scrFailed: break; // loop will retry
|
||||
}
|
||||
esyslog("retrying");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView)
|
||||
{
|
||||
cStatus::MsgChannelSwitch(this, 0);
|
||||
|
||||
StopReplay();
|
||||
if (LiveView)
|
||||
StopReplay();
|
||||
|
||||
// Must set this anyway to avoid getting stuck when switching through
|
||||
// channels with 'Up' and 'Down' keys:
|
||||
@ -269,7 +294,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
|
||||
// If this card can't receive this channel, we must not actually switch
|
||||
// the channel here, because that would irritate the driver when we
|
||||
// start replaying in Transfer Mode immediately after switching the channel:
|
||||
bool NeedsTransferMode = (IsPrimaryDevice() && !ProvidesCa(Channel->ca));
|
||||
bool NeedsTransferMode = (LiveView && IsPrimaryDevice() && !ProvidesChannel(Channel, Setup.PrimaryLimit));
|
||||
|
||||
eSetChannelResult Result = scrOk;
|
||||
|
||||
@ -277,13 +302,18 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
|
||||
// use the card that actually can receive it and transfer data from there:
|
||||
|
||||
if (NeedsTransferMode) {
|
||||
cDevice *CaDevice = GetDevice(Channel->ca, 0);
|
||||
if (CaDevice && !CaDevice->Receiving() && CaDevice->SetChannel(Channel) == scrOk)
|
||||
cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+
|
||||
bool NeedsSwitchChannel = false;
|
||||
cDevice *CaDevice = GetDevice(Channel, 0, &NeedsSwitchChannel);
|
||||
if (CaDevice) {
|
||||
if (!NeedsSwitchChannel || CaDevice->SetChannel(Channel, false) == scrOk) // calling SetChannel() directly, not SwitchChannel()!
|
||||
cControl::Launch(new cTransferControl(CaDevice, Channel->vpid, Channel->apid1, 0, 0, 0));//XXX+
|
||||
else
|
||||
Result = scrNoTransfer;
|
||||
}
|
||||
else
|
||||
Result = scrNoTransfer;
|
||||
Result = scrNotAvailable;
|
||||
}
|
||||
else if (!SetChannelDevice(Channel))
|
||||
else if (!SetChannelDevice(Channel, LiveView))
|
||||
Result = scrFailed;
|
||||
|
||||
if (IsPrimaryDevice())
|
||||
@ -294,7 +324,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel)
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool cDevice::SetChannelDevice(const cChannel *Channel)
|
||||
bool cDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -357,10 +387,6 @@ bool cDevice::Replaying(void)
|
||||
|
||||
bool cDevice::AttachPlayer(cPlayer *Player)
|
||||
{
|
||||
if (Receiving()) {
|
||||
esyslog("ERROR: attempt to attach a cPlayer while receiving on device %d - ignored", CardIndex() + 1);
|
||||
return false;
|
||||
}
|
||||
if (HasDecoder()) {
|
||||
if (player)
|
||||
Detach(player);
|
||||
@ -419,9 +445,7 @@ int cDevice::PlayAudio(const uchar *Data, int Length)
|
||||
|
||||
int cDevice::Priority(void)
|
||||
{
|
||||
if (IsPrimaryDevice() && !Receiving())
|
||||
return Setup.PrimaryLimit - 1;
|
||||
int priority = DEFAULTPRIORITY;
|
||||
int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY;
|
||||
for (int i = 0; i < MAXRECEIVERS; i++) {
|
||||
if (receiver[i])
|
||||
priority = max(receiver[i]->priority, priority);
|
||||
@ -551,12 +575,10 @@ int cDevice::GetTSPacket(uchar *Data)
|
||||
|
||||
bool cDevice::AttachReceiver(cReceiver *Receiver)
|
||||
{
|
||||
//XXX+ check for same transponder???
|
||||
if (!Receiver)
|
||||
return false;
|
||||
if (Receiver->device == this)
|
||||
return true;
|
||||
StopReplay();
|
||||
for (int i = 0; i < MAXRECEIVERS; i++) {
|
||||
if (!receiver[i]) {
|
||||
for (int n = 0; n < MAXRECEIVEPIDS; n++)
|
||||
|
64
device.h
64
device.h
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: device.h 1.10 2002/08/25 09:16:34 kls Exp $
|
||||
* $Id: device.h 1.11 2002/09/04 11:33:12 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __DEVICE_H
|
||||
@ -24,7 +24,7 @@
|
||||
#define TS_SYNC_BYTE 0x47
|
||||
#define PID_MASK_HI 0x1F
|
||||
|
||||
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
|
||||
enum eSetChannelResult { scrOk, scrNotAvailable, scrNoTransfer, scrFailed };
|
||||
|
||||
enum ePlayMode { pmNone, // audio/video from decoder
|
||||
pmAudioVideo, // audio/video from player
|
||||
@ -69,19 +69,13 @@ public:
|
||||
// 1...numDevices) and returns true if this was possible.
|
||||
static cDevice *PrimaryDevice(void) { return primaryDevice; }
|
||||
// Returns the primary device.
|
||||
static cDevice *GetDevice(int Ca, int Priority, int Frequency = 0, int Vpid = 0, bool *ReUse = NULL);
|
||||
// Selects a free device, avoiding the primaryDevice if possible.
|
||||
// If Ca is not 0, the device with the given number will be returned
|
||||
// in case Ca is <= MAXDEVICES, or the device that provides the given
|
||||
// value in its caCaps.
|
||||
// If there is a device that is already receiving and can be re-used to
|
||||
// receive another data stream, that device will be returned.
|
||||
// If all devices are currently receiving, the one receiving with the
|
||||
// lowest priority (if any) that is lower than the given Priority
|
||||
// will be returned.
|
||||
// If ReUse is given, the caller will be informed whether the device can be re-used
|
||||
// for a new recording. If ReUse returns 'true', the caller must NOT switch the channel
|
||||
// (the device is already properly tuned). Otherwise the caller MUST switch the channel.
|
||||
static cDevice *GetDevice(int Index);
|
||||
// Returns the device with the Index (if Index is in the range
|
||||
// 0..numDevices-1, NULL otherwise).
|
||||
static cDevice *GetDevice(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL);
|
||||
// Returns a device that is able to receive the given Channel at the
|
||||
// given Priority (see ProvidesChannel() for more information on how
|
||||
// priorities are handled, and the meaning of NeedsSwitchChannel).
|
||||
static void SetCaCaps(int Index = -1);
|
||||
// Sets the CaCaps of the given device according to the Setup data.
|
||||
// By default the CaCaps of all devices are set.
|
||||
@ -115,18 +109,13 @@ public:
|
||||
bool IsPrimaryDevice(void) const { return this == primaryDevice; }
|
||||
int CardIndex(void) const { return cardIndex; }
|
||||
// Returns the card index of this device (0 ... MAXDEVICES - 1).
|
||||
virtual int ProvidesCa(int Ca);
|
||||
//XXX TODO temporarily made this function virtual - until a general
|
||||
//XXX mechanism has been implemented
|
||||
int ProvidesCa(int Ca);
|
||||
// Checks whether this device provides the given value in its
|
||||
// caCaps. Returns 0 if the value is not provided, 1 if only this
|
||||
// value is provided, and > 1 if this and other values are provided.
|
||||
// If the given value is equal to the number of this device,
|
||||
// 1 is returned. If it is 0 (FTA), 1 plus the number of other values
|
||||
// in caCaps is returned.
|
||||
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.
|
||||
|
||||
@ -145,10 +134,33 @@ public:
|
||||
protected:
|
||||
int currentChannel;
|
||||
public:
|
||||
eSetChannelResult SetChannel(const cChannel *Channel);
|
||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL);
|
||||
// Returns true if this device can provide the given channel.
|
||||
// In case the device has cReceivers attached to it or it is the primary
|
||||
// device, Priority is used to decide whether the caller's request can
|
||||
// be honored.
|
||||
// The special Priority value -1 will tell the caller whether this device
|
||||
// is principally able to provide the given Channel, regardless of any
|
||||
// attached cReceivers.
|
||||
// If NeedsSwitchChannel is given, the resulting value in it will tell the
|
||||
// caller whether or not it shall call SwitchChannel to actually switch the
|
||||
// device to the desired channel. If NeedsSwitchChannel returns false, the
|
||||
// caller must not call SwitchChannel, since there are receivers attached
|
||||
// to the device and it is already switched to the given channel. Note
|
||||
// that the return value in NeedsSwitchChannel is only meaningful if the
|
||||
// function itself actually returns true.
|
||||
// The default implementation always returns false, so a derived cDevice
|
||||
// class that can provide channels must implement this function.
|
||||
bool SwitchChannel(const cChannel *Channel, bool LiveView);
|
||||
// Switches the device to the given Channel, initiating transfer mode
|
||||
// if necessary.
|
||||
private:
|
||||
eSetChannelResult SetChannel(const cChannel *Channel, bool LiveView);
|
||||
// Sets the device to the given channel (general setup).
|
||||
virtual bool SetChannelDevice(const cChannel *Channel);
|
||||
protected:
|
||||
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
||||
// Sets the device to the given channel (actual physical setup).
|
||||
public:
|
||||
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; }
|
||||
@ -169,6 +181,8 @@ protected:
|
||||
cPidHandle(void) { pid = used = 0; handle = -1; }
|
||||
};
|
||||
cPidHandle pidHandles[MAXPIDHANDLES];
|
||||
bool HasPid(int Pid);
|
||||
// Returns true if this device is currently receiving the given PID.
|
||||
bool AddPid(int Pid, ePidType PidType = ptOther);
|
||||
// Adds a PID to the set of PIDs this device shall receive.
|
||||
void DelPid(int Pid);
|
||||
@ -263,12 +277,12 @@ public:
|
||||
private:
|
||||
cReceiver *receiver[MAXRECEIVERS];
|
||||
int ca;
|
||||
int CanShift(int Ca, int Priority, int UsedCards = 0);
|
||||
protected:
|
||||
int Priority(void);
|
||||
// Returns the priority of the current receiving session (0..MAXPRIORITY),
|
||||
// or -1 if no receiver is currently active. The primary device will
|
||||
// always return at least Setup.PrimaryLimit-1.
|
||||
int CanShift(int Ca, int Priority, int UsedCards = 0);
|
||||
protected:
|
||||
virtual bool OpenDvr(void);
|
||||
// Opens the DVR of this device and prepares it to deliver a Transport
|
||||
// Stream for use in a cReceiver.
|
||||
|
412
dvbdevice.c
412
dvbdevice.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: dvbdevice.c 1.8 2002/08/25 09:20:53 kls Exp $
|
||||
* $Id: dvbdevice.c 1.9 2002/09/04 13:46:03 kls Exp $
|
||||
*/
|
||||
|
||||
#include "dvbdevice.h"
|
||||
@ -20,10 +20,12 @@ extern "C" {
|
||||
#include <linux/videodev.h>
|
||||
#ifdef NEWSTRUCT
|
||||
#include <linux/dvb/audio.h>
|
||||
#include <linux/dvb/dmx.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/video.h>
|
||||
#else
|
||||
#include <ost/audio.h>
|
||||
#include <ost/dmx.h>
|
||||
#include <ost/sec.h>
|
||||
#include <ost/video.h>
|
||||
#endif
|
||||
@ -35,8 +37,6 @@ extern "C" {
|
||||
#include "status.h"
|
||||
#include "transfer.h"
|
||||
|
||||
#define MAXDVBDEVICES 4
|
||||
|
||||
#define DEV_VIDEO "/dev/video"
|
||||
#ifdef NEWSTRUCT
|
||||
#define DEV_DVB_ADAPTER "/dev/dvb/adapter"
|
||||
@ -91,10 +91,10 @@ cDvbDevice::cDvbDevice(int n)
|
||||
fd_osd = DvbOpen(DEV_DVB_OSD, n, O_RDWR);
|
||||
fd_video = DvbOpen(DEV_DVB_VIDEO, n, O_RDWR | O_NONBLOCK);
|
||||
fd_audio = DvbOpen(DEV_DVB_AUDIO, n, O_RDWR | O_NONBLOCK);
|
||||
|
||||
|
||||
#ifndef NEWSTRUCT
|
||||
// Devices that are only present on DVB-S cards:
|
||||
|
||||
|
||||
fd_sec = DvbOpen(DEV_DVB_SEC, n, O_RDWR);
|
||||
#endif
|
||||
|
||||
@ -179,15 +179,6 @@ 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;
|
||||
@ -235,10 +226,10 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz
|
||||
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) {
|
||||
@ -253,11 +244,11 @@ bool cDvbDevice::GrabImage(const char *FileName, bool Jpeg, int Quality, int Siz
|
||||
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++)
|
||||
@ -313,6 +304,14 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
||||
else {
|
||||
CHECK(ioctl(Handle->handle, DMX_STOP));
|
||||
if (Handle->used == 0) {
|
||||
dmxPesFilterParams pesFilterParams;
|
||||
memset(&pesFilterParams, 0, sizeof(pesFilterParams));
|
||||
pesFilterParams.pid = 0x1FFF;
|
||||
pesFilterParams.input = DMX_IN_FRONTEND;
|
||||
pesFilterParams.output = DMX_OUT_DECODER;
|
||||
pesFilterParams.pesType = PesTypes[Type < ptOther ? Type : ptOther];
|
||||
pesFilterParams.flags = DMX_IMMEDIATE_START;
|
||||
CHECK(ioctl(Handle->handle, DMX_SET_PES_FILTER, &pesFilterParams));
|
||||
close(Handle->handle);
|
||||
Handle->handle = -1;
|
||||
return true;
|
||||
@ -339,8 +338,58 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool On)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cDvbDevice::SetChannelDevice(const cChannel *Channel)
|
||||
bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *NeedsSwitchChannel)
|
||||
{
|
||||
bool result = false;
|
||||
bool hasPriority = Priority < 0 || Priority > this->Priority();
|
||||
bool needsSwitchChannel = true;
|
||||
|
||||
if (ProvidesCa(Channel->ca)) {
|
||||
if (Receiving()) {
|
||||
if (frequency == Channel->frequency) {
|
||||
needsSwitchChannel = false;
|
||||
if (!HasPid(Channel->vpid)) {
|
||||
if (Channel->ca > CACONFBASE) {
|
||||
needsSwitchChannel = true;
|
||||
result = hasPriority;
|
||||
}
|
||||
else if (!HasDecoder())
|
||||
result = true; // if it has no decoder it can't be the primary device
|
||||
else {
|
||||
#define DVB_DRIVER_VERSION 2002090101 //XXX+
|
||||
#define MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT 2002090101
|
||||
#ifdef DVB_DRIVER_VERSION
|
||||
#if (DVB_DRIVER_VERSION >= MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT)
|
||||
if (pidHandles[ptVideo].used)
|
||||
needsSwitchChannel = true; // to have it turn off the live PIDs
|
||||
result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit;
|
||||
#endif
|
||||
#else
|
||||
#warning "DVB_DRIVER_VERSION not defined - time shift with only one DVB device disabled!"
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
result = !IsPrimaryDevice() || Priority >= Setup.PrimaryLimit;
|
||||
}
|
||||
else
|
||||
result = hasPriority;
|
||||
}
|
||||
else
|
||||
result = hasPriority;
|
||||
}
|
||||
if (NeedsSwitchChannel)
|
||||
*NeedsSwitchChannel = needsSwitchChannel;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
|
||||
{
|
||||
#if (DVB_DRIVER_VERSION < MIN_DVB_DRIVER_VERSION_FOR_TIMESHIFT)
|
||||
if (HasDecoder())
|
||||
LiveView = true;
|
||||
#endif
|
||||
|
||||
// Avoid noise while switching:
|
||||
|
||||
if (HasDecoder()) {
|
||||
@ -357,204 +406,209 @@ bool cDvbDevice::SetChannelDevice(const cChannel *Channel)
|
||||
|
||||
// Turn off current PIDs:
|
||||
|
||||
if (HasDecoder()) {
|
||||
if (HasDecoder() && (LiveView || pidHandles[ptVideo].pid == Channel->vpid)) {
|
||||
DelPid(pidHandles[ptVideo].pid);
|
||||
DelPid(pidHandles[ptAudio].pid);
|
||||
DelPid(pidHandles[ptTeletext].pid);
|
||||
DelPid(pidHandles[ptDolby].pid);
|
||||
}
|
||||
|
||||
if (frequency != Channel->frequency || Channel->ca > CACONFBASE) { // CA channels can only be decrypted in "live" mode
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
dvb_frontend_parameters Frontend;
|
||||
dvb_frontend_parameters Frontend;
|
||||
#else
|
||||
FrontendParameters Frontend;
|
||||
FrontendParameters Frontend;
|
||||
#endif
|
||||
|
||||
memset(&Frontend, 0, sizeof(Frontend));
|
||||
memset(&Frontend, 0, sizeof(Frontend));
|
||||
|
||||
switch (frontendType) {
|
||||
case FE_QPSK: { // DVB-S
|
||||
switch (frontendType) {
|
||||
case FE_QPSK: { // DVB-S
|
||||
|
||||
// Frequency offsets:
|
||||
// Frequency offsets:
|
||||
|
||||
unsigned int freq = Channel->frequency;
|
||||
int tone = SEC_TONE_OFF;
|
||||
unsigned int freq = Channel->frequency;
|
||||
int tone = SEC_TONE_OFF;
|
||||
|
||||
if (freq < (unsigned int)Setup.LnbSLOF) {
|
||||
freq -= Setup.LnbFrequLo;
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
Frontend.frequency = freq * 1000UL;
|
||||
Frontend.inversion = INVERSION_AUTO;
|
||||
Frontend.u.qpsk.symbol_rate = Channel->srate * 1000UL;
|
||||
Frontend.u.qpsk.fec_inner = FEC_AUTO;
|
||||
#else
|
||||
Frontend.Frequency = freq * 1000UL;
|
||||
Frontend.Inversion = INVERSION_AUTO;
|
||||
Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL;
|
||||
Frontend.u.qpsk.FEC_inner = FEC_AUTO;
|
||||
#endif
|
||||
|
||||
int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
|
||||
|
||||
// DiSEqC:
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
struct dvb_diseqc_master_cmd cmd = { {0xE0, 0x10, 0x38, 0xF0, 0x00, 0x00}, 4};
|
||||
cmd.msg[3] = 0xF0 | (((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0));
|
||||
|
||||
if (Setup.DiSEqC)
|
||||
CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
|
||||
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
|
||||
if (Setup.DiSEqC) {
|
||||
usleep(15 * 1000);
|
||||
CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd));
|
||||
usleep(15 * 1000);
|
||||
CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, (Channel->diseqc / 4) % 2 ? SEC_MINI_B : SEC_MINI_A));
|
||||
usleep(15 * 1000);
|
||||
}
|
||||
CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
|
||||
#else
|
||||
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));
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
freq -= Setup.LnbFrequHi;
|
||||
tone = SEC_TONE_ON;
|
||||
break;
|
||||
case FE_QAM: { // DVB-C
|
||||
|
||||
// Frequency and symbol rate:
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
Frontend.frequency = Channel->frequency * 1000000UL;
|
||||
Frontend.inversion = INVERSION_AUTO;
|
||||
Frontend.u.qam.symbol_rate = Channel->srate * 1000UL;
|
||||
Frontend.u.qam.fec_inner = FEC_AUTO;
|
||||
Frontend.u.qam.modulation = QAM_64;
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case FE_OFDM: { // DVB-T
|
||||
|
||||
// Frequency and OFDM paramaters:
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
Frontend.frequency = freq * 1000UL;
|
||||
Frontend.inversion = INVERSION_AUTO;
|
||||
Frontend.u.qpsk.symbol_rate = Channel->srate * 1000UL;
|
||||
Frontend.u.qpsk.fec_inner = FEC_AUTO;
|
||||
Frontend.frequency = Channel->frequency * 1000UL;
|
||||
Frontend.inversion = INVERSION_AUTO;
|
||||
Frontend.u.ofdm.bandwidth=BANDWIDTH_8_MHZ;
|
||||
Frontend.u.ofdm.code_rate_HP = FEC_2_3;
|
||||
Frontend.u.ofdm.code_rate_LP = FEC_1_2;
|
||||
Frontend.u.ofdm.constellation = QAM_64;
|
||||
Frontend.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
|
||||
Frontend.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
|
||||
Frontend.u.ofdm.hierarchy_information = HIERARCHY_NONE;
|
||||
#else
|
||||
Frontend.Frequency = freq * 1000UL;
|
||||
Frontend.Inversion = INVERSION_AUTO;
|
||||
Frontend.u.qpsk.SymbolRate = Channel->srate * 1000UL;
|
||||
Frontend.u.qpsk.FEC_inner = FEC_AUTO;
|
||||
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;
|
||||
#endif
|
||||
|
||||
int volt = (Channel->polarization == 'v' || Channel->polarization == 'V') ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18;
|
||||
|
||||
// DiSEqC:
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
struct dvb_diseqc_master_cmd cmd = { {0xE0, 0x10, 0x38, 0xF0, 0x00, 0x00}, 4};
|
||||
cmd.msg[3] = 0xF0 | (((Channel->diseqc * 4) & 0x0F) | (tone == SEC_TONE_ON ? 1 : 0) | (volt == SEC_VOLTAGE_18 ? 2 : 0));
|
||||
|
||||
if (Setup.DiSEqC)
|
||||
CHECK(ioctl(fd_frontend, FE_SET_TONE, SEC_TONE_OFF));
|
||||
CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, volt));
|
||||
if (Setup.DiSEqC) {
|
||||
usleep(15 * 1000);
|
||||
CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd));
|
||||
usleep(15 * 1000);
|
||||
CHECK(ioctl(fd_frontend, FE_DISEQC_SEND_BURST, (Channel->diseqc / 4) % 2 ? SEC_MINI_B : SEC_MINI_A));
|
||||
usleep(15 * 1000);
|
||||
}
|
||||
CHECK(ioctl(fd_frontend, FE_SET_TONE, tone));
|
||||
#else
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
|
||||
return false;
|
||||
}
|
||||
|
||||
secCmdSequence scmds;
|
||||
scmds.voltage = volt;
|
||||
scmds.miniCommand = SEC_MINI_NONE;
|
||||
scmds.continuousTone = tone;
|
||||
scmds.numCommands = Setup.DiSEqC ? 1 : 0;
|
||||
scmds.commands = &scmd;
|
||||
#ifdef NEWSTRUCT
|
||||
// Discard stale events:
|
||||
|
||||
CHECK(ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds));
|
||||
#endif
|
||||
for (;;) {
|
||||
dvb_frontend_event event;
|
||||
if (ioctl(fd_frontend, FE_GET_EVENT, &event) < 0)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FE_QAM: { // DVB-C
|
||||
#endif
|
||||
|
||||
// Frequency and symbol rate:
|
||||
// Tuning:
|
||||
|
||||
CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
|
||||
|
||||
// Wait for channel lock:
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
Frontend.frequency = Channel->frequency * 1000000UL;
|
||||
Frontend.inversion = INVERSION_AUTO;
|
||||
Frontend.u.qam.symbol_rate = Channel->srate * 1000UL;
|
||||
Frontend.u.qam.fec_inner = FEC_AUTO;
|
||||
Frontend.u.qam.modulation = QAM_64;
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
FrontendStatus status = FrontendStatus(0);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status));
|
||||
if (status & FE_HAS_LOCK)
|
||||
break;
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
break;
|
||||
case FE_OFDM: { // DVB-T
|
||||
|
||||
// Frequency and OFDM paramaters:
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
Frontend.frequency = Channel->frequency * 1000UL;
|
||||
Frontend.inversion = INVERSION_AUTO;
|
||||
Frontend.u.ofdm.bandwidth=BANDWIDTH_8_MHZ;
|
||||
Frontend.u.ofdm.code_rate_HP = FEC_2_3;
|
||||
Frontend.u.ofdm.code_rate_LP = FEC_1_2;
|
||||
Frontend.u.ofdm.constellation = QAM_64;
|
||||
Frontend.u.ofdm.transmission_mode = TRANSMISSION_MODE_2K;
|
||||
Frontend.u.ofdm.guard_interval = GUARD_INTERVAL_1_32;
|
||||
Frontend.u.ofdm.hierarchy_information = HIERARCHY_NONE;
|
||||
if (!(status & FE_HAS_LOCK)) {
|
||||
esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->number, CardIndex() + 1);
|
||||
if (IsPrimaryDevice())
|
||||
cThread::RaisePanic();
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
esyslog("ERROR: attempt to set channel with unknown DVB frontend type");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
// Discard stale events:
|
||||
|
||||
for (;;) {
|
||||
dvb_frontend_event event;
|
||||
if (ioctl(fd_frontend, FE_GET_EVENT, &event) < 0)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Tuning:
|
||||
|
||||
CHECK(ioctl(fd_frontend, FE_SET_FRONTEND, &Frontend));
|
||||
|
||||
// Wait for channel lock:
|
||||
|
||||
#ifdef NEWSTRUCT
|
||||
FrontendStatus status = FrontendStatus(0);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
CHECK(ioctl(fd_frontend, FE_READ_STATUS, &status));
|
||||
if (status & FE_HAS_LOCK)
|
||||
break;
|
||||
usleep(10 * 1000);
|
||||
}
|
||||
if (!(status & FE_HAS_LOCK)) {
|
||||
esyslog("ERROR: channel %d not locked on DVB card %d!", Channel->number, CardIndex() + 1);
|
||||
if (IsPrimaryDevice())
|
||||
cThread::RaisePanic();
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (cFile::FileReady(fd_frontend, 5000)) {
|
||||
FrontendEvent event;
|
||||
if (ioctl(fd_frontend, FE_GET_EVENT, &event) >= 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;
|
||||
if (cFile::FileReady(fd_frontend, 5000)) {
|
||||
FrontendEvent event;
|
||||
if (ioctl(fd_frontend, FE_GET_EVENT, &event) >= 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 in frontend get event (channel %d, card %d): %m", Channel->number, CardIndex() + 1);
|
||||
}
|
||||
else
|
||||
esyslog("ERROR in frontend get event (channel %d, card %d): %m", Channel->number, CardIndex() + 1);
|
||||
}
|
||||
else
|
||||
esyslog("ERROR: timeout while tuning on DVB card %d", CardIndex() + 1);
|
||||
esyslog("ERROR: timeout while tuning on DVB card %d", CardIndex() + 1);
|
||||
#endif
|
||||
|
||||
frequency = Channel->frequency;
|
||||
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 (HasDecoder() && (LiveView || Channel->ca > CACONFBASE)) { // CA channels can only be decrypted in "live" mode
|
||||
if (!HasPid(Channel->vpid)) {
|
||||
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));
|
||||
CHECK(ioctl(fd_audio, AUDIO_SET_MUTE, false));
|
||||
CHECK(ioctl(fd_video, VIDEO_SET_BLANK, 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));
|
||||
else
|
||||
cControl::Launch(new cTransferControl(this, Channel->vpid, Channel->apid1, 0, 0, 0));
|
||||
}
|
||||
|
||||
// Start setting system time:
|
||||
|
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: dvbdevice.h 1.6 2002/08/25 09:19:34 kls Exp $
|
||||
* $Id: dvbdevice.h 1.7 2002/09/04 13:31:42 kls Exp $
|
||||
*/
|
||||
|
||||
#ifndef __DVBDEVICE_H
|
||||
@ -23,6 +23,8 @@
|
||||
#include "device.h"
|
||||
#include "eit.h"
|
||||
|
||||
#define MAXDVBDEVICES 4
|
||||
|
||||
class cDvbDevice : public cDevice {
|
||||
friend class cDvbOsd;
|
||||
private:
|
||||
@ -45,7 +47,6 @@ protected:
|
||||
public:
|
||||
cDvbDevice(int n);
|
||||
virtual ~cDvbDevice();
|
||||
virtual bool CanBeReUsed(int Frequency, int Vpid);
|
||||
virtual bool HasDecoder(void) const;
|
||||
|
||||
// OSD facilities
|
||||
@ -58,7 +59,9 @@ public:
|
||||
private:
|
||||
int frequency;
|
||||
public:
|
||||
virtual bool SetChannelDevice(const cChannel *Channel);
|
||||
virtual bool ProvidesChannel(const cChannel *Channel, int Priority = -1, bool *NeedsSwitchChannel = NULL);
|
||||
protected:
|
||||
virtual bool SetChannelDevice(const cChannel *Channel, bool LiveView);
|
||||
|
||||
// PID handle facilities
|
||||
|
||||
|
17
eitscan.c
17
eitscan.c
@ -4,11 +4,12 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: eitscan.c 1.5 2002/08/11 11:11:39 kls Exp $
|
||||
* $Id: eitscan.c 1.6 2002/09/04 13:32:38 kls Exp $
|
||||
*/
|
||||
|
||||
#include "eitscan.h"
|
||||
#include <stdlib.h>
|
||||
#include "dvbdevice.h"
|
||||
|
||||
cEITScanner::cEITScanner(void)
|
||||
{
|
||||
@ -49,9 +50,9 @@ void cEITScanner::Process(void)
|
||||
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
|
||||
time_t now = time(NULL);
|
||||
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
|
||||
for (int i = 0; i < MAXDEVICES; i++) {
|
||||
cDevice *Device = cDevice::GetDevice(i + 1, MAXPRIORITY + 1);
|
||||
if (Device) {
|
||||
for (int i = 0; i < cDevice::NumDevices(); i++) {
|
||||
cDevice *Device = cDevice::GetDevice(i);
|
||||
if (Device && Device->CardIndex() < MAXDVBDEVICES) {
|
||||
if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
|
||||
if (!(Device->Receiving() || Device->Replaying())) {
|
||||
int oldCh = lastChannel;
|
||||
@ -63,12 +64,12 @@ void cEITScanner::Process(void)
|
||||
}
|
||||
cChannel *Channel = Channels.GetByNumber(ch);
|
||||
if (Channel) {
|
||||
if (Channel->ca <= MAXDEVICES && !Device->ProvidesCa(Channel->ca))
|
||||
break; // the channel says it explicitly needs a different card
|
||||
if (!Device->ProvidesChannel(Channel))
|
||||
break;
|
||||
if (Channel->pnr && !TransponderScanned(Channel)) {
|
||||
if (Device == cDevice::PrimaryDevice() && !currentChannel)
|
||||
currentChannel = Device->Channel();
|
||||
Channel->Switch(Device, false);
|
||||
Device->SwitchChannel(Channel, false);
|
||||
lastChannel = ch;
|
||||
break;
|
||||
}
|
||||
@ -78,6 +79,8 @@ void cEITScanner::Process(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
lastChannel++; // avoid hangup in case the last channel in the list is not provided by a DVB card
|
||||
}
|
||||
lastScan = time(NULL);
|
||||
}
|
||||
|
17
menu.c
17
menu.c
@ -4,7 +4,7 @@
|
||||
* See the main source file 'vdr.c' for copyright information and
|
||||
* how to reach the author.
|
||||
*
|
||||
* $Id: menu.c 1.206 2002/08/25 10:56:09 kls Exp $
|
||||
* $Id: menu.c 1.207 2002/09/04 13:27:13 kls Exp $
|
||||
*/
|
||||
|
||||
#include "menu.h"
|
||||
@ -508,7 +508,7 @@ eOSState cMenuChannels::Switch(void)
|
||||
{
|
||||
cChannel *ch = Channels.Get(Current());
|
||||
if (ch)
|
||||
ch->Switch();
|
||||
cDevice::PrimaryDevice()->SwitchChannel(ch, true);
|
||||
return osEnd;
|
||||
}
|
||||
|
||||
@ -1054,7 +1054,7 @@ eOSState cMenuWhatsOn::Switch(void)
|
||||
cMenuWhatsOnItem *item = (cMenuWhatsOnItem *)Get(Current());
|
||||
if (item) {
|
||||
cChannel *channel = Channels.GetByServiceID(item->eventInfo->GetServiceID());
|
||||
if (channel && channel->Switch())
|
||||
if (channel && cDevice::PrimaryDevice()->SwitchChannel(channel, true))
|
||||
return osEnd;
|
||||
}
|
||||
Interface->Error(tr("Can't switch channel!"));
|
||||
@ -2519,12 +2519,12 @@ bool cRecordControls::Start(cTimer *Timer)
|
||||
cChannel *channel = Channels.GetByNumber(ch);
|
||||
|
||||
if (channel) {
|
||||
bool ReUse = false;
|
||||
cDevice *device = cDevice::GetDevice(channel->ca, Timer ? Timer->priority : Setup.DefaultPriority, channel->frequency, channel->vpid, &ReUse);
|
||||
bool NeedsSwitchChannel = false;
|
||||
cDevice *device = cDevice::GetDevice(channel, Timer ? Timer->priority : Setup.DefaultPriority, &NeedsSwitchChannel);
|
||||
if (device) {
|
||||
if (!ReUse) {
|
||||
if (NeedsSwitchChannel) {
|
||||
Stop(device);
|
||||
if (!channel->Switch(device)) {
|
||||
if (!device->SwitchChannel(channel, false)) {
|
||||
cThread::EmergencyExit(true);
|
||||
return false;
|
||||
}
|
||||
@ -2570,7 +2570,8 @@ void cRecordControls::Stop(cDevice *Device)
|
||||
bool cRecordControls::StopPrimary(bool DoIt)
|
||||
{
|
||||
if (cDevice::PrimaryDevice()->Receiving()) {
|
||||
cDevice *device = cDevice::GetDevice(cDevice::PrimaryDevice()->Ca(), 0);
|
||||
//XXX+ disabled for the moment - might become obsolete with DVB_DRIVER_VERSION >= 2002090101
|
||||
cDevice *device = NULL;//XXX cDevice::GetDevice(cDevice::PrimaryDevice()->Ca(), 0);
|
||||
if (device) {
|
||||
if (DoIt)
|
||||
Stop(cDevice::PrimaryDevice());
|
||||
|
8
svdrp.c
8
svdrp.c
@ -10,7 +10,7 @@
|
||||
* and interact with the Video Disk Recorder - or write a full featured
|
||||
* graphical interface that sits on top of an SVDRP connection.
|
||||
*
|
||||
* $Id: svdrp.c 1.40 2002/08/25 10:40:46 kls Exp $
|
||||
* $Id: svdrp.c 1.41 2002/09/04 10:49:42 kls Exp $
|
||||
*/
|
||||
|
||||
#include "svdrp.h"
|
||||
@ -417,13 +417,9 @@ void cSVDRP::CmdCHAN(const char *Option)
|
||||
Reply(501, "Undefined channel \"%s\"", Option);
|
||||
return;
|
||||
}
|
||||
if (Interface->Recording()) {
|
||||
Reply(550, "Can't switch channel, interface is recording");
|
||||
return;
|
||||
}
|
||||
cChannel *channel = Channels.GetByNumber(n);
|
||||
if (channel) {
|
||||
if (!channel->Switch()) {
|
||||
if (!cDevice::PrimaryDevice()->SwitchChannel(channel, true)) {
|
||||
Reply(554, "Error switching to channel \"%d\"", channel->number);
|
||||
return;
|
||||
}
|
||||
|
4
vdr.c
4
vdr.c
@ -22,7 +22,7 @@
|
||||
*
|
||||
* The project's page is at http://www.cadsoft.de/people/kls/vdr
|
||||
*
|
||||
* $Id: vdr.c 1.120 2002/08/16 09:54:03 kls Exp $
|
||||
* $Id: vdr.c 1.121 2002/09/04 13:29:19 kls Exp $
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
@ -548,7 +548,7 @@ int main(int argc, char *argv[])
|
||||
int n = cDevice::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1);
|
||||
cChannel *channel = Channels.GetByNumber(n);
|
||||
if (channel)
|
||||
channel->Switch();
|
||||
cDevice::PrimaryDevice()->SwitchChannel(channel, true);
|
||||
break;
|
||||
}
|
||||
// Viewing Control:
|
||||
|
Loading…
Reference in New Issue
Block a user