vdr-xine: what's wrong with this piece of code-- threadingissue?

Message ID 424496B3.7060009@gmx.de
State New
Headers

Commit Message

Reinhard Nissl March 25, 2005, 10:54 p.m. UTC
  Hi,

Rantanen Teemu wrote:

>>This typically happens when moving cutting marks, and I'm
>>investigating this already.
 >>
>>Expect it for 0.8.0, but the next release will still be 0.7.3.
> 
> Looking forward to both 0.8.0 and 0.7.3 ...
> 
> In my experience the most problems I've had are starting/ending
> recording, and all rewinds. At these points may happen that xine
> disconnects. Not very often but sometimes. When xine disconnects VDR
> will "play" the recording really fast and it's minutes past the place
> when xine reconnects. I've had no problems with cutting marks...

Please apply the attached patch to vdr-1.3.23 and tell me, whether there 
is any improvement. At least there was one for me ;-)

Bye.
  

Patch

--- ../vdr-1.3.23-orig/dvbplayer.c	2005-01-14 15:00:56.000000000 +0100
+++ dvbplayer.c	2005-03-25 19:44:38.000000000 +0100
@@ -358,6 +358,89 @@  void cDvbPlayer::Activate(bool On)
      }
 }
 
+static uchar *findStartCode(uchar *Data, int Length)
+{
+  uchar *limit = Data + Length;
+  Data += 6 + 3 + Data[6 + 2] + 3; // move to PES payload and skip 00 00 01
+  while (Data < limit) {
+        // possible start codes that appear before/after picture data
+        // 00 00 01 B3: sequence header code
+        // 00 00 01 B8: group start code
+        // 00 00 01 00: picture start code
+        // 00 00 01 B7: sequence end code
+        if (0x01 == Data[-1] && (0xB3 == Data[0] || 0xB8 == Data[0] || 0x00 == Data[0] || 0xB7 == Data[0]) && 0x00 == Data[-2] && 0x00 == Data[-3])
+            return Data - 3;
+        Data++;
+        }
+
+  return 0;
+}
+
+static void fixIFrameHead(uchar *Data, int Length)
+{
+  uchar *p = findStartCode(Data, Length);
+  if (!p) {
+     esyslog("fixIframeHead: start code not found!\n");
+     return;
+     }
+
+  Data += 6 + 3 + Data[6 + 2]; // move to PES payload
+  if (Data < p)
+     memset(Data, 0, p - Data); // zero preceeding bytes
+}
+
+static int fixIFrameTail(uchar *Data, int Length, bool StillImage)
+{
+  uchar *p = findStartCode(Data, Length);
+  if (!p) {
+     esyslog("fixIframeTail: start code not found!\n");
+     return 0;
+     }
+
+  int dropBytes = Length - (p - Data);
+  if (StillImage)
+  {
+     // need to append sequence end code
+     dropBytes -= 4;
+     p[3] = 0xB7;
+  }
+  
+  // adjust PES payload size
+  int payloadSize = Data[4] * 256 + Data[5];
+  payloadSize -= dropBytes;
+  Data[4] = payloadSize >> 8;
+  Data[5] = payloadSize & 0xFF;
+
+  return dropBytes;
+}
+
+static void fixIFrame(uchar *Data, int &Length, bool StillImage)
+{
+  int done = 0;
+
+  while (done < Length) {
+        if (0x00 != Data[0] || 0x00 != Data[1] || 0x01 != Data[2]) {
+           esyslog("fixIFrame: PES start code not found at offset %d (data length: %d)!", done, Length);
+           return;
+           }
+
+        int lenPES = 6 + Data[4] * 256 + Data[5];
+        if (0xE0 == (0xF0 & Data[ 3 ])) { // video packet
+           int todo = Length - done;
+           int bite = (lenPES < todo) ? lenPES : todo;
+           if (0 == done) // first packet
+              fixIFrameHead(Data, bite);
+           else if (bite == todo) // last packet
+              Length -= fixIFrameTail(Data, bite, StillImage);
+           }
+        
+        done += lenPES;
+        Data += lenPES;
+        }
+}
+
+#define IPACKS 2048 // originally defined in remux.c
+
 void cDvbPlayer::Action(void)
 {
   uchar *b = NULL;
@@ -380,18 +463,25 @@  void cDvbPlayer::Action(void)
 
            // Read the next frame from the file:
 
-           if (!readFrame && (replayFile >= 0 || readIndex >= 0)) {
-              if (playMode != pmStill) {
+           if (playMode != pmStill && playMode != pmPause) {
+              if (!readFrame && (replayFile >= 0 || readIndex >= 0)) {
                  if (!nonBlockingFileReader->Reading()) {
                     if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward)) {
                        uchar FileNumber;
                        int FileOffset;
                        int Index = index->GetNextIFrame(readIndex, playDir == pdForward, &FileNumber, &FileOffset, &Length, true);
                        if (Index >= 0) {
+                          Length += IPACKS; // fixIFrame needs next video packet
                           if (!NextFile(FileNumber, FileOffset))
                              continue;
                           }
                        else {
+//                          // hit end of recording: signal end of file but don't change playMode
+//                          if (playDir == pdForward) {
+//                             readIndex = -1;
+//                             eof = true;
+//                             continue;
+//                             }
                           // hit begin of recording: wait for device buffers to drain
                           // before changing play mode:
                           if (!DeviceFlush(100))
@@ -428,6 +518,8 @@  void cDvbPlayer::Action(void)
                     }
                  int r = nonBlockingFileReader->Read(replayFile, b, Length);
                  if (r > 0) {
+                    if (playMode == pmFast || (playMode == pmSlow && playDir == pdBackward))
+                       fixIFrame(b, r, false);
                     readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer
                     b = NULL;
                     }
@@ -438,16 +530,16 @@  void cDvbPlayer::Action(void)
                     break;
                     }
                  }
-              else
-                 cCondWait::SleepMs(3); // this keeps the CPU load low
-              }
 
-           // Store the frame in the buffer:
+              // Store the frame in the buffer:
 
-           if (readFrame) {
-              if (ringBuffer->Put(readFrame))
-                 readFrame = NULL;
+              if (readFrame) {
+                 if (ringBuffer->Put(readFrame))
+                    readFrame = NULL;
+                 }
               }
+           else
+              cCondWait::SleepMs(3); // this keeps the CPU load low
 
            // Get the next frame from the buffer:
 
@@ -659,11 +751,13 @@  void cDvbPlayer::Goto(int Index, bool St
      int FileOffset, Length;
      Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
      if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
+        Length += IPACKS; // fixIFrame needs next video packet
         uchar b[MAXFRAMESIZE];
         int r = ReadFrame(replayFile, b, Length, sizeof(b));
         if (r > 0) {
            if (playMode == pmPause)
               DevicePlay();
+           fixIFrame(b, r, true);
            DeviceStillPicture(b, r);
            }
         playMode = pmStill;