From fd464518b660fb2b0a2eb98d744e3ac145aefdd0 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Sun, 19 Nov 2000 16:49:14 +0100 Subject: [PATCH] Implemented 'Transfer Mode' --- HISTORY | 6 +++- dvbapi.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- dvbapi.h | 18 +++++++++- 3 files changed, 127 insertions(+), 4 deletions(-) diff --git a/HISTORY b/HISTORY index f3542411..485f24a2 100644 --- a/HISTORY +++ b/HISTORY @@ -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. diff --git a/dvbapi.c b/dvbapi.c index 7df3b66a..5e4f2e64 100644 --- a/dvbapi.c +++ b/dvbapi.c @@ -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) { diff --git a/dvbapi.h b/dvbapi.h index 2b536bdc..f6640ff5 100644 --- a/dvbapi.h +++ b/dvbapi.h @@ -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: