Modified cRingBufferLinear to avoid excessive memmove() calls in 'Transfer Mode' and during recordings

This commit is contained in:
Klaus Schmidinger 2003-01-26 09:59:35 +01:00
parent 54eb58e1eb
commit 28d1affa31
6 changed files with 81 additions and 72 deletions

View File

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

View File

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

View File

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

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

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

View File

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