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:
parent
54eb58e1eb
commit
28d1affa31
@ -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'
|
||||
|
5
HISTORY
5
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.
|
||||
|
18
recorder.c
18
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
|
||||
|
82
ringbuffer.c
82
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 ----------------------------------------------------------------
|
||||
|
28
ringbuffer.h
28
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 };
|
||||
|
19
transfer.c
19
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
|
||||
|
Loading…
Reference in New Issue
Block a user