mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Modified cRingBufferLinear to avoid excessive memmove() calls in 'Transfer Mode' and during recordings
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user