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
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).

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
<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>

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;
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;

View File

@ -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(); }

38
tools.c
View File

@ -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 };

14
tools.h
View File

@ -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[];