mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
New ringbuffer for frames
This commit is contained in:
parent
614113cdcb
commit
c2ed9b5daf
3
HISTORY
3
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.
|
||||
|
7
menu.c
7
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:
|
||||
|
304
ringbuffer.c
304
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,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;
|
||||
}
|
||||
|
85
ringbuffer.h
85
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
|
||||
|
12
thread.c
12
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 ----------------------------------------------------------------
|
||||
|
||||
|
8
thread.h
8
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user