mirror of
https://github.com/VDR4Arch/vdr.git
synced 2023-10-10 13:36:52 +02:00
Replaced cBackTrace with cPtsIndex
This commit is contained in:
parent
4c0ab3d3e7
commit
e7ea3b3c70
@ -662,6 +662,8 @@ Oliver Endriss <o.endriss@gmx.de>
|
|||||||
Transfer Mode
|
Transfer Mode
|
||||||
for providing a driver patch that allows direct replaying of TS video on full-featured
|
for providing a driver patch that allows direct replaying of TS video on full-featured
|
||||||
DVB cards
|
DVB cards
|
||||||
|
for improving the firmware of FF DVB cards to allow getting the current STC value
|
||||||
|
even in trick modes
|
||||||
|
|
||||||
Reinhard Walter Buchner <rw.buchner@freenet.de>
|
Reinhard Walter Buchner <rw.buchner@freenet.de>
|
||||||
for adding some satellites to 'sources.conf'
|
for adding some satellites to 'sources.conf'
|
||||||
|
13
HISTORY
13
HISTORY
@ -5979,7 +5979,7 @@ Video Disk Recorder Revision History
|
|||||||
cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this
|
cDevice class reimplements PlayTs() or PlayPes(), it also needs to make sure this
|
||||||
new function works as expected.
|
new function works as expected.
|
||||||
|
|
||||||
2009-02-28: Version 1.7.5
|
2009-03-13: Version 1.7.5
|
||||||
|
|
||||||
- Fixed a hangup when replaying a TS recording with subtitles activated (reported
|
- Fixed a hangup when replaying a TS recording with subtitles activated (reported
|
||||||
by Timo Helkio).
|
by Timo Helkio).
|
||||||
@ -5989,3 +5989,14 @@ Video Disk Recorder Revision History
|
|||||||
Ahrenberg).
|
Ahrenberg).
|
||||||
- Updated the Italian OSD texts (thanks to Diego Pierotto).
|
- Updated the Italian OSD texts (thanks to Diego Pierotto).
|
||||||
- Added cRecordingInfo::GetEvent() (thanks to Marcel Unbehaun).
|
- Added cRecordingInfo::GetEvent() (thanks to Marcel Unbehaun).
|
||||||
|
- Improved synchronizing the progress display, trick modes and subtitle display
|
||||||
|
to the actual audio/video. This now works independent of any buffer sizes the
|
||||||
|
output device might use.
|
||||||
|
+ The cBackTrace class has been replaced with cPtsIndex, which keeps track
|
||||||
|
of the PTS timestamps of recently played frames.
|
||||||
|
+ cDevice::GetSTC() is now required to deliver the STC even in trick modes.
|
||||||
|
It is sufficient if it returns the PTS of the most recently presented
|
||||||
|
audio/video frame.
|
||||||
|
+ The full-featured DVB cards need an improved firmware in order to return
|
||||||
|
proper STC values in trick modes (thanks to Oliver Endriss for enhancing the
|
||||||
|
av7110 firmware).
|
||||||
|
9
device.h
9
device.h
@ -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: device.h 2.6 2009/01/25 11:04:39 kls Exp $
|
* $Id: device.h 2.7 2009/03/01 11:20:34 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DEVICE_H
|
#ifndef __DEVICE_H
|
||||||
@ -543,6 +543,13 @@ public:
|
|||||||
///< Gets the current System Time Counter, which can be used to
|
///< Gets the current System Time Counter, which can be used to
|
||||||
///< synchronize audio and video. If this device is unable to
|
///< synchronize audio and video. If this device is unable to
|
||||||
///< provide the STC, -1 will be returned.
|
///< provide the STC, -1 will be returned.
|
||||||
|
///< The value returned doesn't need to be an actual "clock" value,
|
||||||
|
///< it is sufficient if it holds the PTS (Presentation Time Stamp) of
|
||||||
|
///< the most recently presented frame. A proper value must be returned
|
||||||
|
///< in normal replay mode as well as in any trick modes (like slow motion,
|
||||||
|
///< fast forward/rewind).
|
||||||
|
///< Only the lower 32 bit of this value are actually used, since some
|
||||||
|
///< devices can't handle the msb correctly.
|
||||||
virtual bool IsPlayingVideo(void) const { return isPlayingVideo; }
|
virtual bool IsPlayingVideo(void) const { return isPlayingVideo; }
|
||||||
///< \return Returns true if the currently attached player has delivered
|
///< \return Returns true if the currently attached player has delivered
|
||||||
///< any video packets.
|
///< any video packets.
|
||||||
|
235
dvbplayer.c
235
dvbplayer.c
@ -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: dvbplayer.c 2.3 2009/01/25 11:11:39 kls Exp $
|
* $Id: dvbplayer.c 2.4 2009/03/13 14:42:56 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dvbplayer.h"
|
#include "dvbplayer.h"
|
||||||
@ -16,59 +16,69 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "tools.h"
|
#include "tools.h"
|
||||||
|
|
||||||
// --- cBackTrace ------------------------------------------------------------
|
// --- cPtsIndex -------------------------------------------------------------
|
||||||
|
|
||||||
#define AVG_FRAME_SIZE 15000 // an assumption about the average frame size
|
#define PTSINDEX_ENTRIES 100
|
||||||
#define DVB_BUF_SIZE (256 * 1024) // an assumption about the dvb firmware buffer size
|
|
||||||
#define BACKTRACE_ENTRIES (DVB_BUF_SIZE / AVG_FRAME_SIZE + 20) // how many entries are needed to backtrace buffer contents
|
|
||||||
|
|
||||||
class cBackTrace {
|
class cPtsIndex {
|
||||||
private:
|
private:
|
||||||
int index[BACKTRACE_ENTRIES];
|
struct tPtsIndex {
|
||||||
int length[BACKTRACE_ENTRIES];
|
uint32_t pts; // no need for 33 bit - some devices don't even supply the msb
|
||||||
int pos, num;
|
int index;
|
||||||
|
};
|
||||||
|
tPtsIndex pi[PTSINDEX_ENTRIES];
|
||||||
|
int w, r;
|
||||||
|
int lastFound;
|
||||||
|
cMutex mutex;
|
||||||
public:
|
public:
|
||||||
cBackTrace(void);
|
cPtsIndex(void);
|
||||||
void Clear(void);
|
void Clear(void);
|
||||||
void Add(int Index, int Length);
|
void Put(uint32_t Pts, int Index);
|
||||||
int Get(bool Forward);
|
int FindIndex(uint32_t Pts);
|
||||||
};
|
};
|
||||||
|
|
||||||
cBackTrace::cBackTrace(void)
|
cPtsIndex::cPtsIndex(void)
|
||||||
{
|
{
|
||||||
|
lastFound = 0;
|
||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void cBackTrace::Clear(void)
|
void cPtsIndex::Clear(void)
|
||||||
{
|
{
|
||||||
pos = num = 0;
|
cMutexLock MutexLock(&mutex);
|
||||||
|
w = r = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cBackTrace::Add(int Index, int Length)
|
void cPtsIndex::Put(uint32_t Pts, int Index)
|
||||||
{
|
{
|
||||||
index[pos] = Index;
|
cMutexLock MutexLock(&mutex);
|
||||||
length[pos] = Length;
|
pi[w].pts = Pts;
|
||||||
if (++pos >= BACKTRACE_ENTRIES)
|
pi[w].index = Index;
|
||||||
pos = 0;
|
w = (w + 1) % PTSINDEX_ENTRIES;
|
||||||
if (num < BACKTRACE_ENTRIES)
|
if (w == r)
|
||||||
num++;
|
r = (r + 1) % PTSINDEX_ENTRIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cBackTrace::Get(bool Forward)
|
int cPtsIndex::FindIndex(uint32_t Pts)
|
||||||
{
|
{
|
||||||
int p = pos;
|
cMutexLock MutexLock(&mutex);
|
||||||
int n = num;
|
if (w == r)
|
||||||
int l = DVB_BUF_SIZE + (Forward ? 0 : 256 * 1024); //XXX (256 * 1024) == DVB_BUF_SIZE ???
|
return lastFound; // list is empty, let's not jump way off the last known position
|
||||||
int i = -1;
|
uint32_t Delta = 0xFFFFFFFF;
|
||||||
|
int Index = -1;
|
||||||
while (n && l > 0) {
|
for (int i = w; i != r; ) {
|
||||||
if (--p < 0)
|
if (--i < 0)
|
||||||
p = BACKTRACE_ENTRIES - 1;
|
i = PTSINDEX_ENTRIES - 1;
|
||||||
i = index[p] - 1;
|
uint32_t d = pi[i].pts < Pts ? Pts - pi[i].pts : pi[i].pts - Pts;
|
||||||
l -= length[p];
|
if (d > 0x7FFFFFFF)
|
||||||
n--;
|
d = 0xFFFFFFFF - d; // handle rollover
|
||||||
}
|
if (d < Delta) {
|
||||||
return i;
|
Delta = d;
|
||||||
|
Index = pi[i].index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastFound = Index;
|
||||||
|
return Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- cNonBlockingFileReader ------------------------------------------------
|
// --- cNonBlockingFileReader ------------------------------------------------
|
||||||
@ -183,8 +193,8 @@ bool cNonBlockingFileReader::WaitForDataMs(int msToWait)
|
|||||||
|
|
||||||
#define PLAYERBUFSIZE MEGABYTE(1)
|
#define PLAYERBUFSIZE MEGABYTE(1)
|
||||||
|
|
||||||
// The number of seconds to back up when resuming an interrupted replay session:
|
#define RESUMEBACKUP 10 // number of seconds to back up when resuming an interrupted replay session
|
||||||
#define RESUMEBACKUP 10
|
#define MAXSTUCKATEND 3 // max. number of seconds to wait in case the device doesn't play the last frame
|
||||||
|
|
||||||
class cDvbPlayer : public cPlayer, cThread {
|
class cDvbPlayer : public cPlayer, cThread {
|
||||||
private:
|
private:
|
||||||
@ -193,7 +203,7 @@ private:
|
|||||||
static int Speeds[];
|
static int Speeds[];
|
||||||
cNonBlockingFileReader *nonBlockingFileReader;
|
cNonBlockingFileReader *nonBlockingFileReader;
|
||||||
cRingBufferFrame *ringBuffer;
|
cRingBufferFrame *ringBuffer;
|
||||||
cBackTrace *backTrace;
|
cPtsIndex ptsIndex;
|
||||||
cFileName *fileName;
|
cFileName *fileName;
|
||||||
cIndexFile *index;
|
cIndexFile *index;
|
||||||
cUnbufferedFile *replayFile;
|
cUnbufferedFile *replayFile;
|
||||||
@ -204,7 +214,8 @@ private:
|
|||||||
ePlayModes playMode;
|
ePlayModes playMode;
|
||||||
ePlayDirs playDir;
|
ePlayDirs playDir;
|
||||||
int trickSpeed;
|
int trickSpeed;
|
||||||
int readIndex, writeIndex;
|
int readIndex;
|
||||||
|
bool readIndependent;
|
||||||
cFrame *readFrame;
|
cFrame *readFrame;
|
||||||
cFrame *playFrame;
|
cFrame *playFrame;
|
||||||
void TrickSpeed(int Increment);
|
void TrickSpeed(int Increment);
|
||||||
@ -242,7 +253,6 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
|
|||||||
{
|
{
|
||||||
nonBlockingFileReader = NULL;
|
nonBlockingFileReader = NULL;
|
||||||
ringBuffer = NULL;
|
ringBuffer = NULL;
|
||||||
backTrace = NULL;
|
|
||||||
index = NULL;
|
index = NULL;
|
||||||
cRecording Recording(FileName);
|
cRecording Recording(FileName);
|
||||||
framesPerSecond = Recording.FramesPerSecond();
|
framesPerSecond = Recording.FramesPerSecond();
|
||||||
@ -252,7 +262,8 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
|
|||||||
playMode = pmPlay;
|
playMode = pmPlay;
|
||||||
playDir = pdForward;
|
playDir = pdForward;
|
||||||
trickSpeed = NORMAL_SPEED;
|
trickSpeed = NORMAL_SPEED;
|
||||||
readIndex = writeIndex = -1;
|
readIndex = -1;
|
||||||
|
readIndependent = false;
|
||||||
readFrame = NULL;
|
readFrame = NULL;
|
||||||
playFrame = NULL;
|
playFrame = NULL;
|
||||||
isyslog("replay %s", FileName);
|
isyslog("replay %s", FileName);
|
||||||
@ -269,17 +280,15 @@ cDvbPlayer::cDvbPlayer(const char *FileName)
|
|||||||
delete index;
|
delete index;
|
||||||
index = NULL;
|
index = NULL;
|
||||||
}
|
}
|
||||||
backTrace = new cBackTrace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cDvbPlayer::~cDvbPlayer()
|
cDvbPlayer::~cDvbPlayer()
|
||||||
{
|
{
|
||||||
Detach();
|
|
||||||
Save();
|
Save();
|
||||||
|
Detach();
|
||||||
delete readFrame; // might not have been stored in the buffer in Action()
|
delete readFrame; // might not have been stored in the buffer in Action()
|
||||||
delete index;
|
delete index;
|
||||||
delete fileName;
|
delete fileName;
|
||||||
delete backTrace;
|
|
||||||
delete ringBuffer;
|
delete ringBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,13 +317,13 @@ void cDvbPlayer::Empty(void)
|
|||||||
LOCK_THREAD;
|
LOCK_THREAD;
|
||||||
if (nonBlockingFileReader)
|
if (nonBlockingFileReader)
|
||||||
nonBlockingFileReader->Clear();
|
nonBlockingFileReader->Clear();
|
||||||
if ((readIndex = backTrace->Get(playDir == pdForward)) < 0)
|
if (!firstPacket) // don't set the readIndex twice if Empty() is called more than once
|
||||||
readIndex = writeIndex;
|
readIndex = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
delete readFrame; // might not have been stored in the buffer in Action()
|
delete readFrame; // might not have been stored in the buffer in Action()
|
||||||
readFrame = NULL;
|
readFrame = NULL;
|
||||||
playFrame = NULL;
|
playFrame = NULL;
|
||||||
ringBuffer->Clear();
|
ringBuffer->Clear();
|
||||||
backTrace->Clear();
|
ptsIndex.Clear();
|
||||||
DeviceClear();
|
DeviceClear();
|
||||||
firstPacket = true;
|
firstPacket = true;
|
||||||
}
|
}
|
||||||
@ -346,7 +355,7 @@ int cDvbPlayer::Resume(void)
|
|||||||
bool cDvbPlayer::Save(void)
|
bool cDvbPlayer::Save(void)
|
||||||
{
|
{
|
||||||
if (index) {
|
if (index) {
|
||||||
int Index = writeIndex;
|
int Index = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
Index -= int(round(RESUMEBACKUP * framesPerSecond));
|
Index -= int(round(RESUMEBACKUP * framesPerSecond));
|
||||||
if (Index > 0)
|
if (Index > 0)
|
||||||
@ -384,6 +393,7 @@ void cDvbPlayer::Action(void)
|
|||||||
int Length = 0;
|
int Length = 0;
|
||||||
bool Sleep = false;
|
bool Sleep = false;
|
||||||
bool WaitingForData = false;
|
bool WaitingForData = false;
|
||||||
|
time_t StuckAtEnd = 0;
|
||||||
|
|
||||||
while (Running() && (NextFile() || readIndex >= 0 || ringBuffer->Available() || !DeviceFlush(100))) {
|
while (Running() && (NextFile() || readIndex >= 0 || ringBuffer->Available() || !DeviceFlush(100))) {
|
||||||
if (Sleep) {
|
if (Sleep) {
|
||||||
@ -397,6 +407,8 @@ void cDvbPlayer::Action(void)
|
|||||||
if (DevicePoll(Poller, 100)) {
|
if (DevicePoll(Poller, 100)) {
|
||||||
|
|
||||||
LOCK_THREAD;
|
LOCK_THREAD;
|
||||||
|
bool HitBegin = false;
|
||||||
|
bool HitEnd = false;
|
||||||
|
|
||||||
// Read the next frame from the file:
|
// Read the next frame from the file:
|
||||||
|
|
||||||
@ -408,8 +420,9 @@ void cDvbPlayer::Action(void)
|
|||||||
off_t FileOffset;
|
off_t FileOffset;
|
||||||
bool TimeShiftMode = index->IsStillRecording();
|
bool TimeShiftMode = index->IsStillRecording();
|
||||||
int Index = -1;
|
int Index = -1;
|
||||||
|
readIndependent = false;
|
||||||
if (DeviceHasIBPTrickSpeed() && playDir == pdForward) {
|
if (DeviceHasIBPTrickSpeed() && playDir == pdForward) {
|
||||||
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, NULL, &Length))
|
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length))
|
||||||
Index = readIndex + 1;
|
Index = readIndex + 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -417,42 +430,33 @@ void cDvbPlayer::Action(void)
|
|||||||
if (playDir != pdForward)
|
if (playDir != pdForward)
|
||||||
d = -d;
|
d = -d;
|
||||||
Index = index->GetNextIFrame(readIndex + d, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
|
Index = index->GetNextIFrame(readIndex + d, playDir == pdForward, &FileNumber, &FileOffset, &Length, TimeShiftMode);
|
||||||
|
readIndependent = true;
|
||||||
}
|
}
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
if (!NextFile(FileNumber, FileOffset)) {
|
readIndex = Index;
|
||||||
readIndex = Index;
|
if (!NextFile(FileNumber, FileOffset))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!TimeShiftMode && playDir == pdForward) {
|
if (playDir == pdForward) {
|
||||||
// hit end of recording: signal end of file but don't change playMode
|
if (!TimeShiftMode) {
|
||||||
readIndex = -1;
|
// hit end of recording: signal end of file but don't change playMode
|
||||||
eof = true;
|
eof = true;
|
||||||
continue;
|
HitEnd = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// hit begin of recording: wait for device buffers to drain
|
else
|
||||||
// before changing play mode:
|
HitBegin = true; // hit begin of recording - trigger wait until device has replayed the very first frame:
|
||||||
if (!DeviceFlush(100))
|
|
||||||
continue;
|
|
||||||
// can't call Play() here, because those functions may only be
|
|
||||||
// called from the foreground thread - and we also don't need
|
|
||||||
// to empty the buffer here
|
|
||||||
DevicePlay();
|
|
||||||
playMode = pmPlay;
|
|
||||||
playDir = pdForward;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
readIndex = Index;
|
|
||||||
}
|
}
|
||||||
else if (index) {
|
else if (index) {
|
||||||
uint16_t FileNumber;
|
uint16_t FileNumber;
|
||||||
off_t FileOffset;
|
off_t FileOffset;
|
||||||
readIndex++;
|
if (index->Get(readIndex + 1, &FileNumber, &FileOffset, &readIndependent, &Length) && NextFile(FileNumber, FileOffset))
|
||||||
if (!(index->Get(readIndex, &FileNumber, &FileOffset, NULL, &Length) && NextFile(FileNumber, FileOffset))) {
|
readIndex++;
|
||||||
readIndex = -1;
|
else {
|
||||||
eof = true;
|
eof = true;
|
||||||
continue;
|
HitEnd = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // allows replay even if the index file is missing
|
else // allows replay even if the index file is missing
|
||||||
@ -465,19 +469,24 @@ void cDvbPlayer::Action(void)
|
|||||||
}
|
}
|
||||||
b = MALLOC(uchar, Length);
|
b = MALLOC(uchar, Length);
|
||||||
}
|
}
|
||||||
int r = nonBlockingFileReader->Read(replayFile, b, Length);
|
if (!eof) {
|
||||||
if (r > 0) {
|
int r = nonBlockingFileReader->Read(replayFile, b, Length);
|
||||||
WaitingForData = false;
|
if (r > 0) {
|
||||||
readFrame = new cFrame(b, -r, ftUnknown, readIndex); // hands over b to the ringBuffer
|
WaitingForData = false;
|
||||||
b = NULL;
|
uint32_t Pts = 0;
|
||||||
}
|
if (readIndependent)
|
||||||
else if (r == 0)
|
Pts = isPesRecording ? PesGetPts(b) : TsGetPts(b, r);
|
||||||
eof = true;
|
readFrame = new cFrame(b, -r, ftUnknown, readIndependent ? readIndex : -1, Pts); // hands over b to the ringBuffer
|
||||||
else if (r < 0 && errno == EAGAIN)
|
b = NULL;
|
||||||
WaitingForData = true;
|
}
|
||||||
else if (r < 0 && FATALERRNO) {
|
else if (r == 0)
|
||||||
LOG_ERROR;
|
eof = true;
|
||||||
break;
|
else if (r < 0 && errno == EAGAIN)
|
||||||
|
WaitingForData = true;
|
||||||
|
else if (r < 0 && FATALERRNO) {
|
||||||
|
LOG_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,6 +515,8 @@ void cDvbPlayer::Action(void)
|
|||||||
p = playFrame->Data();
|
p = playFrame->Data();
|
||||||
pc = playFrame->Count();
|
pc = playFrame->Count();
|
||||||
if (p) {
|
if (p) {
|
||||||
|
if (playFrame->Index() >= 0)
|
||||||
|
ptsIndex.Put(playFrame->Pts(), playFrame->Index());
|
||||||
if (firstPacket) {
|
if (firstPacket) {
|
||||||
if (isPesRecording) {
|
if (isPesRecording) {
|
||||||
PlayPes(NULL, 0);
|
PlayPes(NULL, 0);
|
||||||
@ -533,8 +544,6 @@ void cDvbPlayer::Action(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pc <= 0) {
|
if (pc <= 0) {
|
||||||
writeIndex = playFrame->Index();
|
|
||||||
backTrace->Add(playFrame->Index(), playFrame->Count());
|
|
||||||
ringBuffer->Drop(playFrame);
|
ringBuffer->Drop(playFrame);
|
||||||
playFrame = NULL;
|
playFrame = NULL;
|
||||||
p = NULL;
|
p = NULL;
|
||||||
@ -542,6 +551,31 @@ void cDvbPlayer::Action(void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
Sleep = true;
|
Sleep = true;
|
||||||
|
|
||||||
|
// Handle hitting begin/end of recording:
|
||||||
|
|
||||||
|
if (HitBegin || HitEnd) {
|
||||||
|
if (DeviceFlush(10)) // give device a chance to display the last frame
|
||||||
|
cCondWait::SleepMs(10); // don't get into a tight loop
|
||||||
|
}
|
||||||
|
if (HitBegin) {
|
||||||
|
if (ptsIndex.FindIndex(DeviceGetSTC()) <= 0) {
|
||||||
|
Empty();
|
||||||
|
DevicePlay();
|
||||||
|
playMode = pmPlay;
|
||||||
|
playDir = pdForward;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (HitEnd) {
|
||||||
|
if (ptsIndex.FindIndex(DeviceGetSTC()) >= readIndex)
|
||||||
|
break;
|
||||||
|
else if (!StuckAtEnd)
|
||||||
|
StuckAtEnd = time(NULL);
|
||||||
|
else if (time(NULL) - StuckAtEnd > MAXSTUCKATEND)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
StuckAtEnd = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -614,6 +648,7 @@ void cDvbPlayer::Forward(void)
|
|||||||
Pause();
|
Pause();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Empty();
|
||||||
// run into pmPause
|
// run into pmPause
|
||||||
case pmStill:
|
case pmStill:
|
||||||
case pmPause:
|
case pmPause:
|
||||||
@ -661,6 +696,7 @@ void cDvbPlayer::Backward(void)
|
|||||||
Pause();
|
Pause();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Empty();
|
||||||
// run into pmPause
|
// run into pmPause
|
||||||
case pmStill:
|
case pmStill:
|
||||||
case pmPause: {
|
case pmPause: {
|
||||||
@ -696,14 +732,14 @@ void cDvbPlayer::SkipSeconds(int Seconds)
|
|||||||
{
|
{
|
||||||
if (index && Seconds) {
|
if (index && Seconds) {
|
||||||
LOCK_THREAD;
|
LOCK_THREAD;
|
||||||
|
int Index = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
Empty();
|
Empty();
|
||||||
int Index = writeIndex;
|
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
Index = max(Index + SecondsToFrames(Seconds, framesPerSecond), 0);
|
Index = max(Index + SecondsToFrames(Seconds, framesPerSecond), 0);
|
||||||
if (Index > 0)
|
if (Index > 0)
|
||||||
Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true);
|
Index = index->GetNextIFrame(Index, false, NULL, NULL, NULL, true);
|
||||||
if (Index >= 0)
|
if (Index >= 0)
|
||||||
readIndex = writeIndex = Index - 1; // Action() will first increment it!
|
readIndex = Index - 1; // Action() will first increment it!
|
||||||
}
|
}
|
||||||
Play();
|
Play();
|
||||||
}
|
}
|
||||||
@ -727,25 +763,22 @@ void cDvbPlayer::Goto(int Index, bool Still)
|
|||||||
if (playMode == pmPause)
|
if (playMode == pmPause)
|
||||||
DevicePlay();
|
DevicePlay();
|
||||||
DeviceStillPicture(b, r);
|
DeviceStillPicture(b, r);
|
||||||
|
ptsIndex.Put(isPesRecording ? PesGetPts(b) : TsGetPts(b, r), Index);
|
||||||
}
|
}
|
||||||
playMode = pmStill;
|
playMode = pmStill;
|
||||||
}
|
}
|
||||||
readIndex = writeIndex = Index;
|
readIndex = Index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
bool cDvbPlayer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
||||||
{
|
{
|
||||||
if (index) {
|
if (index) {
|
||||||
if (playMode == pmStill)
|
Current = ptsIndex.FindIndex(DeviceGetSTC());
|
||||||
Current = max(readIndex, 0);
|
if (SnapToIFrame) {
|
||||||
else {
|
int i1 = index->GetNextIFrame(Current + 1, false);
|
||||||
Current = max(writeIndex, 0);
|
int i2 = index->GetNextIFrame(Current, true);
|
||||||
if (SnapToIFrame) {
|
Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2;
|
||||||
int i1 = index->GetNextIFrame(Current + 1, false);
|
|
||||||
int i2 = index->GetNextIFrame(Current, true);
|
|
||||||
Current = (abs(Current - i1) <= abs(Current - i2)) ? i1 : i2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Total = index->Last();
|
Total = index->Last();
|
||||||
return true;
|
return true;
|
||||||
|
3
player.h
3
player.h
@ -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: player.h 2.3 2009/01/25 11:03:44 kls Exp $
|
* $Id: player.h 2.4 2009/03/08 12:29:10 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PLAYER_H
|
#ifndef __PLAYER_H
|
||||||
@ -34,6 +34,7 @@ protected:
|
|||||||
void DeviceMute(void) { if (device) device->Mute(); }
|
void DeviceMute(void) { if (device) device->Mute(); }
|
||||||
void DeviceSetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) { if (device) device->SetVideoDisplayFormat(VideoDisplayFormat); }
|
void DeviceSetVideoDisplayFormat(eVideoDisplayFormat VideoDisplayFormat) { if (device) device->SetVideoDisplayFormat(VideoDisplayFormat); }
|
||||||
void DeviceStillPicture(const uchar *Data, int Length) { if (device) device->StillPicture(Data, Length); }
|
void DeviceStillPicture(const uchar *Data, int Length) { if (device) device->StillPicture(Data, Length); }
|
||||||
|
uint64_t DeviceGetSTC(void) { return device ? device->GetSTC() : -1; }
|
||||||
void Detach(void);
|
void Detach(void);
|
||||||
virtual void Activate(bool On) {}
|
virtual void Activate(bool On) {}
|
||||||
// This function is called right after the cPlayer has been attached to
|
// This function is called right after the cPlayer has been attached to
|
||||||
|
17
remux.c
17
remux.c
@ -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: remux.c 2.13 2009/01/24 13:44:45 kls Exp $
|
* $Id: remux.c 2.14 2009/03/08 12:12:17 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "remux.h"
|
#include "remux.h"
|
||||||
@ -109,6 +109,21 @@ void cRemux::SetBrokenLink(uchar *Data, int Length)
|
|||||||
dsyslog("SetBrokenLink: no video packet in frame");
|
dsyslog("SetBrokenLink: no video packet in frame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Some TS handling tools ------------------------------------------------
|
||||||
|
|
||||||
|
int64_t TsGetPts(const uchar *p, int l)
|
||||||
|
{
|
||||||
|
// Find the first packet with a PTS and use it:
|
||||||
|
while (l > 0) {
|
||||||
|
const uchar *d = p;
|
||||||
|
if (TsPayloadStart(d) && TsGetPayload(&d) && PesHasPts(d))
|
||||||
|
return PesGetPts(d);
|
||||||
|
p += TS_SIZE;
|
||||||
|
l -= TS_SIZE;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// --- cPatPmtGenerator ------------------------------------------------------
|
// --- cPatPmtGenerator ------------------------------------------------------
|
||||||
|
|
||||||
cPatPmtGenerator::cPatPmtGenerator(cChannel *Channel)
|
cPatPmtGenerator::cPatPmtGenerator(cChannel *Channel)
|
||||||
|
6
remux.h
6
remux.h
@ -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: remux.h 2.7 2009/01/24 13:38:10 kls Exp $
|
* $Id: remux.h 2.8 2009/03/08 12:05:12 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __REMUX_H
|
#ifndef __REMUX_H
|
||||||
@ -101,6 +101,10 @@ inline int TsGetAdaptationField(const uchar *p)
|
|||||||
return TsHasAdaptationField(p) ? p[5] : 0x00;
|
return TsHasAdaptationField(p) ? p[5] : 0x00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The following functions all take a pointer to a sequence of complete TS packets.
|
||||||
|
|
||||||
|
int64_t TsGetPts(const uchar *p, int l);
|
||||||
|
|
||||||
// Some PES handling tools:
|
// Some PES handling tools:
|
||||||
// The following functions that take a pointer to PES data all assume that
|
// The following functions that take a pointer to PES data all assume that
|
||||||
// there is enough data so that PesLongEnough() returns true.
|
// there is enough data so that PesLongEnough() returns true.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
* Parts of this file were inspired by the 'ringbuffy.c' from the
|
||||||
* LinuxDVB driver (see linuxtv.org).
|
* LinuxDVB driver (see linuxtv.org).
|
||||||
*
|
*
|
||||||
* $Id: ringbuffer.c 1.25 2007/11/17 13:49:34 kls Exp $
|
* $Id: ringbuffer.c 2.1 2009/03/01 11:20:34 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
@ -335,11 +335,12 @@ void cRingBufferLinear::Del(int Count)
|
|||||||
|
|
||||||
// --- cFrame ----------------------------------------------------------------
|
// --- cFrame ----------------------------------------------------------------
|
||||||
|
|
||||||
cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index)
|
cFrame::cFrame(const uchar *Data, int Count, eFrameType Type, int Index, uint32_t Pts)
|
||||||
{
|
{
|
||||||
count = abs(Count);
|
count = abs(Count);
|
||||||
type = Type;
|
type = Type;
|
||||||
index = Index;
|
index = Index;
|
||||||
|
pts = Pts;
|
||||||
if (Count < 0)
|
if (Count < 0)
|
||||||
data = (uchar *)Data;
|
data = (uchar *)Data;
|
||||||
else {
|
else {
|
||||||
|
@ -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: ringbuffer.h 1.18 2007/11/17 13:49:34 kls Exp $
|
* $Id: ringbuffer.h 2.1 2009/03/01 11:20:34 kls Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __RINGBUFFER_H
|
#ifndef __RINGBUFFER_H
|
||||||
@ -108,8 +108,9 @@ private:
|
|||||||
int count;
|
int count;
|
||||||
eFrameType type;
|
eFrameType type;
|
||||||
int index;
|
int index;
|
||||||
|
uint32_t pts;
|
||||||
public:
|
public:
|
||||||
cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1);
|
cFrame(const uchar *Data, int Count, eFrameType = ftUnknown, int Index = -1, uint32_t Pts = 0);
|
||||||
///< Creates a new cFrame object.
|
///< Creates a new cFrame object.
|
||||||
///< If Count is negative, the cFrame object will take ownership of the given
|
///< If Count is negative, the cFrame object will take ownership of the given
|
||||||
///< Data. Otherwise it will allocate Count bytes of memory and copy Data.
|
///< Data. Otherwise it will allocate Count bytes of memory and copy Data.
|
||||||
@ -118,6 +119,7 @@ public:
|
|||||||
int Count(void) const { return count; }
|
int Count(void) const { return count; }
|
||||||
eFrameType Type(void) const { return type; }
|
eFrameType Type(void) const { return type; }
|
||||||
int Index(void) const { return index; }
|
int Index(void) const { return index; }
|
||||||
|
uint32_t Pts(void) const { return pts; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class cRingBufferFrame : public cRingBuffer {
|
class cRingBufferFrame : public cRingBuffer {
|
||||||
|
Loading…
Reference in New Issue
Block a user