vdr/ringbuffer.c
Klaus Schmidinger 8f9cc68f76 Version 0.85
- Added Norwegian language texts (thanks to Jørgen Tvedt).
- Increased the usleep value in cDvbOsd::Cmd() to 5000 in order to work on
  systems with the KURT/utime-patch (thanks to Guido Fiala).
- Changed the check whether the driver is loaded in runvdr to check for the
  'dvb' module (the last one loaded).
- Fixed repeat function with LIRC (thanks to Stefan Huelswitt).
- Increased the upper limit for the symbol rate to 30000 (thanks to Ulrich
  Röder).
- Made the position of the channel display configurable (thanks to Stefan
  Huelswitt).
- Made the width and height of the OSD configurable (thanks to Stefan Huelswitt).
- DiSEqC support can now be generally enabled/disabled in the Setup menu. This
  may be necessary if your multiswitch gets irritated by the default DiSEqC
  codes '0' (thanks to Markus Lang).
- Fixed replaying in case there is no index file.
- Fixed jumping to an editing mark when replay has been paused.
- Avoiding unnecessary code execution in the replay progress display (thanks
  to Guido Fiala).
- When entering time values the digits that still have to be entered are now
  shown as '-' (as in "1-:--").
- When setting an editing mark while the progress display is not active, the
  display will now be turned on for a short while to indicate the successful
  setting of the mark.
- Updated 'channels.conf' for Premiere World (thanks to Helmut Schächner).
  Check your timers if you use this channels.conf file, since the sequence of
  several PW channels has been changed.
- Changed the color of "Info" messages to "black on green" and that of the
  confirmation messages (like "Delete...") to "black on yellow".
- Fixed display with DEBUG_OSD (it still crashes sometimes, esp. when replaying,
  but I can't seem to find what causes this... any ideas anybody?).
- Avoiding audio/video distortions in 'Transfer Mode' by no longer actually
  tuning the primary interface (which can't receive this channel, anyway).
  Apparently the driver gets irritated when the channel is switched and a
  replay session is started immediately after that.
- Increased timeout until reporting "video data stream broken" when recording.
- 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-07-29 18:00:00 +02:00

182 lines
4.3 KiB
C

/*
* ringbuffer.c: A threaded ring buffer
*
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org).
*
* $Id: ringbuffer.c 1.2 2001/05/20 11:58:08 kls Exp $
*/
#include "ringbuffer.h"
#include "tools.h"
// --- cRingBufferInputThread -------------------------------------------------
class cRingBufferInputThread : public cThread {
private:
cRingBuffer *ringBuffer;
protected:
virtual void Action(void) { ringBuffer->Input(); }
public:
cRingBufferInputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
};
// --- cRingBufferOutputThread ------------------------------------------------
class cRingBufferOutputThread : public cThread {
private:
cRingBuffer *ringBuffer;
protected:
virtual void Action(void) { ringBuffer->Output(); }
public:
cRingBufferOutputThread(cRingBuffer *RingBuffer) { ringBuffer = RingBuffer; }
};
// --- cRingBuffer ------------------------------------------------------------
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);
}
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)
{
mutex.Lock();
int diff = head - tail;
int cont = (diff >= 0) ? diff : size + diff;
mutex.Unlock();
return cont;
}
void cRingBuffer::Clear(void)
{
mutex.Lock();
head = tail = 0;
mutex.Unlock();
}
int cRingBuffer::Put(const uchar *Data, int Count)
{
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;
}
int cRingBuffer::Get(uchar *Data, int Count)
{
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;
}
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;
for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) {
if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active())))
break;
}
DELETENULL(inputThread);
DELETENULL(outputThread);
}