From 470415ad230d8455439edadb07dae0a21978783b Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Fri, 16 Aug 2002 09:22:29 +0200 Subject: [PATCH] Using cPoller instead of NeedsData --- HISTORY | 4 +- PLUGINS.html | 4 +- device.c | 4 +- device.h | 9 +-- dvbdevice.c | 17 ++--- dvbdevice.h | 4 +- dvbplayer.c | 189 ++++++++++++++++++++++++++------------------------- player.h | 4 +- tools.c | 38 ++++++++++- tools.h | 14 +++- 10 files changed, 166 insertions(+), 121 deletions(-) diff --git a/HISTORY b/HISTORY index 7ab0708f..87d19d58 100644 --- a/HISTORY +++ b/HISTORY @@ -1405,8 +1405,8 @@ Video Disk Recorder Revision History - Temporarily made cDevice::ProvidesCa() virtual (Andreas Schultz needs this in his DXR3 plugin). - cDevice no longer exposes a file handle to cPlayer. A derived cPlayer class - can now call DeviceNeedsData() to see whether the replay device is ready for - further data. A derived cDevice class must implement NeedsData() and shall + can now call DevicePoll() to see whether the replay device is ready for + further data. A derived cDevice class must implement Poll() and shall check if any of its file handles is ready for data. - Implemented several replay modes to allow players that play only audio (thanks to Stefan Huelswitt). diff --git a/PLUGINS.html b/PLUGINS.html index 105865b0..e1f73f55 100644 --- a/PLUGINS.html +++ b/PLUGINS.html @@ -962,7 +962,7 @@ DVB device doesn't run out of data. To avoid busy loops the player should call its member function


-bool DeviceNeedsData(int Wait = 0); +bool DevicePoll(cPoller &Poller, int TimeoutMs = 0);

to determine whether the device is ready for further data. @@ -1238,7 +1238,7 @@ virtual void Play(void); virtual void Freeze(void); virtual void Mute(void); virtual void StillPicture(const uchar *Data, int Length); -virtual bool NeedsData(int Wait = 0); +virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); virtual int PlayVideo(const uchar *Data, int Length);

diff --git a/device.c b/device.c index 40304618..ff18aebf 100644 --- a/device.c +++ b/device.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.c 1.10 2002/08/15 10:30:08 kls Exp $ + * $Id: device.c 1.11 2002/08/16 08:52:56 kls Exp $ */ #include "device.h" @@ -397,7 +397,7 @@ void cDevice::StopReplay(void) } } -bool cDevice::NeedsData(int Wait) +bool cDevice::Poll(cPoller &Poller, int TimeoutMs) { return false; } diff --git a/device.h b/device.h index bba828a5..14d8ec50 100644 --- a/device.h +++ b/device.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: device.h 1.8 2002/08/15 11:09:21 kls Exp $ + * $Id: device.h 1.9 2002/08/16 08:52:27 kls Exp $ */ #ifndef __DEVICE_H @@ -226,9 +226,10 @@ public: // Turns off audio while replaying. virtual void StillPicture(const uchar *Data, int Length); // Displays the given I-frame as a still picture. - virtual bool NeedsData(int Wait = 0); - // Returns true if the device needs further data for replaying. - // If Wait is not zero, the device will wait up to the given number + virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); + // Returns true if the device itself or any of the file handles in + // Poller is ready for further action. + // If TimeoutMs is not zero, the device will wait up to the given number // of milleseconds before returning in case there is no immediate // need for data. virtual int PlayVideo(const uchar *Data, int Length); diff --git a/dvbdevice.c b/dvbdevice.c index 82587286..54da3bde 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 1.5 2002/08/15 11:13:46 kls Exp $ + * $Id: dvbdevice.c 1.6 2002/08/16 09:22:29 kls Exp $ */ #include "dvbdevice.h" @@ -27,7 +27,6 @@ extern "C" { #include #include #endif -#include #include #include #include "dvbosd.h" @@ -694,9 +693,10 @@ void cDvbDevice::StillPicture(const uchar *Data, int Length) #endif } -bool cDvbDevice::NeedsData(int Wait) +bool cDvbDevice::Poll(cPoller &Poller, int TimeoutMs) { - return cFile::FileReadyForWriting(fd_video, Wait); + Poller.Add(playMode == pmAudioOnly ? fd_audio : fd_video, true); + return Poller.Poll(TimeoutMs); } int cDvbDevice::PlayVideo(const uchar *Data, int Length) @@ -731,13 +731,8 @@ void cDvbDevice::CloseDvr(void) int cDvbDevice::GetTSPacket(uchar *Data) { if (fd_dvr >= 0) { - pollfd pfd; - pfd.fd = fd_dvr; - pfd.events = POLLIN; - - poll(&pfd, 1, 100); - - if (pfd.revents & POLLIN != 0) { + cPoller Poller(fd_dvr, false); + if (Poller.Poll(100)) { int r = read(fd_dvr, Data, TS_SIZE); if (r >= 0) return r; diff --git a/dvbdevice.h b/dvbdevice.h index cbc9b164..ece1b454 100644 --- a/dvbdevice.h +++ b/dvbdevice.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.h 1.4 2002/08/15 10:59:25 kls Exp $ + * $Id: dvbdevice.h 1.5 2002/08/16 08:53:30 kls Exp $ */ #ifndef __DVBDEVICE_H @@ -92,7 +92,7 @@ public: virtual void Freeze(void); virtual void Mute(void); virtual void StillPicture(const uchar *Data, int Length); - virtual bool NeedsData(int Wait = 0); + virtual bool Poll(cPoller &Poller, int TimeoutMs = 0); virtual int PlayVideo(const uchar *Data, int Length); virtual int PlayAudio(const uchar *Data, int Length); diff --git a/dvbplayer.c b/dvbplayer.c index e2d011db..2ca5a62d 100644 --- a/dvbplayer.c +++ b/dvbplayer.c @@ -4,11 +4,10 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbplayer.c 1.10 2002/08/15 10:00:28 kls Exp $ + * $Id: dvbplayer.c 1.11 2002/08/16 09:16:38 kls Exp $ */ #include "dvbplayer.h" -#include #include #include "recording.h" #include "ringbuffer.h" @@ -65,7 +64,7 @@ int cBackTrace::Get(bool Forward) p = BACKTRACE_ENTRIES - 1; i = index[p] - 1; l -= length[p]; - n--; + n--; } return i; } @@ -302,7 +301,6 @@ void cDvbPlayer::Action(void) uchar b[MAXFRAMESIZE]; const uchar *p = NULL; int pc = 0; - bool CanWrite = true; readIndex = Resume(); if (readIndex >= 0) @@ -310,103 +308,106 @@ void cDvbPlayer::Action(void) running = true; while (running && NextFile()) { - { - LOCK_THREAD; + cPoller Poller; + if (!readFrame) + Poller.Add(replayFile, false); + if (DevicePoll(Poller, 100)) { - // Read the next frame from the file: + LOCK_THREAD; - if (!readFrame) { - 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 - } + // Read the next frame from the file: - // Store the frame in the buffer: + if (!readFrame) { + 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 + } - if (readFrame) { - if (ringBuffer->Put(readFrame)) - readFrame = NULL; - } + // Store the frame in the buffer: - // Get the next frame from the buffer: - - if (!playFrame) { - playFrame = ringBuffer->Get(); - p = NULL; - pc = 0; - } + if (readFrame) { + if (ringBuffer->Put(readFrame)) + readFrame = NULL; + } - // Play the frame: + // Get the next frame from the buffer: - if (playFrame && CanWrite) { - 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; - } - } - } - CanWrite = DeviceNeedsData(readFrame ? 10 : 0); + if (!playFrame) { + playFrame = ringBuffer->Get(); + p = NULL; + pc = 0; + } + + // Play the frame: + + if (playFrame) { + 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; + } + } + } } active = running = false; diff --git a/player.h b/player.h index 1eed0b70..12cc2a37 100644 --- a/player.h +++ b/player.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: player.h 1.7 2002/08/15 11:10:09 kls Exp $ + * $Id: player.h 1.8 2002/08/16 09:14:12 kls Exp $ */ #ifndef __PLAYER_H @@ -19,7 +19,7 @@ private: cDevice *device; ePlayMode playMode; protected: - bool DeviceNeedsData(int Wait = 0) { return device ? device->NeedsData(Wait) : false; } + bool DevicePoll(cPoller &Poller, int TimeoutMs = 0) { return device ? device->Poll(Poller, TimeoutMs) : false; } void DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); } void DeviceClear(void) { if (device) device->Clear(); } void DevicePlay(void) { if (device) device->Play(); } diff --git a/tools.c b/tools.c index 40aad70a..f5545c34 100644 --- a/tools.c +++ b/tools.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.c 1.69 2002/08/11 11:49:08 kls Exp $ + * $Id: tools.c 1.70 2002/08/16 08:52:01 kls Exp $ */ #include "tools.h" @@ -482,6 +482,42 @@ const char *DayDateTime(time_t t) return buffer; } +// --- cPoller --------------------------------------------------------------- + +cPoller::cPoller(int FileHandle, bool Out) +{ + numFileHandles = 0; + Add(FileHandle, Out); +} + +bool cPoller::Add(int FileHandle, bool Out) +{ + if (FileHandle >= 0) { + for (int i = 0; i < numFileHandles; i++) { + if (pfd[i].fd == FileHandle) + return true; + } + if (numFileHandles < MaxPollFiles) { + pfd[numFileHandles].fd = FileHandle; + pfd[numFileHandles].events = Out ? POLLOUT : POLLIN; + numFileHandles++; + return true; + } + esyslog("ERROR: too many file handles in cPoller"); + } + return false; +} + +bool cPoller::Poll(int TimeoutMs) +{ + if (numFileHandles) { + if (poll(pfd, numFileHandles, TimeoutMs) != 0) + return true; // returns true even in case of an error, to let the caller + // access the file and thus see the error code + } + return false; +} + // --- cFile ----------------------------------------------------------------- bool cFile::files[FD_SETSIZE] = { false }; diff --git a/tools.h b/tools.h index c61d2f57..ebabb470 100644 --- a/tools.h +++ b/tools.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: tools.h 1.48 2002/08/11 11:34:26 kls Exp $ + * $Id: tools.h 1.49 2002/08/16 08:52:01 kls Exp $ */ #ifndef __TOOLS_H @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -76,6 +77,17 @@ bool SpinUpDisk(const char *FileName); const char *WeekDayName(int WeekDay); // returns a statically allocated string! const char *DayDateTime(time_t t = 0); // returns a statically allocated string! +class cPoller { +private: + enum { MaxPollFiles = 16 }; + pollfd pfd[MaxPollFiles]; + int numFileHandles; +public: + cPoller(int FileHandle = -1, bool Out = false); + bool Add(int FileHandle, bool Out); + bool Poll(int TimeoutMs = 0); + }; + class cFile { private: static bool files[];