mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Totally rearranged device/player/recorder structures
This commit is contained in:
parent
b005b8fc4a
commit
a4bfddd2f9
21
HISTORY
21
HISTORY
@ -1301,7 +1301,7 @@ Video Disk Recorder Revision History
|
|||||||
- Removed compiler option '-m486' to make it work on non-Intel platforms (thanks
|
- Removed compiler option '-m486' to make it work on non-Intel platforms (thanks
|
||||||
to Alastair McKinstry for pointing this out).
|
to Alastair McKinstry for pointing this out).
|
||||||
|
|
||||||
2002-05-26: Version 1.1.3
|
2002-06-16: Version 1.1.3
|
||||||
|
|
||||||
- Improved the VDR Makefile to avoid a warning if the '.dependencies' file does
|
- Improved the VDR Makefile to avoid a warning if the '.dependencies' file does
|
||||||
not exist, and also using $(MAKE) to call recursive makes.
|
not exist, and also using $(MAKE) to call recursive makes.
|
||||||
@ -1328,3 +1328,22 @@ Video Disk Recorder Revision History
|
|||||||
- Removed compiler option '-m486' to make it work on non-Intel platforms. If you
|
- Removed compiler option '-m486' to make it work on non-Intel platforms. If you
|
||||||
have already started a plugin project, you may want to make sure you remove this
|
have already started a plugin project, you may want to make sure you remove this
|
||||||
option from your existing Makefile.
|
option from your existing Makefile.
|
||||||
|
- Completely rearranged the recording and replay functions to make them available
|
||||||
|
to plugins.
|
||||||
|
- Replay is now done in a single thread (no more syncing between input and output
|
||||||
|
thread necessary).
|
||||||
|
- It is now possible to record several channels on the same transponder with "budget
|
||||||
|
cards". VDR automatically attaches a recording timer to a card that already
|
||||||
|
records on the appropriate transponder. How many parallel recordings can actually
|
||||||
|
be done depends on the computer's performance. Currently any number of recordings
|
||||||
|
gets attached to a card, so you should carefully plan your timers to not exceed
|
||||||
|
the limit. On a K6-II/450 it was possible to record three channels from transponder
|
||||||
|
12480 with a single WinTV NOVA-S.
|
||||||
|
- Timers that record two successive shows on the same channel may now overlap and
|
||||||
|
will use the same DVB card. During the time where both timers record the data
|
||||||
|
is simply saved to both files.
|
||||||
|
- The following limitations apply to this version:
|
||||||
|
+ Transfer mode doesn't work yet.
|
||||||
|
+ The '-a' option (for Dolby Digital audio) doesn't work yet.
|
||||||
|
+ Switching between different language tracks doesn't work yet.
|
||||||
|
+ Cutting doesn't work yet.
|
||||||
|
9
Makefile
9
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.39 2002/06/10 16:26:51 kls Exp $
|
# $Id: Makefile 1.40 2002/06/10 16:31:34 kls Exp $
|
||||||
|
|
||||||
.DELETE_ON_ERROR:
|
.DELETE_ON_ERROR:
|
||||||
|
|
||||||
@ -21,9 +21,10 @@ INCLUDES = -I$(DVBDIR)/ost/include
|
|||||||
|
|
||||||
DTVLIB = $(DTVDIR)/libdtv.a
|
DTVLIB = $(DTVDIR)/libdtv.a
|
||||||
|
|
||||||
OBJS = config.o dvbapi.o dvbosd.o eit.o eitscan.o font.o i18n.o interface.o menu.o\
|
OBJS = audio.o config.o device.o dvbplayer.o dvbosd.o eit.o eitscan.o font.o i18n.o\
|
||||||
menuitems.o osdbase.o osd.o plugin.o recording.o remote.o remux.o ringbuffer.o\
|
interface.o menu.o menuitems.o osdbase.o osd.o player.o plugin.o receiver.o\
|
||||||
status.o svdrp.o thread.o tools.o vdr.o videodir.o
|
recorder.o recording.o remote.o remux.o ringbuffer.o status.o svdrp.o thread.o\
|
||||||
|
tools.o vdr.o videodir.o
|
||||||
|
|
||||||
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
|
OSDFONT = -adobe-helvetica-medium-r-normal--23-*-100-100-p-*-iso8859-1
|
||||||
FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
|
FIXFONT = -adobe-courier-bold-r-normal--25-*-100-100-m-*-iso8859-1
|
||||||
|
@ -864,15 +864,15 @@ If a plugin wants to get informed on various events in VDR, it can derive a clas
|
|||||||
|
|
||||||
class cMyStatusMonitor : public cStatusMonitor {
|
class cMyStatusMonitor : public cStatusMonitor {
|
||||||
protected:
|
protected:
|
||||||
virtual void ChannelSwitch(const cDvbApi *DvbApi, int ChannelNumber);
|
virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
|
||||||
};
|
};
|
||||||
|
|
||||||
void cMyStatusMonitor::ChannelSwitch(const cDvbApi *DvbApi, int ChannelNumber)
|
void cMyStatusMonitor::ChannelSwitch(const cDevice *Device, int ChannelNumber)
|
||||||
{
|
{
|
||||||
if (ChannelNumber)
|
if (ChannelNumber)
|
||||||
dsyslog("channel switched to %d on DVB %d", ChannelNumber, DvbApi->CardIndex());
|
dsyslog("channel switched to %d on DVB %d", ChannelNumber, Device->CardIndex());
|
||||||
else
|
else
|
||||||
dsyslog("about to switch channel on DVB %d", DvbApi->CardIndex());
|
dsyslog("about to switch channel on DVB %d", Device->CardIndex());
|
||||||
}
|
}
|
||||||
</pre></td></tr></table><p>
|
</pre></td></tr></table><p>
|
||||||
|
|
||||||
|
11
audio.c
Normal file
11
audio.c
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* audio.c: The basic audio interface
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: audio.c 1.1 2002/06/10 16:30:00 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "audio.h"
|
||||||
|
|
13
audio.h
Normal file
13
audio.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* audio.h: The basic audio interface
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: audio.h 1.1 2002/06/10 16:30:00 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __AUDIO_H
|
||||||
|
#define __AUDIO_H
|
||||||
|
|
||||||
|
#endif //__AUDIO_H
|
29
config.c
29
config.c
@ -4,16 +4,16 @@
|
|||||||
* 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.101 2002/05/13 16:28:12 kls Exp $
|
* $Id: config.c 1.102 2002/06/16 12:57:31 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "dvbapi.h"
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "recording.h"
|
||||||
|
|
||||||
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
|
// IMPORTANT NOTE: in the 'sscanf()' calls there is a blank after the '%d'
|
||||||
// format characters in order to allow any number of blanks after a numeric
|
// format characters in order to allow any number of blanks after a numeric
|
||||||
@ -293,15 +293,15 @@ bool cChannel::Save(FILE *f)
|
|||||||
return fprintf(f, ToText()) > 0;
|
return fprintf(f, ToText()) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
|
bool cChannel::Switch(cDevice *Device, bool Log)
|
||||||
{
|
{
|
||||||
if (!DvbApi)
|
if (!Device)
|
||||||
DvbApi = cDvbApi::PrimaryDvbApi;
|
Device = cDevice::PrimaryDevice();
|
||||||
if (!DvbApi->Recording() && !groupSep) {
|
if (!(Device->IsPrimaryDevice() && Device->Receiving()) && !groupSep) {
|
||||||
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 (DvbApi->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, apid2, dpid1, dpid2, tpid, ca, pnr)) {
|
switch (Device->SetChannel(number, frequency, polarization, diseqc, srate, vpid, apid1, tpid, ca, pnr)) {
|
||||||
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!"));
|
||||||
@ -312,7 +312,7 @@ bool cChannel::Switch(cDvbApi *DvbApi, bool Log)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (DvbApi->Recording())
|
if (Device->IsPrimaryDevice() && Device->Receiving())
|
||||||
Interface->Error(tr("Channel locked (recording)!"));
|
Interface->Error(tr("Channel locked (recording)!"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -326,7 +326,7 @@ cTimer::cTimer(bool Instant)
|
|||||||
startTime = stopTime = 0;
|
startTime = stopTime = 0;
|
||||||
recording = pending = false;
|
recording = pending = false;
|
||||||
active = Instant ? taActInst : taInactive;
|
active = Instant ? taActInst : taInactive;
|
||||||
cChannel *ch = Channels.GetByNumber(cDvbApi::CurrentChannel());
|
cChannel *ch = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||||
channel = ch ? ch->number : 0;
|
channel = ch ? ch->number : 0;
|
||||||
time_t t = time(NULL);
|
time_t t = time(NULL);
|
||||||
struct tm tm_r;
|
struct tm tm_r;
|
||||||
@ -836,10 +836,10 @@ cChannel *cChannels::GetByServiceID(unsigned short ServiceId)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cChannels::SwitchTo(int Number, cDvbApi *DvbApi)
|
bool cChannels::SwitchTo(int Number, cDevice *Device)
|
||||||
{
|
{
|
||||||
cChannel *channel = GetByNumber(Number);
|
cChannel *channel = GetByNumber(Number);
|
||||||
return channel && channel->Switch(DvbApi);
|
return channel && channel->Switch(Device);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *cChannels::GetChannelNameByNumber(int Number)
|
const char *cChannels::GetChannelNameByNumber(int Number)
|
||||||
@ -957,6 +957,7 @@ bool cSetupLine::operator< (const cListObject &ListObject)
|
|||||||
|
|
||||||
bool cSetupLine::Parse(char *s)
|
bool cSetupLine::Parse(char *s)
|
||||||
{
|
{
|
||||||
|
//dsyslog("cSetupLine::Parse '%s'", s);//XXX-
|
||||||
char *p = strchr(s, '=');
|
char *p = strchr(s, '=');
|
||||||
if (p) {
|
if (p) {
|
||||||
*p = 0;
|
*p = 0;
|
||||||
@ -974,6 +975,7 @@ bool cSetupLine::Parse(char *s)
|
|||||||
}
|
}
|
||||||
name = strdup(Name);
|
name = strdup(Name);
|
||||||
value = strdup(Value);
|
value = strdup(Value);
|
||||||
|
//dsyslog("cSetupLine::Parse '%s' = '%s'", name, value);//XXX-
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -982,6 +984,7 @@ bool cSetupLine::Parse(char *s)
|
|||||||
|
|
||||||
bool cSetupLine::Save(FILE *f)
|
bool cSetupLine::Save(FILE *f)
|
||||||
{
|
{
|
||||||
|
//dsyslog("cSetupLine::Save '%s' = '%s'", name, value);//XXX-
|
||||||
return fprintf(f, "%s%s%s = %s\n", plugin ? plugin : "", plugin ? "." : "", name, value) > 0;
|
return fprintf(f, "%s%s%s = %s\n", plugin ? plugin : "", plugin ? "." : "", name, value) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1095,7 +1098,7 @@ bool cSetup::Load(const char *FileName)
|
|||||||
|
|
||||||
void cSetup::StoreCaCaps(const char *Name)
|
void cSetup::StoreCaCaps(const char *Name)
|
||||||
{
|
{
|
||||||
for (int d = 0; d < MAXDVBAPI; d++) {
|
for (int d = 0; d < MAXDEVICES; d++) {
|
||||||
char buffer[MAXPARSEBUFFER];
|
char buffer[MAXPARSEBUFFER];
|
||||||
char *q = buffer;
|
char *q = buffer;
|
||||||
*buffer = 0;
|
*buffer = 0;
|
||||||
@ -1115,7 +1118,7 @@ bool cSetup::ParseCaCaps(const char *Value)
|
|||||||
{
|
{
|
||||||
char *p;
|
char *p;
|
||||||
int d = strtol(Value, &p, 10);
|
int d = strtol(Value, &p, 10);
|
||||||
if (d > 0 && d <= MAXDVBAPI) {
|
if (d > 0 && d <= MAXDEVICES) {
|
||||||
d--;
|
d--;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (p != Value && p && *p) {
|
while (p != Value && p && *p) {
|
||||||
|
10
config.h
10
config.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: config.h 1.117 2002/05/14 21:21:53 kls Exp $
|
* $Id: config.h 1.118 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __CONFIG_H
|
#ifndef __CONFIG_H
|
||||||
@ -15,7 +15,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "dvbapi.h"
|
#include "device.h"
|
||||||
#include "eit.h"
|
#include "eit.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ public:
|
|||||||
const char *ToText(void);
|
const char *ToText(void);
|
||||||
bool Parse(const char *s);
|
bool Parse(const char *s);
|
||||||
bool Save(FILE *f);
|
bool Save(FILE *f);
|
||||||
bool Switch(cDvbApi *DvbApi = NULL, bool Log = true);
|
bool Switch(cDevice *Device = NULL, bool Log = true);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eTimerActive { taInactive = 0,
|
enum eTimerActive { taInactive = 0,
|
||||||
@ -294,7 +294,7 @@ public:
|
|||||||
cChannel *GetByNumber(int Number);
|
cChannel *GetByNumber(int Number);
|
||||||
cChannel *GetByServiceID(unsigned short ServiceId);
|
cChannel *GetByServiceID(unsigned short ServiceId);
|
||||||
const char *GetChannelNameByNumber(int Number);
|
const char *GetChannelNameByNumber(int Number);
|
||||||
bool SwitchTo(int Number, cDvbApi *DvbApi = NULL);
|
bool SwitchTo(int Number, cDevice *Device = NULL);
|
||||||
int MaxNumber(void) { return maxNumber; }
|
int MaxNumber(void) { return maxNumber; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ public:
|
|||||||
int MinEventTimeout, MinUserInactivity;
|
int MinEventTimeout, MinUserInactivity;
|
||||||
int MultiSpeedMode;
|
int MultiSpeedMode;
|
||||||
int ShowReplayMode;
|
int ShowReplayMode;
|
||||||
int CaCaps[MAXDVBAPI][MAXCACAPS];
|
int CaCaps[MAXDEVICES][MAXCACAPS];
|
||||||
int CurrentChannel;
|
int CurrentChannel;
|
||||||
int CurrentVolume;
|
int CurrentVolume;
|
||||||
int __EndData__;
|
int __EndData__;
|
||||||
|
199
device.h
Normal file
199
device.h
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* device.h: The basic device interface
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: device.h 1.1 2002/06/10 16:30:00 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DEVICE_H
|
||||||
|
#define __DEVICE_H
|
||||||
|
|
||||||
|
#include <stdlib.h> // FIXME: this is apparently necessary for the ost/... header files
|
||||||
|
// FIXME: shouldn't every header file include ALL the other header
|
||||||
|
// FIXME: files it depends on? The sequence in which header files
|
||||||
|
// FIXME: are included here should not matter - and it should NOT
|
||||||
|
// FIXME: be necessary to include <stdlib.h> here!
|
||||||
|
#include <ost/dmx.h>
|
||||||
|
#include <ost/frontend.h>
|
||||||
|
#include <ost/audio.h>
|
||||||
|
#include <ost/video.h>
|
||||||
|
#include "eit.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
enum eSetChannelResult { scrOk, scrNoTransfer, scrFailed };
|
||||||
|
|
||||||
|
#define MAXDEVICES 4 // the maximum number of devices in the system
|
||||||
|
#define MAXCACAPS 16 // the maximum number of different CA values per DVB device
|
||||||
|
#define MAXPIDHANDLES 16 // the maximum number of different PIDs per DVB device
|
||||||
|
#define MAXRECEIVERS 16 // the maximum number of receivers per DVB device
|
||||||
|
#define MAXVOLUME 255
|
||||||
|
#define VOLUMEDELTA 5 // used to increase/decrease the volume
|
||||||
|
|
||||||
|
class cPlayer;
|
||||||
|
class cReceiver;
|
||||||
|
|
||||||
|
class cDevice : cThread {
|
||||||
|
friend class cOsd;//XXX
|
||||||
|
private:
|
||||||
|
static int numDevices;
|
||||||
|
static int useDevice;
|
||||||
|
static cDevice *device[MAXDEVICES];
|
||||||
|
static cDevice *primaryDevice;
|
||||||
|
public:
|
||||||
|
static int NumDevices(void) { return numDevices; }
|
||||||
|
// Returns the total number of DVB devices.
|
||||||
|
static void SetUseDevice(int n);
|
||||||
|
// Sets the 'useDevice' flag of the given DVB device.
|
||||||
|
// If this function is not called before Initialize(), all DVB devices
|
||||||
|
// will be used.
|
||||||
|
static bool SetPrimaryDevice(int n);
|
||||||
|
// Sets the primary DVB device to 'n' (which must be in the range
|
||||||
|
// 1...numDevices) and returns true if this was possible.
|
||||||
|
static cDevice *PrimaryDevice(void) { return primaryDevice; }
|
||||||
|
// Returns the primary DVB device.
|
||||||
|
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.
|
||||||
|
// If Ca is not 0, the device with the given number will be returned
|
||||||
|
// in case Ca is <= MAXDEVICES, or the device that provides the given
|
||||||
|
// value in its caCaps.
|
||||||
|
// If there is a device that is already tuned to the given Frequency,
|
||||||
|
// and that device is able to receive multiple channels ("budget" cards),
|
||||||
|
// that device will be returned. Else if a ("full featured") device is
|
||||||
|
// tuned to Frequency and Vpid, that one will be returned.
|
||||||
|
// If all DVB devices are currently receiving, the one receiving the
|
||||||
|
// lowest priority timer (if any) that is lower than the given Priority
|
||||||
|
// will be returned.
|
||||||
|
// If ReUse is given, the caller will be informed whether the device can be re-used
|
||||||
|
// for a new recording. If ReUse returns 'true', the caller must NOT switch the channel
|
||||||
|
// (the device is already properly tuned). Otherwise the caller MUST switch the channel.
|
||||||
|
static void SetCaCaps(void);
|
||||||
|
// Sets the CaCaps of all DVB devices according to the Setup data.
|
||||||
|
static bool Probe(const char *FileName);
|
||||||
|
// Probes for existing DVB devices.
|
||||||
|
static bool Initialize(void);
|
||||||
|
// Initializes the DVB devices.
|
||||||
|
// Must be called before accessing any DVB functions.
|
||||||
|
static void Shutdown(void);
|
||||||
|
// Closes down all DVB devices.
|
||||||
|
// Must be called at the end of the program.
|
||||||
|
private:
|
||||||
|
int cardIndex;
|
||||||
|
int caCaps[MAXCACAPS];
|
||||||
|
FrontendType frontendType;
|
||||||
|
char *dvrFileName;
|
||||||
|
bool active;
|
||||||
|
int fd_osd, fd_frontend, fd_sec, fd_audio, fd_video;
|
||||||
|
int OsdDeviceHandle(void) { return fd_osd; }
|
||||||
|
public:
|
||||||
|
cDevice(int n);
|
||||||
|
virtual ~cDevice();
|
||||||
|
bool IsPrimaryDevice(void) { return this == primaryDevice; }
|
||||||
|
int CardIndex(void) const { return cardIndex; }
|
||||||
|
// Returns the card index of this device (0 ... MAXDEVICES - 1).
|
||||||
|
int ProvidesCa(int Ca);
|
||||||
|
// Checks whether this DVB device provides the given value in its
|
||||||
|
// caCaps. Returns 0 if the value is not provided, 1 if only this
|
||||||
|
// value is provided, and > 1 if this and other values are provided.
|
||||||
|
// If the given value is equal to the number of this DVB device,
|
||||||
|
// 1 is returned. If it is 0 (FTA), 1 plus the number of other values
|
||||||
|
// in caCaps is returned.
|
||||||
|
bool HasDecoder(void) const { return fd_video >= 0 && fd_audio >= 0; }
|
||||||
|
|
||||||
|
// Channel facilities
|
||||||
|
|
||||||
|
private:
|
||||||
|
int currentChannel;
|
||||||
|
int frequency;
|
||||||
|
public:
|
||||||
|
eSetChannelResult SetChannel(int ChannelNumber, int Frequency, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Tpid, int Ca, int Pnr);
|
||||||
|
static int CurrentChannel(void) { return primaryDevice ? primaryDevice->currentChannel : 0; }
|
||||||
|
int Channel(void) { return currentChannel; }
|
||||||
|
|
||||||
|
// PID handle facilities
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum ePidType { ptVideo, ptAudio, ptTeletext, ptDolby, ptOther };
|
||||||
|
class cPidHandle {
|
||||||
|
public:
|
||||||
|
int pid;
|
||||||
|
int fd;
|
||||||
|
int used;
|
||||||
|
cPidHandle(void) { pid = used = 0; fd = -1; }
|
||||||
|
};
|
||||||
|
cPidHandle pidHandles[MAXPIDHANDLES];
|
||||||
|
bool AddPid(int Pid, ePidType PidType = ptOther);
|
||||||
|
bool DelPid(int Pid);
|
||||||
|
bool SetPid(int fd, dmxPesType_t PesType, int Pid, dmxOutput_t Output);
|
||||||
|
virtual void Action(void);
|
||||||
|
|
||||||
|
// Image Grab facilities
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool GrabImage(const char *FileName, bool Jpeg = true, int Quality = -1, int SizeX = -1, int SizeY = -1);
|
||||||
|
|
||||||
|
// Video format facilities
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void SetVideoFormat(videoFormat_t Format);
|
||||||
|
|
||||||
|
// Volume facilities
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mute;
|
||||||
|
int volume;
|
||||||
|
public:
|
||||||
|
bool IsMute(void) { return mute; }
|
||||||
|
bool ToggleMute(void);
|
||||||
|
// Turns the volume off or on and returns the new mute state.
|
||||||
|
void SetVolume(int Volume, bool Absolute = false);
|
||||||
|
// Sets the volume to the given value, either absolutely or relative to
|
||||||
|
// the current volume.
|
||||||
|
static int CurrentVolume(void) { return primaryDevice ? primaryDevice->volume : 0; }//XXX???
|
||||||
|
|
||||||
|
// EIT facilities
|
||||||
|
|
||||||
|
private:
|
||||||
|
cSIProcessor *siProcessor;
|
||||||
|
|
||||||
|
// Player facilities
|
||||||
|
|
||||||
|
private:
|
||||||
|
cPlayer *player;
|
||||||
|
public:
|
||||||
|
void TrickSpeed(int Speed);
|
||||||
|
void Clear(void);
|
||||||
|
void Play(void);
|
||||||
|
void Freeze(void);
|
||||||
|
void Mute(void);
|
||||||
|
void StillPicture(const uchar *Data, int Length);
|
||||||
|
bool Replaying(void);
|
||||||
|
// Returns true if we are currently replaying.
|
||||||
|
void StopReplay(void);
|
||||||
|
// Stops the current replay session (if any).
|
||||||
|
bool Attach(cPlayer *Player);
|
||||||
|
void Detach(cPlayer *Player);
|
||||||
|
virtual int PlayVideo(const uchar *Data, int Length);
|
||||||
|
virtual int PlayAudio(const uchar *Data, int Length);
|
||||||
|
|
||||||
|
// Receiver facilities
|
||||||
|
|
||||||
|
private:
|
||||||
|
cReceiver *receiver[MAXRECEIVERS];
|
||||||
|
int ca;
|
||||||
|
int Priority(void);
|
||||||
|
// Returns the priority of the current receiving session (0..MAXPRIORITY),
|
||||||
|
// or -1 if no receiver is currently active. The primary DVB device will
|
||||||
|
// always return at least Setup.PrimaryLimit-1.
|
||||||
|
int CanShift(int Ca, int Priority, int UsedCards = 0);
|
||||||
|
public:
|
||||||
|
int Ca(void) { return ca; }
|
||||||
|
// Returns the ca of the current receiving session.
|
||||||
|
bool Receiving(void);
|
||||||
|
// Returns true if we are currently receiving.
|
||||||
|
bool Attach(cReceiver *Receiver);
|
||||||
|
void Detach(cReceiver *Receiver);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__DEVICE_H
|
733
dvbplayer.c
Normal file
733
dvbplayer.c
Normal file
@ -0,0 +1,733 @@
|
|||||||
|
/*
|
||||||
|
* dvbplayer.c: The DVB player
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: dvbplayer.c 1.1 2002/06/16 10:59:45 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "dvbplayer.h"
|
||||||
|
#include <poll.h>
|
||||||
|
#include "recording.h"
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
// --- ReadFrame -------------------------------------------------------------
|
||||||
|
|
||||||
|
int ReadFrame(int f, uchar *b, int Length, int Max)
|
||||||
|
{
|
||||||
|
if (Length == -1)
|
||||||
|
Length = Max; // this means we read up to EOF (see cIndex)
|
||||||
|
else if (Length > Max) {
|
||||||
|
esyslog("ERROR: frame larger than buffer (%d > %d)", Length, Max);
|
||||||
|
Length = Max;
|
||||||
|
}
|
||||||
|
int r = safe_read(f, b, Length);
|
||||||
|
if (r < 0)
|
||||||
|
LOG_ERROR;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cBackTrace ----------------------------------------------------------
|
||||||
|
|
||||||
|
#define AVG_FRAME_SIZE 15000 // an assumption about the average frame size
|
||||||
|
#define DVB_BUF_SIZE (256 * 1024) // an assumption about the dvb firmware buffer size
|
||||||
|
#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) // how many entries are needed to backtrace buffer contents
|
||||||
|
|
||||||
|
class cBackTrace {
|
||||||
|
private:
|
||||||
|
int index[BACKTRACE_ENTRIES];
|
||||||
|
int length[BACKTRACE_ENTRIES];
|
||||||
|
int pos, num;
|
||||||
|
public:
|
||||||
|
cBackTrace(void);
|
||||||
|
void Clear(void);
|
||||||
|
void Add(int Index, int Length);
|
||||||
|
int Get(bool Forward);
|
||||||
|
};
|
||||||
|
|
||||||
|
cBackTrace::cBackTrace(void)
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cBackTrace::Clear(void)
|
||||||
|
{
|
||||||
|
pos = num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cBackTrace::Add(int Index, int Length)
|
||||||
|
{
|
||||||
|
index[pos] = Index;
|
||||||
|
length[pos] = Length;
|
||||||
|
if (++pos >= BACKTRACE_ENTRIES)
|
||||||
|
pos = 0;
|
||||||
|
if (num < BACKTRACE_ENTRIES)
|
||||||
|
num++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cBackTrace::Get(bool Forward)
|
||||||
|
{
|
||||||
|
int p = pos;
|
||||||
|
int n = num;
|
||||||
|
int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); //XXX (256 * 1024) == DVB_BUF_SIZE ???
|
||||||
|
int i = -1;
|
||||||
|
|
||||||
|
while (n && l > 0) {
|
||||||
|
if (--p < 0)
|
||||||
|
p = BACKTRACE_ENTRIES - 1;
|
||||||
|
i = index[p] - 1;
|
||||||
|
l -= length[p];
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cDvbPlayer ------------------------------------------------------------
|
||||||
|
|
||||||
|
//XXX+ also used in recorder.c - find a better place???
|
||||||
|
// The size of the array used to buffer video data:
|
||||||
|
// (must be larger than MINVIDEODATA - see remux.h)
|
||||||
|
#define VIDEOBUFSIZE MEGABYTE(1)
|
||||||
|
|
||||||
|
// The maximum size of a single frame:
|
||||||
|
#define MAXFRAMESIZE KILOBYTE(192)
|
||||||
|
|
||||||
|
// The number of frames to back up when resuming an interrupted replay session:
|
||||||
|
#define RESUMEBACKUP (10 * FRAMESPERSEC)
|
||||||
|
|
||||||
|
class cDvbPlayer : public cPlayer, cThread {
|
||||||
|
private:
|
||||||
|
enum ePlayModes { pmPlay, pmPause, pmSlow, pmFast, pmStill };
|
||||||
|
enum ePlayDirs { pdForward, pdBackward };
|
||||||
|
static int Speeds[];
|
||||||
|
cRingBufferFrame *ringBuffer;
|
||||||
|
cBackTrace *backTrace;
|
||||||
|
cFileName *fileName;
|
||||||
|
cIndexFile *index;
|
||||||
|
int replayFile;
|
||||||
|
bool eof;
|
||||||
|
bool active;
|
||||||
|
ePlayModes playMode;
|
||||||
|
ePlayDirs playDir;
|
||||||
|
int trickSpeed;
|
||||||
|
int readIndex, writeIndex;
|
||||||
|
cFrame *readFrame;
|
||||||
|
const cFrame *playFrame;
|
||||||
|
void TrickSpeed(int Increment);
|
||||||
|
void Empty(void);
|
||||||
|
void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
|
||||||
|
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
|
||||||
|
int Resume(void);
|
||||||
|
bool Save(void);
|
||||||
|
protected:
|
||||||
|
virtual void Activate(bool On);
|
||||||
|
virtual void Action(void);
|
||||||
|
public:
|
||||||
|
cDvbPlayer(const char *FileName);
|
||||||
|
virtual ~cDvbPlayer();
|
||||||
|
bool Active(void) { return active; }
|
||||||
|
void Pause(void);
|
||||||
|
void Play(void);
|
||||||
|
void Forward(void);
|
||||||
|
void Backward(void);
|
||||||
|
int SkipFrames(int Frames);
|
||||||
|
void SkipSeconds(int Seconds);
|
||||||
|
void Goto(int Position, bool Still = false);
|
||||||
|
void GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
|
||||||
|
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_VIDEO_SLOWMOTION 63 // max. arg to pass to VIDEO_SLOWMOTION // TODO is this value correct?
|
||||||
|
#define NORMAL_SPEED 4 // the index of the '1' entry in the following array
|
||||||
|
#define MAX_SPEEDS 3 // the offset of the maximum speed from normal speed in either direction
|
||||||
|
#define SPEED_MULT 12 // the speed multiplier
|
||||||
|
int cDvbPlayer::Speeds[] = { 0, -2, -4, -8, 1, 2, 4, 12, 0 };
|
||||||
|
|
||||||
|
cDvbPlayer::cDvbPlayer(const char *FileName)
|
||||||
|
{
|
||||||
|
ringBuffer = NULL;
|
||||||
|
backTrace = NULL;
|
||||||
|
index = NULL;
|
||||||
|
eof = false;
|
||||||
|
active = false;
|
||||||
|
playMode = pmPlay;
|
||||||
|
playDir = pdForward;
|
||||||
|
trickSpeed = NORMAL_SPEED;
|
||||||
|
readIndex = writeIndex = -1;
|
||||||
|
readFrame = NULL;
|
||||||
|
playFrame = NULL;
|
||||||
|
isyslog("replay %s", FileName);
|
||||||
|
fileName = new cFileName(FileName, false);
|
||||||
|
replayFile = fileName->Open();
|
||||||
|
if (replayFile < 0)
|
||||||
|
return;
|
||||||
|
ringBuffer = new cRingBufferFrame(VIDEOBUFSIZE);
|
||||||
|
// Create the index file:
|
||||||
|
index = new cIndexFile(FileName, false);
|
||||||
|
if (!index)
|
||||||
|
esyslog("ERROR: can't allocate index");
|
||||||
|
else if (!index->Ok()) {
|
||||||
|
delete index;
|
||||||
|
index = NULL;
|
||||||
|
}
|
||||||
|
backTrace = new cBackTrace;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDvbPlayer::~cDvbPlayer()
|
||||||
|
{
|
||||||
|
Detach();
|
||||||
|
Save();
|
||||||
|
delete index;
|
||||||
|
delete fileName;
|
||||||
|
delete backTrace;
|
||||||
|
delete ringBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::TrickSpeed(int Increment)
|
||||||
|
{
|
||||||
|
int nts = trickSpeed + Increment;
|
||||||
|
if (Speeds[nts] == 1) {
|
||||||
|
trickSpeed = nts;
|
||||||
|
if (playMode == pmFast)
|
||||||
|
Play();
|
||||||
|
else
|
||||||
|
Pause();
|
||||||
|
}
|
||||||
|
else if (Speeds[nts]) {
|
||||||
|
trickSpeed = nts;
|
||||||
|
int Mult = (playMode == pmSlow && playDir == pdForward) ? 1 : SPEED_MULT;
|
||||||
|
int sp = (Speeds[nts] > 0) ? Mult / Speeds[nts] : -Speeds[nts] * Mult;
|
||||||
|
if (sp > MAX_VIDEO_SLOWMOTION)
|
||||||
|
sp = MAX_VIDEO_SLOWMOTION;
|
||||||
|
DeviceTrickSpeed(sp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Empty(void)
|
||||||
|
{
|
||||||
|
Lock();
|
||||||
|
if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
|
||||||
|
readIndex = writeIndex;
|
||||||
|
readFrame = NULL;
|
||||||
|
playFrame = NULL;
|
||||||
|
ringBuffer->Clear();
|
||||||
|
backTrace->Clear();
|
||||||
|
DeviceClear();
|
||||||
|
Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::StripAudioPackets(uchar *b, int Length, uchar Except)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
for (int i = 0; i < Length - 6; i++) {
|
||||||
|
if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
|
||||||
|
uchar c = b[i + 3];
|
||||||
|
int l = b[i + 4] * 256 + b[i + 5] + 6;
|
||||||
|
switch (c) {
|
||||||
|
case 0xBD: // dolby
|
||||||
|
if (Except)
|
||||||
|
;//XXX+ PlayExternalDolby(&b[i], Length - i);
|
||||||
|
// continue with deleting the data - otherwise it disturbs DVB replay
|
||||||
|
case 0xC0 ... 0xC1: // audio
|
||||||
|
if (c == 0xC1)
|
||||||
|
;//XXX+ canToggleAudioTrack = true;
|
||||||
|
if (!Except || c != Except) {
|
||||||
|
int n = l;
|
||||||
|
for (int j = i; j < Length && n--; j++)
|
||||||
|
b[j] = 0x00;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0xE0 ... 0xEF: // video
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//esyslog("ERROR: unexpected packet id %02X", c);
|
||||||
|
l = 0;
|
||||||
|
}
|
||||||
|
if (l)
|
||||||
|
i += l - 1; // the loop increments, too!
|
||||||
|
}
|
||||||
|
/*XXX
|
||||||
|
else
|
||||||
|
esyslog("ERROR: broken packet header");
|
||||||
|
XXX*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbPlayer::NextFile(uchar FileNumber, int FileOffset)
|
||||||
|
{
|
||||||
|
if (FileNumber > 0)
|
||||||
|
replayFile = fileName->SetOffset(FileNumber, FileOffset);
|
||||||
|
else if (replayFile >= 0 && eof)
|
||||||
|
replayFile = fileName->NextFile();
|
||||||
|
eof = false;
|
||||||
|
return replayFile >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cDvbPlayer::Resume(void)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
int Index = index->GetResume();
|
||||||
|
if (Index >= 0) {
|
||||||
|
uchar FileNumber;
|
||||||
|
int FileOffset;
|
||||||
|
if (index->Get(Index, &FileNumber, &FileOffset) && NextFile(FileNumber, FileOffset))
|
||||||
|
return Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbPlayer::Save(void)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
int Index = writeIndex;
|
||||||
|
if (Index >= 0) {
|
||||||
|
Index -= RESUMEBACKUP;
|
||||||
|
if (Index > 0)
|
||||||
|
Index = index->GetNextIFrame(Index, false);
|
||||||
|
else
|
||||||
|
Index = 0;
|
||||||
|
if (Index >= 0)
|
||||||
|
return index->StoreResume(Index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Activate(bool On)
|
||||||
|
{
|
||||||
|
if (On) {
|
||||||
|
if (replayFile >= 0)
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
else if (active) {
|
||||||
|
active = false;
|
||||||
|
Cancel(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Action(void)
|
||||||
|
{
|
||||||
|
active = true;
|
||||||
|
dsyslog("dvbplayer thread started (pid=%d)", getpid());
|
||||||
|
|
||||||
|
uchar b[MAXFRAMESIZE];
|
||||||
|
const uchar *p = NULL;
|
||||||
|
int pc = 0;
|
||||||
|
|
||||||
|
pollfd pfd[2];
|
||||||
|
pfd[0].fd = DeviceFileHandle();
|
||||||
|
pfd[0].events = pfd[0].revents = POLLOUT;
|
||||||
|
pfd[1].fd = replayFile;
|
||||||
|
pfd[1].events = pfd[1].revents = POLLIN;
|
||||||
|
|
||||||
|
readIndex = Resume();
|
||||||
|
if (readIndex >= 0)
|
||||||
|
isyslog("resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true));
|
||||||
|
|
||||||
|
while (active && NextFile()) {
|
||||||
|
{
|
||||||
|
LOCK_THREAD;
|
||||||
|
|
||||||
|
// Read the next frame from the file:
|
||||||
|
|
||||||
|
if (!readFrame && (pfd[1].revents & POLLIN)) {
|
||||||
|
if (playMode != pmStill) {
|
||||||
|
int r = 0;
|
||||||
|
if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
|
||||||
|
uchar FileNumber;
|
||||||
|
int FileOffset, Length;
|
||||||
|
int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, true);
|
||||||
|
if (Index >= 0) {
|
||||||
|
if (!NextFile(FileNumber, FileOffset))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// can't call Play() here, because those functions may only be
|
||||||
|
// called from the foreground thread - and we also don't need
|
||||||
|
// to empty the buffer here
|
||||||
|
DevicePlay();
|
||||||
|
playMode = pmPlay;
|
||||||
|
playDir = pdForward;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
readIndex = Index;
|
||||||
|
r = ReadFrame(replayFile, b, Length, sizeof(b));
|
||||||
|
// must call StripAudioPackets() here because the buffer is not emptied
|
||||||
|
// when falling back from "fast forward" to "play" (see above)
|
||||||
|
StripAudioPackets(b, r);
|
||||||
|
}
|
||||||
|
else if (index) {
|
||||||
|
uchar FileNumber;
|
||||||
|
int FileOffset, Length;
|
||||||
|
readIndex++;
|
||||||
|
if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))
|
||||||
|
break;
|
||||||
|
r = ReadFrame(replayFile, b, Length, sizeof(b));
|
||||||
|
}
|
||||||
|
else // allows replay even if the index file is missing
|
||||||
|
r = read(replayFile, b, sizeof(b));
|
||||||
|
if (r > 0)
|
||||||
|
readFrame = new cFrame(b, r, ftUnknown, readIndex);
|
||||||
|
else if (r == 0)
|
||||||
|
eof = true;
|
||||||
|
else if (r < 0 && FATALERRNO) {
|
||||||
|
LOG_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else//XXX
|
||||||
|
usleep(1); // this keeps the CPU load low
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the frame in the buffer:
|
||||||
|
|
||||||
|
if (readFrame) {
|
||||||
|
if (ringBuffer->Put(readFrame))
|
||||||
|
readFrame = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the next frame from the buffer:
|
||||||
|
|
||||||
|
if (!playFrame) {
|
||||||
|
playFrame = ringBuffer->Get();
|
||||||
|
p = NULL;
|
||||||
|
pc = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play the frame:
|
||||||
|
|
||||||
|
if (playFrame && (pfd[0].revents & POLLOUT)) {
|
||||||
|
if (!p) {
|
||||||
|
p = playFrame->Data();
|
||||||
|
pc = playFrame->Count();
|
||||||
|
}
|
||||||
|
if (p) {
|
||||||
|
int w = PlayVideo(p, pc);
|
||||||
|
if (w > 0) {
|
||||||
|
p += w;
|
||||||
|
pc -= w;
|
||||||
|
}
|
||||||
|
else if (w < 0 && FATALERRNO) {
|
||||||
|
LOG_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pc == 0) {
|
||||||
|
writeIndex = playFrame->Index();
|
||||||
|
backTrace->Add(playFrame->Index(), playFrame->Count());
|
||||||
|
ringBuffer->Drop(playFrame);
|
||||||
|
playFrame = NULL;
|
||||||
|
p = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for input or output to become ready:
|
||||||
|
|
||||||
|
if (poll(pfd, readFrame ? 1 : 2, 10) < 0 && FATALERRNO) {
|
||||||
|
LOG_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dsyslog("dvbplayer thread ended (pid=%d)", getpid());
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Pause(void)
|
||||||
|
{
|
||||||
|
if (playMode == pmPause || playMode == pmStill)
|
||||||
|
Play();
|
||||||
|
else {
|
||||||
|
LOCK_THREAD;
|
||||||
|
if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))
|
||||||
|
Empty();
|
||||||
|
DeviceFreeze();
|
||||||
|
playMode = pmPause;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Play(void)
|
||||||
|
{
|
||||||
|
if (playMode != pmPlay) {
|
||||||
|
LOCK_THREAD;
|
||||||
|
if (playMode == pmStill || playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))
|
||||||
|
Empty();
|
||||||
|
DevicePlay();
|
||||||
|
playMode = pmPlay;
|
||||||
|
playDir = pdForward;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Forward(void)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
switch (playMode) {
|
||||||
|
case pmFast:
|
||||||
|
if (Setup.MultiSpeedMode) {
|
||||||
|
TrickSpeed(playDir == pdForward ? 1 : -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (playDir == pdForward) {
|
||||||
|
Play();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// run into pmPlay
|
||||||
|
case pmPlay: {
|
||||||
|
LOCK_THREAD;
|
||||||
|
Empty();
|
||||||
|
DeviceMute();
|
||||||
|
playMode = pmFast;
|
||||||
|
playDir = pdForward;
|
||||||
|
trickSpeed = NORMAL_SPEED;
|
||||||
|
TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case pmSlow:
|
||||||
|
if (Setup.MultiSpeedMode) {
|
||||||
|
TrickSpeed(playDir == pdForward ? -1 : 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (playDir == pdForward) {
|
||||||
|
Pause();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// run into pmPause
|
||||||
|
case pmStill:
|
||||||
|
case pmPause:
|
||||||
|
DeviceMute();
|
||||||
|
playMode = pmSlow;
|
||||||
|
playDir = pdForward;
|
||||||
|
trickSpeed = NORMAL_SPEED;
|
||||||
|
TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Backward(void)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
switch (playMode) {
|
||||||
|
case pmFast:
|
||||||
|
if (Setup.MultiSpeedMode) {
|
||||||
|
TrickSpeed(playDir == pdBackward ? 1 : -1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (playDir == pdBackward) {
|
||||||
|
Play();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// run into pmPlay
|
||||||
|
case pmPlay: {
|
||||||
|
LOCK_THREAD;
|
||||||
|
Empty();
|
||||||
|
DeviceMute();
|
||||||
|
playMode = pmFast;
|
||||||
|
playDir = pdBackward;
|
||||||
|
trickSpeed = NORMAL_SPEED;
|
||||||
|
TrickSpeed(Setup.MultiSpeedMode ? 1 : MAX_SPEEDS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case pmSlow:
|
||||||
|
if (Setup.MultiSpeedMode) {
|
||||||
|
TrickSpeed(playDir == pdBackward ? -1 : 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (playDir == pdBackward) {
|
||||||
|
Pause();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// run into pmPause
|
||||||
|
case pmStill:
|
||||||
|
case pmPause: {
|
||||||
|
LOCK_THREAD;
|
||||||
|
Empty();
|
||||||
|
DeviceMute();
|
||||||
|
playMode = pmSlow;
|
||||||
|
playDir = pdBackward;
|
||||||
|
trickSpeed = NORMAL_SPEED;
|
||||||
|
TrickSpeed(Setup.MultiSpeedMode ? -1 : -MAX_SPEEDS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cDvbPlayer::SkipFrames(int Frames)
|
||||||
|
{
|
||||||
|
if (index && Frames) {
|
||||||
|
int Current, Total;
|
||||||
|
GetIndex(Current, Total, true);
|
||||||
|
int OldCurrent = Current;
|
||||||
|
Current = index->GetNextIFrame(Current + Frames, Frames > 0);
|
||||||
|
return Current >= 0 ? Current : OldCurrent;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::SkipSeconds(int Seconds)
|
||||||
|
{
|
||||||
|
if (index && Seconds) {
|
||||||
|
LOCK_THREAD;
|
||||||
|
Empty();
|
||||||
|
int Index = writeIndex;
|
||||||
|
if (Index >= 0) {
|
||||||
|
Index = max(Index + Seconds * FRAMESPERSEC, 0);
|
||||||
|
if (Index > 0)
|
||||||
|
Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true);
|
||||||
|
if (Index >= 0)
|
||||||
|
readIndex = writeIndex = Index - 1; // Input() will first increment it!
|
||||||
|
}
|
||||||
|
Play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::Goto(int Index, bool Still)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
LOCK_THREAD;
|
||||||
|
Empty();
|
||||||
|
if (++Index <= 0)
|
||||||
|
Index = 1; // not '0', to allow GetNextIFrame() below to work!
|
||||||
|
uchar FileNumber;
|
||||||
|
int FileOffset, Length;
|
||||||
|
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
|
||||||
|
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
|
||||||
|
uchar b[MAXFRAMESIZE];
|
||||||
|
int r = ReadFrame(replayFile, b, Length, sizeof(b));
|
||||||
|
if (r > 0) {
|
||||||
|
if (playMode == pmPause)
|
||||||
|
DevicePlay();
|
||||||
|
StripAudioPackets(b, r);
|
||||||
|
DeviceStillPicture(b, r);
|
||||||
|
}
|
||||||
|
playMode = pmStill;
|
||||||
|
}
|
||||||
|
readIndex = writeIndex = Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
if (playMode == pmStill)
|
||||||
|
Current = max(readIndex, 0);
|
||||||
|
else {
|
||||||
|
Current = max(writeIndex, 0);
|
||||||
|
if (SnapToIFrame) {
|
||||||
|
int i1 = index->GetNextIFrame(Current + 1, false);
|
||||||
|
int i2 = index->GetNextIFrame(Current, true);
|
||||||
|
Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Total = index->Last();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Current = Total = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbPlayer::GetReplayMode(bool &Play, bool &Forward, int &Speed)
|
||||||
|
{
|
||||||
|
Play = (playMode == pmPlay || playMode == pmFast);
|
||||||
|
Forward = (playDir == pdForward);
|
||||||
|
if (playMode == pmFast || playMode == pmSlow)
|
||||||
|
Speed = Setup.MultiSpeedMode ? abs(trickSpeed - NORMAL_SPEED) : 0;
|
||||||
|
else
|
||||||
|
Speed = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cDvbPlayerControl -----------------------------------------------------
|
||||||
|
|
||||||
|
cDvbPlayerControl::cDvbPlayerControl(void)
|
||||||
|
{
|
||||||
|
player = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cDvbPlayerControl::~cDvbPlayerControl()
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbPlayerControl::Active(void)
|
||||||
|
{
|
||||||
|
return player && player->Active();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbPlayerControl::Start(const char *FileName)
|
||||||
|
{
|
||||||
|
delete player;
|
||||||
|
player = new cDvbPlayer(FileName);
|
||||||
|
if (cDevice::PrimaryDevice()->Attach(player))
|
||||||
|
return true;
|
||||||
|
Stop();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayerControl::Stop(void)
|
||||||
|
{
|
||||||
|
delete player;
|
||||||
|
player = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayerControl::Pause(void)
|
||||||
|
{
|
||||||
|
if (player)
|
||||||
|
player->Pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayerControl::Play(void)
|
||||||
|
{
|
||||||
|
if (player)
|
||||||
|
player->Play();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayerControl::Forward(void)
|
||||||
|
{
|
||||||
|
if (player)
|
||||||
|
player->Forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayerControl::Backward(void)
|
||||||
|
{
|
||||||
|
if (player)
|
||||||
|
player->Backward();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayerControl::SkipSeconds(int Seconds)
|
||||||
|
{
|
||||||
|
if (player)
|
||||||
|
player->SkipSeconds(Seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cDvbPlayerControl::SkipFrames(int Frames)
|
||||||
|
{
|
||||||
|
if (player)
|
||||||
|
return player->SkipFrames(Frames);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbPlayerControl::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
||||||
|
{
|
||||||
|
if (player) {
|
||||||
|
player->GetIndex(Current, Total, SnapToIFrame);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cDvbPlayerControl::GetReplayMode(bool &Play, bool &Forward, int &Speed)
|
||||||
|
{
|
||||||
|
return player && player->GetReplayMode(Play, Forward, Speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cDvbPlayerControl::Goto(int Position, bool Still)
|
||||||
|
{
|
||||||
|
if (player)
|
||||||
|
player->Goto(Position, Still);
|
||||||
|
}
|
60
dvbplayer.h
Normal file
60
dvbplayer.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* dvbplayer.h: The DVB player
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: dvbplayer.h 1.1 2002/06/16 10:59:14 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __DVBPLAYER_H
|
||||||
|
#define __DVBPLAYER_H
|
||||||
|
|
||||||
|
#include "player.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
class cDvbPlayer;
|
||||||
|
|
||||||
|
class cDvbPlayerControl : public cControl {
|
||||||
|
private:
|
||||||
|
cDvbPlayer *player;
|
||||||
|
public:
|
||||||
|
cDvbPlayerControl(void);
|
||||||
|
virtual ~cDvbPlayerControl();
|
||||||
|
bool Active(void);
|
||||||
|
bool Start(const char *FileName);
|
||||||
|
// Starts replaying the given file.
|
||||||
|
void Stop(void);
|
||||||
|
// Stops the current replay session (if any).
|
||||||
|
void Pause(void);
|
||||||
|
// Pauses the current replay session, or resumes a paused session.
|
||||||
|
void Play(void);
|
||||||
|
// Resumes normal replay mode.
|
||||||
|
void Forward(void);
|
||||||
|
// Runs the current replay session forward at a higher speed.
|
||||||
|
void Backward(void);
|
||||||
|
// Runs the current replay session backwards at a higher speed.
|
||||||
|
int SkipFrames(int Frames);
|
||||||
|
// Returns the new index into the current replay session after skipping
|
||||||
|
// the given number of frames (no actual repositioning is done!).
|
||||||
|
// The sign of 'Frames' determines the direction in which to skip.
|
||||||
|
void SkipSeconds(int Seconds);
|
||||||
|
// Skips the given number of seconds in the current replay session.
|
||||||
|
// The sign of 'Seconds' determines the direction in which to skip.
|
||||||
|
// Use a very large negative value to go all the way back to the
|
||||||
|
// beginning of the recording.
|
||||||
|
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
|
||||||
|
// Returns the current and total frame index, optionally snapped to the
|
||||||
|
// nearest I-frame.
|
||||||
|
bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
|
||||||
|
// Returns the current replay mode (if applicable).
|
||||||
|
// 'Play' tells whether we are playing or pausing, 'Forward' tells whether
|
||||||
|
// we are going forward or backward and 'Speed' is -1 if this is normal
|
||||||
|
// play/pause mode, 0 if it is single speed fast/slow forward/back mode
|
||||||
|
// and >0 if this is multi speed mode.
|
||||||
|
void Goto(int Index, bool Still = false);
|
||||||
|
// Positions to the given index and displays that frame as a still picture
|
||||||
|
// if Still is true.
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__DVBPLAYER_H
|
3
eit.c
3
eit.c
@ -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.c 1.45 2002/05/13 16:35:49 kls Exp $
|
* $Id: eit.c 1.46 2002/06/10 16:30:00 kls Exp $
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
#include "eit.h"
|
#include "eit.h"
|
||||||
@ -26,6 +26,7 @@
|
|||||||
#include <iomanip.h>
|
#include <iomanip.h>
|
||||||
#include <iostream.h>
|
#include <iostream.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
|
#include <ost/dmx.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
20
eitscan.c
20
eitscan.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: eitscan.c 1.1 2002/05/20 10:58:10 kls Exp $
|
* $Id: eitscan.c 1.2 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "eitscan.h"
|
#include "eitscan.h"
|
||||||
@ -48,11 +48,11 @@ void cEITScanner::Process(void)
|
|||||||
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
|
if (Setup.EPGScanTimeout && Channels.MaxNumber() > 1) {
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
|
if (now - lastScan > ScanTimeout && now - lastActivity > ActivityTimeout) {
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
for (int i = 0; i < MAXDEVICES; i++) {
|
||||||
cDvbApi *DvbApi = cDvbApi::GetDvbApi(i + 1, MAXPRIORITY + 1);
|
cDevice *Device = cDevice::GetDevice(i + 1, MAXPRIORITY + 1);
|
||||||
if (DvbApi) {
|
if (Device) {
|
||||||
if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
|
if (Device != cDevice::PrimaryDevice() || (cDevice::NumDevices() == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
|
||||||
if (!(DvbApi->Recording() || DvbApi->Replaying() || DvbApi->Transferring())) {
|
if (!(Device->Receiving() || Device->Replaying()/*XXX+ || Device->Transferring()XXX*/)) {
|
||||||
int oldCh = lastChannel;
|
int oldCh = lastChannel;
|
||||||
int ch = oldCh + 1;
|
int ch = oldCh + 1;
|
||||||
while (ch != oldCh) {
|
while (ch != oldCh) {
|
||||||
@ -62,12 +62,12 @@ void cEITScanner::Process(void)
|
|||||||
}
|
}
|
||||||
cChannel *Channel = Channels.GetByNumber(ch);
|
cChannel *Channel = Channels.GetByNumber(ch);
|
||||||
if (Channel) {
|
if (Channel) {
|
||||||
if (Channel->ca <= MAXDVBAPI && !DvbApi->ProvidesCa(Channel->ca))
|
if (Channel->ca <= MAXDEVICES && !Device->ProvidesCa(Channel->ca))
|
||||||
break; // the channel says it explicitly needs a different card
|
break; // the channel says it explicitly needs a different card
|
||||||
if (Channel->pnr && !TransponderScanned(Channel)) {
|
if (Channel->pnr && !TransponderScanned(Channel)) {
|
||||||
if (DvbApi == cDvbApi::PrimaryDvbApi && !currentChannel)
|
if (Device == cDevice::PrimaryDevice() && !currentChannel)
|
||||||
currentChannel = DvbApi->Channel();
|
currentChannel = Device->Channel();
|
||||||
Channel->Switch(DvbApi, false);
|
Channel->Switch(Device, false);
|
||||||
lastChannel = ch;
|
lastChannel = ch;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -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: interface.c 1.50 2002/05/19 12:02:57 kls Exp $
|
* $Id: interface.c 1.51 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
@ -484,6 +484,6 @@ void cInterface::DisplayRecording(int Index, bool On)
|
|||||||
|
|
||||||
bool cInterface::Recording(void)
|
bool cInterface::Recording(void)
|
||||||
{
|
{
|
||||||
// This is located here because the Interface has to do with the "PrimaryDvbApi" anyway
|
// This is located here because the Interface has to do with the "PrimaryDevice" anyway
|
||||||
return cDvbApi::PrimaryDvbApi->Recording();
|
return cDevice::PrimaryDevice()->Receiving();
|
||||||
}
|
}
|
||||||
|
186
menu.c
186
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.195 2002/05/19 14:55:22 kls Exp $
|
* $Id: menu.c 1.196 2002/06/16 12:11:02 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
@ -18,6 +18,7 @@
|
|||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "menuitems.h"
|
#include "menuitems.h"
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
|
#include "recording.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
#include "videodir.h"
|
#include "videodir.h"
|
||||||
|
|
||||||
@ -25,6 +26,7 @@
|
|||||||
#define MAXWAIT4EPGINFO 10 // seconds
|
#define MAXWAIT4EPGINFO 10 // seconds
|
||||||
#define MODETIMEOUT 3 // seconds
|
#define MODETIMEOUT 3 // seconds
|
||||||
|
|
||||||
|
#define MAXRECORDCONTROLS (MAXDEVICES * MAXRECEIVERS)
|
||||||
#define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
|
#define MAXINSTANTRECTIME (24 * 60 - 1) // 23:59 hours
|
||||||
|
|
||||||
#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels...
|
#define CHNUMWIDTH (Channels.Count() > 999 ? 5 : 4) // there are people with more than 999 channels...
|
||||||
@ -376,7 +378,7 @@ eOSState cMenuEditCaItem::ProcessKey(eKeys Key)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (NORMALKEY(Key) == kRight) {
|
else if (NORMALKEY(Key) == kRight) {
|
||||||
if (ca && ca->Next() && (allowCardNr || ((cCaDefinition *)ca->Next())->Number() > MAXDVBAPI)) {
|
if (ca && ca->Next() && (allowCardNr || ((cCaDefinition *)ca->Next())->Number() > MAXDEVICES)) {
|
||||||
ca = (cCaDefinition *)ca->Next();
|
ca = (cCaDefinition *)ca->Next();
|
||||||
*value = ca->Number();
|
*value = ca->Number();
|
||||||
}
|
}
|
||||||
@ -494,7 +496,7 @@ cMenuChannels::cMenuChannels(void)
|
|||||||
//TODO
|
//TODO
|
||||||
int i = 0;
|
int i = 0;
|
||||||
cChannel *channel;
|
cChannel *channel;
|
||||||
int curr = ((channel = Channels.GetByNumber(cDvbApi::CurrentChannel())) != NULL) ? channel->Index() : -1;
|
int curr = ((channel = Channels.GetByNumber(cDevice::CurrentChannel())) != NULL) ? channel->Index() : -1;
|
||||||
|
|
||||||
while ((channel = Channels.Get(i)) != NULL) {
|
while ((channel = Channels.Get(i)) != NULL) {
|
||||||
Add(new cMenuChannelItem(i, channel), i == curr);
|
Add(new cMenuChannelItem(i, channel), i == curr);
|
||||||
@ -1145,7 +1147,7 @@ cMenuSchedule::cMenuSchedule(void)
|
|||||||
{
|
{
|
||||||
now = next = false;
|
now = next = false;
|
||||||
otherChannel = 0;
|
otherChannel = 0;
|
||||||
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
|
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||||
if (channel) {
|
if (channel) {
|
||||||
cMenuWhatsOn::SetCurrentChannel(channel->number);
|
cMenuWhatsOn::SetCurrentChannel(channel->number);
|
||||||
schedules = cSIProcessor::Schedules(mutexLock);
|
schedules = cSIProcessor::Schedules(mutexLock);
|
||||||
@ -1264,7 +1266,7 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
|
|||||||
cChannel *channel = Channels.GetByServiceID(ei->GetServiceID());
|
cChannel *channel = Channels.GetByServiceID(ei->GetServiceID());
|
||||||
if (channel) {
|
if (channel) {
|
||||||
PrepareSchedule(channel);
|
PrepareSchedule(channel);
|
||||||
if (channel->number != cDvbApi::CurrentChannel()) {
|
if (channel->number != cDevice::CurrentChannel()) {
|
||||||
otherChannel = channel->number;
|
otherChannel = channel->number;
|
||||||
SetHelp(tr("Record"), tr("Now"), tr("Next"), tr("Switch"));
|
SetHelp(tr("Record"), tr("Now"), tr("Next"), tr("Switch"));
|
||||||
}
|
}
|
||||||
@ -1441,7 +1443,7 @@ eOSState cMenuRecordings::Rewind(void)
|
|||||||
{
|
{
|
||||||
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
|
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
|
||||||
if (ri && !ri->IsDirectory()) {
|
if (ri && !ri->IsDirectory()) {
|
||||||
cDvbApi::PrimaryDvbApi->StopReplay(); // must do this first to be able to rewind the currently replayed recording
|
cDevice::PrimaryDevice()->StopReplay(); // must do this first to be able to rewind the currently replayed recording
|
||||||
cResumeFile ResumeFile(ri->FileName());
|
cResumeFile ResumeFile(ri->FileName());
|
||||||
ResumeFile.Delete();
|
ResumeFile.Delete();
|
||||||
return Play();
|
return Play();
|
||||||
@ -1614,7 +1616,7 @@ public:
|
|||||||
cMenuSetupDVB::cMenuSetupDVB(void)
|
cMenuSetupDVB::cMenuSetupDVB(void)
|
||||||
{
|
{
|
||||||
SetSection(tr("DVB"));
|
SetSection(tr("DVB"));
|
||||||
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis));
|
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDevice::NumDevices()));
|
||||||
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
|
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1626,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;
|
||||||
cDvbApi::PrimaryDvbApi->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
|
cDevice::PrimaryDevice()->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
@ -1659,7 +1661,7 @@ public:
|
|||||||
cMenuSetupCICAM::cMenuSetupCICAM(void)
|
cMenuSetupCICAM::cMenuSetupCICAM(void)
|
||||||
{
|
{
|
||||||
SetSection(tr("CICAM"));
|
SetSection(tr("CICAM"));
|
||||||
for (int d = 0; d < cDvbApi::NumDvbApis; d++) {
|
for (int d = 0; d < cDevice::NumDevices(); d++) {
|
||||||
for (int i = 0; i < 2; i++) {
|
for (int i = 0; i < 2; i++) {
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
snprintf(buffer, sizeof(buffer), "%s%d %d", tr("Setup.CICAM$CICAM DVB"), d + 1, i + 1);
|
snprintf(buffer, sizeof(buffer), "%s%d %d", tr("Setup.CICAM$CICAM DVB"), d + 1, i + 1);
|
||||||
@ -1673,7 +1675,7 @@ eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
|
|||||||
eOSState state = cMenuSetupBase::ProcessKey(Key);
|
eOSState state = cMenuSetupBase::ProcessKey(Key);
|
||||||
|
|
||||||
if (state == osBack && Key == kOk)
|
if (state == osBack && Key == kOk)
|
||||||
cDvbApi::SetCaCaps();
|
cDevice::SetCaCaps();
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2024,12 +2026,14 @@ void cMenuMain::Set(void)
|
|||||||
|
|
||||||
// Editing control:
|
// Editing control:
|
||||||
|
|
||||||
|
/*XXX+
|
||||||
if (cVideoCutter::Active())
|
if (cVideoCutter::Active())
|
||||||
Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit));
|
Add(new cOsdItem(tr(" Cancel editing"), osCancelEdit));
|
||||||
|
XXX*/
|
||||||
|
|
||||||
// Color buttons:
|
// Color buttons:
|
||||||
|
|
||||||
SetHelp(tr("Record"), cDvbApi::PrimaryDvbApi->CanToggleAudioTrack() ? tr("Language") : NULL, NULL, replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
|
SetHelp(tr("Record"), /*XXX+ cDevice::PrimaryDevice()->CanToggleAudioTrack() ? tr("Language") :XXX*/ NULL, NULL, replaying ? tr("Button$Stop") : cReplayControl::LastReplayed() ? tr("Resume") : NULL);
|
||||||
Display();
|
Display();
|
||||||
lastActivity = time(NULL);
|
lastActivity = time(NULL);
|
||||||
}
|
}
|
||||||
@ -2059,7 +2063,7 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
|
case osCancelEdit: if (Interface->Confirm(tr("Cancel editing?"))) {
|
||||||
cVideoCutter::Stop();
|
//XXX+cVideoCutter::Stop();
|
||||||
return osEnd;
|
return osEnd;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2082,11 +2086,13 @@ eOSState cMenuMain::ProcessKey(eKeys Key)
|
|||||||
state = osRecord;
|
state = osRecord;
|
||||||
break;
|
break;
|
||||||
case kGreen: if (!HasSubMenu()) {
|
case kGreen: if (!HasSubMenu()) {
|
||||||
if (cDvbApi::PrimaryDvbApi->CanToggleAudioTrack()) {
|
/*XXX+
|
||||||
|
if (cDevice::PrimaryDevice()->CanToggleAudioTrack()) {
|
||||||
Interface->Clear();
|
Interface->Clear();
|
||||||
cDvbApi::PrimaryDvbApi->ToggleAudioTrack();
|
cDevice::PrimaryDevice()->ToggleAudioTrack();
|
||||||
state = osEnd;
|
state = osEnd;
|
||||||
}
|
}
|
||||||
|
XXX*/
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kBlue: if (!HasSubMenu())
|
case kBlue: if (!HasSubMenu())
|
||||||
@ -2134,7 +2140,7 @@ cDisplayChannel::cDisplayChannel(eKeys FirstKey)
|
|||||||
:cOsdObject(true)
|
:cOsdObject(true)
|
||||||
{
|
{
|
||||||
group = -1;
|
group = -1;
|
||||||
oldNumber = cDvbApi::CurrentChannel();
|
oldNumber = cDevice::CurrentChannel();
|
||||||
number = 0;
|
number = 0;
|
||||||
lastTime = time_ms();
|
lastTime = time_ms();
|
||||||
int EpgLines = Setup.ShowInfoOnChSwitch ? 5 : 1;
|
int EpgLines = Setup.ShowInfoOnChSwitch ? 5 : 1;
|
||||||
@ -2253,7 +2259,7 @@ eOSState cDisplayChannel::ProcessKey(eKeys Key)
|
|||||||
case kRight:
|
case kRight:
|
||||||
withInfo = false;
|
withInfo = false;
|
||||||
if (group < 0) {
|
if (group < 0) {
|
||||||
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
|
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||||
if (channel)
|
if (channel)
|
||||||
group = channel->Index();
|
group = channel->Index();
|
||||||
}
|
}
|
||||||
@ -2328,7 +2334,7 @@ cDisplayVolume::cDisplayVolume(void)
|
|||||||
:cOsdObject(true)
|
:cOsdObject(true)
|
||||||
{
|
{
|
||||||
displayVolume = this;
|
displayVolume = this;
|
||||||
timeout = time_ms() + (cDvbApi::PrimaryDvbApi->IsMute() ? MUTETIMEOUT : VOLUMETIMEOUT);
|
timeout = time_ms() + (cDevice::PrimaryDevice()->IsMute() ? MUTETIMEOUT : VOLUMETIMEOUT);
|
||||||
Interface->Open(Setup.OSDwidth, -1);
|
Interface->Open(Setup.OSDwidth, -1);
|
||||||
Show();
|
Show();
|
||||||
}
|
}
|
||||||
@ -2341,13 +2347,13 @@ cDisplayVolume::~cDisplayVolume()
|
|||||||
|
|
||||||
void cDisplayVolume::Show(void)
|
void cDisplayVolume::Show(void)
|
||||||
{
|
{
|
||||||
cDvbApi *dvbApi = cDvbApi::PrimaryDvbApi;
|
cDevice *device = cDevice::PrimaryDevice();
|
||||||
if (dvbApi->IsMute()) {
|
if (device->IsMute()) {
|
||||||
Interface->Fill(0, 0, Width(), 1, clrTransparent);
|
Interface->Fill(0, 0, Width(), 1, clrTransparent);
|
||||||
Interface->Write(0, 0, tr("Mute"), clrGreen);
|
Interface->Write(0, 0, tr("Mute"), clrGreen);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int Current = cDvbApi::CurrentVolume();
|
int Current = cDevice::CurrentVolume();
|
||||||
int Total = MAXVOLUME;
|
int Total = MAXVOLUME;
|
||||||
const char *Prompt = tr("Volume ");
|
const char *Prompt = tr("Volume ");
|
||||||
#ifdef DEBUG_OSD
|
#ifdef DEBUG_OSD
|
||||||
@ -2387,7 +2393,7 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key)
|
|||||||
timeout = time_ms() + VOLUMETIMEOUT;
|
timeout = time_ms() + VOLUMETIMEOUT;
|
||||||
break;
|
break;
|
||||||
case kMute:
|
case kMute:
|
||||||
if (cDvbApi::PrimaryDvbApi->IsMute()) {
|
if (cDevice::PrimaryDevice()->IsMute()) {
|
||||||
Show();
|
Show();
|
||||||
timeout = time_ms() + MUTETIMEOUT;
|
timeout = time_ms() + MUTETIMEOUT;
|
||||||
}
|
}
|
||||||
@ -2405,23 +2411,24 @@ eOSState cDisplayVolume::ProcessKey(eKeys Key)
|
|||||||
|
|
||||||
// --- cRecordControl --------------------------------------------------------
|
// --- cRecordControl --------------------------------------------------------
|
||||||
|
|
||||||
cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
|
cRecordControl::cRecordControl(cDevice *Device, cTimer *Timer)
|
||||||
{
|
{
|
||||||
eventInfo = NULL;
|
eventInfo = NULL;
|
||||||
instantId = NULL;
|
instantId = NULL;
|
||||||
fileName = NULL;
|
fileName = NULL;
|
||||||
dvbApi = DvbApi;
|
recorder = NULL;
|
||||||
if (!dvbApi) dvbApi = cDvbApi::PrimaryDvbApi;//XXX
|
device = Device;
|
||||||
|
if (!device) device = cDevice::PrimaryDevice();//XXX
|
||||||
timer = Timer;
|
timer = Timer;
|
||||||
if (!timer) {
|
if (!timer) {
|
||||||
timer = new cTimer(true);
|
timer = new cTimer(true);
|
||||||
Timers.Add(timer);
|
Timers.Add(timer);
|
||||||
Timers.Save();
|
Timers.Save();
|
||||||
asprintf(&instantId, cDvbApi::NumDvbApis > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), dvbApi->CardIndex() + 1);
|
asprintf(&instantId, cDevice::NumDevices() > 1 ? "%s - %d" : "%s", Channels.GetChannelNameByNumber(timer->channel), device->CardIndex() + 1);
|
||||||
}
|
}
|
||||||
timer->SetPending(true);
|
timer->SetPending(true);
|
||||||
timer->SetRecording(true);
|
timer->SetRecording(true);
|
||||||
if (Channels.SwitchTo(timer->channel, dvbApi)) {
|
|
||||||
const char *Title = NULL;
|
const char *Title = NULL;
|
||||||
const char *Subtitle = NULL;
|
const char *Subtitle = NULL;
|
||||||
const char *Summary = NULL;
|
const char *Summary = NULL;
|
||||||
@ -2434,14 +2441,15 @@ cRecordControl::cRecordControl(cDvbApi *DvbApi, cTimer *Timer)
|
|||||||
cRecording Recording(timer, Title, Subtitle, Summary);
|
cRecording Recording(timer, Title, Subtitle, Summary);
|
||||||
fileName = strdup(Recording.FileName());
|
fileName = strdup(Recording.FileName());
|
||||||
cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName);
|
cRecordingUserCommand::InvokeCommand(RUC_BEFORERECORDING, fileName);
|
||||||
if (dvbApi->StartRecord(fileName, Channels.GetByNumber(timer->channel)->ca, timer->priority)) {
|
cChannel *ch = Channels.GetByNumber(timer->channel);
|
||||||
|
recorder = new cRecorder(fileName, ch->ca, timer->priority, ch->vpid, ch->apid1, ch->apid2, ch->dpid1, ch->dpid2);
|
||||||
|
if (device->Attach(recorder)) {
|
||||||
Recording.WriteSummary();
|
Recording.WriteSummary();
|
||||||
cStatusMonitor::MsgRecording(dvbApi, fileName);
|
cStatusMonitor::MsgRecording(device, fileName);
|
||||||
}
|
Interface->DisplayRecording(device->CardIndex(), true);
|
||||||
Interface->DisplayRecording(dvbApi->CardIndex(), true);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cThread::EmergencyExit(true);
|
DELETENULL(recorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
cRecordControl::~cRecordControl()
|
cRecordControl::~cRecordControl()
|
||||||
@ -2484,8 +2492,8 @@ bool cRecordControl::GetEventInfo(void)
|
|||||||
void cRecordControl::Stop(bool KeepInstant)
|
void cRecordControl::Stop(bool KeepInstant)
|
||||||
{
|
{
|
||||||
if (timer) {
|
if (timer) {
|
||||||
cStatusMonitor::MsgRecording(dvbApi, NULL);
|
cStatusMonitor::MsgRecording(device, NULL);
|
||||||
dvbApi->StopRecord();
|
DELETENULL(recorder);
|
||||||
timer->SetRecording(false);
|
timer->SetRecording(false);
|
||||||
if ((IsInstant() && !KeepInstant) || (timer->IsSingleEvent() && !timer->Matches())) {
|
if ((IsInstant() && !KeepInstant) || (timer->IsSingleEvent() && !timer->Matches())) {
|
||||||
// checking timer->Matches() to make sure we don't delete the timer
|
// checking timer->Matches() to make sure we don't delete the timer
|
||||||
@ -2495,14 +2503,14 @@ void cRecordControl::Stop(bool KeepInstant)
|
|||||||
Timers.Save();
|
Timers.Save();
|
||||||
}
|
}
|
||||||
timer = NULL;
|
timer = NULL;
|
||||||
Interface->DisplayRecording(dvbApi->CardIndex(), false);
|
Interface->DisplayRecording(device->CardIndex(), false);
|
||||||
cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName);
|
cRecordingUserCommand::InvokeCommand(RUC_AFTERRECORDING, fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cRecordControl::Process(time_t t)
|
bool cRecordControl::Process(time_t t)
|
||||||
{
|
{
|
||||||
if (!timer || !timer->Matches(t))
|
if (!recorder || !timer || !timer->Matches(t))
|
||||||
return false;
|
return false;
|
||||||
AssertFreeDiskSpace(timer->priority);
|
AssertFreeDiskSpace(timer->priority);
|
||||||
return true;
|
return true;
|
||||||
@ -2510,20 +2518,27 @@ bool cRecordControl::Process(time_t t)
|
|||||||
|
|
||||||
// --- cRecordControls -------------------------------------------------------
|
// --- cRecordControls -------------------------------------------------------
|
||||||
|
|
||||||
cRecordControl *cRecordControls::RecordControls[MAXDVBAPI] = { NULL };
|
cRecordControl *cRecordControls::RecordControls[MAXRECORDCONTROLS] = { NULL };
|
||||||
|
|
||||||
bool cRecordControls::Start(cTimer *Timer)
|
bool cRecordControls::Start(cTimer *Timer)
|
||||||
{
|
{
|
||||||
int ch = Timer ? Timer->channel : cDvbApi::CurrentChannel();
|
int ch = Timer ? Timer->channel : cDevice::CurrentChannel();
|
||||||
cChannel *channel = Channels.GetByNumber(ch);
|
cChannel *channel = Channels.GetByNumber(ch);
|
||||||
|
|
||||||
if (channel) {
|
if (channel) {
|
||||||
cDvbApi *dvbApi = cDvbApi::GetDvbApi(channel->ca, Timer ? Timer->priority : Setup.DefaultPriority);
|
bool ReUse = false;
|
||||||
if (dvbApi) {
|
cDevice *device = cDevice::GetDevice(channel->ca, Timer ? Timer->priority : Setup.DefaultPriority, channel->frequency, channel->vpid, &ReUse);
|
||||||
Stop(dvbApi);
|
if (device) {
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
if (!ReUse) {
|
||||||
|
Stop(device);
|
||||||
|
if (!channel->Switch(device)) {
|
||||||
|
cThread::EmergencyExit(true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
if (!RecordControls[i]) {
|
if (!RecordControls[i]) {
|
||||||
RecordControls[i] = new cRecordControl(dvbApi, Timer);
|
RecordControls[i] = new cRecordControl(device, Timer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2538,7 +2553,7 @@ bool cRecordControls::Start(cTimer *Timer)
|
|||||||
|
|
||||||
void cRecordControls::Stop(const char *InstantId)
|
void cRecordControls::Stop(const char *InstantId)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
if (RecordControls[i]) {
|
if (RecordControls[i]) {
|
||||||
const char *id = RecordControls[i]->InstantId();
|
const char *id = RecordControls[i]->InstantId();
|
||||||
if (id && strcmp(id, InstantId) == 0)
|
if (id && strcmp(id, InstantId) == 0)
|
||||||
@ -2547,12 +2562,12 @@ void cRecordControls::Stop(const char *InstantId)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cRecordControls::Stop(cDvbApi *DvbApi)
|
void cRecordControls::Stop(cDevice *Device)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
if (RecordControls[i]) {
|
if (RecordControls[i]) {
|
||||||
if (RecordControls[i]->Uses(DvbApi)) {
|
if (RecordControls[i]->Uses(Device)) {
|
||||||
isyslog("stopping recording on DVB device %d due to higher priority", DvbApi->CardIndex() + 1);
|
isyslog("stopping recording on DVB device %d due to higher priority", Device->CardIndex() + 1);
|
||||||
RecordControls[i]->Stop(true);
|
RecordControls[i]->Stop(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2561,11 +2576,11 @@ void cRecordControls::Stop(cDvbApi *DvbApi)
|
|||||||
|
|
||||||
bool cRecordControls::StopPrimary(bool DoIt)
|
bool cRecordControls::StopPrimary(bool DoIt)
|
||||||
{
|
{
|
||||||
if (cDvbApi::PrimaryDvbApi->Recording()) {
|
if (cDevice::PrimaryDevice()->Receiving()) {
|
||||||
cDvbApi *dvbApi = cDvbApi::GetDvbApi(cDvbApi::PrimaryDvbApi->Ca(), 0);
|
cDevice *device = cDevice::GetDevice(cDevice::PrimaryDevice()->Ca(), 0);
|
||||||
if (dvbApi) {
|
if (device) {
|
||||||
if (DoIt)
|
if (DoIt)
|
||||||
Stop(cDvbApi::PrimaryDvbApi);
|
Stop(cDevice::PrimaryDevice());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2574,7 +2589,7 @@ bool cRecordControls::StopPrimary(bool DoIt)
|
|||||||
|
|
||||||
const char *cRecordControls::GetInstantId(const char *LastInstantId)
|
const char *cRecordControls::GetInstantId(const char *LastInstantId)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
if (RecordControls[i]) {
|
if (RecordControls[i]) {
|
||||||
if (!LastInstantId && RecordControls[i]->InstantId())
|
if (!LastInstantId && RecordControls[i]->InstantId())
|
||||||
return RecordControls[i]->InstantId();
|
return RecordControls[i]->InstantId();
|
||||||
@ -2587,7 +2602,7 @@ const char *cRecordControls::GetInstantId(const char *LastInstantId)
|
|||||||
|
|
||||||
cRecordControl *cRecordControls::GetRecordControl(const char *FileName)
|
cRecordControl *cRecordControls::GetRecordControl(const char *FileName)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
|
if (RecordControls[i] && strcmp(RecordControls[i]->FileName(), FileName) == 0)
|
||||||
return RecordControls[i];
|
return RecordControls[i];
|
||||||
}
|
}
|
||||||
@ -2596,7 +2611,7 @@ cRecordControl *cRecordControls::GetRecordControl(const char *FileName)
|
|||||||
|
|
||||||
void cRecordControls::Process(time_t t)
|
void cRecordControls::Process(time_t t)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
if (RecordControls[i]) {
|
if (RecordControls[i]) {
|
||||||
if (!RecordControls[i]->Process(t))
|
if (!RecordControls[i]->Process(t))
|
||||||
DELETENULL(RecordControls[i]);
|
DELETENULL(RecordControls[i]);
|
||||||
@ -2606,13 +2621,19 @@ void cRecordControls::Process(time_t t)
|
|||||||
|
|
||||||
bool cRecordControls::Active(void)
|
bool cRecordControls::Active(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MAXDVBAPI; i++) {
|
for (int i = 0; i < MAXRECORDCONTROLS; i++) {
|
||||||
if (RecordControls[i])
|
if (RecordControls[i])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cRecordControls::Shutdown(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAXRECORDCONTROLS; i++)
|
||||||
|
DELETENULL(RecordControls[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// --- cProgressBar ----------------------------------------------------------
|
// --- cProgressBar ----------------------------------------------------------
|
||||||
|
|
||||||
class cProgressBar : public cBitmap {
|
class cProgressBar : public cBitmap {
|
||||||
@ -2664,25 +2685,24 @@ char *cReplayControl::title = NULL;
|
|||||||
|
|
||||||
cReplayControl::cReplayControl(void)
|
cReplayControl::cReplayControl(void)
|
||||||
{
|
{
|
||||||
dvbApi = cDvbApi::PrimaryDvbApi;
|
|
||||||
visible = modeOnly = shown = displayFrames = false;
|
visible = modeOnly = shown = displayFrames = false;
|
||||||
lastCurrent = lastTotal = -1;
|
lastCurrent = lastTotal = -1;
|
||||||
timeoutShow = 0;
|
timeoutShow = 0;
|
||||||
timeSearchActive = false;
|
timeSearchActive = false;
|
||||||
if (fileName) {
|
if (fileName) {
|
||||||
marks.Load(fileName);
|
marks.Load(fileName);
|
||||||
if (!dvbApi->StartReplay(fileName))
|
if (!Start(fileName))
|
||||||
Interface->Error(tr("Channel locked (recording)!"));
|
Interface->Error(tr("Channel locked (recording)!"));//XXX+
|
||||||
else
|
else
|
||||||
cStatusMonitor::MsgReplaying(dvbApi, fileName);
|
cStatusMonitor::MsgReplaying(this, fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cReplayControl::~cReplayControl()
|
cReplayControl::~cReplayControl()
|
||||||
{
|
{
|
||||||
Hide();
|
Hide();
|
||||||
cStatusMonitor::MsgReplaying(dvbApi, NULL);
|
cStatusMonitor::MsgReplaying(this, NULL);
|
||||||
dvbApi->StopReplay();
|
Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cReplayControl::SetRecording(const char *FileName, const char *Title)
|
void cReplayControl::SetRecording(const char *FileName, const char *Title)
|
||||||
@ -2744,7 +2764,7 @@ void cReplayControl::ShowMode(void)
|
|||||||
if (Setup.ShowReplayMode && !timeSearchActive) {
|
if (Setup.ShowReplayMode && !timeSearchActive) {
|
||||||
bool Play, Forward;
|
bool Play, Forward;
|
||||||
int Speed;
|
int Speed;
|
||||||
if (dvbApi->GetReplayMode(Play, Forward, Speed)) {
|
if (GetReplayMode(Play, Forward, Speed)) {
|
||||||
bool NormalPlay = (Play && Speed == -1);
|
bool NormalPlay = (Play && Speed == -1);
|
||||||
|
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
@ -2782,7 +2802,7 @@ bool cReplayControl::ShowProgress(bool Initial)
|
|||||||
{
|
{
|
||||||
int Current, Total;
|
int Current, Total;
|
||||||
|
|
||||||
if (dvbApi->GetIndex(Current, Total) && Total > 0) {
|
if (GetIndex(Current, Total) && Total > 0) {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
Interface->Open(Setup.OSDwidth, -3);
|
Interface->Open(Setup.OSDwidth, -3);
|
||||||
needsFastResponse = visible = true;
|
needsFastResponse = visible = true;
|
||||||
@ -2857,14 +2877,14 @@ void cReplayControl::TimeSearchProcess(eKeys Key)
|
|||||||
int dir = (Key == kRight ? 1 : -1);
|
int dir = (Key == kRight ? 1 : -1);
|
||||||
if (dir > 0)
|
if (dir > 0)
|
||||||
Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
|
Seconds = min(Total - Current - STAY_SECONDS_OFF_END, Seconds);
|
||||||
dvbApi->SkipSeconds(Seconds * dir);
|
SkipSeconds(Seconds * dir);
|
||||||
timeSearchActive = false;
|
timeSearchActive = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case kUp:
|
case kUp:
|
||||||
case kDown:
|
case kDown:
|
||||||
Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
|
Seconds = min(Total - STAY_SECONDS_OFF_END, Seconds);
|
||||||
dvbApi->Goto(Seconds * FRAMESPERSEC, Key == kDown);
|
Goto(Seconds * FRAMESPERSEC, Key == kDown);
|
||||||
timeSearchActive = false;
|
timeSearchActive = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -2902,7 +2922,7 @@ void cReplayControl::TimeSearch(void)
|
|||||||
void cReplayControl::MarkToggle(void)
|
void cReplayControl::MarkToggle(void)
|
||||||
{
|
{
|
||||||
int Current, Total;
|
int Current, Total;
|
||||||
if (dvbApi->GetIndex(Current, Total, true)) {
|
if (GetIndex(Current, Total, true)) {
|
||||||
cMark *m = marks.Get(Current);
|
cMark *m = marks.Get(Current);
|
||||||
lastCurrent = -1; // triggers redisplay
|
lastCurrent = -1; // triggers redisplay
|
||||||
if (m)
|
if (m)
|
||||||
@ -2919,10 +2939,10 @@ void cReplayControl::MarkJump(bool Forward)
|
|||||||
{
|
{
|
||||||
if (marks.Count()) {
|
if (marks.Count()) {
|
||||||
int Current, Total;
|
int Current, Total;
|
||||||
if (dvbApi->GetIndex(Current, Total)) {
|
if (GetIndex(Current, Total)) {
|
||||||
cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current);
|
cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current);
|
||||||
if (m)
|
if (m)
|
||||||
dvbApi->Goto(m->position, true);
|
Goto(m->position, true);
|
||||||
}
|
}
|
||||||
displayFrames = true;
|
displayFrames = true;
|
||||||
}
|
}
|
||||||
@ -2931,11 +2951,11 @@ void cReplayControl::MarkJump(bool Forward)
|
|||||||
void cReplayControl::MarkMove(bool Forward)
|
void cReplayControl::MarkMove(bool Forward)
|
||||||
{
|
{
|
||||||
int Current, Total;
|
int Current, Total;
|
||||||
if (dvbApi->GetIndex(Current, Total)) {
|
if (GetIndex(Current, Total)) {
|
||||||
cMark *m = marks.Get(Current);
|
cMark *m = marks.Get(Current);
|
||||||
if (m) {
|
if (m) {
|
||||||
displayFrames = true;
|
displayFrames = true;
|
||||||
int p = dvbApi->SkipFrames(Forward ? 1 : -1);
|
int p = SkipFrames(Forward ? 1 : -1);
|
||||||
cMark *m2;
|
cMark *m2;
|
||||||
if (Forward) {
|
if (Forward) {
|
||||||
if ((m2 = marks.Next(m)) != NULL && m2->position <= p)
|
if ((m2 = marks.Next(m)) != NULL && m2->position <= p)
|
||||||
@ -2945,7 +2965,7 @@ void cReplayControl::MarkMove(bool Forward)
|
|||||||
if ((m2 = marks.Prev(m)) != NULL && m2->position >= p)
|
if ((m2 = marks.Prev(m)) != NULL && m2->position >= p)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dvbApi->Goto(m->position = p, true);
|
Goto(m->position = p, true);
|
||||||
marks.Save();
|
marks.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2953,6 +2973,7 @@ void cReplayControl::MarkMove(bool Forward)
|
|||||||
|
|
||||||
void cReplayControl::EditCut(void)
|
void cReplayControl::EditCut(void)
|
||||||
{
|
{
|
||||||
|
/*XXX+
|
||||||
if (fileName) {
|
if (fileName) {
|
||||||
Hide();
|
Hide();
|
||||||
if (!cVideoCutter::Active()) {
|
if (!cVideoCutter::Active()) {
|
||||||
@ -2965,12 +2986,13 @@ void cReplayControl::EditCut(void)
|
|||||||
Interface->Error(tr("Editing process already active!"));
|
Interface->Error(tr("Editing process already active!"));
|
||||||
ShowMode();
|
ShowMode();
|
||||||
}
|
}
|
||||||
|
XXX*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void cReplayControl::EditTest(void)
|
void cReplayControl::EditTest(void)
|
||||||
{
|
{
|
||||||
int Current, Total;
|
int Current, Total;
|
||||||
if (dvbApi->GetIndex(Current, Total)) {
|
if (GetIndex(Current, Total)) {
|
||||||
cMark *m = marks.Get(Current);
|
cMark *m = marks.Get(Current);
|
||||||
if (!m)
|
if (!m)
|
||||||
m = marks.GetNext(Current);
|
m = marks.GetNext(Current);
|
||||||
@ -2978,8 +3000,8 @@ void cReplayControl::EditTest(void)
|
|||||||
if ((m->Index() & 0x01) != 0)
|
if ((m->Index() & 0x01) != 0)
|
||||||
m = marks.Next(m);
|
m = marks.Next(m);
|
||||||
if (m) {
|
if (m) {
|
||||||
dvbApi->Goto(m->position - dvbApi->SecondsToFrames(3));
|
Goto(m->position - SecondsToFrames(3));
|
||||||
dvbApi->Play();
|
Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2987,7 +3009,7 @@ void cReplayControl::EditTest(void)
|
|||||||
|
|
||||||
eOSState cReplayControl::ProcessKey(eKeys Key)
|
eOSState cReplayControl::ProcessKey(eKeys Key)
|
||||||
{
|
{
|
||||||
if (!dvbApi->Replaying())
|
if (!Active())
|
||||||
return osEnd;
|
return osEnd;
|
||||||
if (visible) {
|
if (visible) {
|
||||||
if (timeoutShow && time(NULL) > timeoutShow) {
|
if (timeoutShow && time(NULL) > timeoutShow) {
|
||||||
@ -3009,21 +3031,21 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
|
|||||||
bool DoShowMode = true;
|
bool DoShowMode = true;
|
||||||
switch (Key) {
|
switch (Key) {
|
||||||
// Positioning:
|
// Positioning:
|
||||||
case kUp: dvbApi->Play(); break;
|
case kUp: Play(); break;
|
||||||
case kDown: dvbApi->Pause(); break;
|
case kDown: Pause(); break;
|
||||||
case kLeft|k_Release:
|
case kLeft|k_Release:
|
||||||
if (Setup.MultiSpeedMode) break;
|
if (Setup.MultiSpeedMode) break;
|
||||||
case kLeft: dvbApi->Backward(); break;
|
case kLeft: Backward(); break;
|
||||||
case kRight|k_Release:
|
case kRight|k_Release:
|
||||||
if (Setup.MultiSpeedMode) break;
|
if (Setup.MultiSpeedMode) break;
|
||||||
case kRight: dvbApi->Forward(); break;
|
case kRight: Forward(); break;
|
||||||
case kRed: TimeSearch(); break;
|
case kRed: TimeSearch(); break;
|
||||||
case kGreen|k_Repeat:
|
case kGreen|k_Repeat:
|
||||||
case kGreen: dvbApi->SkipSeconds(-60); break;
|
case kGreen: SkipSeconds(-60); break;
|
||||||
case kYellow|k_Repeat:
|
case kYellow|k_Repeat:
|
||||||
case kYellow: dvbApi->SkipSeconds( 60); break;
|
case kYellow: SkipSeconds( 60); break;
|
||||||
case kBlue: Hide();
|
case kBlue: Hide();
|
||||||
dvbApi->StopReplay();
|
Stop();
|
||||||
return osEnd;
|
return osEnd;
|
||||||
default: {
|
default: {
|
||||||
DoShowMode = false;
|
DoShowMode = false;
|
||||||
|
21
menu.h
21
menu.h
@ -4,14 +4,16 @@
|
|||||||
* 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.h 1.43 2002/05/18 12:36:06 kls Exp $
|
* $Id: menu.h 1.44 2002/06/14 12:33:35 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __MENU_H
|
#ifndef __MENU_H
|
||||||
#define __MENU_H
|
#define __MENU_H
|
||||||
|
|
||||||
#include "dvbapi.h"
|
#include "device.h"
|
||||||
#include "osd.h"
|
#include "osd.h"
|
||||||
|
#include "dvbplayer.h"
|
||||||
|
#include "recorder.h"
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
|
|
||||||
class cMenuMain : public cOsdMenu {
|
class cMenuMain : public cOsdMenu {
|
||||||
@ -76,17 +78,18 @@ public:
|
|||||||
|
|
||||||
class cRecordControl {
|
class cRecordControl {
|
||||||
private:
|
private:
|
||||||
cDvbApi *dvbApi;
|
cDevice *device;
|
||||||
cTimer *timer;
|
cTimer *timer;
|
||||||
|
cRecorder *recorder;
|
||||||
const cEventInfo *eventInfo;
|
const cEventInfo *eventInfo;
|
||||||
char *instantId;
|
char *instantId;
|
||||||
char *fileName;
|
char *fileName;
|
||||||
bool GetEventInfo(void);
|
bool GetEventInfo(void);
|
||||||
public:
|
public:
|
||||||
cRecordControl(cDvbApi *DvbApi, cTimer *Timer = NULL);
|
cRecordControl(cDevice *Device, cTimer *Timer = NULL);
|
||||||
virtual ~cRecordControl();
|
virtual ~cRecordControl();
|
||||||
bool Process(time_t t);
|
bool Process(time_t t);
|
||||||
bool Uses(cDvbApi *DvbApi) { return DvbApi == dvbApi; }
|
bool Uses(cDevice *Device) { return Device == device; }
|
||||||
void Stop(bool KeepInstant = false);
|
void Stop(bool KeepInstant = false);
|
||||||
bool IsInstant(void) { return instantId; }
|
bool IsInstant(void) { return instantId; }
|
||||||
const char *InstantId(void) { return instantId; }
|
const char *InstantId(void) { return instantId; }
|
||||||
@ -96,21 +99,21 @@ public:
|
|||||||
|
|
||||||
class cRecordControls {
|
class cRecordControls {
|
||||||
private:
|
private:
|
||||||
static cRecordControl *RecordControls[MAXDVBAPI];
|
static cRecordControl *RecordControls[];
|
||||||
public:
|
public:
|
||||||
static bool Start(cTimer *Timer = NULL);
|
static bool Start(cTimer *Timer = NULL);
|
||||||
static void Stop(const char *InstantId);
|
static void Stop(const char *InstantId);
|
||||||
static void Stop(cDvbApi *DvbApi);
|
static void Stop(cDevice *Device);
|
||||||
static bool StopPrimary(bool DoIt = false);
|
static bool StopPrimary(bool DoIt = false);
|
||||||
static const char *GetInstantId(const char *LastInstantId);
|
static const char *GetInstantId(const char *LastInstantId);
|
||||||
static cRecordControl *GetRecordControl(const char *FileName);
|
static cRecordControl *GetRecordControl(const char *FileName);
|
||||||
static void Process(time_t t);
|
static void Process(time_t t);
|
||||||
static bool Active(void);
|
static bool Active(void);
|
||||||
|
static void Shutdown(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cReplayControl : public cOsdObject {
|
class cReplayControl : public cDvbPlayerControl {
|
||||||
private:
|
private:
|
||||||
cDvbApi *dvbApi;
|
|
||||||
cMarks marks;
|
cMarks marks;
|
||||||
bool visible, modeOnly, shown, displayFrames;
|
bool visible, modeOnly, shown, displayFrames;
|
||||||
int lastCurrent, lastTotal;
|
int lastCurrent, lastTotal;
|
||||||
|
6
osd.c
6
osd.c
@ -4,12 +4,12 @@
|
|||||||
* 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.27 2002/05/19 12:56:57 kls Exp $
|
* $Id: osd.c 1.28 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "osd.h"
|
#include "osd.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "dvbapi.h"
|
#include "device.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ void cOsd::Open(int w, int h)
|
|||||||
int x = (720 - w + charWidth) / 2; //TODO PAL vs. NTSC???
|
int x = (720 - w + charWidth) / 2; //TODO PAL vs. NTSC???
|
||||||
int y = (576 - Setup.OSDheight * lineHeight) / 2 + d;
|
int y = (576 - Setup.OSDheight * lineHeight) / 2 + d;
|
||||||
//XXX
|
//XXX
|
||||||
osd = new cDvbOsd(cDvbApi::PrimaryDvbApi->OsdDeviceHandle(), x, y);
|
osd = new cDvbOsd(cDevice::PrimaryDevice()->OsdDeviceHandle(), x, y);
|
||||||
//XXX TODO this should be transferred to the places where the individual windows are requested (there's too much detailed knowledge here!)
|
//XXX TODO this should be transferred to the places where the individual windows are requested (there's too much detailed knowledge here!)
|
||||||
if (h / lineHeight == 5) { //XXX channel display
|
if (h / lineHeight == 5) { //XXX channel display
|
||||||
osd->Create(0, 0, w, h, 4);
|
osd->Create(0, 0, w, h, 4);
|
||||||
|
55
player.c
Normal file
55
player.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* player.c: The basic player interface
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: player.c 1.1 2002/06/16 10:34:50 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "player.h"
|
||||||
|
|
||||||
|
// --- cPlayer ---------------------------------------------------------------
|
||||||
|
|
||||||
|
cPlayer::cPlayer(void)
|
||||||
|
{
|
||||||
|
device = NULL;
|
||||||
|
deviceFileHandle = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cPlayer::~cPlayer()
|
||||||
|
{
|
||||||
|
Detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPlayer::PlayVideo(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
if (device)
|
||||||
|
return device->PlayVideo(Data, Length);
|
||||||
|
esyslog("ERROR: attempt to use cPlayer::PlayVideo() without attaching to a cDevice!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cPlayer::PlayAudio(const uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
if (device)
|
||||||
|
return device->PlayAudio(Data, Length);
|
||||||
|
esyslog("ERROR: attempt to use cPlayer::PlayAudio() without attaching to a cDevice!");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPlayer::Detach(void)
|
||||||
|
{
|
||||||
|
if (device)
|
||||||
|
device->Detach(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cControl --------------------------------------------------------------
|
||||||
|
|
||||||
|
cControl::cControl(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cControl::~cControl()
|
||||||
|
{
|
||||||
|
}
|
51
player.h
Normal file
51
player.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* player.h: The basic player interface
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: player.h 1.1 2002/06/16 11:52:45 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLAYER_H
|
||||||
|
#define __PLAYER_H
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "osd.h"
|
||||||
|
|
||||||
|
class cPlayer {
|
||||||
|
friend class cDevice;
|
||||||
|
private:
|
||||||
|
cDevice *device;
|
||||||
|
int deviceFileHandle;
|
||||||
|
protected:
|
||||||
|
int DeviceFileHandle(void) { return deviceFileHandle; } //XXX+ needed for polling
|
||||||
|
void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
|
||||||
|
void DeviceClear(void) { if (device) device->Clear(); }
|
||||||
|
void DevicePlay(void) { if (device) device->Play(); }
|
||||||
|
void DeviceFreeze(void) { if (device) device->Freeze(); }
|
||||||
|
void DeviceMute(void) { if (device) device->Mute(); }
|
||||||
|
void DeviceStillPicture(const uchar *Data, int Length) { if (device) device->StillPicture(Data, Length); }
|
||||||
|
void Detach(void);
|
||||||
|
virtual void Activate(bool On) {}
|
||||||
|
// This function is called right after the cPlayer has been attached to
|
||||||
|
// (On == true) or before it gets detached from (On == false) a cDevice.
|
||||||
|
// It can be used to do things like starting/stopping a thread.
|
||||||
|
int PlayVideo(const uchar *Data, int Length);
|
||||||
|
// Sends the given Data to the video device and returns the number of
|
||||||
|
// bytes that have actually been accepted by the video device (or a
|
||||||
|
// negative value in case of an error).
|
||||||
|
int PlayAudio(const uchar *Data, int Length);
|
||||||
|
// XXX+ TODO
|
||||||
|
public:
|
||||||
|
cPlayer(void);
|
||||||
|
virtual ~cPlayer();
|
||||||
|
};
|
||||||
|
|
||||||
|
class cControl : public cOsdObject {
|
||||||
|
public:
|
||||||
|
cControl(void);
|
||||||
|
virtual ~cControl();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__PLAYER_H
|
55
receiver.c
Normal file
55
receiver.c
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* receiver.c: The basic receiver interface
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: receiver.c 1.1 2002/06/10 16:30:00 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "receiver.h"
|
||||||
|
|
||||||
|
cReceiver::cReceiver(int Ca, int Priority, int NumPids, ...)
|
||||||
|
{
|
||||||
|
device = NULL;
|
||||||
|
ca = Ca;
|
||||||
|
priority = Priority;
|
||||||
|
if (NumPids) {
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, NumPids);
|
||||||
|
int n = 0;
|
||||||
|
while (n < MAXRECEIVEPIDS && NumPids--) {
|
||||||
|
if ((pids[n] = va_arg(ap, int)) != 0)
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: cReceiver called without a PID!");
|
||||||
|
}
|
||||||
|
|
||||||
|
cReceiver::~cReceiver()
|
||||||
|
{
|
||||||
|
Detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cReceiver::WantsPid(int Pid)
|
||||||
|
{
|
||||||
|
if (Pid) {
|
||||||
|
for (int i = 0; i < MAXRECEIVEPIDS; i++) {
|
||||||
|
if (pids[i] == Pid)
|
||||||
|
return true;
|
||||||
|
if (!pids[i])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cReceiver::Detach(void)
|
||||||
|
{
|
||||||
|
if (device)
|
||||||
|
device->Detach(this);
|
||||||
|
}
|
48
receiver.h
Normal file
48
receiver.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* receiver.h: The basic receiver interface
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: receiver.h 1.1 2002/06/10 16:30:00 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RECEIVER_H
|
||||||
|
#define __RECEIVER_H
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#define MAXRECEIVEPIDS 16 // the maximum number of PIDs per receiver
|
||||||
|
|
||||||
|
class cReceiver {
|
||||||
|
friend class cDevice;
|
||||||
|
private:
|
||||||
|
cDevice *device;
|
||||||
|
int ca;
|
||||||
|
int priority;
|
||||||
|
int pids[MAXRECEIVEPIDS];
|
||||||
|
bool WantsPid(int Pid);
|
||||||
|
protected:
|
||||||
|
void Detach(void);
|
||||||
|
virtual void Activate(bool On) {}
|
||||||
|
// This function is called just before the cReceiver gets attached to
|
||||||
|
// (On == true) or detached from (On == false) a cDevice. It can be used
|
||||||
|
// to do things like starting/stopping a thread.
|
||||||
|
// It is guaranteed that Receive() will not be called before Activate(true).
|
||||||
|
virtual void Receive(uchar *Data, int Length) = 0;
|
||||||
|
// This function is called from the cDevice we are attached to, and
|
||||||
|
// delivers one TS packet from the set of PIDs the cReceiver has requested.
|
||||||
|
// The data packet must be accepted immediately, and the call must return
|
||||||
|
// as soon as possible, without any unnecessary delay. Each TS packet
|
||||||
|
// will be delivered only ONCE, so the cReceiver must make sure that
|
||||||
|
// it will be able to buffer the data if necessary.
|
||||||
|
public:
|
||||||
|
cReceiver(int Ca, int Priority, int NumPids, ...);
|
||||||
|
// Creates a new receiver that requires conditional access Ca and has
|
||||||
|
// the given Priority. NumPids defines the number of PIDs that follow
|
||||||
|
// this parameter. If any of these PIDs are 0, they will be silently ignored.
|
||||||
|
// The total number of non-zero PIDs must not exceed MAXRECEIVEPIDS.
|
||||||
|
virtual ~cReceiver();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__RECEIVER_H
|
149
recorder.c
Normal file
149
recorder.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
/*
|
||||||
|
* recorder.h: The actual DVB recorder
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: recorder.c 1.1 2002/06/16 10:03:25 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "recorder.h"
|
||||||
|
|
||||||
|
// The size of the array used to buffer video data:
|
||||||
|
// (must be larger than MINVIDEODATA - see remux.h)
|
||||||
|
#define VIDEOBUFSIZE MEGABYTE(1)
|
||||||
|
|
||||||
|
#define MINFREEDISKSPACE (512) // MB
|
||||||
|
#define DISKCHECKINTERVAL 100 // seconds
|
||||||
|
|
||||||
|
cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2)
|
||||||
|
:cReceiver(Ca, Priority, 5, VPid, APid1, APid2, DPid1, DPid2)
|
||||||
|
{
|
||||||
|
ringBuffer = NULL;
|
||||||
|
remux = NULL;
|
||||||
|
fileName = NULL;
|
||||||
|
index = NULL;
|
||||||
|
pictureType = NO_PICTURE;
|
||||||
|
fileSize = 0;
|
||||||
|
active = false;
|
||||||
|
lastDiskSpaceCheck = time(NULL);
|
||||||
|
isyslog("record %s", FileName);
|
||||||
|
|
||||||
|
// Create directories if necessary:
|
||||||
|
|
||||||
|
if (!MakeDirs(FileName, true))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Make sure the disk is up and running:
|
||||||
|
|
||||||
|
SpinUpDisk(FileName);
|
||||||
|
|
||||||
|
ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
|
||||||
|
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
|
||||||
|
fileName = new cFileName(FileName, true);
|
||||||
|
recordFile = fileName->Open();
|
||||||
|
if (recordFile < 0)
|
||||||
|
return;
|
||||||
|
// Create the index file:
|
||||||
|
index = new cIndexFile(FileName, true);
|
||||||
|
if (!index)
|
||||||
|
esyslog("ERROR: can't allocate index");
|
||||||
|
// let's continue without index, so we'll at least have the recording
|
||||||
|
}
|
||||||
|
|
||||||
|
cRecorder::~cRecorder()
|
||||||
|
{
|
||||||
|
Detach();
|
||||||
|
delete index;
|
||||||
|
delete fileName;
|
||||||
|
delete remux;
|
||||||
|
delete ringBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRecorder::Activate(bool On)
|
||||||
|
{
|
||||||
|
if (On) {
|
||||||
|
if (recordFile >= 0)
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
else if (active) {
|
||||||
|
active = false;
|
||||||
|
Cancel(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cRecorder::RunningLowOnDiskSpace(void)
|
||||||
|
{
|
||||||
|
if (time(NULL) > lastDiskSpaceCheck + DISKCHECKINTERVAL) {
|
||||||
|
int Free = FreeDiskSpaceMB(fileName->Name());
|
||||||
|
lastDiskSpaceCheck = time(NULL);
|
||||||
|
if (Free < MINFREEDISKSPACE) {
|
||||||
|
dsyslog("low disk space (%d MB, limit is %d MB)", Free, MINFREEDISKSPACE);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cRecorder::NextFile(void)
|
||||||
|
{
|
||||||
|
if (recordFile >= 0 && pictureType == I_FRAME) { // every file shall start with an I_FRAME
|
||||||
|
if (fileSize > MEGABYTE(Setup.MaxVideoFileSize) || RunningLowOnDiskSpace()) {
|
||||||
|
recordFile = fileName->NextFile();
|
||||||
|
fileSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return recordFile >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRecorder::Receive(uchar *Data, int Length)
|
||||||
|
{
|
||||||
|
int p = ringBuffer->Put(Data, Length);
|
||||||
|
if (p != Length && active)
|
||||||
|
esyslog("ERROR: ring buffer overflow (%d bytes dropped)", Length - p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRecorder::Action(void)
|
||||||
|
{
|
||||||
|
dsyslog("recording thread started (pid=%d)", getpid());
|
||||||
|
|
||||||
|
uchar b[MINVIDEODATA];
|
||||||
|
int r = 0;
|
||||||
|
active = true;
|
||||||
|
while (active) {
|
||||||
|
int g = ringBuffer->Get(b + r, sizeof(b) - r);
|
||||||
|
if (g > 0)
|
||||||
|
r += g;
|
||||||
|
if (r > 0) {
|
||||||
|
int Count = r, Result;
|
||||||
|
const uchar *p = remux->Process(b, Count, Result, &pictureType);
|
||||||
|
if (p) {
|
||||||
|
//XXX+ active??? see old version (Busy)
|
||||||
|
if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame
|
||||||
|
break;
|
||||||
|
if (NextFile()) {
|
||||||
|
if (index && pictureType != NO_PICTURE)
|
||||||
|
index->Write(pictureType, fileName->Number(), fileSize);
|
||||||
|
if (safe_write(recordFile, p, Result) < 0) {
|
||||||
|
LOG_ERROR_STR(fileName->Name());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fileSize += Result;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (Count > 0) {
|
||||||
|
r -= Count;
|
||||||
|
memmove(b, b + Count, r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
usleep(1); // this keeps the CPU load low
|
||||||
|
}
|
||||||
|
|
||||||
|
dsyslog("recording thread ended (pid=%d)", getpid());
|
||||||
|
}
|
43
recorder.h
Normal file
43
recorder.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* recorder.h: The actual DVB recorder
|
||||||
|
*
|
||||||
|
* See the main source file 'vdr.c' for copyright information and
|
||||||
|
* how to reach the author.
|
||||||
|
*
|
||||||
|
* $Id: recorder.h 1.1 2002/06/10 16:30:00 kls Exp $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __RECORDER_H
|
||||||
|
#define __RECORDER_H
|
||||||
|
|
||||||
|
#include "receiver.h"
|
||||||
|
#include "recording.h"
|
||||||
|
#include "remux.h"
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
class cRecorder : public cReceiver, cThread {
|
||||||
|
private:
|
||||||
|
cRingBufferLinear *ringBuffer;
|
||||||
|
cRemux *remux;
|
||||||
|
cFileName *fileName;
|
||||||
|
cIndexFile *index;
|
||||||
|
uchar pictureType;
|
||||||
|
int fileSize;
|
||||||
|
int recordFile;
|
||||||
|
bool active;
|
||||||
|
time_t lastDiskSpaceCheck;
|
||||||
|
bool RunningLowOnDiskSpace(void);
|
||||||
|
bool NextFile(void);
|
||||||
|
protected:
|
||||||
|
virtual void Activate(bool On);
|
||||||
|
virtual void Receive(uchar *Data, int Length);
|
||||||
|
virtual void Action(void);
|
||||||
|
public:
|
||||||
|
cRecorder(const char *FileName, int Ca, int Priority, int VPid, int APid1, int APid2, int DPid1, int DPid2);
|
||||||
|
// Creates a new recorder that requires conditional access Ca, has
|
||||||
|
// the given Priority and will record the given PIDs into the file FileName.
|
||||||
|
virtual ~cRecorder();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //__RECORDER_H
|
350
recording.c
350
recording.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: recording.c 1.62 2002/05/13 16:31:21 kls Exp $
|
* $Id: recording.c 1.63 2002/06/16 11:29:27 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "recording.h"
|
#include "recording.h"
|
||||||
@ -16,6 +16,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
|
#include "remux.h" //XXX+ I_FRAME
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
#include "videodir.h"
|
#include "videodir.h"
|
||||||
|
|
||||||
@ -732,3 +733,350 @@ void cRecordingUserCommand::InvokeCommand(const char *State, const char *Recordi
|
|||||||
delete cmd;
|
delete cmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- XXX+
|
||||||
|
|
||||||
|
//XXX+ somewhere else???
|
||||||
|
// --- cIndexFile ------------------------------------------------------------
|
||||||
|
|
||||||
|
#define INDEXFILESUFFIX "/index.vdr"
|
||||||
|
|
||||||
|
// The maximum time to wait before giving up while catching up on an index file:
|
||||||
|
#define MAXINDEXCATCHUP 2 // seconds
|
||||||
|
|
||||||
|
cIndexFile::cIndexFile(const char *FileName, bool Record)
|
||||||
|
:resumeFile(FileName)
|
||||||
|
{
|
||||||
|
f = -1;
|
||||||
|
fileName = NULL;
|
||||||
|
size = 0;
|
||||||
|
last = -1;
|
||||||
|
index = NULL;
|
||||||
|
if (FileName) {
|
||||||
|
fileName = new char[strlen(FileName) + strlen(INDEXFILESUFFIX) + 1];
|
||||||
|
if (fileName) {
|
||||||
|
strcpy(fileName, FileName);
|
||||||
|
char *pFileExt = fileName + strlen(fileName);
|
||||||
|
strcpy(pFileExt, INDEXFILESUFFIX);
|
||||||
|
int delta = 0;
|
||||||
|
if (access(fileName, R_OK) == 0) {
|
||||||
|
struct stat buf;
|
||||||
|
if (stat(fileName, &buf) == 0) {
|
||||||
|
delta = buf.st_size % sizeof(tIndex);
|
||||||
|
if (delta) {
|
||||||
|
delta = sizeof(tIndex) - delta;
|
||||||
|
esyslog("ERROR: invalid file size (%ld) in '%s'", buf.st_size, fileName);
|
||||||
|
}
|
||||||
|
last = (buf.st_size + delta) / sizeof(tIndex) - 1;
|
||||||
|
if (!Record && last >= 0) {
|
||||||
|
size = last + 1;
|
||||||
|
index = new tIndex[size];
|
||||||
|
if (index) {
|
||||||
|
f = open(fileName, O_RDONLY);
|
||||||
|
if (f >= 0) {
|
||||||
|
if ((int)safe_read(f, index, buf.st_size) != buf.st_size) {
|
||||||
|
esyslog("ERROR: can't read from file '%s'", fileName);
|
||||||
|
delete index;
|
||||||
|
index = NULL;
|
||||||
|
close(f);
|
||||||
|
f = -1;
|
||||||
|
}
|
||||||
|
// we don't close f here, see CatchUp()!
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: can't allocate %d bytes for index '%s'", size * sizeof(tIndex), fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG_ERROR;
|
||||||
|
}
|
||||||
|
else if (!Record)
|
||||||
|
isyslog("missing index file %s", fileName);
|
||||||
|
if (Record) {
|
||||||
|
if ((f = open(fileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) >= 0) {
|
||||||
|
if (delta) {
|
||||||
|
esyslog("ERROR: padding index file with %d '0' bytes", delta);
|
||||||
|
while (delta--)
|
||||||
|
writechar(f, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: can't copy file name '%s'", FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cIndexFile::~cIndexFile()
|
||||||
|
{
|
||||||
|
if (f >= 0)
|
||||||
|
close(f);
|
||||||
|
delete fileName;
|
||||||
|
delete index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIndexFile::CatchUp(int Index)
|
||||||
|
{
|
||||||
|
if (index && f >= 0) {
|
||||||
|
for (int i = 0; i <= MAXINDEXCATCHUP && (Index < 0 || Index >= last); i++) {
|
||||||
|
struct stat buf;
|
||||||
|
if (fstat(f, &buf) == 0) {
|
||||||
|
int newLast = buf.st_size / sizeof(tIndex) - 1;
|
||||||
|
if (newLast > last) {
|
||||||
|
if (size <= newLast) {
|
||||||
|
size *= 2;
|
||||||
|
if (size <= newLast)
|
||||||
|
size = newLast + 1;
|
||||||
|
}
|
||||||
|
index = (tIndex *)realloc(index, size * sizeof(tIndex));
|
||||||
|
if (index) {
|
||||||
|
int offset = (last + 1) * sizeof(tIndex);
|
||||||
|
int delta = (newLast - last) * sizeof(tIndex);
|
||||||
|
if (lseek(f, offset, SEEK_SET) == offset) {
|
||||||
|
if (safe_read(f, &index[last + 1], delta) != delta) {
|
||||||
|
esyslog("ERROR: can't read from index");
|
||||||
|
delete index;
|
||||||
|
index = NULL;
|
||||||
|
close(f);
|
||||||
|
f = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last = newLast;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog("ERROR: can't realloc() index");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
if (Index >= last)
|
||||||
|
sleep(1);
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIndexFile::Write(uchar PictureType, uchar FileNumber, int FileOffset)
|
||||||
|
{
|
||||||
|
if (f >= 0) {
|
||||||
|
tIndex i = { FileOffset, PictureType, FileNumber, 0 };
|
||||||
|
if (safe_write(f, &i, sizeof(i)) < 0) {
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
close(f);
|
||||||
|
f = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
last++;
|
||||||
|
}
|
||||||
|
return f >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool cIndexFile::Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType, int *Length)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
CatchUp(Index);
|
||||||
|
if (Index >= 0 && Index <= last) {
|
||||||
|
*FileNumber = index[Index].number;
|
||||||
|
*FileOffset = index[Index].offset;
|
||||||
|
if (PictureType)
|
||||||
|
*PictureType = index[Index].type;
|
||||||
|
if (Length) {
|
||||||
|
int fn = index[Index + 1].number;
|
||||||
|
int fo = index[Index + 1].offset;
|
||||||
|
if (fn == *FileNumber)
|
||||||
|
*Length = fo - *FileOffset;
|
||||||
|
else
|
||||||
|
*Length = -1; // this means "everything up to EOF" (the buffer's Read function will act accordingly)
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIndexFile::GetNextIFrame(int Index, bool Forward, uchar *FileNumber, int *FileOffset, int *Length, bool StayOffEnd)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
CatchUp();
|
||||||
|
int d = Forward ? 1 : -1;
|
||||||
|
for (;;) {
|
||||||
|
Index += d;
|
||||||
|
if (Index >= 0 && Index < last - ((Forward && StayOffEnd) ? 100 : 0)) {
|
||||||
|
if (index[Index].type == I_FRAME) {
|
||||||
|
if (FileNumber)
|
||||||
|
*FileNumber = index[Index].number;
|
||||||
|
else
|
||||||
|
FileNumber = &index[Index].number;
|
||||||
|
if (FileOffset)
|
||||||
|
*FileOffset = index[Index].offset;
|
||||||
|
else
|
||||||
|
FileOffset = &index[Index].offset;
|
||||||
|
if (Length) {
|
||||||
|
// all recordings end with a non-I_FRAME, so the following should be safe:
|
||||||
|
int fn = index[Index + 1].number;
|
||||||
|
int fo = index[Index + 1].offset;
|
||||||
|
if (fn == *FileNumber)
|
||||||
|
*Length = fo - *FileOffset;
|
||||||
|
else {
|
||||||
|
esyslog("ERROR: 'I' frame at end of file #%d", *FileNumber);
|
||||||
|
*Length = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cIndexFile::Get(uchar FileNumber, int FileOffset)
|
||||||
|
{
|
||||||
|
if (index) {
|
||||||
|
CatchUp();
|
||||||
|
//TODO implement binary search!
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < last; i++) {
|
||||||
|
if (index[i].number > FileNumber || (index[i].number == FileNumber) && index[i].offset >= FileOffset)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cFileName -------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "videodir.h"
|
||||||
|
|
||||||
|
#define MAXFILESPERRECORDING 255
|
||||||
|
#define RECORDFILESUFFIX "/%03d.vdr"
|
||||||
|
#define RECORDFILESUFFIXLEN 20 // some additional bytes for safety...
|
||||||
|
|
||||||
|
cFileName::cFileName(const char *FileName, bool Record, bool Blocking)
|
||||||
|
{
|
||||||
|
file = -1;
|
||||||
|
fileNumber = 0;
|
||||||
|
record = Record;
|
||||||
|
blocking = Blocking;
|
||||||
|
// Prepare the file name:
|
||||||
|
fileName = new char[strlen(FileName) + RECORDFILESUFFIXLEN];
|
||||||
|
if (!fileName) {
|
||||||
|
esyslog("ERROR: can't copy file name '%s'", fileName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
strcpy(fileName, FileName);
|
||||||
|
pFileNumber = fileName + strlen(fileName);
|
||||||
|
SetOffset(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cFileName::~cFileName()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
delete fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cFileName::Open(void)
|
||||||
|
{
|
||||||
|
if (file < 0) {
|
||||||
|
int BlockingFlag = blocking ? 0 : O_NONBLOCK;
|
||||||
|
if (record) {
|
||||||
|
dsyslog("recording to '%s'", fileName);
|
||||||
|
file = OpenVideoFile(fileName, O_RDWR | O_CREAT | BlockingFlag);
|
||||||
|
if (file < 0)
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (access(fileName, R_OK) == 0) {
|
||||||
|
dsyslog("playing '%s'", fileName);
|
||||||
|
file = open(fileName, O_RDONLY | BlockingFlag);
|
||||||
|
if (file < 0)
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
}
|
||||||
|
else if (errno != ENOENT)
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cFileName::Close(void)
|
||||||
|
{
|
||||||
|
if (file >= 0) {
|
||||||
|
if ((record && CloseVideoFile(file) < 0) || (!record && close(file) < 0))
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
file = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cFileName::SetOffset(int Number, int Offset)
|
||||||
|
{
|
||||||
|
if (fileNumber != Number)
|
||||||
|
Close();
|
||||||
|
if (0 < Number && Number <= MAXFILESPERRECORDING) {
|
||||||
|
fileNumber = Number;
|
||||||
|
sprintf(pFileNumber, RECORDFILESUFFIX, fileNumber);
|
||||||
|
if (record) {
|
||||||
|
if (access(fileName, F_OK) == 0) // file exists, let's try next suffix
|
||||||
|
return SetOffset(Number + 1);
|
||||||
|
else if (errno != ENOENT) { // something serious has happened
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// found a non existing file suffix
|
||||||
|
}
|
||||||
|
if (Open() >= 0) {
|
||||||
|
if (!record && Offset >= 0 && lseek(file, Offset, SEEK_SET) != Offset) {
|
||||||
|
LOG_ERROR_STR(fileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
esyslog("ERROR: max number of files (%d) exceeded", MAXFILESPERRECORDING);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cFileName::NextFile(void)
|
||||||
|
{
|
||||||
|
return SetOffset(fileNumber + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *IndexToHMSF(int Index, bool WithFrame)
|
||||||
|
{
|
||||||
|
static char buffer[16];
|
||||||
|
int f = (Index % FRAMESPERSEC) + 1;
|
||||||
|
int s = (Index / FRAMESPERSEC);
|
||||||
|
int m = s / 60 % 60;
|
||||||
|
int h = s / 3600;
|
||||||
|
s %= 60;
|
||||||
|
snprintf(buffer, sizeof(buffer), WithFrame ? "%d:%02d:%02d.%02d" : "%d:%02d:%02d", h, m, s, f);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int HMSFToIndex(const char *HMSF)
|
||||||
|
{
|
||||||
|
int h, m, s, f = 0;
|
||||||
|
if (3 <= sscanf(HMSF, "%d:%d:%d.%d", &h, &m, &s, &f))
|
||||||
|
return (h * 3600 + m * 60 + s) * FRAMESPERSEC + f - 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SecondsToFrames(int Seconds)
|
||||||
|
{
|
||||||
|
return Seconds * FRAMESPERSEC;
|
||||||
|
}
|
||||||
|
61
recording.h
61
recording.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: recording.h 1.22 2002/02/03 11:59:49 kls Exp $
|
* $Id: recording.h 1.23 2002/06/16 11:29:47 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __RECORDING_H
|
#ifndef __RECORDING_H
|
||||||
@ -104,4 +104,63 @@ public:
|
|||||||
static void InvokeCommand(const char *State, const char *RecordingFileName);
|
static void InvokeCommand(const char *State, const char *RecordingFileName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//XXX+
|
||||||
|
#define FRAMESPERSEC 25
|
||||||
|
|
||||||
|
// The maximum file size is limited by the range that can be covered
|
||||||
|
// with 'int'. 4GB might be possible (if the range is considered
|
||||||
|
// 'unsigned'), 2GB should be possible (even if the range is considered
|
||||||
|
// 'signed'), so let's use 2000MB for absolute safety (the actual file size
|
||||||
|
// may be slightly higher because we stop recording only before the next
|
||||||
|
// 'I' frame, to have a complete Group Of Pictures):
|
||||||
|
#define MAXVIDEOFILESIZE 2000 // MB
|
||||||
|
#define MINVIDEOFILESIZE 100 // MB
|
||||||
|
|
||||||
|
class cIndexFile {
|
||||||
|
private:
|
||||||
|
struct tIndex { int offset; uchar type; uchar number; short reserved; };
|
||||||
|
int f;
|
||||||
|
char *fileName;
|
||||||
|
int size, last;
|
||||||
|
tIndex *index;
|
||||||
|
cResumeFile resumeFile;
|
||||||
|
bool CatchUp(int Index = -1);
|
||||||
|
public:
|
||||||
|
cIndexFile(const char *FileName, bool Record);
|
||||||
|
~cIndexFile();
|
||||||
|
bool Ok(void) { return index != NULL; }
|
||||||
|
bool Write(uchar PictureType, uchar FileNumber, int FileOffset);
|
||||||
|
bool Get(int Index, uchar *FileNumber, int *FileOffset, uchar *PictureType = NULL, int *Length = NULL);
|
||||||
|
int GetNextIFrame(int Index, bool Forward, uchar *FileNumber = NULL, int *FileOffset = NULL, int *Length = NULL, bool StayOffEnd = false);
|
||||||
|
int Get(uchar FileNumber, int FileOffset);
|
||||||
|
int Last(void) { CatchUp(); return last; }
|
||||||
|
int GetResume(void) { return resumeFile.Read(); }
|
||||||
|
bool StoreResume(int Index) { return resumeFile.Save(Index); }
|
||||||
|
};
|
||||||
|
|
||||||
|
class cFileName {
|
||||||
|
private:
|
||||||
|
int file;
|
||||||
|
int fileNumber;
|
||||||
|
char *fileName, *pFileNumber;
|
||||||
|
bool record;
|
||||||
|
bool blocking;
|
||||||
|
public:
|
||||||
|
cFileName(const char *FileName, bool Record, bool Blocking = false);
|
||||||
|
~cFileName();
|
||||||
|
const char *Name(void) { return fileName; }
|
||||||
|
int Number(void) { return fileNumber; }
|
||||||
|
int Open(void);
|
||||||
|
void Close(void);
|
||||||
|
int SetOffset(int Number, int Offset = 0);
|
||||||
|
int NextFile(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *IndexToHMSF(int Index, bool WithFrame = false);
|
||||||
|
// Converts the given index to a string, optionally containing the frame number.
|
||||||
|
int HMSFToIndex(const char *HMSF);
|
||||||
|
// Converts the given string (format: "hh:mm:ss.ff") to an index.
|
||||||
|
int SecondsToFrames(int Seconds); //XXX+ ->player???
|
||||||
|
// Returns the number of frames corresponding to the given number of seconds.
|
||||||
|
|
||||||
#endif //__RECORDING_H
|
#endif //__RECORDING_H
|
||||||
|
93
ringbuffer.c
93
ringbuffer.c
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* ringbuffer.c: A threaded ring buffer
|
* ringbuffer.c: A ring buffer
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
@ -7,50 +7,25 @@
|
|||||||
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
||||||
* LinuxDVB driver (see linuxtv.org).
|
* LinuxDVB driver (see linuxtv.org).
|
||||||
*
|
*
|
||||||
* $Id: ringbuffer.c 1.8 2002/05/18 08:54:52 kls Exp $
|
* $Id: ringbuffer.c 1.9 2002/06/16 11:24:40 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
|
#include <unistd.h>
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
// --- cRingBufferInputThread -------------------------------------------------
|
// --- cRingBuffer -----------------------------------------------------------
|
||||||
|
|
||||||
class cRingBufferInputThread : public cThread {
|
|
||||||
private:
|
|
||||||
cRingBuffer *ringBuffer;
|
|
||||||
protected:
|
|
||||||
virtual void Action(void) { ringBuffer->Input(); }
|
|
||||||
public:
|
|
||||||
cRingBufferInputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- cRingBufferOutputThread ------------------------------------------------
|
|
||||||
|
|
||||||
class cRingBufferOutputThread : public cThread {
|
|
||||||
private:
|
|
||||||
cRingBuffer *ringBuffer;
|
|
||||||
protected:
|
|
||||||
virtual void Action(void) { ringBuffer->Output(); }
|
|
||||||
public:
|
|
||||||
cRingBufferOutputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// --- cRingBuffer ------------------------------------------------------------
|
|
||||||
|
|
||||||
cRingBuffer::cRingBuffer(int Size, bool Statistics)
|
cRingBuffer::cRingBuffer(int Size, bool Statistics)
|
||||||
{
|
{
|
||||||
size = Size;
|
size = Size;
|
||||||
statistics = Statistics;
|
statistics = Statistics;
|
||||||
inputThread = NULL;
|
|
||||||
outputThread = NULL;
|
|
||||||
busy = false;
|
|
||||||
maxFill = 0;
|
maxFill = 0;
|
||||||
|
lastPercent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cRingBuffer::~cRingBuffer()
|
cRingBuffer::~cRingBuffer()
|
||||||
{
|
{
|
||||||
delete inputThread;
|
|
||||||
delete outputThread;
|
|
||||||
if (statistics)
|
if (statistics)
|
||||||
dsyslog("buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
|
dsyslog("buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
|
||||||
}
|
}
|
||||||
@ -79,45 +54,13 @@ void cRingBuffer::EnableGet(void)
|
|||||||
readyForGet.Broadcast();
|
readyForGet.Broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cRingBuffer::Start(void)
|
// --- cRingBufferLinear -----------------------------------------------------
|
||||||
{
|
|
||||||
if (!busy) {
|
|
||||||
busy = true;
|
|
||||||
outputThread = new cRingBufferOutputThread(this);
|
|
||||||
if (!outputThread->Start())
|
|
||||||
DELETENULL(outputThread);
|
|
||||||
inputThread = new cRingBufferInputThread(this);
|
|
||||||
if (!inputThread->Start()) {
|
|
||||||
DELETENULL(inputThread);
|
|
||||||
DELETENULL(outputThread);
|
|
||||||
}
|
|
||||||
busy = outputThread && inputThread;
|
|
||||||
}
|
|
||||||
return busy;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool cRingBuffer::Active(void)
|
|
||||||
{
|
|
||||||
return outputThread && outputThread->Active() && inputThread && inputThread->Active();
|
|
||||||
}
|
|
||||||
|
|
||||||
void cRingBuffer::Stop(void)
|
|
||||||
{
|
|
||||||
busy = false;
|
|
||||||
for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
|
|
||||||
if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
DELETENULL(inputThread);
|
|
||||||
DELETENULL(outputThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- cRingBufferLinear ----------------------------------------------------
|
|
||||||
|
|
||||||
cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
|
cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
|
||||||
:cRingBuffer(Size, Statistics)
|
:cRingBuffer(Size, Statistics)
|
||||||
{
|
{
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
|
getThreadPid = -1;
|
||||||
if (Size > 1) { // 'Size - 1' must not be 0!
|
if (Size > 1) { // 'Size - 1' must not be 0!
|
||||||
buffer = new uchar[Size];
|
buffer = new uchar[Size];
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
@ -146,6 +89,8 @@ void cRingBufferLinear::Clear(void)
|
|||||||
Lock();
|
Lock();
|
||||||
head = tail = 0;
|
head = tail = 0;
|
||||||
Unlock();
|
Unlock();
|
||||||
|
EnablePut();
|
||||||
|
EnableGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cRingBufferLinear::Put(const uchar *Data, int Count)
|
int cRingBufferLinear::Put(const uchar *Data, int Count)
|
||||||
@ -159,11 +104,13 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
|
|||||||
int fill = Size() - free - 1 + Count;
|
int fill = Size() - free - 1 + Count;
|
||||||
if (fill >= Size())
|
if (fill >= Size())
|
||||||
fill = Size() - 1;
|
fill = Size() - 1;
|
||||||
if (fill > maxFill) {
|
if (fill > maxFill)
|
||||||
maxFill = fill;
|
maxFill = fill;
|
||||||
int percent = maxFill * 100 / (Size() - 1);
|
int percent = maxFill * 100 / (Size() - 1) / 5 * 5;
|
||||||
|
if (abs(lastPercent - percent) >= 5) {
|
||||||
if (percent > 75)
|
if (percent > 75)
|
||||||
dsyslog("buffer usage: %d%%", percent);
|
dsyslog("buffer usage: %d%% (pid=%d)", percent, getThreadPid);
|
||||||
|
lastPercent = percent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (free > 0) {
|
if (free > 0) {
|
||||||
@ -185,6 +132,7 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
|
|||||||
else
|
else
|
||||||
Count = 0;
|
Count = 0;
|
||||||
Unlock();
|
Unlock();
|
||||||
|
EnableGet();
|
||||||
}
|
}
|
||||||
return Count;
|
return Count;
|
||||||
}
|
}
|
||||||
@ -193,6 +141,8 @@ int cRingBufferLinear::Get(uchar *Data, int Count)
|
|||||||
{
|
{
|
||||||
if (Count > 0) {
|
if (Count > 0) {
|
||||||
Lock();
|
Lock();
|
||||||
|
if (getThreadPid < 0)
|
||||||
|
getThreadPid = getpid();
|
||||||
int rest = Size() - tail;
|
int rest = Size() - tail;
|
||||||
int diff = head - tail;
|
int diff = head - tail;
|
||||||
int cont = (diff >= 0) ? diff : Size() + diff;
|
int cont = (diff >= 0) ? diff : Size() + diff;
|
||||||
@ -213,6 +163,8 @@ int cRingBufferLinear::Get(uchar *Data, int Count)
|
|||||||
else
|
else
|
||||||
Count = 0;
|
Count = 0;
|
||||||
Unlock();
|
Unlock();
|
||||||
|
if (Count == 0)
|
||||||
|
WaitForGet();
|
||||||
}
|
}
|
||||||
return Count;
|
return Count;
|
||||||
}
|
}
|
||||||
@ -255,7 +207,7 @@ void cRingBufferFrame::Clear(void)
|
|||||||
{
|
{
|
||||||
Lock();
|
Lock();
|
||||||
const cFrame *p;
|
const cFrame *p;
|
||||||
while ((p = Get(false)) != NULL)
|
while ((p = Get()) != NULL)
|
||||||
Drop(p);
|
Drop(p);
|
||||||
Unlock();
|
Unlock();
|
||||||
EnablePut();
|
EnablePut();
|
||||||
@ -279,17 +231,14 @@ bool cRingBufferFrame::Put(cFrame *Frame)
|
|||||||
EnableGet();
|
EnableGet();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
WaitForPut();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cFrame *cRingBufferFrame::Get(bool Wait)
|
const cFrame *cRingBufferFrame::Get(void)
|
||||||
{
|
{
|
||||||
Lock();
|
Lock();
|
||||||
cFrame *p = head ? head->next : NULL;
|
cFrame *p = head ? head->next : NULL;
|
||||||
Unlock();
|
Unlock();
|
||||||
if (!p && Wait)
|
|
||||||
WaitForGet();
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
ringbuffer.h
42
ringbuffer.h
@ -1,10 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* ringbuffer.h: A threaded ring buffer
|
* ringbuffer.h: A ring buffer
|
||||||
*
|
*
|
||||||
* 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.5 2001/11/03 10:41:33 kls Exp $
|
* $Id: ringbuffer.h 1.6 2002/06/16 11:30:07 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __RINGBUFFER_H
|
#ifndef __RINGBUFFER_H
|
||||||
@ -12,24 +12,17 @@
|
|||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
typedef unsigned char uchar;
|
typedef unsigned char uchar;//XXX+
|
||||||
|
|
||||||
class cRingBufferInputThread;
|
|
||||||
class cRingBufferOutputThread;
|
|
||||||
|
|
||||||
class cRingBuffer {
|
class cRingBuffer {
|
||||||
friend class cRingBufferInputThread;
|
|
||||||
friend class cRingBufferOutputThread;
|
|
||||||
private:
|
private:
|
||||||
cRingBufferInputThread *inputThread;
|
|
||||||
cRingBufferOutputThread *outputThread;
|
|
||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
cCondVar readyForPut, readyForGet;
|
cCondVar readyForPut, readyForGet;
|
||||||
cMutex putMutex, getMutex;
|
cMutex putMutex, getMutex;
|
||||||
int size;
|
int size;
|
||||||
bool busy;
|
|
||||||
protected:
|
protected:
|
||||||
int maxFill;//XXX
|
int maxFill;//XXX
|
||||||
|
int lastPercent;
|
||||||
bool statistics;//XXX
|
bool statistics;//XXX
|
||||||
void WaitForPut(void);
|
void WaitForPut(void);
|
||||||
void WaitForGet(void);
|
void WaitForGet(void);
|
||||||
@ -41,26 +34,19 @@ protected:
|
|||||||
void Lock(void) { mutex.Lock(); }
|
void Lock(void) { mutex.Lock(); }
|
||||||
void Unlock(void) { mutex.Unlock(); }
|
void Unlock(void) { mutex.Unlock(); }
|
||||||
int Size(void) { return size; }
|
int Size(void) { return size; }
|
||||||
bool Busy(void) { return busy; }
|
|
||||||
virtual void Input(void) = 0;
|
|
||||||
// Runs as a separate thread and shall continuously read data from
|
|
||||||
// a source and call Put() to store the data in the ring buffer.
|
|
||||||
virtual void Output(void) = 0;
|
|
||||||
// Runs as a separate thread and shall continuously call Get() to
|
|
||||||
// retrieve data from the ring buffer and write it to a destination.
|
|
||||||
public:
|
public:
|
||||||
cRingBuffer(int Size, bool Statistics = false);
|
cRingBuffer(int Size, bool Statistics = false);
|
||||||
virtual ~cRingBuffer();
|
virtual ~cRingBuffer();
|
||||||
bool Start(void);
|
|
||||||
bool Active(void);
|
|
||||||
void Stop(void);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class cRingBufferLinear : public cRingBuffer {
|
class cRingBufferLinear : public cRingBuffer {
|
||||||
private:
|
private:
|
||||||
int head, tail;
|
int head, tail;
|
||||||
uchar *buffer;
|
uchar *buffer;
|
||||||
protected:
|
pid_t getThreadPid;
|
||||||
|
public:
|
||||||
|
cRingBufferLinear(int Size, bool Statistics = false);
|
||||||
|
virtual ~cRingBufferLinear();
|
||||||
virtual int Available(void);
|
virtual int Available(void);
|
||||||
virtual void Clear(void);
|
virtual void Clear(void);
|
||||||
// Immediately clears the ring buffer.
|
// Immediately clears the ring buffer.
|
||||||
@ -70,9 +56,6 @@ protected:
|
|||||||
int Get(uchar *Data, int Count);
|
int Get(uchar *Data, int Count);
|
||||||
// Gets at most Count bytes of Data from the ring buffer.
|
// Gets at most Count bytes of Data from the ring buffer.
|
||||||
// Returns the number of bytes actually retrieved.
|
// Returns the number of bytes actually retrieved.
|
||||||
public:
|
|
||||||
cRingBufferLinear(int Size, bool Statistics = false);
|
|
||||||
virtual ~cRingBufferLinear();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby };
|
enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby };
|
||||||
@ -99,21 +82,20 @@ private:
|
|||||||
cFrame *head;
|
cFrame *head;
|
||||||
int currentFill;
|
int currentFill;
|
||||||
void Delete(const cFrame *Frame);
|
void Delete(const cFrame *Frame);
|
||||||
protected:
|
public:
|
||||||
|
cRingBufferFrame(int Size, bool Statistics = false);
|
||||||
|
virtual ~cRingBufferFrame();
|
||||||
virtual int Available(void);
|
virtual int Available(void);
|
||||||
virtual void Clear(void);
|
virtual void Clear(void);
|
||||||
// Immediately clears the ring buffer.
|
// Immediately clears the ring buffer.
|
||||||
bool Put(cFrame *Frame);
|
bool Put(cFrame *Frame);
|
||||||
// Puts the Frame into the ring buffer.
|
// Puts the Frame into the ring buffer.
|
||||||
// Returns true if this was possible.
|
// Returns true if this was possible.
|
||||||
const cFrame *Get(bool Wait = true);
|
const cFrame *Get(void);
|
||||||
// Gets the next frame from the ring buffer.
|
// Gets the next frame from the ring buffer.
|
||||||
// The actual data still remains in the buffer until Drop() is called.
|
// The actual data still remains in the buffer until Drop() is called.
|
||||||
void Drop(const cFrame *Frame);
|
void Drop(const cFrame *Frame);
|
||||||
// Drops the Frame that has just been fetched with Get().
|
// Drops the Frame that has just been fetched with Get().
|
||||||
public:
|
|
||||||
cRingBufferFrame(int Size, bool Statistics = false);
|
|
||||||
virtual ~cRingBufferFrame();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __RINGBUFFER_H
|
#endif // __RINGBUFFER_H
|
||||||
|
14
status.c
14
status.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: status.c 1.1 2002/05/19 14:54:30 kls Exp $
|
* $Id: status.c 1.2 2002/06/16 12:10:44 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
@ -23,22 +23,22 @@ cStatusMonitor::~cStatusMonitor()
|
|||||||
statusMonitors.Del(this, false);
|
statusMonitors.Del(this, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cStatusMonitor::MsgChannelSwitch(const cDvbApi *DvbApi, int ChannelNumber)
|
void cStatusMonitor::MsgChannelSwitch(const cDevice *Device, int ChannelNumber)
|
||||||
{
|
{
|
||||||
for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
|
for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
|
||||||
sm->ChannelSwitch(DvbApi, ChannelNumber);
|
sm->ChannelSwitch(Device, ChannelNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cStatusMonitor::MsgRecording(const cDvbApi *DvbApi, const char *Name)
|
void cStatusMonitor::MsgRecording(const cDevice *Device, const char *Name)
|
||||||
{
|
{
|
||||||
for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
|
for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
|
||||||
sm->Recording(DvbApi, Name);
|
sm->Recording(Device, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cStatusMonitor::MsgReplaying(const cDvbApi *DvbApi, const char *Name)
|
void cStatusMonitor::MsgReplaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name)
|
||||||
{
|
{
|
||||||
for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
|
for (cStatusMonitor *sm = statusMonitors.First(); sm; sm = statusMonitors.Next(sm))
|
||||||
sm->Replaying(DvbApi, Name);
|
sm->Replaying(DvbPlayerControl, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cStatusMonitor::MsgSetVolume(int Volume, bool Absolute)
|
void cStatusMonitor::MsgSetVolume(int Volume, bool Absolute)
|
||||||
|
23
status.h
23
status.h
@ -4,14 +4,15 @@
|
|||||||
* 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: status.h 1.1 2002/05/19 14:54:15 kls Exp $
|
* $Id: status.h 1.2 2002/06/16 12:09:55 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __STATUS_H
|
#ifndef __STATUS_H
|
||||||
#define __STATUS_H
|
#define __STATUS_H
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "dvbapi.h"
|
#include "device.h"
|
||||||
|
#include "dvbplayer.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
class cStatusMonitor : public cListObject {
|
class cStatusMonitor : public cListObject {
|
||||||
@ -19,15 +20,15 @@ private:
|
|||||||
static cList<cStatusMonitor> statusMonitors;
|
static cList<cStatusMonitor> statusMonitors;
|
||||||
protected:
|
protected:
|
||||||
// These functions can be implemented by derived classes to receive status information:
|
// These functions can be implemented by derived classes to receive status information:
|
||||||
virtual void ChannelSwitch(const cDvbApi *DvbApi, int ChannelNumber) {}
|
virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber) {}
|
||||||
// Indicates a channel switch on DVB device DvbApi.
|
// Indicates a channel switch on the given DVB device.
|
||||||
// If ChannelNumber is 0, this is before the channel is being switched,
|
// If ChannelNumber is 0, this is before the channel is being switched,
|
||||||
// otherwise ChannelNumber is the number of the channel that has been switched to.
|
// otherwise ChannelNumber is the number of the channel that has been switched to.
|
||||||
virtual void Recording(const cDvbApi *DvbApi, const char *Name) {}
|
virtual void Recording(const cDevice *Device, const char *Name) {}
|
||||||
// DVB device DvbApi has started recording Name. Name is the full directory
|
// The given DVB device has started recording Name. Name is the full directory
|
||||||
// name of the recording. If Name is NULL, the recording has ended.
|
// name of the recording. If Name is NULL, the recording has ended.
|
||||||
virtual void Replaying(const cDvbApi *DvbApi, const char *Name) {}
|
virtual void Replaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name) {}
|
||||||
// DVB device DvbApi has started replaying Name. Name is the full directory
|
// The given player control has started replaying Name. Name is the full directory
|
||||||
// name of the recording. If Name is NULL, the replay has ended.
|
// name of the recording. If Name is NULL, the replay has ended.
|
||||||
virtual void SetVolume(int Volume, bool Absolute) {}
|
virtual void SetVolume(int Volume, bool Absolute) {}
|
||||||
// The volume has been set to the given value, either
|
// The volume has been set to the given value, either
|
||||||
@ -57,9 +58,9 @@ public:
|
|||||||
cStatusMonitor(void);
|
cStatusMonitor(void);
|
||||||
virtual ~cStatusMonitor();
|
virtual ~cStatusMonitor();
|
||||||
// These functions are called whenever the related status information changes:
|
// These functions are called whenever the related status information changes:
|
||||||
static void MsgChannelSwitch(const cDvbApi *DvbApi, int ChannelNumber);
|
static void MsgChannelSwitch(const cDevice *Device, int ChannelNumber);
|
||||||
static void MsgRecording(const cDvbApi *DvbApi, const char *Name);
|
static void MsgRecording(const cDevice *Device, const char *Name);
|
||||||
static void MsgReplaying(const cDvbApi *DvbApi, const char *Name);
|
static void MsgReplaying(const cDvbPlayerControl *DvbPlayerControl, const char *Name);
|
||||||
static void MsgSetVolume(int Volume, bool Absolute);
|
static void MsgSetVolume(int Volume, bool Absolute);
|
||||||
static void MsgOsdClear(void);
|
static void MsgOsdClear(void);
|
||||||
static void MsgOsdTitle(const char *Title);
|
static void MsgOsdTitle(const char *Title);
|
||||||
|
26
svdrp.c
26
svdrp.c
@ -10,7 +10,7 @@
|
|||||||
* and interact with the Video Disk Recorder - or write a full featured
|
* and interact with the Video Disk Recorder - or write a full featured
|
||||||
* graphical interface that sits on top of an SVDRP connection.
|
* graphical interface that sits on top of an SVDRP connection.
|
||||||
*
|
*
|
||||||
* $Id: svdrp.c 1.37 2002/05/13 16:32:05 kls Exp $
|
* $Id: svdrp.c 1.38 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "svdrp.h"
|
#include "svdrp.h"
|
||||||
@ -27,7 +27,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "dvbapi.h"
|
#include "device.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
@ -390,12 +390,12 @@ void cSVDRP::CmdCHAN(const char *Option)
|
|||||||
n = o;
|
n = o;
|
||||||
}
|
}
|
||||||
else if (strcmp(Option, "-") == 0) {
|
else if (strcmp(Option, "-") == 0) {
|
||||||
n = cDvbApi::CurrentChannel();
|
n = cDevice::CurrentChannel();
|
||||||
if (n > 1)
|
if (n > 1)
|
||||||
n--;
|
n--;
|
||||||
}
|
}
|
||||||
else if (strcmp(Option, "+") == 0) {
|
else if (strcmp(Option, "+") == 0) {
|
||||||
n = cDvbApi::CurrentChannel();
|
n = cDevice::CurrentChannel();
|
||||||
if (n < Channels.MaxNumber())
|
if (n < Channels.MaxNumber())
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
@ -430,11 +430,11 @@ void cSVDRP::CmdCHAN(const char *Option)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cChannel *channel = Channels.GetByNumber(cDvbApi::CurrentChannel());
|
cChannel *channel = Channels.GetByNumber(cDevice::CurrentChannel());
|
||||||
if (channel)
|
if (channel)
|
||||||
Reply(250, "%d %s", channel->number, channel->name);
|
Reply(250, "%d %s", channel->number, channel->name);
|
||||||
else
|
else
|
||||||
Reply(550, "Unable to find channel \"%d\"", cDvbApi::CurrentChannel());
|
Reply(550, "Unable to find channel \"%d\"", cDevice::CurrentChannel());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cSVDRP::CmdDELC(const char *Option)
|
void cSVDRP::CmdDELC(const char *Option)
|
||||||
@ -541,7 +541,7 @@ void cSVDRP::CmdGRAB(const char *Option)
|
|||||||
Reply(501, "Unexpected parameter \"%s\"", p);
|
Reply(501, "Unexpected parameter \"%s\"", p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (cDvbApi::PrimaryDvbApi->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY))
|
if (cDevice::PrimaryDevice()->GrabImage(FileName, Jpeg, Quality, SizeX, SizeY))
|
||||||
Reply(250, "Grabbed image %s", Option);
|
Reply(250, "Grabbed image %s", Option);
|
||||||
else
|
else
|
||||||
Reply(451, "Grab image failed");
|
Reply(451, "Grab image failed");
|
||||||
@ -926,22 +926,22 @@ void cSVDRP::CmdVOLU(const char *Option)
|
|||||||
{
|
{
|
||||||
if (*Option) {
|
if (*Option) {
|
||||||
if (isnumber(Option))
|
if (isnumber(Option))
|
||||||
cDvbApi::PrimaryDvbApi->SetVolume(strtol(Option, NULL, 10), true);
|
cDevice::PrimaryDevice()->SetVolume(strtol(Option, NULL, 10), true);
|
||||||
else if (strcmp(Option, "+") == 0)
|
else if (strcmp(Option, "+") == 0)
|
||||||
cDvbApi::PrimaryDvbApi->SetVolume(VOLUMEDELTA);
|
cDevice::PrimaryDevice()->SetVolume(VOLUMEDELTA);
|
||||||
else if (strcmp(Option, "-") == 0)
|
else if (strcmp(Option, "-") == 0)
|
||||||
cDvbApi::PrimaryDvbApi->SetVolume(-VOLUMEDELTA);
|
cDevice::PrimaryDevice()->SetVolume(-VOLUMEDELTA);
|
||||||
else if (strcasecmp(Option, "MUTE") == 0)
|
else if (strcasecmp(Option, "MUTE") == 0)
|
||||||
cDvbApi::PrimaryDvbApi->ToggleMute();
|
cDevice::PrimaryDevice()->ToggleMute();
|
||||||
else {
|
else {
|
||||||
Reply(501, "Unknown option: \"%s\"", Option);
|
Reply(501, "Unknown option: \"%s\"", Option);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cDvbApi::PrimaryDvbApi->IsMute())
|
if (cDevice::PrimaryDevice()->IsMute())
|
||||||
Reply(250, "Audio is mute");
|
Reply(250, "Audio is mute");
|
||||||
else
|
else
|
||||||
Reply(250, "Audio volume is %d", cDvbApi::CurrentVolume());
|
Reply(250, "Audio volume is %d", cDevice::CurrentVolume());
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CMD(c) (strcasecmp(Cmd, c) == 0)
|
#define CMD(c) (strcasecmp(Cmd, c) == 0)
|
||||||
|
3
thread.c
3
thread.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: thread.c 1.20 2002/05/13 16:32:09 kls Exp $
|
* $Id: thread.c 1.21 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
@ -147,6 +147,7 @@ bool cThread::Active(void)
|
|||||||
|
|
||||||
void cThread::Cancel(int WaitSeconds)
|
void cThread::Cancel(int WaitSeconds)
|
||||||
{
|
{
|
||||||
|
running = false;
|
||||||
if (WaitSeconds > 0) {
|
if (WaitSeconds > 0) {
|
||||||
for (time_t t0 = time(NULL) + WaitSeconds; time(NULL) < t0; ) {
|
for (time_t t0 = time(NULL) + WaitSeconds; time(NULL) < t0; ) {
|
||||||
if (!Active())
|
if (!Active())
|
||||||
|
4
thread.h
4
thread.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: thread.h 1.12 2002/02/23 13:53:38 kls Exp $
|
* $Id: thread.h 1.13 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __THREAD_H
|
#ifndef __THREAD_H
|
||||||
@ -54,9 +54,9 @@ private:
|
|||||||
static bool signalHandlerInstalled;
|
static bool signalHandlerInstalled;
|
||||||
static void SignalHandler(int signum);
|
static void SignalHandler(int signum);
|
||||||
static void *StartThread(cThread *Thread);
|
static void *StartThread(cThread *Thread);
|
||||||
|
protected:
|
||||||
void Lock(void) { mutex.Lock(); }
|
void Lock(void) { mutex.Lock(); }
|
||||||
void Unlock(void) { mutex.Unlock(); }
|
void Unlock(void) { mutex.Unlock(); }
|
||||||
protected:
|
|
||||||
void WakeUp(void);
|
void WakeUp(void);
|
||||||
virtual void Action(void) = 0;
|
virtual void Action(void) = 0;
|
||||||
void Cancel(int WaitSeconds = 0);
|
void Cancel(int WaitSeconds = 0);
|
||||||
|
9
tools.h
9
tools.h
@ -4,13 +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: tools.h 1.46 2002/05/18 15:10:10 kls Exp $
|
* $Id: tools.h 1.47 2002/06/10 16:30:00 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __TOOLS_H
|
#ifndef __TOOLS_H
|
||||||
#define __TOOLS_H
|
#define __TOOLS_H
|
||||||
|
|
||||||
//#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -18,6 +18,8 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
typedef unsigned char uchar;
|
||||||
|
|
||||||
extern int SysLogLevel;
|
extern int SysLogLevel;
|
||||||
|
|
||||||
#define esyslog(a...) void( (SysLogLevel > 0) ? syslog(LOG_ERR, a) : void() )
|
#define esyslog(a...) void( (SysLogLevel > 0) ? syslog(LOG_ERR, a) : void() )
|
||||||
@ -36,6 +38,9 @@ extern int SysLogLevel;
|
|||||||
|
|
||||||
#define DELETENULL(p) (delete (p), p = NULL)
|
#define DELETENULL(p) (delete (p), p = NULL)
|
||||||
|
|
||||||
|
#define CHECK(s) { if ((s) < 0) LOG_ERROR; } // used for 'ioctl()' calls
|
||||||
|
#define FATALERRNO (errno != EAGAIN && errno != EINTR)
|
||||||
|
|
||||||
template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
|
template<class T> inline T min(T a, T b) { return a <= b ? a : b; }
|
||||||
template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
|
template<class T> inline T max(T a, T b) { return a >= b ? a : b; }
|
||||||
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
|
template<class T> inline void swap(T &a, T &b) { T t = a; a = b; b = t; }
|
||||||
|
51
vdr.c
51
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.113 2002/05/20 11:02:10 kls Exp $
|
* $Id: vdr.c 1.114 2002/06/16 11:30:28 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "dvbapi.h"
|
#include "device.h"
|
||||||
#include "eitscan.h"
|
#include "eitscan.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
@ -118,15 +118,17 @@ int main(int argc, char *argv[])
|
|||||||
int c;
|
int c;
|
||||||
while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:L:mp:P:r:s:t:v:Vw:", long_options, NULL)) != -1) {
|
while ((c = getopt_long(argc, argv, "a:c:dD:E:hl:L:mp:P:r:s:t:v:Vw:", long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'a': cDvbApi::SetAudioCommand(optarg);
|
/*XXX+
|
||||||
|
case 'a': cDevice::SetAudioCommand(optarg);
|
||||||
break;
|
break;
|
||||||
|
XXX*/
|
||||||
case 'c': ConfigDirectory = optarg;
|
case 'c': ConfigDirectory = optarg;
|
||||||
break;
|
break;
|
||||||
case 'd': DaemonMode = true; break;
|
case 'd': DaemonMode = true; break;
|
||||||
case 'D': if (isnumber(optarg)) {
|
case 'D': if (isnumber(optarg)) {
|
||||||
int n = atoi(optarg);
|
int n = atoi(optarg);
|
||||||
if (0 <= n && n < MAXDVBAPI) {
|
if (0 <= n && n < MAXDEVICES) {
|
||||||
cDvbApi::SetUseDvbApi(n);
|
cDevice::SetUseDevice(n);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -323,10 +325,10 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
// DVB interfaces:
|
// DVB interfaces:
|
||||||
|
|
||||||
if (!cDvbApi::Initialize())
|
if (!cDevice::Initialize())
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB);
|
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
|
||||||
|
|
||||||
cSIProcessor::Read();
|
cSIProcessor::Read();
|
||||||
|
|
||||||
@ -343,9 +345,9 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
Channels.SwitchTo(Setup.CurrentChannel);
|
Channels.SwitchTo(Setup.CurrentChannel);
|
||||||
if (MuteAudio)
|
if (MuteAudio)
|
||||||
cDvbApi::PrimaryDvbApi->ToggleMute();
|
cDevice::PrimaryDevice()->ToggleMute();
|
||||||
else
|
else
|
||||||
cDvbApi::PrimaryDvbApi->SetVolume(Setup.CurrentVolume, true);
|
cDevice::PrimaryDevice()->SetVolume(Setup.CurrentVolume, true);
|
||||||
|
|
||||||
cEITScanner EITScanner;
|
cEITScanner EITScanner;
|
||||||
|
|
||||||
@ -371,7 +373,7 @@ int main(int argc, char *argv[])
|
|||||||
cOsdObject *Menu = NULL;
|
cOsdObject *Menu = NULL;
|
||||||
cReplayControl *ReplayControl = NULL;
|
cReplayControl *ReplayControl = NULL;
|
||||||
int LastChannel = -1;
|
int LastChannel = -1;
|
||||||
int PreviousChannel = cDvbApi::CurrentChannel();
|
int PreviousChannel = cDevice::CurrentChannel();
|
||||||
time_t LastActivity = 0;
|
time_t LastActivity = 0;
|
||||||
int MaxLatencyTime = 0;
|
int MaxLatencyTime = 0;
|
||||||
bool ForceShutdown = false;
|
bool ForceShutdown = false;
|
||||||
@ -396,12 +398,12 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Channel display:
|
// Channel display:
|
||||||
if (!EITScanner.Active() && cDvbApi::CurrentChannel() != LastChannel) {
|
if (!EITScanner.Active() && cDevice::CurrentChannel() != LastChannel) {
|
||||||
if (!Menu)
|
if (!Menu)
|
||||||
Menu = new cDisplayChannel(cDvbApi::CurrentChannel(), LastChannel > 0);
|
Menu = new cDisplayChannel(cDevice::CurrentChannel(), LastChannel > 0);
|
||||||
if (LastChannel > 0)
|
if (LastChannel > 0)
|
||||||
PreviousChannel = LastChannel;
|
PreviousChannel = LastChannel;
|
||||||
LastChannel = cDvbApi::CurrentChannel();
|
LastChannel = cDevice::CurrentChannel();
|
||||||
}
|
}
|
||||||
// Timers and Recordings:
|
// Timers and Recordings:
|
||||||
if (!Menu) {
|
if (!Menu) {
|
||||||
@ -429,11 +431,11 @@ int main(int argc, char *argv[])
|
|||||||
case kVolDn:
|
case kVolDn:
|
||||||
case kMute:
|
case kMute:
|
||||||
if (key == kMute) {
|
if (key == kMute) {
|
||||||
if (!cDvbApi::PrimaryDvbApi->ToggleMute() && !Menu)
|
if (!cDevice::PrimaryDevice()->ToggleMute() && !Menu)
|
||||||
break; // no need to display "mute off"
|
break; // no need to display "mute off"
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cDvbApi::PrimaryDvbApi->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
|
cDevice::PrimaryDevice()->SetVolume(NORMALKEY(key) == kVolDn ? -VOLUMEDELTA : VOLUMEDELTA);
|
||||||
if (!Menu && (!ReplayControl || !ReplayControl->Visible()))
|
if (!Menu && (!ReplayControl || !ReplayControl->Visible()))
|
||||||
Menu = cDisplayVolume::Create();
|
Menu = cDisplayVolume::Create();
|
||||||
cDisplayVolume::Process(key);
|
cDisplayVolume::Process(key);
|
||||||
@ -477,7 +479,7 @@ int main(int argc, char *argv[])
|
|||||||
case osSwitchDvb:
|
case osSwitchDvb:
|
||||||
DELETENULL(*Interact);
|
DELETENULL(*Interact);
|
||||||
Interface->Info(tr("Switching primary DVB..."));
|
Interface->Info(tr("Switching primary DVB..."));
|
||||||
cDvbApi::SetPrimaryDvbApi(Setup.PrimaryDVB);
|
cDevice::SetPrimaryDevice(Setup.PrimaryDVB);
|
||||||
break;
|
break;
|
||||||
case osBack:
|
case osBack:
|
||||||
case osEnd: DELETENULL(*Interact);
|
case osEnd: DELETENULL(*Interact);
|
||||||
@ -490,7 +492,7 @@ int main(int argc, char *argv[])
|
|||||||
switch (key) {
|
switch (key) {
|
||||||
// Toggle channels:
|
// Toggle channels:
|
||||||
case k0: {
|
case k0: {
|
||||||
int CurrentChannel = cDvbApi::CurrentChannel();
|
int CurrentChannel = cDevice::CurrentChannel();
|
||||||
Channels.SwitchTo(PreviousChannel);
|
Channels.SwitchTo(PreviousChannel);
|
||||||
PreviousChannel = CurrentChannel;
|
PreviousChannel = CurrentChannel;
|
||||||
break;
|
break;
|
||||||
@ -511,7 +513,7 @@ int main(int argc, char *argv[])
|
|||||||
case kUp:
|
case kUp:
|
||||||
case kDown|k_Repeat:
|
case kDown|k_Repeat:
|
||||||
case kDown: {
|
case kDown: {
|
||||||
int n = cDvbApi::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1);
|
int n = cDevice::CurrentChannel() + (NORMALKEY(key) == kUp ? 1 : -1);
|
||||||
cChannel *channel = Channels.GetByNumber(n);
|
cChannel *channel = Channels.GetByNumber(n);
|
||||||
if (channel)
|
if (channel)
|
||||||
channel->Switch();
|
channel->Switch();
|
||||||
@ -527,14 +529,16 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if (!Menu) {
|
if (!Menu) {
|
||||||
EITScanner.Process();
|
EITScanner.Process();
|
||||||
|
/*XXX+
|
||||||
if (!cVideoCutter::Active() && cVideoCutter::Ended()) {
|
if (!cVideoCutter::Active() && cVideoCutter::Ended()) {
|
||||||
if (cVideoCutter::Error())
|
if (cVideoCutter::Error())
|
||||||
Interface->Error(tr("Editing process failed!"));
|
Interface->Error(tr("Editing process failed!"));
|
||||||
else
|
else
|
||||||
Interface->Info(tr("Editing process finished"));
|
Interface->Info(tr("Editing process finished"));
|
||||||
}
|
}
|
||||||
|
XXX*/
|
||||||
}
|
}
|
||||||
if (!*Interact && ((!cRecordControls::Active() && !cVideoCutter::Active()) || ForceShutdown)) {
|
if (!*Interact && ((!cRecordControls::Active() /*XXX+&& !cVideoCutter::Active()XXX*/) || ForceShutdown)) {
|
||||||
time_t Now = time(NULL);
|
time_t Now = time(NULL);
|
||||||
if (Now - LastActivity > ACTIVITYTIMEOUT) {
|
if (Now - LastActivity > ACTIVITYTIMEOUT) {
|
||||||
// Shutdown:
|
// Shutdown:
|
||||||
@ -593,16 +597,17 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if (Interrupted)
|
if (Interrupted)
|
||||||
isyslog("caught signal %d", Interrupted);
|
isyslog("caught signal %d", Interrupted);
|
||||||
cVideoCutter::Stop();
|
cRecordControls::Shutdown();
|
||||||
|
//XXX+cVideoCutter::Stop();
|
||||||
delete Menu;
|
delete Menu;
|
||||||
delete ReplayControl;
|
delete ReplayControl;
|
||||||
delete Interface;
|
delete Interface;
|
||||||
cOsd::Shutdown();
|
cOsd::Shutdown();
|
||||||
PluginManager.Shutdown(true);
|
PluginManager.Shutdown(true);
|
||||||
Setup.CurrentChannel = cDvbApi::CurrentChannel();
|
Setup.CurrentChannel = cDevice::CurrentChannel();
|
||||||
Setup.CurrentVolume = cDvbApi::CurrentVolume();
|
Setup.CurrentVolume = cDevice::CurrentVolume();
|
||||||
Setup.Save();
|
Setup.Save();
|
||||||
cDvbApi::Shutdown();
|
cDevice::Shutdown();
|
||||||
if (WatchdogTimeout > 0)
|
if (WatchdogTimeout > 0)
|
||||||
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
dsyslog("max. latency time %d seconds", MaxLatencyTime);
|
||||||
isyslog("exiting");
|
isyslog("exiting");
|
||||||
|
Loading…
Reference in New Issue
Block a user