diff options
| -rw-r--r-- | HISTORY | 3 | ||||
| -rw-r--r-- | dvbapi.c | 712 | ||||
| -rw-r--r-- | menu.c | 7 | ||||
| -rw-r--r-- | ringbuffer.c | 252 | ||||
| -rw-r--r-- | ringbuffer.h | 85 | ||||
| -rw-r--r-- | thread.c | 12 | ||||
| -rw-r--r-- | thread.h | 8 | 
7 files changed, 562 insertions, 517 deletions
| @@ -610,7 +610,7 @@ Video Disk Recorder Revision History  - Explicitly switching back to the previously active channel after ending a    replay session (to have it shown correctly in case it was in 'Transfer Mode'). -2001-08-03: Version 0.86 +2001-08-05: Version 0.86  - Modified the display of the channel group separators (thanks to Markus Lang    for this suggestion). @@ -618,3 +618,4 @@ Video Disk Recorder Revision History    the 'libdvdread' library to be installed.  - Fixed replay progress display in case replay is paused while watching an    ongoing recording. +- Ringbuffer uses semaphores to signal empty/full conditions. @@ -6,7 +6,7 @@   *   * DVD support initially written by Andreas Schultz <aschultz@warp10.net>   * - * $Id: dvbapi.c 1.97 2001/08/03 13:08:22 kls Exp $ + * $Id: dvbapi.c 1.98 2001/08/05 12:17:02 kls Exp $   */  //#define DVDDEBUG        1 @@ -448,7 +448,7 @@ int cFileName::NextFile(void)  // --- cRecordBuffer --------------------------------------------------------- -class cRecordBuffer : public cRingBuffer { +class cRecordBuffer : public cRingBufferLinear {  private:    cDvbApi *dvbApi;    cFileName fileName; @@ -471,7 +471,7 @@ public:    };  cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2) -:cRingBuffer(VIDEOBUFSIZE, true) +:cRingBufferLinear(VIDEOBUFSIZE, true)  ,fileName(FileName, true)  ,remux(VPid, APid1, APid2, DPid1, DPid2, true)  { @@ -628,23 +628,27 @@ int ReadFrame(int f, uchar *b, int Length, int Max)  // --- cPlayBuffer --------------------------------------------------------- -class cPlayBuffer : public cRingBuffer { +class cPlayBuffer : public cRingBufferFrame {  protected:    cDvbApi *dvbApi;    int videoDev, audioDev;    FILE *dolbyDev;    int blockInput, blockOutput; -  bool paused, fastForward, fastRewind; +  bool still, paused, fastForward, fastRewind; +  int readIndex, writeIndex; +  bool canDoTrickMode;    bool canToggleAudioTrack;    uchar audioTrack; -  virtual void Clear(bool Block = false); +  virtual void Empty(bool Block = false); +  virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00) {} +  virtual void Output(void);  public:    cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);    virtual ~cPlayBuffer(); -  virtual void Pause(void) {} -  virtual void Play(void) = 0; -  virtual void Forward(void) {} -  virtual void Backward(void) {} +  virtual void Pause(void); +  virtual void Play(void); +  virtual void Forward(void); +  virtual void Backward(void);    virtual int SkipFrames(int Frames) { return -1; }    virtual void SkipSeconds(int Seconds) {}    virtual void Goto(int Position, bool Still = false) {} @@ -654,14 +658,16 @@ public:    };  cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev) -:cRingBuffer(VIDEOBUFSIZE) +:cRingBufferFrame(VIDEOBUFSIZE)  {    dvbApi = DvbApi;    videoDev = VideoDev;    audioDev = AudioDev;    dolbyDev = NULL;    blockInput = blockOutput = false; -  paused = fastForward = fastRewind = false; +  still = paused = fastForward = fastRewind = false; +  readIndex = writeIndex = -1; +  canDoTrickMode = false;    canToggleAudioTrack = false;    audioTrack = 0xC0;    if (cDvbApi::AudioCommand()) { @@ -677,18 +683,136 @@ cPlayBuffer::~cPlayBuffer()       pclose(dolbyDev);  } -void cPlayBuffer::Clear(bool Block) +void cPlayBuffer::Output(void)  { -  cRingBuffer::Clear(); -  CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); -  CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); +  dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); + +  while (Busy()) { +        if (blockOutput) { +           if (blockOutput > 1) +              blockOutput = 1; +           continue; +           } +        const cFrame *frame = Get(); +        if (frame) { +           StripAudioPackets((uchar *)frame->Data(), frame->Count(), (fastForward || fastRewind) ? 0x00 : audioTrack);//XXX +           for (int i = 0; i < ((paused && fastRewind) ? 24 : 1); i++) { // show every I_FRAME 24 times in slow rewind mode to achieve roughly the same speed as in slow forward mode +               const uchar *p = frame->Data(); +               int r = frame->Count(); +               while (r > 0 && Busy() && !blockOutput) { +                     cFile::FileReadyForWriting(videoDev, 100); +                     int w = write(videoDev, p, r); +                     if (w > 0) { +                        p += w; +                        r -= w; +                        } +                     else if (w < 0 && errno != EAGAIN) { +                        LOG_ERROR; +                        Stop(); +                        return; +                        } +                     } +               writeIndex = frame->Index(); +               } +           Drop(frame); +           } +        } + +  dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); +} + +void cPlayBuffer::Empty(bool Block) +{ +  if (!(blockInput || blockOutput)) { +     blockInput = blockOutput = 2; +     EnablePut(); +     EnableGet(); +     time_t t0 = time(NULL); +     while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) +           usleep(1); +     Lock(); +     readIndex = writeIndex; +     cRingBufferFrame::Clear(); +     CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER)); +     CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER)); +     } +  if (!Block) { +     blockInput = blockOutput = 0; +     Unlock(); +     } +} + +void cPlayBuffer::Pause(void) +{ +  paused = !paused; +  bool empty = fastForward || fastRewind; +  if (empty) +     Empty(true); +  fastForward = fastRewind = false; +  CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); +  CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); +  still = false; +  if (empty) +     Empty(false); +} + +void cPlayBuffer::Play(void) +{ +  if (fastForward || fastRewind || paused) { +     bool empty = !paused || fastRewind; +     if (empty) +        Empty(true); +     still = false; +     CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); +     CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); +     CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); +     if (empty) +        Empty(false); +     fastForward = fastRewind = paused = false; +     } +} + +void cPlayBuffer::Forward(void) +{ +  if (canDoTrickMode || paused) { +     bool empty = !paused || fastRewind; +     if (empty) { +        Empty(true); +        if (fastForward) +           readIndex -= 150; // this about compensates for the buffered data, so that we don't get too far ahead +        } +     still = false; +     fastForward = !fastForward; +     fastRewind = false; +     if (paused) +        CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2)); +     CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward)); +     CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused)); +     if (empty) +        Empty(false); +     } +} + +void cPlayBuffer::Backward(void) +{ +  if (canDoTrickMode) { +     Empty(true); +     still = false; +     fastRewind = !fastRewind; +     fastForward = false; +     if (paused) +        CHECK(ioctl(videoDev, fastRewind ? VIDEO_CONTINUE : VIDEO_FREEZE)); +     CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind)); +     CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused)); +     Empty(false); +     }  }  void cPlayBuffer::ToggleAudioTrack(void)  {    if (CanToggleAudioTrack()) {       audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0; -     Clear(); +     Empty();       }  } @@ -698,27 +822,19 @@ class cReplayBuffer : public cPlayBuffer {  private:    cIndexFile *index;    cFileName fileName; -  int fileOffset;    int replayFile;    bool eof; -  int lastIndex, stillIndex, playIndex;    bool NextFile(uchar FileNumber = 0, int FileOffset = -1); -  void Clear(bool Block = false);    void Close(void); -  void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00); +  virtual void StripAudioPackets(uchar *b, int Length, uchar Except = 0x00);    void DisplayFrame(uchar *b, int Length);    int Resume(void);    bool Save(void);  protected:    virtual void Input(void); -  virtual void Output(void);  public:    cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName);    virtual ~cReplayBuffer(); -  virtual void Pause(void); -  virtual void Play(void); -  virtual void Forward(void); -  virtual void Backward(void);    virtual int SkipFrames(int Frames);    virtual void SkipSeconds(int Seconds);    virtual void Goto(int Position, bool Still = false); @@ -730,10 +846,8 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const  ,fileName(FileName, false)  {    index = NULL; -  fileOffset = 0;    replayFile = fileName.Open();    eof = false; -  lastIndex = stillIndex = playIndex = -1;    if (!fileName.Name())       return;    // Create the index file: @@ -745,6 +859,7 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const       delete index;       index = NULL;       } +  canDoTrickMode = index != NULL;    dvbApi->SetModeReplay();    Start();  } @@ -762,22 +877,23 @@ void cReplayBuffer::Input(void)  {    dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid()); -  int ResumeIndex = Resume(); -  if (ResumeIndex >= 0) -     isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, IndexToHMSF(ResumeIndex, true)); +  readIndex = Resume(); +  if (readIndex >= 0) +     isyslog(LOG_INFO, "resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true)); -  int lastIndex = -1; -  int brakeCounter = 0;    uchar b[MAXFRAMESIZE];    while (Busy() && (blockInput || NextFile())) { -        if (!blockInput && stillIndex < 0) { +        if (blockInput) { +           if (blockInput > 1) +              blockInput = 1; +           continue; +           } +        if (!still) {             int r = 0;             if (fastForward && !paused || fastRewind) { -              int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset);                uchar FileNumber;                int FileOffset, Length; -              if (!paused || (brakeCounter++ % 24) == 0) // show every I_FRAME 24 times in rmSlowRewind mode to achieve roughly the same speed as in slow forward mode -                 Index = index->GetNextIFrame(Index, fastForward, &FileNumber, &FileOffset, &Length); +              int Index = index->GetNextIFrame(readIndex, fastForward, &FileNumber, &FileOffset, &Length);                if (Index >= 0) {                   if (!NextFile(FileNumber, FileOffset))                      break; @@ -787,126 +903,85 @@ void cReplayBuffer::Input(void)                   Play();                   continue;                   } -              lastIndex = Index; -              playIndex = -1; +              readIndex = Index;                r = ReadFrame(replayFile, b, Length, sizeof(b)); -              StripAudioPackets(b, r);                }             else if (index) { -              lastIndex = -1; -              playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset);                uchar FileNumber;                int FileOffset, Length; -              if (!(index->Get(playIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) +              readIndex++; +              if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset)))                   break;                r = ReadFrame(replayFile, b, Length, sizeof(b)); -              StripAudioPackets(b, r, audioTrack);                }             else // allows replay even if the index file is missing                r = read(replayFile, b, sizeof(b));             if (r > 0) { -              uchar *p = b; -              while (r > 0 && Busy() && !blockInput) { -                    int w = Put(p, r); -                    p += w; -                    r -= w; -                    usleep(1); // this keeps the CPU load low -                    } +              cFrame *frame = new cFrame(b, r, readIndex); +              while (Busy() && !blockInput && !Put(frame)) +                    ;                } -           else if (r ==0) +           else if (r == 0)                eof = true;             else if (r < 0 && errno != EAGAIN) {                LOG_ERROR;                break;                }             } -        else +        else//XXX             usleep(1); // this keeps the CPU load low -        if (blockInput > 1) -           blockInput = 1;          }    dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid());  } -void cReplayBuffer::Output(void) -{ -  dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); - -  uchar b[MINVIDEODATA]; -  while (Busy()) { -        int r = blockOutput ? 0 : Get(b, sizeof(b)); -        if (r > 0) { -           uchar *p = b; -           while (r > 0 && Busy() && !blockOutput) { -                 cFile::FileReadyForWriting(videoDev, 100); -                 int w = write(videoDev, p, r); -                 if (w > 0) { -                    p += w; -                    r -= w; -                    fileOffset += w; -                    } -                 else if (w < 0 && errno != EAGAIN) { -                    LOG_ERROR; -                    Stop(); -                    return; -                    } -                 } -           } -        else -           usleep(1); // this keeps the CPU load low -        if (blockOutput > 1) -           blockOutput = 1; -        } - -  dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); -} -  void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)  { -  for (int i = 0; i < Length - 6; i++) { -      if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { -         uchar c = b[i + 3]; -         int l = b[i + 4] * 256 + b[i + 5] + 6; -         switch (c) { -           case 0xBD: // dolby -                if (Except && dolbyDev) { -                   int written = b[i + 8] + 9; // skips the PES header -                   int n = l - written; -                   while (n > 0) { -                         int w = fwrite(&b[i + written], 1, n, dolbyDev); -                         if (w < 0) { -                            LOG_ERROR; -                            break; +  if (canDoTrickMode) { +     for (int i = 0; i < Length - 6; i++) { +         if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) { +            uchar c = b[i + 3]; +            int l = b[i + 4] * 256 + b[i + 5] + 6; +            switch (c) { +              case 0xBD: // dolby +                   if (Except && dolbyDev) { +                      int written = b[i + 8] + 9; // skips the PES header +                      int n = l - written; +                      while (n > 0) { +                            int w = fwrite(&b[i + written], 1, n, dolbyDev); +                            if (w < 0) { +                               LOG_ERROR; +                               break; +                               } +                            n -= w; +                            written += w;                              } -                         n -= w; -                         written += w; -                         } -                   } -                // continue with deleting the data - otherwise it disturbs DVB replay -           case 0xC0 ... 0xC1: // audio -                if (c == 0xC1) -                   canToggleAudioTrack = true; -                if (!Except || c != Except) { -                   int n = l; -                   for (int j = i; j < Length && n--; j++) -                       b[j] = 0x00; -                   } -                break; -           case 0xE0 ... 0xEF: // video -                break; -           default: -                //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c); -                l = 0; -           } -         if (l) -            i += l - 1; // the loop increments, too! +                      } +                   // continue with deleting the data - otherwise it disturbs DVB replay +              case 0xC0 ... 0xC1: // audio +                   if (c == 0xC1) +                      canToggleAudioTrack = true; +                   if (!Except || c != Except) { +                      int n = l; +                      for (int j = i; j < Length && n--; j++) +                          b[j] = 0x00; +                      } +                   break; +              case 0xE0 ... 0xEF: // video +                   break; +              default: +                   //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c); +                   l = 0; +              } +            if (l) +               i += l - 1; // the loop increments, too! +            } +         /*XXX +         else +            esyslog(LOG_ERR, "ERROR: broken packet header"); +            XXX*/           } -      /*XXX -      else -         esyslog(LOG_ERR, "ERROR: broken packet header"); -         XXX*/ -      } +     }  }  void cReplayBuffer::DisplayFrame(uchar *b, int Length) @@ -918,85 +993,11 @@ void cReplayBuffer::DisplayFrame(uchar *b, int Length)    CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp));  } -void cReplayBuffer::Clear(bool Block) -{ -  if (!(blockInput || blockOutput)) { -     blockInput = blockOutput = 2; -     time_t t0 = time(NULL); -     while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) -           usleep(1); -     Lock(); -     playIndex = -1; -     cPlayBuffer::Clear(); -     } -  if (!Block) { -     blockInput = blockOutput = 0; -     Unlock(); -     } -} - -void cReplayBuffer::Pause(void) -{ -  paused = !paused; -  CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); -  if (fastForward || fastRewind) { -     if (paused) -        Clear(); -     fastForward = fastRewind = false; -     } -  CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); -  stillIndex = -1; -} - -void cReplayBuffer::Play(void) -{ -  if (fastForward || fastRewind || paused) { -     if (!paused) -        Clear(); -     stillIndex = -1; -     CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); -     CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); -     CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); -     fastForward = fastRewind = paused = false; -     } -} - -void cReplayBuffer::Forward(void) -{ -  if (index || paused) { -     if (!paused) -        Clear(true); -     stillIndex = -1; -     fastForward = !fastForward; -     fastRewind = false; -     if (paused) -        CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2)); -     CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward)); -     CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused)); -     if (!paused) -        Clear(false); -     } -} - -void cReplayBuffer::Backward(void) -{ -  if (index) { -     Clear(true); -     stillIndex = -1; -     fastRewind = !fastRewind; -     fastForward = false; -     CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind)); -     CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused)); -     Clear(false); -     } -} -  void cReplayBuffer::Close(void)  {    if (replayFile >= 0) {       fileName.Close();       replayFile = -1; -     fileOffset = 0;       }  } @@ -1017,7 +1018,7 @@ int cReplayBuffer::Resume(void)  bool cReplayBuffer::Save(void)  {    if (index) { -     int Index = index->Get(fileName.Number(), fileOffset); +     int Index = writeIndex;       if (Index >= 0) {          Index -= RESUMEBACKUP;          if (Index > 0) @@ -1046,8 +1047,8 @@ int cReplayBuffer::SkipFrames(int Frames)  void cReplayBuffer::SkipSeconds(int Seconds)  {    if (index && Seconds) { -     Clear(true); -     int Index = index->Get(fileName.Number(), fileOffset); +     Empty(true); +     int Index = writeIndex;       if (Index >= 0) {          if (Seconds < 0) {             int sec = index->Last() / FRAMESPERSEC; @@ -1059,10 +1060,9 @@ void cReplayBuffer::SkipSeconds(int Seconds)             Index = 1; // not '0', to allow GetNextIFrame() below to work!          uchar FileNumber;          int FileOffset; -        if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0) -           NextFile(FileNumber, FileOffset); +        readIndex = writeIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) - 1; // Input() will first increment it!          } -     Clear(false); +     Empty(false);       Play();       }  } @@ -1070,7 +1070,7 @@ void cReplayBuffer::SkipSeconds(int Seconds)  void cReplayBuffer::Goto(int Index, bool Still)  {    if (index) { -     Clear(true); +     Empty(true);       if (paused)          CHECK(ioctl(videoDev, VIDEO_CONTINUE));       if (++Index <= 0) @@ -1079,28 +1079,27 @@ void cReplayBuffer::Goto(int Index, bool Still)       int FileOffset, Length;       Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);       if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) { -        stillIndex = Index; -        playIndex = -1; +        still = true;          uchar b[MAXFRAMESIZE];          int r = ReadFrame(replayFile, b, Length, sizeof(b));          if (r > 0)             DisplayFrame(b, r); -        fileOffset += Length;          paused = true;          }       else -        stillIndex = playIndex = -1; -     Clear(false); +        still = false; +     readIndex = writeIndex = Index; +     Empty(false);       }  }  void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)  {    if (index) { -     if (stillIndex >= 0) -        Current = stillIndex; +     if (still) +        Current = readIndex;       else { -        Current = index->Get(fileName.Number(), fileOffset); +        Current = writeIndex;          if (SnapToIFrame) {             int i1 = index->GetNextIFrame(Current + 1, false);             int i2 = index->GetNextIFrame(Current, true); @@ -1115,10 +1114,8 @@ void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)  bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)  { -  if (FileNumber > 0) { -     fileOffset = FileOffset; +  if (FileNumber > 0)       replayFile = fileName.SetOffset(FileNumber, FileOffset); -     }    else if (replayFile >= 0 && eof) {       Close();       replayFile = fileName.NextFile(); @@ -1131,12 +1128,6 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)  class cDVDplayBuffer : public cPlayBuffer {  private: -  cCondVar ready4input; -  cMutex   inputMutex; - -  cCondVar ready4output; -  cMutex   outputMutex; -    uchar audioTrack;    cDVD *dvd;//XXX necessary??? @@ -1186,7 +1177,7 @@ private:    int lpcm_count;    int is_nav_pack(unsigned char *buffer);    void Close(void); -  void Clear(bool Block = false); +  virtual void Empty(bool Block = false);    int decode_packet(unsigned char *sector, int iframe);    int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType);    bool PacketStart(uchar **Data, int len); @@ -1201,14 +1192,9 @@ private:    void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }  protected:    virtual void Input(void); -  virtual void Output(void);  public:    cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title);    virtual ~cDVDplayBuffer(); -  virtual void Pause(void); -  virtual void Play(void); -  virtual void Forward(void); -  virtual void Backward(void);    virtual int SkipFrames(int Frames);    virtual void SkipSeconds(int Seconds);    virtual void Goto(int Position, bool Still = false); @@ -1224,6 +1210,41 @@ public:  #define cOUTPACK         5  #define cOUTFRAMES       6 +cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title) +:cPlayBuffer(DvbApi, VideoDev, AudioDev) +{ +  dvd = DvD; +  titleid = title; +  chapid = 0; +  angle = 0; +  cyclestate = cOPENDVD; +  prevcycle = 0; +  brakeCounter = 0; +  skipCnt = 0; +  logAudioTrack = 0; +  canToggleAudioTrack = true;//XXX determine from cDVD! +  ac3_config.num_output_ch = 2; +  //    ac3_config.flags = /* mm_accel() | */ MM_ACCEL_MLIB; +  ac3_config.flags = 0; +  ac3_init(&ac3_config); +  data = new uchar[1024 * DVD_VIDEO_LB_LEN]; +  ac3data = new uchar[AC3_BUFFER_SIZE]; +  ac3inp = ac3outp = 0; +  ac3stat = AC3_START; +  canDoTrickMode = true; +  dvbApi->SetModeReplay(); +  Start(); +} + +cDVDplayBuffer::~cDVDplayBuffer() +{ +  Stop(); +  Close(); +  dvbApi->SetModeNormal(false); +  delete ac3data; +  delete data; +} +  unsigned int cDVDplayBuffer::getAudioStream(unsigned int StreamId)  {    unsigned int trackID; @@ -1267,40 +1288,6 @@ void cDVDplayBuffer::ToggleAudioTrack(void)       }  } -cDVDplayBuffer::cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title) -:cPlayBuffer(DvbApi, VideoDev, AudioDev) -{ -  dvd = DvD; -  titleid = title; -  chapid = 0; -  angle = 0; -  cyclestate = cOPENDVD; -  prevcycle = 0; -  brakeCounter = 0; -  skipCnt = 0; -  logAudioTrack = 0; -  canToggleAudioTrack = true;//XXX determine from cDVD! -  ac3_config.num_output_ch = 2; -  //    ac3_config.flags = /* mm_accel() | */ MM_ACCEL_MLIB; -  ac3_config.flags = 0; -  ac3_init(&ac3_config); -  data = new uchar[1024 * DVD_VIDEO_LB_LEN]; -  ac3data = new uchar[AC3_BUFFER_SIZE]; -  ac3inp = ac3outp = 0; -  ac3stat = AC3_START; -  dvbApi->SetModeReplay(); -  Start(); -} - -cDVDplayBuffer::~cDVDplayBuffer() -{ -  Stop(); -  Close(); -  dvbApi->SetModeNormal(false); -  delete ac3data; -  delete data; -} -  /**   * Returns true if the pack is a NAV pack.  This check is clearly insufficient,   * and sometimes we incorrectly think that valid other packs are NAV packs.  I @@ -1317,15 +1304,13 @@ void cDVDplayBuffer::Input(void)    doplay = true;    while (Busy() && doplay) { -        inputMutex.Lock(); -        while (blockInput) { -              if (blockInput > 1) -                 blockInput = 1; -              ready4input.Wait(inputMutex); -              } -        inputMutex.Unlock(); +        if (blockInput) { +           if (blockInput > 1) +              blockInput = 1; +           continue; +           } -        //BEGIN: riped from play_title +        //BEGIN: ripped from play_title          /**           * Playback by cell in this pgc, starting at the cell for our chapter. @@ -1659,8 +1644,6 @@ void cDVDplayBuffer::Input(void)          }          // dsyslog(LOG_INF, "DVD: new cyclestate: %d, pktcnt: %d, cur: %d", cyclestate, pktcnt, cur_output_size); -        if (blockInput > 1) -           blockInput = 1;          }    dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); @@ -1761,6 +1744,7 @@ int cDVDplayBuffer::SendPCM(int size)          while (p_size) {               if (ac3outp != ac3inp) { // data in the buffer                  buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder +                                                             // XXX there is no 'swab' here??? (kls)                  p_size--;                  length++;                  ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE; @@ -1791,18 +1775,9 @@ int cDVDplayBuffer::SendPCM(int size)          length += 6; -        inputMutex.Lock(); -        while (Free() < length && Busy() && !blockInput) -              ready4input.Wait(inputMutex); -        inputMutex.Unlock(); - -        if (Busy() && !blockInput) { -           if ((Put(buffer, length) != length)) { -              esyslog(LOG_ERR, "ERROR: Put(buffer, length) != length"); -              return 0; -              } -           ready4output.Broadcast(); -           } +        cFrame *frame = new cFrame(buffer, length); +        while (Busy() && !blockInput && !Put(frame)) +              ;          size -= MAXSIZE;          }    return 0; @@ -1834,7 +1809,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)    uchar *osect = sector;  #endif -  //make sure we got an PS packet header +  //make sure we got a PS packet header    if (!PacketStart(§or, DVD_VIDEO_LB_LEN) && GetPacketType(sector) != 0xBA) {       esyslog(LOG_ERR, "ERROR: got unexpected packet: %x %x %x %x", sector[0], sector[1], sector[2], sector[3]);       return -1; @@ -1885,7 +1860,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)             sector += 6;             //we are now at the beginning of the payload -           //correct a3 data lenght - FIXME: why 13 ??? +           //correct ac3 data lenght - FIXME: why 13 ???             ac3datalen -= 13;             if (audioTrack == *sector) {                sector +=4; @@ -1933,154 +1908,23 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)             return pt;           }      } -  inputMutex.Lock(); -  while (Free() < r && Busy() && !blockInput) -        ready4input.Wait(inputMutex); -  inputMutex.Unlock(); -  if (Busy() && !blockInput) { -     if (Put(sector, r) != r) { -        esyslog(LOG_ERR, "ERROR: Put(sector, r) != r"); -        return 0; -        } -     ready4output.Broadcast(); -     } +  cFrame *frame = new cFrame(sector, r); +  while (Busy() && !blockInput && !Put(frame)) +        ;    playDecodedAC3();    return pt;  } -void cDVDplayBuffer::Output(void) -{ -  dsyslog(LOG_INFO, "output thread started (pid=%d)", getpid()); - -#ifdef DVDDEBUG_BUFFER -  long long cyl = 0; -  long long emp = 0; -  long long low = 0; -#endif - -  uchar b[MINVIDEODATA]; -  while (Busy()) { -#ifdef DVDDEBUG_BUFFER -        cyl++; -#endif -        outputMutex.Lock(); -        if (blockOutput > 1) -           blockOutput = 1; - -        int r = 0; -        while (Busy() && ((r = blockOutput ? 0 : Get(b, sizeof(b))) == 0)) { -#ifdef DVDDEBUG_BUFFER -              if (r == 0) { -                 //ups we just emptied the entire buffer -                 dsyslog(LOG_INFO, "DVD: %12Ld warning: Get() failed due to empty buffer %12Ld", cyl, emp); -                 emp++; -                 } -#endif -              ready4output.Wait(outputMutex); -              if (blockOutput > 1) -                 blockOutput = 1; -              } -        outputMutex.Unlock(); - -        if (r > 0) { -#ifdef DVDDEBUG_BUFFER -           if (Available() != 0 && Available() < (VIDEOBUFSIZE/20)) { -              //5% warning limit -              dsyslog(LOG_INFO, "DVD: %12Ld warning: buffer almost empty: %d, %10.2f %12Ld", cyl, Available(), (float)Available() * 100.0 / (float) VIDEOBUFSIZE, low); -              low++; -              } -#endif -           ready4input.Broadcast(); -           uchar *p = b; -           while (r > 0 && Busy() && !blockOutput) { -                 cFile::FileReadyForWriting(videoDev, 100); -                 int w = write(videoDev, p, r); -                 if (w > 0) { -                    p += w; -                    r -= w; -                    } -                 else if (w < 0 && errno != EAGAIN) { -                    LOG_ERROR; -                    Stop(); -                    return; -                    } -                 } -           } -        if (blockOutput > 1) -           blockOutput = 1; -        } - -  dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid()); -} - -void cDVDplayBuffer::Clear(bool Block) +void cDVDplayBuffer::Empty(bool Block)  {    if (!(blockInput || blockOutput)) { -     blockInput = blockOutput = 2; -     ready4input.Broadcast(); -     ready4output.Broadcast(); -     time_t t0 = time(NULL); -     while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2) -           usleep(1); -     Lock(); -     cPlayBuffer::Clear(); +     cPlayBuffer::Empty(true);       ac3stat = AC3_START;       ac3outp = ac3inp;       } -  if (!Block) { -     blockInput = blockOutput = 0; -     ready4input.Broadcast(); -     ready4output.Broadcast(); -     Unlock(); -     } -} -void cDVDplayBuffer::Pause(void) -{ -  paused = !paused; -  CHECK(ioctl(videoDev, paused ? VIDEO_FREEZE : VIDEO_CONTINUE)); -  if (fastForward || fastRewind) { -      if (paused) -         Clear(); -      fastForward = fastRewind = false; -      } -  CHECK(ioctl(audioDev, AUDIO_SET_MUTE, paused)); -} - -void cDVDplayBuffer::Play(void) -{ -  if (fastForward || fastRewind || paused) { -     if (!paused) -        Clear(); -     CHECK(ioctl(videoDev, paused ? VIDEO_CONTINUE : VIDEO_PLAY)); -     CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, true)); -     CHECK(ioctl(audioDev, AUDIO_SET_MUTE, false)); -     fastForward = fastRewind = paused = false; -     } -} - -void cDVDplayBuffer::Forward(void) -{ -  if (!paused) -     Clear(true); -  fastForward = !fastForward; -  fastRewind = false; -  if (paused) -     CHECK(ioctl(videoDev, fastForward ? VIDEO_SLOWMOTION : VIDEO_FREEZE, 2)); -  CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastForward)); -  CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastForward || paused)); -  if (!paused) -     Clear(false); -} - -void cDVDplayBuffer::Backward(void) -{ -  Clear(true); -  fastRewind = !fastRewind; -  fastForward = false; -  CHECK(ioctl(audioDev, AUDIO_SET_AV_SYNC, !fastRewind)); -  CHECK(ioctl(audioDev, AUDIO_SET_MUTE, fastRewind || paused)); -  Clear(false); +  if (!Block) +     cPlayBuffer::Empty(false);  }  void cDVDplayBuffer::Close(void) @@ -2116,13 +1960,13 @@ void cDVDplayBuffer::SkipSeconds(int Seconds)       int newchapid = Seconds > 0 ? chapid + 1 : chapid - 1;       if (newchapid >= 0 && newchapid < tt_srpt->title[titleid].nr_of_ptts) { -        Clear(true); +        Empty(true);          chapid = newchapid;          NextState(cOPENCHAPTER);          if (ac3stat != AC3_STOP) -           ac3stat=AC3_START; +           ac3stat = AC3_START;          ac3outp = ac3inp; -        Clear(false); +        Empty(false);          Play();          }       } @@ -2139,7 +1983,7 @@ void cDVDplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)  // --- cTransferBuffer ------------------------------------------------------- -class cTransferBuffer : public cRingBuffer { +class cTransferBuffer : public cRingBufferLinear {  private:    cDvbApi *dvbApi;    int fromDevice, toDevice; @@ -2155,7 +1999,7 @@ public:    };  cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid) -:cRingBuffer(VIDEOBUFSIZE, true) +:cRingBufferLinear(VIDEOBUFSIZE, true)  ,remux(VPid, APid, 0, 0, 0)  {    dvbApi = DvbApi; @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: menu.c 1.91 2001/08/04 08:08:44 kls Exp $ + * $Id: menu.c 1.92 2001/08/05 10:33:54 kls Exp $   */  #include "menu.h" @@ -2438,11 +2438,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key)      // Positioning:      case kUp:      dvbApi->Play(); break;      case kDown:    dvbApi->Pause(); break; -    case kLeft:    dvbApi->Backward(); break; -    case kRight:   dvbApi->Forward(); break;      case kLeft|k_Release: +    case kLeft:    dvbApi->Backward(); break;      case kRight|k_Release: -                   dvbApi->Play(); break; +    case kRight:   dvbApi->Forward(); break;      case kGreen|k_Repeat:      case kGreen:   dvbApi->SkipSeconds(-60); break;      case kYellow|k_Repeat: diff --git a/ringbuffer.c b/ringbuffer.c index 79ece885..7e09b2af 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.3 2001/08/02 13:48:38 kls Exp $ + * $Id: ringbuffer.c 1.4 2001/08/05 12:17:45 kls Exp $   */  #include "ringbuffer.h" @@ -41,60 +41,128 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)  {    size = Size;    statistics = Statistics; -  buffer = NULL;    inputThread = NULL;    outputThread = NULL; +  busy = false;    maxFill = 0; +} + +cRingBuffer::~cRingBuffer() +{ +  delete inputThread; +  delete outputThread; +  if (statistics) +     dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1)); +} + +void cRingBuffer::WaitForPut(void) +{ +  putMutex.Lock(); +  readyForPut.Wait(putMutex); +  putMutex.Unlock(); +} + +void cRingBuffer::WaitForGet(void) +{ +  getMutex.Lock(); +  readyForGet.Wait(getMutex); +  getMutex.Unlock(); +} + +void cRingBuffer::EnablePut(void) +{ +  readyForPut.Broadcast(); +} + +void cRingBuffer::EnableGet(void) +{ +  readyForGet.Broadcast(); +} + +bool cRingBuffer::Start(void) +{ +  if (!busy) { +     busy = true; +     outputThread = new cRingBufferOutputThread(this); +     if (!outputThread->Start()) +        DELETENULL(outputThread); +     inputThread = new cRingBufferInputThread(this); +     if (!inputThread->Start()) { +        DELETENULL(inputThread); +        DELETENULL(outputThread); +        } +     busy = outputThread && inputThread; +     } +  return busy; +} + +bool cRingBuffer::Active(void) +{ +  return outputThread && outputThread->Active() && inputThread && inputThread->Active(); +} + +void cRingBuffer::Stop(void) +{    busy = false; -  if (size > 1) { // 'size - 1' must not be 0! -     buffer = new uchar[size]; +  for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) { +      if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active()))) +         break; +      } +  DELETENULL(inputThread); +  DELETENULL(outputThread); +} + +// --- cRingBufferLinear ---------------------------------------------------- + +cRingBufferLinear::cRingBufferLinear(int Size, bool Statistics) +:cRingBuffer(Size, Statistics) +{ +  buffer = NULL; +  if (Size > 1) { // 'Size - 1' must not be 0! +     buffer = new uchar[Size];       if (!buffer) -        esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", size); +        esyslog(LOG_ERR, "ERROR: can't allocate ring buffer (size=%d)", Size);       Clear();       }    else -     esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", size); +     esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", Size);  } -cRingBuffer::~cRingBuffer() +cRingBufferLinear::~cRingBufferLinear()  { -  delete inputThread; -  delete outputThread;    delete buffer; -  if (statistics) -     dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));  } -int cRingBuffer::Available(void) +int cRingBufferLinear::Available(void)  { -  mutex.Lock(); +  Lock();    int diff = head - tail; -  mutex.Unlock(); -  return (diff >= 0) ? diff : size + diff; +  Unlock(); +  return (diff >= 0) ? diff : Size() + diff;  } -void cRingBuffer::Clear(void) +void cRingBufferLinear::Clear(void)  { -  mutex.Lock(); +  Lock();    head = tail = 0; -  mutex.Unlock(); +  Unlock();  } -int cRingBuffer::Put(const uchar *Data, int Count) +int cRingBufferLinear::Put(const uchar *Data, int Count)  {    if (Count > 0) { -     mutex.Lock(); -     int rest = size - head; +     Lock(); +     int rest = Size() - head;       int diff = tail - head; -     mutex.Unlock(); -     int free = (diff > 0) ? diff - 1 : size + diff - 1; +     Unlock(); +     int free = (diff > 0) ? diff - 1 : Size() + diff - 1;       if (statistics) { -        int fill = size - free - 1 + Count; -        if (fill >= size) -           fill = size - 1; +        int fill = Size() - free - 1 + Count; +        if (fill >= Size()) +           fill = Size() - 1;          if (fill > maxFill) {             maxFill = fill; -           int percent = maxFill * 100 / (size - 1); +           int percent = maxFill * 100 / (Size() - 1);             if (percent > 75)                dsyslog(LOG_INFO, "buffer usage: %d%%", percent);             } @@ -119,14 +187,14 @@ int cRingBuffer::Put(const uchar *Data, int Count)    return Count;  } -int cRingBuffer::Get(uchar *Data, int Count) +int cRingBufferLinear::Get(uchar *Data, int Count)  {    if (Count > 0) { -     mutex.Lock(); -     int rest = size - tail; +     Lock(); +     int rest = Size() - tail;       int diff = head - tail; -     mutex.Unlock(); -     int cont = (diff >= 0) ? diff : size + diff; +     Unlock(); +     int cont = (diff >= 0) ? diff : Size() + diff;       if (rest <= 0)          return 0;       if (cont < Count) @@ -145,36 +213,112 @@ int cRingBuffer::Get(uchar *Data, int Count)    return Count;  } -bool cRingBuffer::Start(void) +// --- cFrame ---------------------------------------------------------------- + +cFrame::cFrame(const uchar *Data, int Count, int Index)  { -  if (!busy) { -     busy = true; -     outputThread = new cRingBufferOutputThread(this); -     if (!outputThread->Start()) -        DELETENULL(outputThread); -     inputThread = new cRingBufferInputThread(this); -     if (!inputThread->Start()) { -        DELETENULL(inputThread); -        DELETENULL(outputThread); +  count = Count; +  index = Index; +  data = new uchar[count]; +  if (data) +     memcpy(data, Data, count); +  else +     esyslog(LOG_ERR, "ERROR: can't allocate frame buffer (count=%d)", count); +  next = NULL; +} + +cFrame::~cFrame() +{ +  delete data; +} + +// --- cRingBufferFrame ------------------------------------------------------ + +cRingBufferFrame::cRingBufferFrame(int Size, bool Statistics = false) +:cRingBuffer(Size, Statistics) +{ +  head = NULL; +  currentFill = 0; +} + +cRingBufferFrame::~cRingBufferFrame() +{ +  Clear(); +} + +void cRingBufferFrame::Clear(void) +{ +  Lock(); +  const cFrame *p; +  while ((p = Get(false)) != NULL) +        Drop(p); +  Unlock(); +  EnablePut(); +  EnableGet(); +} + +bool cRingBufferFrame::Put(cFrame *Frame) +{ +  if (Frame->Count() <= Free()) { +     Lock(); +     if (head) { +        Frame->next = head->next; +        head->next = Frame; +        head = Frame;          } -     busy = outputThread && inputThread; +     else { +        head = Frame->next = Frame; +        } +     currentFill += Frame->Count(); +     Unlock(); +     EnableGet(); +     return true;       } -  return busy; +  WaitForPut(); +  return false;  } -bool cRingBuffer::Active(void) +const cFrame *cRingBufferFrame::Get(bool Wait)  { -  return outputThread && outputThread->Active() && inputThread && inputThread->Active(); +  Lock(); +  cFrame *p = head ? head->next : NULL; +  Unlock(); +  if (!p && Wait) +     WaitForGet(); +  return p;  } -void cRingBuffer::Stop(void) +void cRingBufferFrame::Delete(const cFrame *Frame)  { -  busy = false; -  for (time_t t0 = time(NULL) + 3; time(NULL) < t0; ) { -      if (!((outputThread && outputThread->Active()) || (inputThread && inputThread->Active()))) -         break; -      } -  DELETENULL(inputThread); -  DELETENULL(outputThread); +  currentFill -= Frame->Count(); +  delete Frame; +} + +void cRingBufferFrame::Drop(const cFrame *Frame) +{ +  Lock(); +  if (head) { +     if (Frame == head->next) { +        if (head->next != head) { +           head->next = Frame->next; +           Delete(Frame); +           } +        else { +           Delete(head); +           head = NULL; +           } +        } +     else +        esyslog(LOG_ERR, "ERROR: attempt to drop wrong frame from ring buffer!"); +     } +  Unlock(); +  EnablePut();  } +int cRingBufferFrame::Available(void) +{ +  Lock(); +  int av = currentFill; +  Unlock(); +  return av; +} diff --git a/ringbuffer.h b/ringbuffer.h index 2121332b..f61d9e04 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.3 2001/08/02 13:48:42 kls Exp $ + * $Id: ringbuffer.h 1.4 2001/08/05 11:12:06 kls Exp $   */  #ifndef __RINGBUFFER_H @@ -24,25 +24,24 @@ private:    cRingBufferInputThread *inputThread;    cRingBufferOutputThread *outputThread;    cMutex mutex; -  int size, head, tail; -  uchar *buffer; -  int maxFill; +  cCondVar readyForPut, readyForGet; +  cMutex putMutex, getMutex; +  int size;    bool busy; -  bool statistics;  protected: +  int maxFill;//XXX +  bool statistics;//XXX +  void WaitForPut(void); +  void WaitForGet(void); +  void EnablePut(void); +  void EnableGet(void); +  virtual void Clear(void) = 0; +  virtual int Available(void) = 0; +  int Free(void) { return size - Available() - 1; }    void Lock(void) { mutex.Lock(); }    void Unlock(void) { mutex.Unlock(); } -  int Available(void); -  int Free(void) { return size - Available() - 1; } +  int Size(void) { return size; }    bool Busy(void) { return busy; } -  void Clear(void); -    // 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.    virtual void Input(void) = 0;      // Runs as a separate thread and shall continuously read data from      // a source and call Put() to store the data in the ring buffer. @@ -57,4 +56,60 @@ public:    void Stop(void);    }; +class cRingBufferLinear : public cRingBuffer { +private: +  int head, tail; +  uchar *buffer; +protected: +  virtual int Available(void); +  virtual void Clear(void); +    // 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. +public: +  cRingBufferLinear(int Size, bool Statistics = false); +  virtual ~cRingBufferLinear(); +  }; + +class cFrame { +  friend class cRingBufferFrame; +private: +  cFrame *next; +  uchar *data; +  int count; +  int index; +public: +  cFrame(const uchar *Data, int Count, int Index = -1); +  ~cFrame(); +  const uchar *Data(void) const { return data; } +  int Count(void) const { return count; } +  int Index(void) const { return index; } +  }; + +class cRingBufferFrame : public cRingBuffer { +private: +  cFrame *head; +  int currentFill; +  void Delete(const cFrame *Frame); +protected: +  virtual int Available(void); +  virtual void Clear(void); +    // Immediately clears the ring buffer. +  bool Put(cFrame *Frame); +    // Puts the Frame into the ring buffer. +    // Returns true if this was possible. +  const cFrame *Get(bool Wait = true); +    // Gets the next frame from the ring buffer. +    // The actual data still remains in the buffer until Drop() is called. +  void Drop(const cFrame *Frame); +    // Drops the Frame that has just been fetched with Get(). +public: +  cRingBufferFrame(int Size, bool Statistics = false); +  virtual ~cRingBufferFrame(); +  }; +  #endif // __RINGBUFFER_H @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: thread.c 1.10 2001/08/02 13:48:45 kls Exp $ + * $Id: thread.c 1.11 2001/08/05 10:36:52 kls Exp $   */  #include "thread.h" @@ -26,15 +26,15 @@ cCondVar::~cCondVar()    pthread_cond_destroy(&cond);  } -bool cCondVar::Wait(cMutex &_mutex) +bool cCondVar::Wait(cMutex &Mutex)  { -  return pthread_cond_wait(&cond, &_mutex.mutex); +  return pthread_cond_wait(&cond, &Mutex.mutex);  }  /* -bool cCondVar::TimedWait(cMutex &_mutex, unsigned long tmout) +bool cCondVar::TimedWait(cMutex &Mutex, unsigned long tmout)  { -  return pthread_cond_timedwait(&cond, &_mutex.mutex, tmout); +  return pthread_cond_timedwait(&cond, &Mutex.mutex, tmout);  }  */ @@ -43,10 +43,12 @@ void cCondVar::Broadcast(void)    pthread_cond_broadcast(&cond);  } +/*  void cCondVar::Signal(void)  {    pthread_cond_signal(&cond);  } +*/  // --- cMutex ---------------------------------------------------------------- @@ -4,7 +4,7 @@   * See the main source file 'vdr.c' for copyright information and   * how to reach the author.   * - * $Id: thread.h 1.7 2001/08/02 13:48:48 kls Exp $ + * $Id: thread.h 1.8 2001/08/05 10:36:47 kls Exp $   */  #ifndef __THREAD_H @@ -21,10 +21,10 @@ private:  public:    cCondVar(void);    ~cCondVar(); -  bool Wait(cMutex &_mutex); -  //bool TimedWait(cMutex &_mutex, unsigned long tmout); +  bool Wait(cMutex &Mutex); +  //bool TimedWait(cMutex &Mutex, unsigned long tmout);    void Broadcast(void); -  void Signal(void); +  //void Signal(void);    };  class cMutex { | 
