diff options
| -rw-r--r-- | CONTRIBUTORS | 1 | ||||
| -rw-r--r-- | HISTORY | 5 | ||||
| -rw-r--r-- | recorder.c | 18 | ||||
| -rw-r--r-- | ringbuffer.c | 82 | ||||
| -rw-r--r-- | ringbuffer.h | 28 | ||||
| -rw-r--r-- | transfer.c | 19 | 
6 files changed, 81 insertions, 72 deletions
| diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f3b5ef3b..f38b3c7b 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -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' @@ -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. @@ -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 diff --git a/ringbuffer.c b/ringbuffer.c index ed92be59..0734c28d 100644 --- a/ringbuffer.c +++ b/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 ---------------------------------------------------------------- diff --git a/ringbuffer.h b/ringbuffer.h index f96143c9..9205df7f 100644 --- a/ringbuffer.h +++ b/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 }; @@ -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 | 
