1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Adapted frame detection to driver 0.8+

This commit is contained in:
Klaus Schmidinger 2001-01-07 17:00:50 +01:00
parent 05c61fe624
commit 7c79f61dd5
4 changed files with 126 additions and 60 deletions

View File

@ -320,7 +320,8 @@ Video Disk Recorder Revision History
the DVB/driver directory. the DVB/driver directory.
Old recordings (in AV_PES mode) can still be replayed (as long as the driver Old recordings (in AV_PES mode) can still be replayed (as long as the driver
still supports replaying AV_PES files). The only limitation with this is that still supports replaying AV_PES files). The only limitation with this is that
in fast forward/back mode the picture may be slightly distorted. in fast forward/back mode the picture may be slightly distorted and there may
be sound fragments.
- The EPG data is now dumped into the file /video/epg.data every ten minutes. - The EPG data is now dumped into the file /video/epg.data every ten minutes.
Use the Perl script 'epg2html.pl' to convert the raw EPG data into a simple Use the Perl script 'epg2html.pl' to convert the raw EPG data into a simple
HTML programme listing. HTML programme listing.

170
dvbapi.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.c 1.44 2000/12/25 15:18:02 kls Exp $ * $Id: dvbapi.c 1.45 2001/01/07 17:00:50 kls Exp $
*/ */
#include "dvbapi.h" #include "dvbapi.h"
@ -45,8 +45,10 @@ extern "C" {
#define B_FRAME 3 #define B_FRAME 3
// Start codes: // Start codes:
#define SC_PICTURE 0x00 #define SC_PICTURE 0x00 // "picture header"
#define SC_BLOCK 0xBA #define SC_SEQU 0xB3 // "sequence header"
#define SC_PHEAD 0xBA // "pack header"
#define SC_SHEAD 0xBB // "system header"
#define SC_AUDIO 0xC0 #define SC_AUDIO 0xC0
#define SC_VIDEO 0xE0 #define SC_VIDEO 0xE0
@ -409,12 +411,12 @@ protected:
int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap! int Readable(void) { return (tail >= head) ? size - tail - (head ? 0 : 1) : head - tail - 1; } // keep a 1 byte gap!
int Writeable(void) { return (tail >= head) ? tail - head : size - head; } int Writeable(void) { return (tail >= head) ? tail - head : size - head; }
int Byte(int Offset); int Byte(int Offset);
void Set(int Offset, int Length, int Value); bool Set(int Offset, int Length, int Value);
protected: protected:
int GetStartCode(int Offset) { return (Byte(Offset) == 0x00 && Byte(Offset + 1) == 0x00 && Byte(Offset + 2) == 0x01) ? Byte(Offset + 3) : -1; } int GetStartCode(int Offset) { return (Byte(Offset) == 0x00 && Byte(Offset + 1) == 0x00 && Byte(Offset + 2) == 0x01) ? Byte(Offset + 3) : -1; }
int GetPictureType(int Offset) { return (Byte(Offset + 5) >> 3) & 0x07; } int GetPictureType(int Offset) { return (Byte(Offset + 5) >> 3) & 0x07; }
int FindStartCode(uchar Code, int Offset = 0); int FindStartCode(uchar Code, int Offset = 0);
int GetAudioPacketLength(int Offset = 0); int GetPacketLength(int Offset = 0);
public: public:
cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0); cRingBuffer(int *InFile, int *OutFile, int Size, int FreeLimit = 0, int AvailLimit = 0);
virtual ~cRingBuffer(); virtual ~cRingBuffer();
@ -459,7 +461,7 @@ int cRingBuffer::Byte(int Offset)
return -1; return -1;
} }
void cRingBuffer::Set(int Offset, int Length, int Value) bool cRingBuffer::Set(int Offset, int Length, int Value)
{ {
if (buffer && Offset + Length <= Available() ) { if (buffer && Offset + Length <= Available() ) {
Offset += head; Offset += head;
@ -469,7 +471,9 @@ void cRingBuffer::Set(int Offset, int Length, int Value)
buffer[Offset] = Value; buffer[Offset] = Value;
Offset++; Offset++;
} }
return true;
} }
return false;
} }
void cRingBuffer::Skip(int n) void cRingBuffer::Skip(int n)
@ -598,15 +602,15 @@ int cRingBuffer::FindStartCode(uchar Code, int Offset)
int c = GetStartCode(Offset + i); int c = GetStartCode(Offset + i);
if (c == Code) if (c == Code)
return i; return i;
if (i > 0 && c == SC_BLOCK) if (i > 0 && c == SC_PHEAD)
break; // found another block start while looking for a different code break; // found another block start while looking for a different code
} }
return -1; return -1;
} }
int cRingBuffer::GetAudioPacketLength(int Offset) int cRingBuffer::GetPacketLength(int Offset)
{ {
// Returns the entire length of the audio packet starting at offset. // Returns the entire length of the packet starting at offset.
return (Byte(Offset + 4) << 8) + Byte(Offset + 5) + 6; return (Byte(Offset + 4) << 8) + Byte(Offset + 5) + 6;
} }
@ -729,6 +733,7 @@ private:
bool ok, synced, stop; bool ok, synced, stop;
time_t lastDiskSpaceCheck; time_t lastDiskSpaceCheck;
bool RunningLowOnDiskSpace(void); bool RunningLowOnDiskSpace(void);
int ScanVideoPacket(int *PictureType, int Offset);
int Synchronize(void); int Synchronize(void);
bool NextFile(void); bool NextFile(void);
virtual int Write(int Max = -1); virtual int Write(int Max = -1);
@ -807,40 +812,81 @@ bool cRecordBuffer::RunningLowOnDiskSpace(void)
return false; return false;
} }
int cRecordBuffer::ScanVideoPacket(int *PictureType, int Offset)
{
// Scans the video packet starting at Offset and returns its length.
// If the return value is -1 the packet was not completely in the buffer.
int Length = GetPacketLength(Offset);
if (Length <= Available()) {
for (int i = Offset; i < Offset + Length; i++) {
if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) {
switch (Byte(i + 3)) {
case SC_PICTURE: *PictureType = GetPictureType(i);
return Length;
}
}
}
*PictureType = NO_PICTURE;
return Length;
}
return -1;
}
int cRecordBuffer::Synchronize(void) int cRecordBuffer::Synchronize(void)
{ {
// Positions to the start of a data block (skipping everything up to // Positions to the start of a data block (skipping everything up to
// an I-frame if not synced) and returns the block length. // an I-frame if not synced) and returns the block length.
int LastPackHeader = -1;
pictureType = NO_PICTURE; pictureType = NO_PICTURE;
bool Block = false;
for (int i = 0; Available() > MINVIDEODATA && i < MINVIDEODATA; i++) { for (int i = 0; Available() > MINVIDEODATA && i < MINVIDEODATA; i++) {
if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) { if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) {
switch (Byte(i + 3)) { switch (Byte(i + 3)) {
case SC_BLOCK: if (Block && synced) case SC_PHEAD: LastPackHeader = i;
return i; // found a block, so return its length
if (i) {
Skip(i);
if (synced)
esyslog(LOG_ERR, "ERROR: skipped %d bytes", i);
i = 0;
}
Block = true;
break; break;
case SC_PICTURE: if (Block) { case SC_VIDEO: {
pictureType = GetPictureType(i); int pt = NO_PICTURE;
switch (pictureType) { int l = ScanVideoPacket(&pt, i);
case I_FRAME: synced = true; if (l < 0)
case P_FRAME: return 0; // no useful data found, wait for more
case B_FRAME: break; if (pt != NO_PICTURE) {
default: esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pictureType); if (pt < I_FRAME || B_FRAME < pt) {
pictureType = NO_PICTURE; esyslog(LOG_ERR, "ERROR: unknown picture type '%d'", pt);
}
else if (pictureType == NO_PICTURE) {
if (!synced) {
if (LastPackHeader == 0) {
if (pt == I_FRAME)
synced = true;
}
else if (LastPackHeader > 0) {
Skip(LastPackHeader);
LastPackHeader = -1;
i = 0;
break;
}
else { // LastPackHeader < 0
Skip(i + l);
i = 0;
break;
}
}
if (synced)
pictureType = pt;
}
else if (LastPackHeader > 0)
return LastPackHeader;
else
return i;
} }
} i += l - 1; // -1 to compensate for i++ in the loop!
else LastPackHeader = -1;
esyslog(LOG_ERR, "ERROR: picture header outside of block"); }
break; break;
case SC_AUDIO: i += GetAudioPacketLength(i) - 1; // -1 to compensate for i++ in the loop! case SC_AUDIO: i += GetPacketLength(i) - 1; // -1 to compensate for i++ in the loop!
break; break;
} }
} }
@ -919,12 +965,13 @@ private:
int replayFile; int replayFile;
eReplayMode mode; eReplayMode mode;
int lastIndex, stillIndex; int lastIndex, stillIndex;
int brakeCounter, stillCounter; int brakeCounter;
eReplayCmd command; eReplayCmd command;
bool active; bool active;
bool NextFile(uchar FileNumber = 0, int FileOffset = -1); bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
void Close(void); void Close(void);
void SetCmd(eReplayCmd Cmd) { LOCK_THREAD; command = Cmd; } void SetCmd(eReplayCmd Cmd) { LOCK_THREAD; command = Cmd; }
void SetTemporalReference(void);
protected: protected:
virtual void Action(void); virtual void Action(void);
public: public:
@ -941,7 +988,7 @@ public:
void Backward(void) { SetCmd(rcBackward); } void Backward(void) { SetCmd(rcBackward); }
int SkipFrames(int Frames); int SkipFrames(int Frames);
void SkipSeconds(int Seconds); void SkipSeconds(int Seconds);
void Goto(int Position); void Goto(int Position, bool Still = false);
void GetIndex(int &Current, int &Total, bool SnapToIFrame = false); void GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
}; };
@ -954,7 +1001,7 @@ cReplayBuffer::cReplayBuffer(int *OutFile, const char *FileName)
videoDev = *OutFile; videoDev = *OutFile;
replayFile = fileName.Open(); replayFile = fileName.Open();
mode = rmPlay; mode = rmPlay;
brakeCounter = stillCounter = 0; brakeCounter = 0;
command = rcNone; command = rcNone;
lastIndex = stillIndex = -1; lastIndex = stillIndex = -1;
active = false; active = false;
@ -1154,18 +1201,18 @@ void cReplayBuffer::SkipSeconds(int Seconds)
} }
} }
void cReplayBuffer::Goto(int Index) void cReplayBuffer::Goto(int Index, bool Still)
{ {
LOCK_THREAD; LOCK_THREAD;
command = rcStill; if (Still)
command = rcStill;
if (++Index <= 0) if (++Index <= 0)
Index = 1; // not '0', to allow GetNextIFrame() below to work! Index = 1; // not '0', to allow GetNextIFrame() below to work!
uchar FileNumber; uchar FileNumber;
int FileOffset; int FileOffset;
if ((stillIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset)) >= 0) if ((stillIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset)) >= 0)
NextFile(FileNumber, FileOffset); NextFile(FileNumber, FileOffset);
stillCounter = 20; // apparently we need to repeat the still frame several times to flush all buffers?!
SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER); SetPlayMode(videoDev, VID_PLAY_CLEAR_BUFFER);
Clear(); Clear();
} }
@ -1206,6 +1253,23 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
return replayFile >= 0; return replayFile >= 0;
} }
void cReplayBuffer::SetTemporalReference(void)
{
for (int i = 0; i < Available(); i++) {
if (Byte(i) == 0 && Byte(i + 1) == 0 && Byte(i + 2) == 1) {
switch (Byte(i + 3)) {
case SC_PICTURE: {
unsigned short m = (Byte(i + 4) << 8) | Byte(i + 5);
m &= 0x003F;
Set(i + 4, 1, m >> 8);
Set(i + 5, 1, m & 0xFF);
}
return;
}
}
}
}
int cReplayBuffer::Read(int Max = -1) int cReplayBuffer::Read(int Max = -1)
{ {
if (mode != rmPlay) { if (mode != rmPlay) {
@ -1213,18 +1277,14 @@ int cReplayBuffer::Read(int Max = -1)
if (Available()) if (Available())
return 0; // write out the entire block return 0; // write out the entire block
if (mode == rmStill) { if (mode == rmStill) {
if (stillCounter > 0) { uchar FileNumber;
stillCounter--; int FileOffset, Length;
uchar FileNumber; if (index->GetNextIFrame(stillIndex + 1, false, &FileNumber, &FileOffset, &Length) >= 0) {
int FileOffset, Length; if (!NextFile(FileNumber, FileOffset))
if (index->GetNextIFrame(stillIndex + 1, false, &FileNumber, &FileOffset, &Length) >= 0) { return -1;
if (!NextFile(FileNumber, FileOffset)) Max = Length;
return -1;
Max = Length;
}
} }
else command = rcPause;
command = rcPause;
} }
else { else {
int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset); int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset);
@ -1268,9 +1328,13 @@ int cReplayBuffer::Read(int Max = -1)
} while (readin < Max && Free() > 0); } while (readin < Max && Free() > 0);
if (mode != rmPlay) { if (mode != rmPlay) {
// delete the audio data in modes other than rmPlay: // delete the audio data in modes other than rmPlay:
int AudioOffset = FindStartCode(SC_AUDIO); int AudioOffset, StartOffset = 0;
if (AudioOffset >= 0) while ((AudioOffset = FindStartCode(SC_AUDIO, StartOffset)) >= 0) {
Set(AudioOffset, GetAudioPacketLength(AudioOffset), 0); if (!Set(StartOffset + AudioOffset, GetPacketLength(StartOffset + AudioOffset), 0))
break; // to be able to replay old AV_PES recordings!
StartOffset += AudioOffset;
}
SetTemporalReference();
} }
return readin; return readin;
} }
@ -2319,10 +2383,10 @@ bool cDvbApi::GetIndex(int &Current, int &Total, bool SnapToIFrame)
return false; return false;
} }
void cDvbApi::Goto(int Position) void cDvbApi::Goto(int Position, bool Still)
{ {
if (replayBuffer) if (replayBuffer)
replayBuffer->Goto(Position); replayBuffer->Goto(Position, Still);
} }
// --- cEITScanner ----------------------------------------------------------- // --- cEITScanner -----------------------------------------------------------

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: dvbapi.h 1.29 2000/12/25 15:17:03 kls Exp $ * $Id: dvbapi.h 1.30 2001/01/07 15:56:10 kls Exp $
*/ */
#ifndef __DVBAPI_H #ifndef __DVBAPI_H
@ -239,8 +239,9 @@ public:
bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false); bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
// Returns the current and total frame index, optionally snapped to the // Returns the current and total frame index, optionally snapped to the
// nearest I-frame. // nearest I-frame.
void Goto(int Index); void Goto(int Index, bool Still = false);
// Positions to the given index and displays that frame as a still picture. // Positions to the given index and displays that frame as a still picture
// if Still is true.
}; };
class cEITScanner { class cEITScanner {

6
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.56 2000/12/25 15:18:32 kls Exp $ * $Id: menu.c 1.57 2001/01/07 15:59:56 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -2155,7 +2155,7 @@ void cReplayControl::MarkJump(bool Forward)
if (dvbApi->GetIndex(Current, Total)) { if (dvbApi->GetIndex(Current, Total)) {
cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current); cMark *m = Forward ? marks.GetNext(Current) : marks.GetPrev(Current);
if (m) if (m)
dvbApi->Goto(m->position); dvbApi->Goto(m->position, true);
} }
} }
@ -2175,7 +2175,7 @@ void cReplayControl::MarkMove(bool Forward)
if ((m2 = marks.Prev(m)) != NULL && m2->position >= p) if ((m2 = marks.Prev(m)) != NULL && m2->position >= p)
return; return;
} }
dvbApi->Goto(m->position = p); dvbApi->Goto(m->position = p, true);
marks.Save(); marks.Save();
} }
} }