vdr-xine: what's wrong with this piece of code-- threadingissue?
Commit Message
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.
@@ -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;