summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY4
-rw-r--r--PLUGINS.html4
-rw-r--r--device.c4
-rw-r--r--device.h9
-rw-r--r--dvbdevice.c17
-rw-r--r--dvbdevice.h4
-rw-r--r--dvbplayer.c203
-rw-r--r--player.h4
-rw-r--r--tools.c38
-rw-r--r--tools.h14
10 files changed, 173 insertions, 128 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
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
-bool DeviceNeedsData(int Wait = 0);
+bool DevicePoll(cPoller &amp;Poller, int TimeoutMs = 0);
</pre></td></tr></table><p>
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 &amp;Poller, int TimeoutMs = 0);
virtual int PlayVideo(const uchar *Data, int Length);
</pre></td></tr></table><p>
<!--X1.1.7--></td></tr></table>
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 <ost/sec.h>
#include <ost/video.h>
#endif
-#include <poll.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#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 <poll.h>
#include <stdlib.h>
#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;
-
- // Read the next frame from the file:
-
- 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
- }
-
- // 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 && 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);
+ cPoller Poller;
+ if (!readFrame)
+ Poller.Add(replayFile, false);
+ if (DevicePoll(Poller, 100)) {
+
+ LOCK_THREAD;
+
+ // Read the next frame from the file:
+
+ 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
+ }
+
+ // 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) {
+ 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 <errno.h>
#include <fcntl.h>
+#include <poll.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
@@ -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[];