1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

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 for increased the maximum possible packet size in remux.c to avoid corrupted streams
with broadcasters that send extremely large PES packets with broadcasters that send extremely large PES packets
for adding TS error checking to remux.c 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 EPG data, that string is now limited in length when used in a recording's
file name. 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 - Added 'Hrvatska radiotelevizija' and 'RTV Slovenija' to ca.conf (thanks to
Paul Gohn). Paul Gohn).
@ -1928,3 +1928,6 @@ Video Disk Recorder Revision History
- Increased the maximum possible packet size in remux.c to avoid corrupted streams - 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). with broadcasters that send extremely large PES packets (thanks to Teemu Rantanen).
- Added TS error checking to remux.c (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 * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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> #include <stdarg.h>
@ -41,7 +41,7 @@ cRecorder::cRecorder(const char *FileName, int Ca, int Priority, int VPid, int A
SpinUpDisk(FileName); SpinUpDisk(FileName);
ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, true); ringBuffer = new cRingBufferLinear(VIDEOBUFSIZE, TS_SIZE * 2, true);
remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true); remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2, true);
fileName = new cFileName(FileName, true); fileName = new cFileName(FileName, true);
recordFile = fileName->Open(); recordFile = fileName->Open();
@ -110,16 +110,14 @@ void cRecorder::Action(void)
{ {
dsyslog("recording thread started (pid=%d)", getpid()); dsyslog("recording thread started (pid=%d)", getpid());
uchar b[MINVIDEODATA];
int r = 0;
active = true; active = true;
while (active) { while (active) {
int g = ringBuffer->Get(b + r, sizeof(b) - r); int r;
if (g > 0) const uchar *b = ringBuffer->Get(r);
r += g; if (b) {
if (r > 0) {
int Count = r, Result; int Count = r, Result;
uchar *p = remux->Process(b, Count, Result, &pictureType); uchar *p = remux->Process(b, Count, Result, &pictureType);
ringBuffer->Del(Count);
if (p) { if (p) {
//XXX+ active??? see old version (Busy) //XXX+ active??? see old version (Busy)
if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame if (!active && pictureType == I_FRAME) // finish the recording before the next 'I' frame
@ -136,10 +134,6 @@ void cRecorder::Action(void)
else else
break; break;
} }
if (Count > 0) {
r -= Count;
memmove(b, b + Count, r);
}
} }
else else
usleep(1); // this keeps the CPU load low 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 * Parts of this file were inspired by the 'ringbuffy.c' from the
* LinuxDVB driver (see linuxtv.org). * 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" #include "ringbuffer.h"
@ -57,13 +57,14 @@ void cRingBuffer::EnableGet(void)
// --- cRingBufferLinear ----------------------------------------------------- // --- cRingBufferLinear -----------------------------------------------------
cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics) cRingBufferLinear::cRingBufferLinear(int Size, int Margin, bool Statistics)
:cRingBuffer(Size, Statistics) :cRingBuffer(Size, Statistics)
{ {
margin = Margin;
buffer = NULL; buffer = NULL;
getThreadPid = -1; getThreadPid = -1;
if (Size > 1) { // 'Size - 1' must not be 0! if (Size > 1) { // 'Size - 1' must not be 0!
buffer = new uchar[Size]; buffer = MALLOC(uchar, Size);
if (!buffer) if (!buffer)
esyslog("ERROR: can't allocate ring buffer (size=%d)", Size); esyslog("ERROR: can't allocate ring buffer (size=%d)", Size);
Clear(); Clear();
@ -74,7 +75,7 @@ cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics)
cRingBufferLinear::~cRingBufferLinear() cRingBufferLinear::~cRingBufferLinear()
{ {
delete buffer; free(buffer);
} }
int cRingBufferLinear::Available(void) int cRingBufferLinear::Available(void)
@ -82,13 +83,14 @@ int cRingBufferLinear::Available(void)
Lock(); Lock();
int diff = head - tail; int diff = head - tail;
Unlock(); Unlock();
return (diff >= 0) ? diff : Size() + diff; return (diff >= 0) ? diff : Size() + diff - margin;
} }
void cRingBufferLinear::Clear(void) void cRingBufferLinear::Clear(void)
{ {
Lock(); Lock();
head = tail = 0; head = tail = margin;
lastGet = -1;
Unlock(); Unlock();
EnablePut(); EnablePut();
EnableGet(); EnableGet();
@ -100,7 +102,7 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
Lock(); Lock();
int rest = Size() - head; int rest = Size() - head;
int diff = tail - 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) { if (statistics) {
int fill = Size() - free - 1 + Count; int fill = Size() - free - 1 + Count;
if (fill >= Size()) if (fill >= Size())
@ -122,8 +124,8 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
if (Count >= rest) { if (Count >= rest) {
memcpy(buffer + head, Data, rest); memcpy(buffer + head, Data, rest);
if (Count - rest) if (Count - rest)
memcpy(buffer, Data + rest, Count - rest); memcpy(buffer + margin, Data + rest, Count - rest);
head = Count - rest; head = margin + Count - rest;
} }
else { else {
memcpy(buffer + head, Data, Count); memcpy(buffer + head, Data, Count);
@ -138,36 +140,42 @@ int cRingBufferLinear::Put(const uchar *Data, int Count)
return Count; return Count;
} }
int cRingBufferLinear::Get(uchar *Data, int Count) const uchar *cRingBufferLinear::Get(int &Count)
{ {
if (Count > 0) { const uchar *p = NULL;
Lock(); Lock();
if (getThreadPid < 0) if (getThreadPid < 0)
getThreadPid = getpid(); getThreadPid = getpid();
int rest = Size() - tail; int rest = Size() - tail;
int diff = head - tail; if (tail > Size() - margin && head < tail) {
int cont = (diff >= 0) ? diff : Size() + diff; int t = margin - rest;
if (rest > 0) { memcpy(buffer + t, buffer + tail, rest);
if (cont < Count) tail = t;
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();
} }
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 ---------------------------------------------------------------- // --- cFrame ----------------------------------------------------------------

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __RINGBUFFER_H
@ -40,21 +40,31 @@ public:
class cRingBufferLinear : public cRingBuffer { class cRingBufferLinear : public cRingBuffer {
private: private:
int head, tail; int margin, head, tail;
int lastGet;
uchar *buffer; uchar *buffer;
pid_t getThreadPid; pid_t getThreadPid;
public: 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 ~cRingBufferLinear();
virtual int Available(void); virtual int Available(void);
virtual void Clear(void); virtual void Clear(void);
// Immediately clears the ring buffer. ///< Immediately clears the ring buffer.
int Put(const uchar *Data, int Count); int Put(const uchar *Data, int Count);
// Puts at most Count bytes of Data into the ring buffer. ///< Puts at most Count bytes of Data into the ring buffer.
// Returns the number of bytes actually stored. ///< \return Returns the number of bytes actually stored.
int Get(uchar *Data, int Count); const uchar *Get(int &Count);
// Gets at most Count bytes of Data from the ring buffer. ///< Gets data from the ring buffer.
// Returns the number of bytes actually retrieved. ///< 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 }; enum eFrameType { ftUnknown, ftVideo, ftAudio, ftDolby };

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "transfer.h"
@ -19,7 +19,7 @@
cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2) cTransfer::cTransfer(int VPid, int APid1, int APid2, int DPid1, int DPid2)
:cReceiver(0, -1, 5, VPid, APid1, APid2, DPid1, 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); remux = new cRemux(VPid, APid1, APid2, DPid1, DPid2);
canToggleAudioTrack = false; canToggleAudioTrack = false;
audioTrack = 0xC0; audioTrack = 0xC0;
@ -60,8 +60,6 @@ void cTransfer::Action(void)
{ {
dsyslog("transfer thread started (pid=%d)", getpid()); dsyslog("transfer thread started (pid=%d)", getpid());
uchar b[MINVIDEODATA];
int r = 0;
active = true; active = true;
while (active) { while (active) {
@ -80,15 +78,15 @@ void cTransfer::Action(void)
// Get data from the buffer: // Get data from the buffer:
int g = ringBuffer->Get(b + r, sizeof(b) - r); int r;
if (g > 0) const uchar *b = ringBuffer->Get(r);
r += g;
// Play the data: // Play the data:
if (r > 0) { if (b) {
int Count = r, Result; int Count = r, Result;
uchar *p = remux->Process(b, Count, Result); uchar *p = remux->Process(b, Count, Result);
ringBuffer->Del(Count);
if (p) { if (p) {
StripAudioPackets(p, Result, audioTrack); StripAudioPackets(p, Result, audioTrack);
while (Result > 0 && active) { 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 else
usleep(1); // this keeps the CPU load low usleep(1); // this keeps the CPU load low