1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Using cPoller instead of NeedsData

This commit is contained in:
Klaus Schmidinger 2002-08-16 09:22:29 +02:00
parent 038766dccd
commit 470415ad23
10 changed files with 166 additions and 121 deletions

View File

@ -1405,8 +1405,8 @@ Video Disk Recorder Revision History
- Temporarily made cDevice::ProvidesCa() virtual (Andreas Schultz needs this - Temporarily made cDevice::ProvidesCa() virtual (Andreas Schultz needs this
in his DXR3 plugin). in his DXR3 plugin).
- cDevice no longer exposes a file handle to cPlayer. A derived cPlayer class - 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 can now call DevicePoll() to see whether the replay device is ready for
further data. A derived cDevice class must implement NeedsData() and shall further data. A derived cDevice class must implement Poll() and shall
check if any of its file handles is ready for data. check if any of its file handles is ready for data.
- Implemented several replay modes to allow players that play only audio (thanks - Implemented several replay modes to allow players that play only audio (thanks
to Stefan Huelswitt). to Stefan Huelswitt).

View File

@ -962,7 +962,7 @@ DVB device doesn't run out of data.
To avoid busy loops the player should call its member function To avoid busy loops the player should call its member function
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <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> </pre></td></tr></table><p>
to determine whether the device is ready for further data. to determine whether the device is ready for further data.
@ -1238,7 +1238,7 @@ virtual void Play(void);
virtual void Freeze(void); virtual void Freeze(void);
virtual void Mute(void); virtual void Mute(void);
virtual void StillPicture(const uchar *Data, int Length); 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); virtual int PlayVideo(const uchar *Data, int Length);
</pre></td></tr></table><p> </pre></td></tr></table><p>
<!--X1.1.7--></td></tr></table> <!--X1.1.7--></td></tr></table>

View File

@ -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: 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" #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; return false;
} }

View File

@ -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: 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 #ifndef __DEVICE_H
@ -226,9 +226,10 @@ public:
// Turns off audio while replaying. // Turns off audio while replaying.
virtual void StillPicture(const uchar *Data, int Length); virtual void StillPicture(const uchar *Data, int Length);
// Displays the given I-frame as a still picture. // Displays the given I-frame as a still picture.
virtual bool NeedsData(int Wait = 0); virtual bool Poll(cPoller &Poller, int TimeoutMs = 0);
// Returns true if the device needs further data for replaying. // Returns true if the device itself or any of the file handles in
// If Wait is not zero, the device will wait up to the given number // 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 // of milleseconds before returning in case there is no immediate
// need for data. // need for data.
virtual int PlayVideo(const uchar *Data, int Length); virtual int PlayVideo(const uchar *Data, int Length);

View File

@ -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: 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" #include "dvbdevice.h"
@ -27,7 +27,6 @@ extern "C" {
#include <ost/sec.h> #include <ost/sec.h>
#include <ost/video.h> #include <ost/video.h>
#endif #endif
#include <poll.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include "dvbosd.h" #include "dvbosd.h"
@ -694,9 +693,10 @@ void cDvbDevice::StillPicture(const uchar *Data, int Length)
#endif #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) int cDvbDevice::PlayVideo(const uchar *Data, int Length)
@ -731,13 +731,8 @@ void cDvbDevice::CloseDvr(void)
int cDvbDevice::GetTSPacket(uchar *Data) int cDvbDevice::GetTSPacket(uchar *Data)
{ {
if (fd_dvr >= 0) { if (fd_dvr >= 0) {
pollfd pfd; cPoller Poller(fd_dvr, false);
pfd.fd = fd_dvr; if (Poller.Poll(100)) {
pfd.events = POLLIN;
poll(&pfd, 1, 100);
if (pfd.revents & POLLIN != 0) {
int r = read(fd_dvr, Data, TS_SIZE); int r = read(fd_dvr, Data, TS_SIZE);
if (r >= 0) if (r >= 0)
return r; return r;

View File

@ -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: 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 #ifndef __DVBDEVICE_H
@ -92,7 +92,7 @@ public:
virtual void Freeze(void); virtual void Freeze(void);
virtual void Mute(void); virtual void Mute(void);
virtual void StillPicture(const uchar *Data, int Length); 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 PlayVideo(const uchar *Data, int Length);
virtual int PlayAudio(const uchar *Data, int Length); virtual int PlayAudio(const uchar *Data, int Length);

View File

@ -4,11 +4,10 @@
* 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: 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 "dvbplayer.h"
#include <poll.h>
#include <stdlib.h> #include <stdlib.h>
#include "recording.h" #include "recording.h"
#include "ringbuffer.h" #include "ringbuffer.h"
@ -65,7 +64,7 @@ int cBackTrace::Get(bool Forward)
p = BACKTRACE_ENTRIES - 1; p = BACKTRACE_ENTRIES - 1;
i = index[p] - 1; i = index[p] - 1;
l -= length[p]; l -= length[p];
n--; n--;
} }
return i; return i;
} }
@ -302,7 +301,6 @@ void cDvbPlayer::Action(void)
uchar b[MAXFRAMESIZE]; uchar b[MAXFRAMESIZE];
const uchar *p = NULL; const uchar *p = NULL;
int pc = 0; int pc = 0;
bool CanWrite = true;
readIndex = Resume(); readIndex = Resume();
if (readIndex >= 0) if (readIndex >= 0)
@ -310,103 +308,106 @@ void cDvbPlayer::Action(void)
running = true; running = true;
while (running && NextFile()) { while (running && NextFile()) {
{ cPoller Poller;
LOCK_THREAD; if (!readFrame)
Poller.Add(replayFile, false);
if (DevicePoll(Poller, 100)) {
// Read the next frame from the file: LOCK_THREAD;
if (!readFrame) { // Read the next frame from the file:
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 (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) { // Store the frame in the buffer:
if (ringBuffer->Put(readFrame))
readFrame = NULL;
}
// Get the next frame from the buffer: if (readFrame) {
if (ringBuffer->Put(readFrame))
if (!playFrame) { readFrame = NULL;
playFrame = ringBuffer->Get(); }
p = NULL;
pc = 0;
}
// Play the frame: // Get the next frame from the buffer:
if (playFrame && CanWrite) { if (!playFrame) {
if (!p) { playFrame = ringBuffer->Get();
p = playFrame->Data(); p = NULL;
pc = playFrame->Count(); pc = 0;
} }
if (p) {
int w = PlayVideo(p, pc); // Play the frame:
if (w > 0) {
p += w; if (playFrame) {
pc -= w; if (!p) {
} p = playFrame->Data();
else if (w < 0 && FATALERRNO) { pc = playFrame->Count();
LOG_ERROR; }
break; if (p) {
} int w = PlayVideo(p, pc);
} if (w > 0) {
if (pc == 0) { p += w;
writeIndex = playFrame->Index(); pc -= w;
backTrace->Add(playFrame->Index(), playFrame->Count()); }
ringBuffer->Drop(playFrame); else if (w < 0 && FATALERRNO) {
playFrame = NULL; LOG_ERROR;
p = 0; break;
} }
} }
} if (pc == 0) {
CanWrite = DeviceNeedsData(readFrame ? 10 : 0); writeIndex = playFrame->Index();
backTrace->Add(playFrame->Index(), playFrame->Count());
ringBuffer->Drop(playFrame);
playFrame = NULL;
p = 0;
}
}
}
} }
active = running = false; active = running = false;

View File

@ -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: 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 #ifndef __PLAYER_H
@ -19,7 +19,7 @@ private:
cDevice *device; cDevice *device;
ePlayMode playMode; ePlayMode playMode;
protected: 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 DeviceTrickSpeed(int Speed) { if (device) device->TrickSpeed(Speed); }
void DeviceClear(void) { if (device) device->Clear(); } void DeviceClear(void) { if (device) device->Clear(); }
void DevicePlay(void) { if (device) device->Play(); } void DevicePlay(void) { if (device) device->Play(); }

38
tools.c
View File

@ -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: 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" #include "tools.h"
@ -482,6 +482,42 @@ const char *DayDateTime(time_t t)
return buffer; 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 ----------------------------------------------------------------- // --- cFile -----------------------------------------------------------------
bool cFile::files[FD_SETSIZE] = { false }; bool cFile::files[FD_SETSIZE] = { false };

14
tools.h
View File

@ -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: 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 #ifndef __TOOLS_H
@ -12,6 +12,7 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <syslog.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 *WeekDayName(int WeekDay); // returns a statically allocated string!
const char *DayDateTime(time_t t = 0); // 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 { class cFile {
private: private:
static bool files[]; static bool files[];