Implemented 'Transfer Mode'

This commit is contained in:
Klaus Schmidinger 2000-11-19 16:49:14 +01:00
parent 061f344ffa
commit fd464518b6
3 changed files with 127 additions and 4 deletions

View File

@ -266,7 +266,7 @@ Video Disk Recorder Revision History
are programmed via the "Schedules" menu) are now replaced by suitable
substitutes.
2000-11-18: Version 0.68
2000-11-19: Version 0.68
- Date and time in the title of an event info page are now always right adjusted.
- The 'current channel' is now handled device specific (in case there is more
@ -307,3 +307,7 @@ Video Disk Recorder Revision History
that don't send the EIT information correctly (like, e.g., 'VOX').
- Implemented a 10 seconds latency when removing files.
- Fixed unwanted reaction on the "Green" and "Yellow" button in the "Event" display.
- Implemented 'Transfer Mode' to display video data from the DVB card that actually
can receive a certain channel on the primary interface. This is currently in
an early state and may still cause some problems, but it appears to work nice
already.

107
dvbapi.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.c 1.39 2000/11/18 15:30:57 kls Exp $
* $Id: dvbapi.c 1.40 2000/11/19 16:46:37 kls Exp $
*/
#include "dvbapi.h"
@ -372,7 +372,9 @@ private:
int *inFile, *outFile;
protected:
int Free(void) { return ((tail >= head) ? size + head - tail : head - tail) - 1; }
public:
int Available(void) { return (tail >= head) ? tail - head : size - head + tail; }
protected:
int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap!
int Writeable(void) { return (tail >= head) ? tail - head : size - head; }
int Byte(int Offset);
@ -1079,6 +1081,63 @@ int cReplayBuffer::Write(int Max)
return Written;
}
// --- cTransferBuffer -------------------------------------------------------
class cTransferBuffer : public cThread {
private:
bool active;
int fromDevice, toDevice;
protected:
virtual void Action(void);
public:
cTransferBuffer(int FromDevice, int ToDevice);
virtual ~cTransferBuffer();
};
cTransferBuffer::cTransferBuffer(int FromDevice, int ToDevice)
{
fromDevice = FromDevice;
toDevice = ToDevice;
active = true;
Start();
}
cTransferBuffer::~cTransferBuffer()
{
{
LOCK_THREAD;
active = false;
}
for (time_t t0 = time(NULL); time(NULL) - t0 < 3; ) {
LOCK_THREAD;
if (active)
break;
}
}
void cTransferBuffer::Action(void)
{
dsyslog(LOG_INFO, "data transfer thread started (pid=%d)", getpid());
//XXX hack to make the video device go into 'replaying' mode:
char *dummy = "AV"; // must be "AV" to make the driver go into AV_PES mode!
write(toDevice, dummy, strlen(dummy));
{
cRingBuffer Buffer(&fromDevice, &toDevice, VIDEOBUFSIZE, 0, 0);
while (active && Buffer.Available() < 100000) { // need to give the read buffer a head start
Buffer.Read(); // initializes fromDevice for reading
usleep(1); // this keeps the CPU load low
}
for (; active;) {
if (Buffer.Read() < 0 || Buffer.Write() < 0)
break;
usleep(1); // this keeps the CPU load low
}
}
dsyslog(LOG_INFO, "data transfer thread stopped (pid=%d)", getpid());
LOCK_THREAD;
active = true;
}
// --- cDvbApi ---------------------------------------------------------------
int cDvbApi::NumDvbApis = 0;
@ -1093,6 +1152,8 @@ cDvbApi::cDvbApi(const char *VideoFileName, const char *VbiFileName)
fromReplay = toReplay = -1;
ca = 0;
priority = -1;
transferBuffer = NULL;
transferringFromDvbApi = NULL;
videoDev = open(VideoFileName, O_RDWR | O_NONBLOCK);
if (videoDev >= 0) {
siProcessor = new cSIProcessor(VbiFileName);
@ -1142,6 +1203,7 @@ cDvbApi::~cDvbApi()
Close();
Stop();
StopRecord();
StopTransfer();
OvlO(false); //Overlay off!
//XXX the following call sometimes causes a segfault - driver problem?
close(videoDev);
@ -1717,6 +1779,12 @@ bool cDvbApi::ShowProgress(bool Initial)
bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization, int Diseqc, int Srate, int Vpid, int Apid, int Ca, int Pnr)
{
if (videoDev >= 0) {
StopTransfer();
if (transferringFromDvbApi) {
transferringFromDvbApi->StopTransfer();
transferringFromDvbApi = NULL;
}
SetReplayMode(VID_PLAY_RESET);
struct frontend front;
ioctl(videoDev, VIDIOCGFRONTEND, &front);
unsigned int freq = FrequencyMHz;
@ -1740,6 +1808,17 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
if (this == PrimaryDvbApi && siProcessor)
siProcessor->SetCurrentServiceID(Pnr);
currentChannel = ChannelNumber;
// If this DVB card can't receive this channel, let's see if we can
// use the card that actually can receive it and transfer data from there:
if (Ca && Ca != Index() + 1) {
cDvbApi *CaDvbApi = GetDvbApi(Ca, 0);
if (CaDvbApi) {
if (!CaDvbApi->Recording()) {
if (CaDvbApi->SetChannel(ChannelNumber, FrequencyMHz, Polarization, Diseqc, Srate, Vpid, Apid, Ca, Pnr))
transferringFromDvbApi = CaDvbApi->StartTransfer(videoDev);
}
}
}
return true;
}
esyslog(LOG_ERR, "ERROR: channel not sync'ed (front.sync=%X)!", front.sync);
@ -1747,6 +1826,27 @@ bool cDvbApi::SetChannel(int ChannelNumber, int FrequencyMHz, char Polarization,
return false;
}
bool cDvbApi::Transferring(void)
{
return transferBuffer;
}
cDvbApi *cDvbApi::StartTransfer(int TransferToVideoDev)
{
StopTransfer();
transferBuffer = new cTransferBuffer(videoDev, TransferToVideoDev);
return this;
}
void cDvbApi::StopTransfer(void)
{
if (transferBuffer) {
delete transferBuffer;
transferBuffer = NULL;
SetReplayMode(VID_PLAY_RESET);
}
}
bool cDvbApi::Recording(void)
{
if (pidRecord && !CheckProcess(pidRecord))
@ -1769,6 +1869,8 @@ bool cDvbApi::StartRecord(const char *FileName, int Ca, int Priority)
}
if (videoDev >= 0) {
StopTransfer();
Stop(); // TODO: remove this if the driver is able to do record and replay at the same time
// Check FileName:
@ -1896,6 +1998,7 @@ bool cDvbApi::StartReplay(const char *FileName, const char *Title)
esyslog(LOG_ERR, "ERROR: StartReplay() called while recording - ignored!");
return false;
}
StopTransfer();
Stop();
if (videoDev >= 0) {
@ -2144,7 +2247,7 @@ void cEITScanner::Process(void)
cDvbApi *DvbApi = cDvbApi::GetDvbApi(i, 0);
if (DvbApi) {
if (DvbApi != cDvbApi::PrimaryDvbApi || (cDvbApi::NumDvbApis == 1 && Setup.EPGScanTimeout && now - lastActivity > Setup.EPGScanTimeout * 3600)) {
if (!(DvbApi->Recording() || DvbApi->Replaying())) {
if (!(DvbApi->Recording() || DvbApi->Replaying() || DvbApi->Transferring())) {
int oldCh = lastChannel;
int ch = oldCh + 1;
while (ch != oldCh) {

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: dvbapi.h 1.25 2000/11/18 15:30:09 kls Exp $
* $Id: dvbapi.h 1.26 2000/11/19 14:09:41 kls Exp $
*/
#ifndef __DVBAPI_H
@ -42,6 +42,8 @@ public:
bool Save(int Index);
};
class cTransferBuffer;
class cDvbApi {
private:
int videoDev;
@ -152,6 +154,20 @@ public:
static int CurrentChannel(void) { return PrimaryDvbApi ? PrimaryDvbApi->currentChannel : 0; }
int Channel(void) { return currentChannel; }
// Transfer facilities
private:
cTransferBuffer *transferBuffer;
cDvbApi *transferringFromDvbApi;
public:
bool Transferring(void);
// Returns true if we are currently transferring video data.
private:
cDvbApi *StartTransfer(int TransferToVideoDev);
// Starts transferring video data from this DVB device to TransferToVideoDev.
void StopTransfer(void);
// Stops transferring video data (in case a transfer is currently active).
// Record/Replay facilities
private: