New ringbuffer for frames

This commit is contained in:
Klaus Schmidinger 2001-08-05 12:23:24 +02:00
parent 614113cdcb
commit c2ed9b5daf
7 changed files with 588 additions and 543 deletions

View File

@ -610,7 +610,7 @@ Video Disk Recorder Revision History
- Explicitly switching back to the previously active channel after ending a - 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'). 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 - Modified the display of the channel group separators (thanks to Markus Lang
for this suggestion). for this suggestion).
@ -618,3 +618,4 @@ Video Disk Recorder Revision History
the 'libdvdread' library to be installed. the 'libdvdread' library to be installed.
- Fixed replay progress display in case replay is paused while watching an - Fixed replay progress display in case replay is paused while watching an
ongoing recording. ongoing recording.
- Ringbuffer uses semaphores to signal empty/full conditions.

712
dvbapi.c

File diff suppressed because it is too large Load Diff

7
menu.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: 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" #include "menu.h"
@ -2438,11 +2438,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
// Positioning: // Positioning:
case kUp: dvbApi->Play(); break; case kUp: dvbApi->Play(); break;
case kDown: dvbApi->Pause(); break; case kDown: dvbApi->Pause(); break;
case kLeft: dvbApi->Backward(); break;
case kRight: dvbApi->Forward(); break;
case kLeft|k_Release: case kLeft|k_Release:
case kLeft: dvbApi->Backward(); break;
case kRight|k_Release: case kRight|k_Release:
dvbApi->Play(); break; case kRight: dvbApi->Forward(); break;
case kGreen|k_Repeat: case kGreen|k_Repeat:
case kGreen: dvbApi->SkipSeconds(-60); break; case kGreen: dvbApi->SkipSeconds(-60); break;
case kYellow|k_Repeat: case kYellow|k_Repeat:

View File

@ -7,7 +7,7 @@
* Parts of this file were inspired by the 'ringbuffy.c' from the * Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org). * 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" #include "ringbuffer.h"
@ -41,108 +41,42 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
{ {
size = Size; size = Size;
statistics = Statistics; statistics = Statistics;
buffer = NULL;
inputThread = NULL; inputThread = NULL;
outputThread = NULL; outputThread = NULL;
maxFill = 0;
busy = false; busy = false;
if (size > 1) { // 'size - 1' must not be 0! maxFill = 0;
buffer = new uchar[size];
if (!buffer)
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);
} }
cRingBuffer::~cRingBuffer() cRingBuffer::~cRingBuffer()
{ {
delete inputThread; delete inputThread;
delete outputThread; delete outputThread;
delete buffer;
if (statistics) if (statistics)
dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
} }
int cRingBuffer::Available(void) void cRingBuffer::WaitForPut(void)
{ {
mutex.Lock(); putMutex.Lock();
int diff = head - tail; readyForPut.Wait(putMutex);
mutex.Unlock(); putMutex.Unlock();
return (diff >= 0) ? diff : size + diff;
} }
void cRingBuffer::Clear(void) void cRingBuffer::WaitForGet(void)
{ {
mutex.Lock(); getMutex.Lock();
head = tail = 0; readyForGet.Wait(getMutex);
mutex.Unlock(); getMutex.Unlock();
} }
int cRingBuffer::Put(const uchar *Data, int Count) void cRingBuffer::EnablePut(void)
{ {
if (Count > 0) { readyForPut.Broadcast();
mutex.Lock();
int rest = size - head;
int diff = tail - head;
mutex.Unlock();
int free = (diff > 0) ? diff - 1 : size + diff - 1;
if (statistics) {
int fill = size - free - 1 + Count;
if (fill >= size)
fill = size - 1;
if (fill > maxFill) {
maxFill = fill;
int percent = maxFill * 100 / (size - 1);
if (percent > 75)
dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
}
}
if (free <= 0)
return 0;
if (free < Count)
Count = free;
if (Count > maxFill)
maxFill = Count;
if (Count >= rest) {
memcpy(buffer + head, Data, rest);
if (Count - rest)
memcpy(buffer, Data + rest, Count - rest);
head = Count - rest;
}
else {
memcpy(buffer + head, Data, Count);
head += Count;
}
}
return Count;
} }
int cRingBuffer::Get(uchar *Data, int Count) void cRingBuffer::EnableGet(void)
{ {
if (Count > 0) { readyForGet.Broadcast();
mutex.Lock();
int rest = size - tail;
int diff = head - tail;
mutex.Unlock();
int cont = (diff >= 0) ? diff : size + diff;
if (rest <= 0)
return 0;
if (cont < Count)
Count = cont;
if (Count >= rest) {
memcpy(Data, buffer + tail, rest);
if (Count - rest)
memcpy(Data + rest, buffer, Count - rest);
tail = Count - rest;
}
else {
memcpy(Data, buffer + tail, Count);
tail += Count;
}
}
return Count;
} }
bool cRingBuffer::Start(void) bool cRingBuffer::Start(void)
@ -178,3 +112,213 @@ void cRingBuffer::Stop(void)
DELETENULL(outputThread); 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);
Clear();
}
else
esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", Size);
}
cRingBufferLinear::~cRingBufferLinear()
{
delete buffer;
}
int cRingBufferLinear::Available(void)
{
Lock();
int diff = head - tail;
Unlock();
return (diff >= 0) ? diff : Size() + diff;
}
void cRingBufferLinear::Clear(void)
{
Lock();
head = tail = 0;
Unlock();
}
int cRingBufferLinear::Put(const uchar *Data, int Count)
{
if (Count > 0) {
Lock();
int rest = Size() - head;
int diff = tail - head;
Unlock();
int free = (diff > 0) ? diff - 1 : Size() + diff - 1;
if (statistics) {
int fill = Size() - free - 1 + Count;
if (fill >= Size())
fill = Size() - 1;
if (fill > maxFill) {
maxFill = fill;
int percent = maxFill * 100 / (Size() - 1);
if (percent > 75)
dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
}
}
if (free <= 0)
return 0;
if (free < Count)
Count = free;
if (Count > maxFill)
maxFill = Count;
if (Count >= rest) {
memcpy(buffer + head, Data, rest);
if (Count - rest)
memcpy(buffer, Data + rest, Count - rest);
head = Count - rest;
}
else {
memcpy(buffer + head, Data, Count);
head += Count;
}
}
return Count;
}
int cRingBufferLinear::Get(uchar *Data, int Count)
{
if (Count > 0) {
Lock();
int rest = Size() - tail;
int diff = head - tail;
Unlock();
int cont = (diff >= 0) ? diff : Size() + diff;
if (rest <= 0)
return 0;
if (cont < Count)
Count = cont;
if (Count >= rest) {
memcpy(Data, buffer + tail, rest);
if (Count - rest)
memcpy(Data + rest, buffer, Count - rest);
tail = Count - rest;
}
else {
memcpy(Data, buffer + tail, Count);
tail += Count;
}
}
return Count;
}
// --- cFrame ----------------------------------------------------------------
cFrame::cFrame(const uchar *Data, int Count, int Index)
{
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;
}
else {
head = Frame->next = Frame;
}
currentFill += Frame->Count();
Unlock();
EnableGet();
return true;
}
WaitForPut();
return false;
}
const cFrame *cRingBufferFrame::Get(bool Wait)
{
Lock();
cFrame *p = head ? head->next : NULL;
Unlock();
if (!p && Wait)
WaitForGet();
return p;
}
void cRingBufferFrame::Delete(const cFrame *Frame)
{
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;
}

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: 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 #ifndef __RINGBUFFER_H
@ -24,25 +24,24 @@ private:
cRingBufferInputThread *inputThread; cRingBufferInputThread *inputThread;
cRingBufferOutputThread *outputThread; cRingBufferOutputThread *outputThread;
cMutex mutex; cMutex mutex;
int size, head, tail; cCondVar readyForPut, readyForGet;
uchar *buffer; cMutex putMutex, getMutex;
int maxFill; int size;
bool busy; bool busy;
bool statistics;
protected: 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 Lock(void) { mutex.Lock(); }
void Unlock(void) { mutex.Unlock(); } void Unlock(void) { mutex.Unlock(); }
int Available(void); int Size(void) { return size; }
int Free(void) { return size - Available() - 1; }
bool Busy(void) { return busy; } 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; virtual void Input(void) = 0;
// Runs as a separate thread and shall continuously read data from // Runs as a separate thread and shall continuously read data from
// a source and call Put() to store the data in the ring buffer. // a source and call Put() to store the data in the ring buffer.
@ -57,4 +56,60 @@ public:
void Stop(void); 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 #endif // __RINGBUFFER_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: 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" #include "thread.h"
@ -26,15 +26,15 @@ cCondVar::~cCondVar()
pthread_cond_destroy(&cond); 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); pthread_cond_broadcast(&cond);
} }
/*
void cCondVar::Signal(void) void cCondVar::Signal(void)
{ {
pthread_cond_signal(&cond); pthread_cond_signal(&cond);
} }
*/
// --- cMutex ---------------------------------------------------------------- // --- cMutex ----------------------------------------------------------------

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: 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 #ifndef __THREAD_H
@ -21,10 +21,10 @@ private:
public: public:
cCondVar(void); cCondVar(void);
~cCondVar(); ~cCondVar();
bool Wait(cMutex &_mutex); bool Wait(cMutex &Mutex);
//bool TimedWait(cMutex &_mutex, unsigned long tmout); //bool TimedWait(cMutex &Mutex, unsigned long tmout);
void Broadcast(void); void Broadcast(void);
void Signal(void); //void Signal(void);
}; };
class cMutex { class cMutex {