summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2001-08-05 12:23:24 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2001-08-05 12:23:24 +0200
commitc2ed9b5daf19b86823b27a06799d7d43d476f654 (patch)
treee7c24b75e4cd2b181ebc9e88ad22bb888960c39d
parent614113cdcb1ebb176891664426e9c0cc2bb63c9d (diff)
downloadvdr-c2ed9b5daf19b86823b27a06799d7d43d476f654.tar.gz
vdr-c2ed9b5daf19b86823b27a06799d7d43d476f654.tar.bz2
New ringbuffer for frames
-rw-r--r--HISTORY3
-rw-r--r--dvbapi.c712
-rw-r--r--menu.c7
-rw-r--r--ringbuffer.c252
-rw-r--r--ringbuffer.h85
-rw-r--r--thread.c12
-rw-r--r--thread.h8
7 files changed, 562 insertions, 517 deletions
diff --git a/HISTORY b/HISTORY
index 8e6777f2..51867369 100644
--- a/HISTORY
+++ b/HISTORY
@@ -610,7 +610,7 @@ Video Disk Recorder Revision History
- Explicitly switching back to the previously active channel after ending a
replay session (to have it shown correctly in case it was in 'Transfer Mode').
-2001-08-03: Version 0.86
+2001-08-05: Version 0.86
- Modified the display of the channel group separators (thanks to Markus Lang
for this suggestion).
@@ -618,3 +618,4 @@ Video Disk Recorder Revision History
the 'libdvdread' library to be installed.
- Fixed replay progress display in case replay is paused while watching an
ongoing recording.
+- Ringbuffer uses semaphores to signal empty/full conditions.
diff --git a/dvbapi.c b/dvbapi.c
index 1be6db34..cb2f85c5 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -6,7 +6,7 @@
*
* DVD support initially written by Andreas Schultz <aschultz@warp10.net>
*
- * $Id: dvbapi.c 1.97 2001/08/03 13:08:22 kls Exp $
+ * $Id: dvbapi.c 1.98 2001/08/05 12:17:02 kls Exp $
*/
//#define DVDDEBUG 1
@@ -448,7 +448,7 @@ int cFileName::NextFile(void)
// --- cRecordBuffer ---------------------------------------------------------
-class cRecordBuffer : public cRingBuffer {
+class cRecordBuffer : public cRingBufferLinear {
private:
cDvbApi *dvbApi;
cFileName fileName;
@@ -471,7 +471,7 @@ public:
};
cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2)
-:cRingBuffer(VIDEOBUFSIZE, true)
+:cRingBufferLinear(VIDEOBUFSIZE, true)
,fileName(FileName, true)
,remux(VPid, APid1, APid2, DPid1, DPid2, true)
{
@@ -628,23 +628,27 @@ int ReadFrame(int f, uchar *b, int Length, int Max)
// --- cPlayBuffer ---------------------------------------------------------
-class cPlayBuffer : public cRingBuffer {
+class cPlayBuffer : public cRingBufferFrame {
protected:
cDvbApi *dvbApi;
int videoDev, audioDev;
FILE *dolbyDev;
int blockInput, blockOutput;
- bool paused, fastForward, fastRewind;
+ bool still, paused, fastForward, fastRewind;
+ int readIndex, writeIndex;
+ bool canDoTrickMode;
bool canToggleAudioTrack;
uchar audioTrack;
- virtual void Clear(bool Block = false);
+ virtual void Empty(bool Block = false);
+ virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {}
+ virtual void Output(void);
public:
cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
virtual ~cPlayBuffer();
- virtual void Pause(void) {}
- virtual void Play(void) = 0;
- virtual void Forward(void) {}
- virtual void Backward(void) {}
+ virtual void Pause(void);
+ virtual void Play(void);
+ virtual void Forward(void);
+ virtual void Backward(void);
virtual int SkipFrames(int Frames) { return -1; }
virtual void SkipSeconds(int Seconds) {}
virtual void Goto(int Position, bool Still = false) {}
@@ -654,14 +658,16 @@ public:
};
cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev)
-:cRingBuffer(VIDEOBUFSIZE)
+:cRingBufferFrame(VIDEOBUFSIZE)
{
dvbApi = DvbApi;
videoDev = VideoDev;
audioDev = AudioDev;
dolbyDev = NULL;
blockInput = blockOutput = false;
- paused = fastForward = fastRewind = false;
+ still = paused = fastForward = fastRewind = false;
+ readIndex = writeIndex = -1;
+ canDoTrickMode = false;
canToggleAudioTrack = false;
audioTrack = 0xC0;
if (cDvbApi::AudioCommand()) {
@@ -677,18 +683,136 @@ cPlayBuffer::~cPlayBuffer()
pclose(dolbyDev);
}
-void cPlayBuffer::Clear(bool Block)
+void cPlayBuffer::Output(void)
{
- cRingBuffer::Clear();
- CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER));
- CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER));
+ dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid());
+
+ while (Busy()) {
+ if (blockOutput) {
+ if (blockOutput > 1)
+ blockOutput = 1;
+ continue;
+ }
+ const cFrame *frame = Get();
+ if (frame) {
+ StripAudioPackets((uchar *)frame->Data(), frame->Count(), (fastForward || fastRewind) ? 0x00 : audioTrack);//XXX
+ for (int i = 0; i < ((paused && fastRewind) ? 24 : 1); i++) { // show every I_FRAME 24 times in slow rewind mode to achieve roughly the same speed as in slow forward mode
+ const uchar *p = frame->Data();
+ int r = frame->Count();
+ while (r > 0 && Busy() && !blockOutput) {
+ cFile::FileReadyForWriting(videoDev, 100);
+ int w = write(videoDev, p, r);
+ if (w > 0) {
+ p += w;
+ r -= w;
+ }
+ else if (w < 0 && errno != EAGAIN) {
+ LOG_ERROR;
+ Stop();
+ return;
+ }
+ }
+ writeIndex = frame->Index();
+ }
+ Drop(frame);
+ }
+ }
+
+ dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
+}
+
+void cPlayBuffer::Empty(bool Block)
+{
+ if (!(blockInput || blockOutput)) {
+ blockInput = blockOutput = 2;
+ EnablePut();
+ EnableGet();
+ time_t t0 = time(NULL);
+ while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2)
+ usleep(1);
+ Lock();
+ readIndex = writeIndex;
+ cRingBufferFrame::Clear();
+ CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER));
+ CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER));
+ }
+ if (!Block) {
+ blockInput = blockOutput = 0;
+ Unlock();
+ }
+}
+
+void cPlayBuffer::Pause(void)
+{
+ paused = !paused;
+ bool empty = fastForward || fastRewind;
+ if (empty)
+ Empty(true);
+ fastForward = fastRewind = false;
+ CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE));
+ CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused));
+ still = false;
+ if (empty)
+ Empty(false);
+}
+
+void cPlayBuffer::Play(void)
+{
+ if (fastForward || fastRewind || paused) {
+ bool empty = !paused || fastRewind;
+ if (empty)
+ Empty(true);
+ still = false;
+ CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY));
+ CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true));
+ CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false));
+ if (empty)
+ Empty(false);
+ fastForward = fastRewind = paused = false;
+ }
+}
+
+void cPlayBuffer::Forward(void)
+{
+ if (canDoTrickMode || paused) {
+ bool empty = !paused || fastRewind;
+ if (empty) {
+ Empty(true);
+ if (fastForward)
+ readIndex -= 150; // this about compensates for the buffered data, so that we don't get too far ahead
+ }
+ still = false;
+ fastForward = !fastForward;
+ fastRewind = false;
+ if (paused)
+ CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2));
+ CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward));
+ CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused));
+ if (empty)
+ Empty(false);
+ }
+}
+
+void cPlayBuffer::Backward(void)
+{
+ if (canDoTrickMode) {
+ Empty(true);
+ still = false;
+ fastRewind = !fastRewind;
+ fastForward = false;
+ if (paused)
+ CHECK(ioctl(videoDev, fastRewind ? VIDEO_CONTINUE : VIDEO_FREEZE));
+ CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind));
+ CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused));
+ Empty(false);
+ }
}
void cPlayBuffer::ToggleAudioTrack(void)
{
if (CanToggleAudioTrack()) {
audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0;
- Clear();
+ Empty();
}
}
@@ -698,27 +822,19 @@ class cReplayBuffer : public cPlayBuffer {
private:
cIndexFile *index;
cFileName fileName;
- int fileOffset;
int replayFile;
bool eof;
- int lastIndex, stillIndex, playIndex;
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
- void Clear(bool Block = false);
void Close(void);
- void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
+ virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);
void DisplayFrame(uchar *b, int Length);
int Resume(void);
bool Save(void);
protected:
virtual void Input(void);
- virtual void Output(void);
public:
cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName);
virtual ~cReplayBuffer();
- virtual void Pause(void);
- virtual void Play(void);
- virtual void Forward(void);
- virtual void Backward(void);
virtual int SkipFrames(int Frames);
virtual void SkipSeconds(int Seconds);
virtual void Goto(int Position, bool Still = false);
@@ -730,10 +846,8 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
,fileName(FileName, false)
{
index = NULL;
- fileOffset = 0;
replayFile = fileName.Open();
eof = false;
- lastIndex = stillIndex = playIndex = -1;
if (!fileName.Name())
return;
// Create the index file:
@@ -745,6 +859,7 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
delete index;
index = NULL;
}
+ canDoTrickMode = index != NULL;
dvbApi->SetModeReplay();
Start();
}
@@ -762,22 +877,23 @@ void cReplayBuffer::Input(void)
{
dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid());
- int ResumeIndex = Resume();
- if (ResumeIndex >= 0)
- isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, IndexToHMSF(ResumeIndex, true));
+ readIndex = Resume();
+ if (readIndex >= 0)
+ isyslog(LOG_INFO, "resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true));
- int lastIndex = -1;
- int brakeCounter = 0;
uchar b[MAXFRAMESIZE];
while (Busy() && (blockInput || NextFile())) {
- if (!blockInput && stillIndex < 0) {
+ if (blockInput) {
+ if (blockInput > 1)
+ blockInput = 1;
+ continue;
+ }
+ if (!still) {
int r = 0;
if (fastForward && !paused || fastRewind) {
- int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset);
uchar FileNumber;
int FileOffset, Length;
- if (!paused || (brakeCounter++ % 24) == 0) // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode
- Index = index->GetNextIFrame(Index, fastForward, &FileNumber, &FileOffset, &Length);
+ int Index = index->GetNextIFrame(readIndex, fastForward, &FileNumber, &FileOffset, &Length);
if (Index >= 0) {
if (!NextFile(FileNumber, FileOffset))
break;
@@ -787,126 +903,85 @@ void cReplayBuffer::Input(void)
Play();
continue;
}
- lastIndex = Index;
- playIndex = -1;
+ readIndex = Index;
r = ReadFrame(replayFile, b, Length, sizeof(b));
- StripAudioPackets(b, r);
}
else if (index) {
- lastIndex = -1;
- playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset);
uchar FileNumber;
int FileOffset, Length;
- if (!(index->Get(playIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))
+ readIndex++;
+ if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))
break;
r = ReadFrame(replayFile, b, Length, sizeof(b));
- StripAudioPackets(b, r, audioTrack);
}
else // allows replay even if the index file is missing
r = read(replayFile, b, sizeof(b));
if (r > 0) {
- uchar *p = b;
- while (r > 0 && Busy() && !blockInput) {
- int w = Put(p, r);
- p += w;
- r -= w;
- usleep(1); // this keeps the CPU load low
- }
+ cFrame *frame = new cFrame(b, r, readIndex);
+ while (Busy() && !blockInput && !Put(frame))
+ ;
}
- else if (r ==0)
+ else if (r == 0)
eof = true;
else if (r < 0 && errno != EAGAIN) {
LOG_ERROR;
break;
}
}
- else
+ else//XXX
usleep(1); // this keeps the CPU load low
- if (blockInput > 1)
- blockInput = 1;
}
dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid());
}
-void cReplayBuffer::Output(void)
-{
- dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid());
-
- uchar b[MINVIDEODATA];
- while (Busy()) {
- int r = blockOutput ? 0 : Get(b, sizeof(b));
- if (r > 0) {
- uchar *p = b;
- while (r > 0 && Busy() && !blockOutput) {
- cFile::FileReadyForWriting(videoDev, 100);
- int w = write(videoDev, p, r);
- if (w > 0) {
- p += w;
- r -= w;
- fileOffset += w;
- }
- else if (w < 0 && errno != EAGAIN) {
- LOG_ERROR;
- Stop();
- return;
- }
- }
- }
- else
- usleep(1); // this keeps the CPU load low
- if (blockOutput > 1)
- blockOutput = 1;
- }
-
- dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
-}
-
void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)
{
- for (int i = 0; i < Length - 6; i++) {
- if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
- uchar c = b[i + 3];
- int l = b[i + 4] * 256 + b[i + 5] + 6;
- switch (c) {
- case 0xBD: // dolby
- if (Except && dolbyDev) {
- int written = b[i + 8] + 9; // skips the PES header
- int n = l - written;
- while (n > 0) {
- int w = fwrite(&b[i + written], 1, n, dolbyDev);
- if (w < 0) {
- LOG_ERROR;
- break;
+ if (canDoTrickMode) {
+ for (int i = 0; i < Length - 6; i++) {
+ if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
+ uchar c = b[i + 3];
+ int l = b[i + 4] * 256 + b[i + 5] + 6;
+ switch (c) {
+ case 0xBD: // dolby
+ if (Except && dolbyDev) {
+ int written = b[i + 8] + 9; // skips the PES header
+ int n = l - written;
+ while (n > 0) {
+ int w = fwrite(&b[i + written], 1, n, dolbyDev);
+ if (w < 0) {
+ LOG_ERROR;
+ break;
+ }
+ n -= w;
+ written += w;
}
- n -= w;
- written += w;
- }
- }
- // continue with deleting the data - otherwise it disturbs DVB replay
- case 0xC0 ... 0xC1: // audio
- if (c == 0xC1)
- canToggleAudioTrack = true;
- if (!Except || c != Except) {
- int n = l;
- for (int j = i; j < Length && n--; j++)
- b[j] = 0x00;
- }
- break;
- case 0xE0 ... 0xEF: // video
- break;
- default:
- //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c);
- l = 0;
- }
- if (l)
- i += l - 1; // the loop increments, too!
+ }
+ // continue with deleting the data - otherwise it disturbs DVB replay
+ case 0xC0 ... 0xC1: // audio
+ if (c == 0xC1)
+ canToggleAudioTrack = true;
+ if (!Except || c != Except) {
+ int n = l;
+ for (int j = i; j < Length && n--; j++)
+ b[j] = 0x00;
+ }
+ break;
+ case 0xE0 ... 0xEF: // video
+ break;
+ default:
+ //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c);
+ l = 0;
+ }
+ if (l)
+ i += l - 1; // the loop increments, too!
+ }
+ /*XXX
+ else
+ esyslog(LOG_ERR, "ERROR: broken packet header");
+ XXX*/
}
- /*XXX
- else
- esyslog(LOG_ERR, "ERROR: broken packet header");
- XXX*/
- }
+ }
}
void cReplayBuffer::DisplayFrame(uchar *b, int Length)
@@ -918,85 +993,11 @@ void cReplayBuffer::DisplayFrame(uchar *b, int Length)
CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp));
}
-void cReplayBuffer::Clear(bool Block)
-{
- if (!(blockInput || blockOutput)) {
- blockInput = blockOutput = 2;
- time_t t0 = time(NULL);
- while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2)
- usleep(1);
- Lock();
- playIndex = -1;
- cPlayBuffer::Clear();
- }
- if (!Block) {
- blockInput = blockOutput = 0;
- Unlock();
- }
-}
-
-void cReplayBuffer::Pause(void)
-{
- paused = !paused;
- CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE));
- if (fastForward || fastRewind) {
- if (paused)
- Clear();
- fastForward = fastRewind = false;
- }
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused));
- stillIndex = -1;
-}
-
-void cReplayBuffer::Play(void)
-{
- if (fastForward || fastRewind || paused) {
- if (!paused)
- Clear();
- stillIndex = -1;
- CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY));
- CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true));
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false));
- fastForward = fastRewind = paused = false;
- }
-}
-
-void cReplayBuffer::Forward(void)
-{
- if (index || paused) {
- if (!paused)
- Clear(true);
- stillIndex = -1;
- fastForward = !fastForward;
- fastRewind = false;
- if (paused)
- CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2));
- CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward));
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused));
- if (!paused)
- Clear(false);
- }
-}
-
-void cReplayBuffer::Backward(void)
-{
- if (index) {
- Clear(true);
- stillIndex = -1;
- fastRewind = !fastRewind;
- fastForward = false;
- CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind));
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused));
- Clear(false);
- }
-}
-
void cReplayBuffer::Close(void)
{
if (replayFile >= 0) {
fileName.Close();
replayFile = -1;
- fileOffset = 0;
}
}
@@ -1017,7 +1018,7 @@ int cReplayBuffer::Resume(void)
bool cReplayBuffer::Save(void)
{
if (index) {
- int Index = index->Get(fileName.Number(), fileOffset);
+ int Index = writeIndex;
if (Index >= 0) {
Index -= RESUMEBACKUP;
if (Index > 0)
@@ -1046,8 +1047,8 @@ int cReplayBuffer::SkipFrames(int Frames)
void cReplayBuffer::SkipSeconds(int Seconds)
{
if (index && Seconds) {
- Clear(true);
- int Index = index->Get(fileName.Number(), fileOffset);
+ Empty(true);
+ int Index = writeIndex;
if (Index >= 0) {
if (Seconds < 0) {
int sec = index->Last() / FRAMESPERSEC;
@@ -1059,10 +1060,9 @@ void cReplayBuffer::SkipSeconds(int Seconds)
Index = 1; // not '0', to allow GetNextIFrame() below to work!
uchar FileNumber;
int FileOffset;
- if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0)
- NextFile(FileNumber, FileOffset);
+ readIndex = writeIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) - 1; // Input() will first increment it!
}
- Clear(false);
+ Empty(false);
Play();
}
}
@@ -1070,7 +1070,7 @@ void cReplayBuffer::SkipSeconds(int Seconds)
void cReplayBuffer::Goto(int Index, bool Still)
{
if (index) {
- Clear(true);
+ Empty(true);
if (paused)
CHECK(ioctl(videoDev, VIDEO_CONTINUE));
if (++Index <= 0)
@@ -1079,28 +1079,27 @@ void cReplayBuffer::Goto(int Index, bool Still)
int FileOffset, Length;
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
- stillIndex = Index;
- playIndex = -1;
+ still = true;
uchar b[MAXFRAMESIZE];
int r = ReadFrame(replayFile, b, Length, sizeof(b));
if (r > 0)
DisplayFrame(b, r);
- fileOffset += Length;
paused = true;
}
else
- stillIndex = playIndex = -1;
- Clear(false);
+ still = false;
+ readIndex = writeIndex = Index;
+ Empty(false);
}
}
void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
{
if (index) {
- if (stillIndex >= 0)
- Current = stillIndex;
+ if (still)
+ Current = readIndex;
else {
- Current = index->Get(fileName.Number(), fileOffset);
+ Current = writeIndex;
if (SnapToIFrame) {
int i1 = index->GetNextIFrame(Current + 1, false);
int i2 = index->GetNextIFrame(Current, true);
@@ -1115,10 +1114,8 @@ void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
{
- if (FileNumber > 0) {
- fileOffset = FileOffset;
+ if (FileNumber > 0)
replayFile = fileName.SetOffset(FileNumber, FileOffset);
- }
else if (replayFile >= 0 && eof) {
Close();
replayFile = fileName.NextFile();
@@ -1131,12 +1128,6 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
class cDVDplayBuffer : public cPlayBuffer {
private:
- cCondVar ready4input;
- cMutex inputMutex;
-
- cCondVar ready4output;
- cMutex outputMutex;
-
uchar audioTrack;
cDVD *dvd;//XXX necessary???
@@ -1186,7 +1177,7 @@ private:
int lpcm_count;
int is_nav_pack(unsigned char *buffer);
void Close(void);
- void Clear(bool Block = false);
+ virtual void Empty(bool Block = false);
int decode_packet(unsigned char *sector, int iframe);
int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType);
bool PacketStart(uchar **Data, int len);
@@ -1201,14 +1192,9 @@ private:
void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }
protected:
virtual void Input(void);
- virtual void Output(void);
public:
cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title);
virtual ~cDVDplayBuffer();
- virtual void Pause(void);
- virtual void Play(void);
- virtual void Forward(void);
- virtual void Backward(void);
virtual int SkipFrames(int Frames);
virtual void SkipSeconds(int Seconds);
virtual void Goto(int Position, bool Still = false);
@@ -1224,6 +1210,41 @@ public:
#define cOUTPACK 5
#define cOUTFRAMES 6
+cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title)
+:cPlayBuffer(DvbApi, VideoDev, AudioDev)
+{
+ dvd = DvD;
+ titleid = title;
+ chapid = 0;
+ angle = 0;
+ cyclestate = cOPENDVD;
+ prevcycle = 0;
+ brakeCounter = 0;
+ skipCnt = 0;
+ logAudioTrack = 0;
+ canToggleAudioTrack = true;//XXX determine from cDVD!
+ ac3_config.num_output_ch = 2;
+ // ac3_config.flags = /* mm_accel() | */ MM_ACCEL_MLIB;
+ ac3_config.flags = 0;
+ ac3_init(&ac3_config);
+ data = new uchar[1024 * DVD_VIDEO_LB_LEN];
+ ac3data = new uchar[AC3_BUFFER_SIZE];
+ ac3inp = ac3outp = 0;
+ ac3stat = AC3_START;
+ canDoTrickMode = true;
+ dvbApi->SetModeReplay();
+ Start();
+}
+
+cDVDplayBuffer::~cDVDplayBuffer()
+{
+ Stop();
+ Close();
+ dvbApi->SetModeNormal(false);
+ delete ac3data;
+ delete data;
+}
+
unsigned int cDVDplayBuffer::getAudioStream(unsigned int StreamId)
{
unsigned int trackID;
@@ -1267,40 +1288,6 @@ void cDVDplayBuffer::ToggleAudioTrack(void)
}
}
-cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title)
-:cPlayBuffer(DvbApi, VideoDev, AudioDev)
-{
- dvd = DvD;
- titleid = title;
- chapid = 0;
- angle = 0;
- cyclestate = cOPENDVD;
- prevcycle = 0;
- brakeCounter = 0;
- skipCnt = 0;
- logAudioTrack = 0;
- canToggleAudioTrack = true;//XXX determine from cDVD!
- ac3_config.num_output_ch = 2;
- // ac3_config.flags = /* mm_accel() | */ MM_ACCEL_MLIB;
- ac3_config.flags = 0;
- ac3_init(&ac3_config);
- data = new uchar[1024 * DVD_VIDEO_LB_LEN];
- ac3data = new uchar[AC3_BUFFER_SIZE];
- ac3inp = ac3outp = 0;
- ac3stat = AC3_START;
- dvbApi->SetModeReplay();
- Start();
-}
-
-cDVDplayBuffer::~cDVDplayBuffer()
-{
- Stop();
- Close();
- dvbApi->SetModeNormal(false);
- delete ac3data;
- delete data;
-}
-
/**
* Returns true if the pack is a NAV pack. This check is clearly insufficient,
* and sometimes we incorrectly think that valid other packs are NAV packs. I
@@ -1317,15 +1304,13 @@ void cDVDplayBuffer::Input(void)
doplay = true;
while (Busy() && doplay) {
- inputMutex.Lock();
- while (blockInput) {
- if (blockInput > 1)
- blockInput = 1;
- ready4input.Wait(inputMutex);
- }
- inputMutex.Unlock();
+ if (blockInput) {
+ if (blockInput > 1)
+ blockInput = 1;
+ continue;
+ }
- //BEGIN: riped from play_title
+ //BEGIN: ripped from play_title
/**
* Playback by cell in this pgc, starting at the cell for our chapter.
@@ -1659,8 +1644,6 @@ void cDVDplayBuffer::Input(void)
}
// dsyslog(LOG_INF, "DVD: new cyclestate: %d, pktcnt: %d, cur: %d", cyclestate, pktcnt, cur_output_size);
- if (blockInput > 1)
- blockInput = 1;
}
dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
@@ -1761,6 +1744,7 @@ int cDVDplayBuffer::SendPCM(int size)
while (p_size) {
if (ac3outp != ac3inp) { // data in the buffer
buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder
+ // XXX there is no 'swab' here??? (kls)
p_size--;
length++;
ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
@@ -1791,18 +1775,9 @@ int cDVDplayBuffer::SendPCM(int size)
length += 6;
- inputMutex.Lock();
- while (Free() < length && Busy() && !blockInput)
- ready4input.Wait(inputMutex);
- inputMutex.Unlock();
-
- if (Busy() && !blockInput) {
- if ((Put(buffer, length) != length)) {
- esyslog(LOG_ERR, "ERROR: Put(buffer, length) != length");
- return 0;
- }
- ready4output.Broadcast();
- }
+ cFrame *frame = new cFrame(buffer, length);
+ while (Busy() && !blockInput && !Put(frame))
+ ;
size -= MAXSIZE;
}
return 0;
@@ -1834,7 +1809,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
uchar *osect = sector;
#endif
- //make sure we got an PS packet header
+ //make sure we got a PS packet header
if (!PacketStart(&sector, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) {
esyslog(LOG_ERR, "ERROR: got unexpected packet: %x %x %x %x", sector[0], sector[1], sector[2], sector[3]);
return -1;
@@ -1885,7 +1860,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
sector += 6;
//we are now at the beginning of the payload
- //correct a3 data lenght - FIXME: why 13 ???
+ //correct ac3 data lenght - FIXME: why 13 ???
ac3datalen -= 13;
if (audioTrack == *sector) {
sector +=4;
@@ -1933,154 +1908,23 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
return pt;
}
}
- inputMutex.Lock();
- while (Free() < r && Busy() && !blockInput)
- ready4input.Wait(inputMutex);
- inputMutex.Unlock();
- if (Busy() && !blockInput) {
- if (Put(sector, r) != r) {
- esyslog(LOG_ERR, "ERROR: Put(sector, r) != r");
- return 0;
- }
- ready4output.Broadcast();
- }
+ cFrame *frame = new cFrame(sector, r);
+ while (Busy() && !blockInput && !Put(frame))
+ ;
playDecodedAC3();
return pt;
}
-void cDVDplayBuffer::Output(void)
-{
- dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid());
-
-#ifdef DVDDEBUG_BUFFER
- long long cyl = 0;
- long long emp = 0;
- long long low = 0;
-#endif
-
- uchar b[MINVIDEODATA];
- while (Busy()) {
-#ifdef DVDDEBUG_BUFFER
- cyl++;
-#endif
- outputMutex.Lock();
- if (blockOutput > 1)
- blockOutput = 1;
-
- int r = 0;
- while (Busy() && ((r = blockOutput ? 0 : Get(b, sizeof(b))) == 0)) {
-#ifdef DVDDEBUG_BUFFER
- if (r == 0) {
- //ups we just emptied the entire buffer
- dsyslog(LOG_INFO, "DVD: %12Ld warning: Get() failed due to empty buffer %12Ld", cyl, emp);
- emp++;
- }
-#endif
- ready4output.Wait(outputMutex);
- if (blockOutput > 1)
- blockOutput = 1;
- }
- outputMutex.Unlock();
-
- if (r > 0) {
-#ifdef DVDDEBUG_BUFFER
- if (Available() != 0 && Available() < (VIDEOBUFSIZE/20)) {
- //5% warning limit
- dsyslog(LOG_INFO, "DVD: %12Ld warning: buffer almost empty: %d, %10.2f %12Ld", cyl, Available(), (float)Available() * 100.0 / (float) VIDEOBUFSIZE, low);
- low++;
- }
-#endif
- ready4input.Broadcast();
- uchar *p = b;
- while (r > 0 && Busy() && !blockOutput) {
- cFile::FileReadyForWriting(videoDev, 100);
- int w = write(videoDev, p, r);
- if (w > 0) {
- p += w;
- r -= w;
- }
- else if (w < 0 && errno != EAGAIN) {
- LOG_ERROR;
- Stop();
- return;
- }
- }
- }
- if (blockOutput > 1)
- blockOutput = 1;
- }
-
- dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
-}
-
-void cDVDplayBuffer::Clear(bool Block)
+void cDVDplayBuffer::Empty(bool Block)
{
if (!(blockInput || blockOutput)) {
- blockInput = blockOutput = 2;
- ready4input.Broadcast();
- ready4output.Broadcast();
- time_t t0 = time(NULL);
- while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2)
- usleep(1);
- Lock();
- cPlayBuffer::Clear();
+ cPlayBuffer::Empty(true);
ac3stat = AC3_START;
ac3outp = ac3inp;
}
- if (!Block) {
- blockInput = blockOutput = 0;
- ready4input.Broadcast();
- ready4output.Broadcast();
- Unlock();
- }
-}
-void cDVDplayBuffer::Pause(void)
-{
- paused = !paused;
- CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE));
- if (fastForward || fastRewind) {
- if (paused)
- Clear();
- fastForward = fastRewind = false;
- }
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused));
-}
-
-void cDVDplayBuffer::Play(void)
-{
- if (fastForward || fastRewind || paused) {
- if (!paused)
- Clear();
- CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY));
- CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true));
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false));
- fastForward = fastRewind = paused = false;
- }
-}
-
-void cDVDplayBuffer::Forward(void)
-{
- if (!paused)
- Clear(true);
- fastForward = !fastForward;
- fastRewind = false;
- if (paused)
- CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2));
- CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward));
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused));
- if (!paused)
- Clear(false);
-}
-
-void cDVDplayBuffer::Backward(void)
-{
- Clear(true);
- fastRewind = !fastRewind;
- fastForward = false;
- CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind));
- CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused));
- Clear(false);
+ if (!Block)
+ cPlayBuffer::Empty(false);
}
void cDVDplayBuffer::Close(void)
@@ -2116,13 +1960,13 @@ void cDVDplayBuffer::SkipSeconds(int Seconds)
int newchapid = Seconds > 0 ? chapid + 1 : chapid - 1;
if (newchapid >= 0 && newchapid < tt_srpt->title[titleid].nr_of_ptts) {
- Clear(true);
+ Empty(true);
chapid = newchapid;
NextState(cOPENCHAPTER);
if (ac3stat != AC3_STOP)
- ac3stat=AC3_START;
+ ac3stat = AC3_START;
ac3outp = ac3inp;
- Clear(false);
+ Empty(false);
Play();
}
}
@@ -2139,7 +1983,7 @@ void cDVDplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
// --- cTransferBuffer -------------------------------------------------------
-class cTransferBuffer : public cRingBuffer {
+class cTransferBuffer : public cRingBufferLinear {
private:
cDvbApi *dvbApi;
int fromDevice, toDevice;
@@ -2155,7 +1999,7 @@ public:
};
cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid)
-:cRingBuffer(VIDEOBUFSIZE, true)
+:cRingBufferLinear(VIDEOBUFSIZE, true)
,remux(VPid, APid, 0, 0, 0)
{
dvbApi = DvbApi;
diff --git a/menu.c b/menu.c
index 74dbedec..6f8c5997 100644
--- a/menu.c
+++ b/menu.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: menu.c 1.91 2001/08/04 08:08:44 kls Exp $
+ * $Id: menu.c 1.92 2001/08/05 10:33:54 kls Exp $
*/
#include "menu.h"
@@ -2438,11 +2438,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
// Positioning:
case kUp: dvbApi->Play(); break;
case kDown: dvbApi->Pause(); break;
- case kLeft: dvbApi->Backward(); break;
- case kRight: dvbApi->Forward(); break;
case kLeft|k_Release:
+ case kLeft: dvbApi->Backward(); break;
case kRight|k_Release:
- dvbApi->Play(); break;
+ case kRight: dvbApi->Forward(); break;
case kGreen|k_Repeat:
case kGreen: dvbApi->SkipSeconds(-60); break;
case kYellow|k_Repeat:
diff --git a/ringbuffer.c b/ringbuffer.c
index 79ece885..7e09b2af 100644
--- a/ringbuffer.c
+++ b/ringbuffer.c
@@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
- * $Id: ringbuffer.c 1.3 2001/08/02 13:48:38 kls Exp $
+ * $Id: ringbuffer.c 1.4 2001/08/05 12:17:45 kls Exp $
*/
#include "ringbuffer.h"
@@ -41,60 +41,128 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
{
size = Size;
statistics = Statistics;
- buffer = NULL;
inputThread = NULL;
outputThread = NULL;
+ busy = false;
maxFill = 0;
+}
+
+cRingBuffer::~cRingBuffer()
+{
+ delete inputThread;
+ delete outputThread;
+ if (statistics)
+ dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
+}
+
+void cRingBuffer::WaitForPut(void)
+{
+ putMutex.Lock();
+ readyForPut.Wait(putMutex);
+ putMutex.Unlock();
+}
+
+void cRingBuffer::WaitForGet(void)
+{
+ getMutex.Lock();
+ readyForGet.Wait(getMutex);
+ getMutex.Unlock();
+}
+
+void cRingBuffer::EnablePut(void)
+{
+ readyForPut.Broadcast();
+}
+
+void cRingBuffer::EnableGet(void)
+{
+ readyForGet.Broadcast();
+}
+
+bool cRingBuffer::Start(void)
+{
+ if (!busy) {
+ busy = true;
+ outputThread = new cRingBufferOutputThread(this);
+ if (!outputThread->Start())
+ DELETENULL(outputThread);
+ inputThread = new cRingBufferInputThread(this);
+ if (!inputThread->Start()) {
+ DELETENULL(inputThread);
+ DELETENULL(outputThread);
+ }
+ busy = outputThread && inputThread;
+ }
+ return busy;
+}
+
+bool cRingBuffer::Active(void)
+{
+ return outputThread && outputThread->Active() && inputThread && inputThread->Active();
+}
+
+void cRingBuffer::Stop(void)
+{
busy = false;
- if (size > 1) { // 'size - 1' must not be 0!
- buffer = new uchar[size];
+ for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
+ if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
+ break;
+ }
+ DELETENULL(inputThread);
+ DELETENULL(outputThread);
+}
+
+// --- cRingBufferLinear ----------------------------------------------------
+
+cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
+:cRingBuffer(Size, Statistics)
+{
+ buffer = NULL;
+ if (Size > 1) { // 'Size - 1' must not be 0!
+ buffer = new uchar[Size];
if (!buffer)
- esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size);
+ esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", Size);
Clear();
}
else
- esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", size);
+ esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", Size);
}
-cRingBuffer::~cRingBuffer()
+cRingBufferLinear::~cRingBufferLinear()
{
- delete inputThread;
- delete outputThread;
delete buffer;
- if (statistics)
- dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
}
-int cRingBuffer::Available(void)
+int cRingBufferLinear::Available(void)
{
- mutex.Lock();
+ Lock();
int diff = head - tail;
- mutex.Unlock();
- return (diff >= 0) ? diff : size + diff;
+ Unlock();
+ return (diff >= 0) ? diff : Size() + diff;
}
-void cRingBuffer::Clear(void)
+void cRingBufferLinear::Clear(void)
{
- mutex.Lock();
+ Lock();
head = tail = 0;
- mutex.Unlock();
+ Unlock();
}
-int cRingBuffer::Put(const uchar *Data, int Count)
+int cRingBufferLinear::Put(const uchar *Data, int Count)
{
if (Count > 0) {
- mutex.Lock();
- int rest = size - head;
+ Lock();
+ int rest = Size() - head;
int diff = tail - head;
- mutex.Unlock();
- int free = (diff > 0) ? diff - 1 : size + diff - 1;
+ Unlock();
+ int free = (diff > 0) ? diff - 1 : Size() + diff - 1;
if (statistics) {
- int fill = size - free - 1 + Count;
- if (fill >= size)
- fill = size - 1;
+ int fill = Size() - free - 1 + Count;
+ if (fill >= Size())
+ fill = Size() - 1;
if (fill > maxFill) {
maxFill = fill;
- int percent = maxFill * 100 / (size - 1);
+ int percent = maxFill * 100 / (Size() - 1);
if (percent > 75)
dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
}
@@ -119,14 +187,14 @@ int cRingBuffer::Put(const uchar *Data, int Count)
return Count;
}
-int cRingBuffer::Get(uchar *Data, int Count)
+int cRingBufferLinear::Get(uchar *Data, int Count)
{
if (Count > 0) {
- mutex.Lock();
- int rest = size - tail;
+ Lock();
+ int rest = Size() - tail;
int diff = head - tail;
- mutex.Unlock();
- int cont = (diff >= 0) ? diff : size + diff;
+ Unlock();
+ int cont = (diff >= 0) ? diff : Size() + diff;
if (rest <= 0)
return 0;
if (cont < Count)
@@ -145,36 +213,112 @@ int cRingBuffer::Get(uchar *Data, int Count)
return Count;
}
-bool cRingBuffer::Start(void)
+// --- cFrame ----------------------------------------------------------------
+
+cFrame::cFrame(const uchar *Data, int Count, int Index)
{
- if (!busy) {
- busy = true;
- outputThread = new cRingBufferOutputThread(this);
- if (!outputThread->Start())
- DELETENULL(outputThread);
- inputThread = new cRingBufferInputThread(this);
- if (!inputThread->Start()) {
- DELETENULL(inputThread);
- DELETENULL(outputThread);
+ count = Count;
+ index = Index;
+ data = new uchar[count];
+ if (data)
+ memcpy(data, Data, count);
+ else
+ esyslog(LOG_ERR, "ERROR: can't allocate frame buffer (count=%d)", count);
+ next = NULL;
+}
+
+cFrame::~cFrame()
+{
+ delete data;
+}
+
+// --- cRingBufferFrame ------------------------------------------------------
+
+cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics = false)
+:cRingBuffer(Size, Statistics)
+{
+ head = NULL;
+ currentFill = 0;
+}
+
+cRingBufferFrame::~cRingBufferFrame()
+{
+ Clear();
+}
+
+void cRingBufferFrame::Clear(void)
+{
+ Lock();
+ const cFrame *p;
+ while ((p = Get(false)) != NULL)
+ Drop(p);
+ Unlock();
+ EnablePut();
+ EnableGet();
+}
+
+bool cRingBufferFrame::Put(cFrame *Frame)
+{
+ if (Frame->Count() <= Free()) {
+ Lock();
+ if (head) {
+ Frame->next = head->next;
+ head->next = Frame;
+ head = Frame;
}
- busy = outputThread && inputThread;
+ else {
+ head = Frame->next = Frame;
+ }
+ currentFill += Frame->Count();
+ Unlock();
+ EnableGet();
+ return true;
}
- return busy;
+ WaitForPut();
+ return false;
}
-bool cRingBuffer::Active(void)
+const cFrame *cRingBufferFrame::Get(bool Wait)
{
- return outputThread && outputThread->Active() && inputThread && inputThread->Active();
+ Lock();
+ cFrame *p = head ? head->next : NULL;
+ Unlock();
+ if (!p && Wait)
+ WaitForGet();
+ return p;
}
-void cRingBuffer::Stop(void)
+void cRingBufferFrame::Delete(const cFrame *Frame)
{
- busy = false;
- for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
- if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
- break;
- }
- DELETENULL(inputThread);
- DELETENULL(outputThread);
+ currentFill -= Frame->Count();
+ delete Frame;
+}
+
+void cRingBufferFrame::Drop(const cFrame *Frame)
+{
+ Lock();
+ if (head) {
+ if (Frame == head->next) {
+ if (head->next != head) {
+ head->next = Frame->next;
+ Delete(Frame);
+ }
+ else {
+ Delete(head);
+ head = NULL;
+ }
+ }
+ else
+ esyslog(LOG_ERR, "ERROR: attempt to drop wrong frame from ring buffer!");
+ }
+ Unlock();
+ EnablePut();
}
+int cRingBufferFrame::Available(void)
+{
+ Lock();
+ int av = currentFill;
+ Unlock();
+ return av;
+}
diff --git a/ringbuffer.h b/ringbuffer.h
index 2121332b..f61d9e04 100644
--- a/ringbuffer.h
+++ b/ringbuffer.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: ringbuffer.h 1.3 2001/08/02 13:48:42 kls Exp $
+ * $Id: ringbuffer.h 1.4 2001/08/05 11:12:06 kls Exp $
*/
#ifndef __RINGBUFFER_H
@@ -24,25 +24,24 @@ private:
cRingBufferInputThread *inputThread;
cRingBufferOutputThread *outputThread;
cMutex mutex;
- int size, head, tail;
- uchar *buffer;
- int maxFill;
+ cCondVar readyForPut, readyForGet;
+ cMutex putMutex, getMutex;
+ int size;
bool busy;
- bool statistics;
protected:
+ int maxFill;//XXX
+ bool statistics;//XXX
+ void WaitForPut(void);
+ void WaitForGet(void);
+ void EnablePut(void);
+ void EnableGet(void);
+ virtual void Clear(void) = 0;
+ virtual int Available(void) = 0;
+ int Free(void) { return size - Available() - 1; }
void Lock(void) { mutex.Lock(); }
void Unlock(void) { mutex.Unlock(); }
- int Available(void);
- int Free(void) { return size - Available() - 1; }
+ int Size(void) { return size; }
bool Busy(void) { return busy; }
- void Clear(void);
- // Immediately clears the ring buffer.
- int Put(const uchar *Data, int Count);
- // Puts at most Count bytes of Data into the ring buffer.
- // Returns the number of bytes actually stored.
- int Get(uchar *Data, int Count);
- // Gets at most Count bytes of Data from the ring buffer.
- // Returns the number of bytes actually retrieved.
virtual void Input(void) = 0;
// Runs as a separate thread and shall continuously read data from
// a source and call Put() to store the data in the ring buffer.
@@ -57,4 +56,60 @@ public:
void Stop(void);
};
+class cRingBufferLinear : public cRingBuffer {
+private:
+ int head, tail;
+ uchar *buffer;
+protected:
+ virtual int Available(void);
+ virtual void Clear(void);
+ // Immediately clears the ring buffer.
+ int Put(const uchar *Data, int Count);
+ // Puts at most Count bytes of Data into the ring buffer.
+ // Returns the number of bytes actually stored.
+ int Get(uchar *Data, int Count);
+ // Gets at most Count bytes of Data from the ring buffer.
+ // Returns the number of bytes actually retrieved.
+public:
+ cRingBufferLinear(int Size, bool Statistics = false);
+ virtual ~cRingBufferLinear();
+ };
+
+class cFrame {
+ friend class cRingBufferFrame;
+private:
+ cFrame *next;
+ uchar *data;
+ int count;
+ int index;
+public:
+ cFrame(const uchar *Data, int Count, int Index = -1);
+ ~cFrame();
+ const uchar *Data(void) const { return data; }
+ int Count(void) const { return count; }
+ int Index(void) const { return index; }
+ };
+
+class cRingBufferFrame : public cRingBuffer {
+private:
+ cFrame *head;
+ int currentFill;
+ void Delete(const cFrame *Frame);
+protected:
+ virtual int Available(void);
+ virtual void Clear(void);
+ // Immediately clears the ring buffer.
+ bool Put(cFrame *Frame);
+ // Puts the Frame into the ring buffer.
+ // Returns true if this was possible.
+ const cFrame *Get(bool Wait = true);
+ // Gets the next frame from the ring buffer.
+ // The actual data still remains in the buffer until Drop() is called.
+ void Drop(const cFrame *Frame);
+ // Drops the Frame that has just been fetched with Get().
+public:
+ cRingBufferFrame(int Size, bool Statistics = false);
+ virtual ~cRingBufferFrame();
+ };
+
#endif // __RINGBUFFER_H
diff --git a/thread.c b/thread.c
index 63f104a3..bfc8aab1 100644
--- a/thread.c
+++ b/thread.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: thread.c 1.10 2001/08/02 13:48:45 kls Exp $
+ * $Id: thread.c 1.11 2001/08/05 10:36:52 kls Exp $
*/
#include "thread.h"
@@ -26,15 +26,15 @@ cCondVar::~cCondVar()
pthread_cond_destroy(&cond);
}
-bool cCondVar::Wait(cMutex &_mutex)
+bool cCondVar::Wait(cMutex &Mutex)
{
- return pthread_cond_wait(&cond, &_mutex.mutex);
+ return pthread_cond_wait(&cond, &Mutex.mutex);
}
/*
-bool cCondVar::TimedWait(cMutex &_mutex, unsigned long tmout)
+bool cCondVar::TimedWait(cMutex &Mutex, unsigned long tmout)
{
- return pthread_cond_timedwait(&cond, &_mutex.mutex, tmout);
+ return pthread_cond_timedwait(&cond, &Mutex.mutex, tmout);
}
*/
@@ -43,10 +43,12 @@ void cCondVar::Broadcast(void)
pthread_cond_broadcast(&cond);
}
+/*
void cCondVar::Signal(void)
{
pthread_cond_signal(&cond);
}
+*/
// --- cMutex ----------------------------------------------------------------
diff --git a/thread.h b/thread.h
index ff4c8304..e8e796eb 100644
--- a/thread.h
+++ b/thread.h
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: thread.h 1.7 2001/08/02 13:48:48 kls Exp $
+ * $Id: thread.h 1.8 2001/08/05 10:36:47 kls Exp $
*/
#ifndef __THREAD_H
@@ -21,10 +21,10 @@ private:
public:
cCondVar(void);
~cCondVar();
- bool Wait(cMutex &_mutex);
- //bool TimedWait(cMutex &_mutex, unsigned long tmout);
+ bool Wait(cMutex &Mutex);
+ //bool TimedWait(cMutex &Mutex, unsigned long tmout);
void Broadcast(void);
- void Signal(void);
+ //void Signal(void);
};
class cMutex {