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

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

View File

@ -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,108 +41,42 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
{
size = Size;
statistics = Statistics;
buffer = NULL;
inputThread = NULL;
outputThread = NULL;
maxFill = 0;
busy = false;
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);
maxFill = 0;
}
cRingBuffer::~cRingBuffer()
{
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)
void cRingBuffer::WaitForPut(void)
{
mutex.Lock();
int diff = head - tail;
mutex.Unlock();
return (diff >= 0) ? diff : size + diff;
putMutex.Lock();
readyForPut.Wait(putMutex);
putMutex.Unlock();
}
void cRingBuffer::Clear(void)
void cRingBuffer::WaitForGet(void)
{
mutex.Lock();
head = tail = 0;
mutex.Unlock();
getMutex.Lock();
readyForGet.Wait(getMutex);
getMutex.Unlock();
}
int cRingBuffer::Put(const uchar *Data, int Count)
void cRingBuffer::EnablePut(void)
{
if (Count > 0) {
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;
readyForPut.Broadcast();
}
int cRingBuffer::Get(uchar *Data, int Count)
void cRingBuffer::EnableGet(void)
{
if (Count > 0) {
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;
readyForGet.Broadcast();
}
bool cRingBuffer::Start(void)
@ -178,3 +112,213 @@ void cRingBuffer::Stop(void)
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
* 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

View File

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

View File

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