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
|
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'
|
||||||
|
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
|
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.
|
||||||
|
18
recorder.c
18
recorder.c
@ -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
|
||||||
|
82
ringbuffer.c
82
ringbuffer.c
@ -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 ----------------------------------------------------------------
|
||||||
|
28
ringbuffer.h
28
ringbuffer.h
@ -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 };
|
||||||
|
19
transfer.c
19
transfer.c
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user