summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CONTRIBUTORS1
-rw-r--r--HISTORY5
-rw-r--r--recorder.c18
-rw-r--r--ringbuffer.c82
-rw-r--r--ringbuffer.h28
-rw-r--r--transfer.c19
6 files changed, 81 insertions, 72 deletions
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index f3b5ef3b..f38b3c7b 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -530,3 +530,4 @@ Teemu Rantanen <tvr@iki.fi>
for increased the maximum possible packet size in remux.c to avoid corrupted streams
with broadcasters that send extremely large PES packets
for adding TS error checking to remux.c
+ for pinpointing a problem with excessive memmove() calls in 'Transfer Mode'
diff --git a/HISTORY b/HISTORY
index a784e062..761925c6 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1917,7 +1917,7 @@ Video Disk Recorder Revision History
EPG data, that string is now limited in length when used in a recording's
file name.
-2003-01-24: Version 1.1.22
+2003-01-25: Version 1.1.22
- Added 'Hrvatska radiotelevizija' and 'RTV Slovenija' to ca.conf (thanks to
Paul Gohn).
@@ -1928,3 +1928,6 @@ Video Disk Recorder Revision History
- Increased the maximum possible packet size in remux.c to avoid corrupted streams
with broadcasters that send extremely large PES packets (thanks to Teemu Rantanen).
- Added TS error checking to remux.c (thanks to Teemu Rantanen).
+- Modified cRingBufferLinear to avoid excessive memmove() calls in 'Transfer Mode'
+ and during recordings, which dramatically reduces CPU load. Thanks to Teemu
+ Rantanen for pinpointing the problem with the excessive memmove() calls.
diff --git a/recorder.c b/recorder.c
index 426b5551..15e86463 100644
--- a/recorder.c
+++ b/recorder.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: recorder.c 1.4 2002/12/22 11:33:08 kls Exp $
+ * $Id: recorder.c 1.5 2003/01/25 16:23:36 kls Exp $
*/
#include <stdarg.h>
@@ -41,7 +41,7 @@ cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int A
SpinUpDisk(FileName);
- ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
+ ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true);
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
fileName = new cFileName(FileName, true);
recordFile = fileName->Open();
@@ -110,16 +110,14 @@ void cRecorder::Action(void)
{
dsyslog("recording thread started (pid=%d)", getpid());
- uchar b[MINVIDEODATA];
- int r = 0;
active = true;
while (active) {
- int g = ringBuffer->Get(b + r, sizeof(b) - r);
- if (g > 0)
- r += g;
- if (r > 0) {
+ int r;
+ const uchar *b = ringBuffer->Get(r);
+ if (b) {
int Count = r, Result;
uchar *p = remux->Process(b, Count, Result, &pictureType);
+ ringBuffer->Del(Count);
if (p) {
//XXX+ active??? see old version (Busy)
if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame
@@ -136,10 +134,6 @@ void cRecorder::Action(void)
else
break;
}
- if (Count > 0) {
- r -= Count;
- memmove(b, b + Count, r);
- }
}
else
usleep(1); // this keeps the CPU load low
diff --git a/ringbuffer.c b/ringbuffer.c
index ed92be59..0734c28d 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.11 2003/01/19 15:03:00 kls Exp $
+ * $Id: ringbuffer.c 1.12 2003/01/26 09:39:24 kls Exp $
*/
#include "ringbuffer.h"
@@ -57,13 +57,14 @@ void cRingBuffer::EnableGet(void)
// --- cRingBufferLinear -----------------------------------------------------
-cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
+cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics)
:cRingBuffer(Size, Statistics)
{
+ margin = Margin;
buffer = NULL;
getThreadPid = -1;
if (Size > 1) { // 'Size - 1' must not be 0!
- buffer = new uchar[Size];
+ buffer = MALLOC(uchar, Size);
if (!buffer)
esyslog("ERROR: can't allocate ring buffer (size=%d)", Size);
Clear();
@@ -74,7 +75,7 @@ cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
cRingBufferLinear::~cRingBufferLinear()
{
- delete buffer;
+ free(buffer);
}
int cRingBufferLinear::Available(void)
@@ -82,13 +83,14 @@ int cRingBufferLinear::Available(void)
Lock();
int diff = head - tail;
Unlock();
- return (diff >= 0) ? diff : Size() + diff;
+ return (diff >= 0) ? diff : Size() + diff - margin;
}
void cRingBufferLinear::Clear(void)
{
Lock();
- head = tail = 0;
+ head = tail = margin;
+ lastGet = -1;
Unlock();
EnablePut();
EnableGet();
@@ -100,7 +102,7 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
Lock();
int rest = Size() - head;
int diff = tail - head;
- int free = (diff > 0) ? diff - 1 : Size() + diff - 1;
+ int free = (diff > 0) ? diff - 1 : Size() + diff - (tail < margin ? -(margin - tail) : margin) - 1;
if (statistics) {
int fill = Size() - free - 1 + Count;
if (fill >= Size())
@@ -122,8 +124,8 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
if (Count >= rest) {
memcpy(buffer + head, Data, rest);
if (Count - rest)
- memcpy(buffer, Data + rest, Count - rest);
- head = Count - rest;
+ memcpy(buffer + margin, Data + rest, Count - rest);
+ head = margin + Count - rest;
}
else {
memcpy(buffer + head, Data, Count);
@@ -138,36 +140,42 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
return Count;
}
-int cRingBufferLinear::Get(uchar *Data, int Count)
+const uchar *cRingBufferLinear::Get(int &Count)
{
- if (Count > 0) {
- Lock();
- if (getThreadPid < 0)
- getThreadPid = getpid();
- int rest = Size() - tail;
- int diff = head - tail;
- int cont = (diff >= 0) ? diff : Size() + diff;
- if (rest > 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;
- }
- }
- else
- Count = 0;
- Unlock();
- if (Count == 0)
- WaitForGet();
+ const uchar *p = NULL;
+ Lock();
+ if (getThreadPid < 0)
+ getThreadPid = getpid();
+ int rest = Size() - tail;
+ if (tail > Size() - margin && head < tail) {
+ int t = margin - rest;
+ memcpy(buffer + t, buffer + tail, rest);
+ tail = t;
}
- return Count;
+ int diff = head - tail;
+ int cont = (diff >= 0) ? diff : Size() + diff - margin;
+ if (cont > rest)
+ cont = rest;
+ if (cont >= margin) {
+ p = buffer + tail;
+ Count = lastGet = cont;
+ }
+ Unlock();
+ if (!p)
+ WaitForGet();
+ return p;
+}
+
+void cRingBufferLinear::Del(int Count)
+{
+ if (Count > 0 && Count <= lastGet) {
+ tail += Count;
+ lastGet -= Count;
+ if (tail >= Size())
+ tail = margin;
+ }
+ else
+ esyslog("ERROR: invalid Count in cRingBufferLinear::Del: %d", Count);
}
// --- cFrame ----------------------------------------------------------------
diff --git a/ringbuffer.h b/ringbuffer.h
index f96143c9..9205df7f 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.8 2003/01/19 15:03:00 kls Exp $
+ * $Id: ringbuffer.h 1.9 2003/01/26 09:47:39 kls Exp $
*/
#ifndef __RINGBUFFER_H
@@ -40,21 +40,31 @@ public:
class cRingBufferLinear : public cRingBuffer {
private:
- int head, tail;
+ int margin, head, tail;
+ int lastGet;
uchar *buffer;
pid_t getThreadPid;
public:
- cRingBufferLinear(int Size, bool Statistics = false);
+ cRingBufferLinear(int Size, int Margin = 0, bool Statistics = false);
+ ///< Creates a linear ring buffer.
+ ///< The buffer will be able to hold at most Size bytes of data, and will
+ ///< be guaranteed to return at least Margin bytes in one consecutive block.
virtual ~cRingBufferLinear();
virtual int Available(void);
virtual void Clear(void);
- // Immediately clears the ring buffer.
+ ///< 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.
+ ///< Puts at most Count bytes of Data into the ring buffer.
+ ///< \return Returns the number of bytes actually stored.
+ const uchar *Get(int &Count);
+ ///< Gets data from the ring buffer.
+ ///< The data will remain in the buffer until a call to Del() deletes it.
+ ///< \return Returns a pointer to the data, and stores the number of bytes
+ ///< actually retrieved in Count. If the returned pointer is NULL, Count has no meaning.
+ void Del(int Count);
+ ///< Deletes at most Count bytes from the ring buffer.
+ ///< Count must be less or equal to the number that was returned by a previous
+ ///< call to Get().
};
enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby };
diff --git a/transfer.c b/transfer.c
index d8975a92..abcb9d08 100644
--- a/transfer.c
+++ b/transfer.c
@@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
- * $Id: transfer.c 1.8 2002/12/14 13:14:53 kls Exp $
+ * $Id: transfer.c 1.9 2003/01/26 09:59:35 kls Exp $
*/
#include "transfer.h"
@@ -19,7 +19,7 @@
cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(0, -1, 5, VPid, APid1, APid2, DPid1, DPid2)
{
- ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true);
+ ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true);
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
canToggleAudioTrack = false;
audioTrack = 0xC0;
@@ -60,8 +60,6 @@ void cTransfer::Action(void)
{
dsyslog("transfer thread started (pid=%d)", getpid());
- uchar b[MINVIDEODATA];
- int r = 0;
active = true;
while (active) {
@@ -80,15 +78,15 @@ void cTransfer::Action(void)
// Get data from the buffer:
- int g = ringBuffer->Get(b + r, sizeof(b) - r);
- if (g > 0)
- r += g;
+ int r;
+ const uchar *b = ringBuffer->Get(r);
// Play the data:
- if (r > 0) {
+ if (b) {
int Count = r, Result;
uchar *p = remux->Process(b, Count, Result);
+ ringBuffer->Del(Count);
if (p) {
StripAudioPackets(p, Result, audioTrack);
while (Result > 0 && active) {
@@ -103,11 +101,6 @@ void cTransfer::Action(void)
}
}
}
- if (Count > 0) {
- r -= Count;
- if (r > 0)
- memmove(b, b + Count, r);
- }
}
else
usleep(1); // this keeps the CPU load low