mirror of
https://github.com/vdr-projects/vdr.git
synced 2025-03-01 10:50:46 +00:00
New ringbuffer for frames
This commit is contained in:
parent
614113cdcb
commit
c2ed9b5daf
3
HISTORY
3
HISTORY
@ -610,7 +610,7 @@ Video Disk Recorder Revision History
|
|||||||
- Explicitly switching back to the previously active channel after ending a
|
- 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').
|
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
|
- Modified the display of the channel group separators (thanks to Markus Lang
|
||||||
for this suggestion).
|
for this suggestion).
|
||||||
@ -618,3 +618,4 @@ Video Disk Recorder Revision History
|
|||||||
the 'libdvdread' library to be installed.
|
the 'libdvdread' library to be installed.
|
||||||
- Fixed replay progress display in case replay is paused while watching an
|
- Fixed replay progress display in case replay is paused while watching an
|
||||||
ongoing recording.
|
ongoing recording.
|
||||||
|
- Ringbuffer uses semaphores to signal empty/full conditions.
|
||||||
|
616
dvbapi.c
616
dvbapi.c
@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
* DVD support initially written by Andreas Schultz <aschultz@warp10.net>
|
* 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
|
//#define DVDDEBUG 1
|
||||||
@ -448,7 +448,7 @@ int cFileName::NextFile(void)
|
|||||||
|
|
||||||
// --- cRecordBuffer ---------------------------------------------------------
|
// --- cRecordBuffer ---------------------------------------------------------
|
||||||
|
|
||||||
class cRecordBuffer : public cRingBuffer {
|
class cRecordBuffer : public cRingBufferLinear {
|
||||||
private:
|
private:
|
||||||
cDvbApi *dvbApi;
|
cDvbApi *dvbApi;
|
||||||
cFileName fileName;
|
cFileName fileName;
|
||||||
@ -471,7 +471,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
cRecordBuffer::cRecordBuffer(cDvbApi *DvbApi, const char *FileName, int VPid, int APid1, int APid2, int DPid1, int DPid2)
|
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)
|
,fileName(FileName, true)
|
||||||
,remux(VPid, APid1, APid2, DPid1, DPid2, true)
|
,remux(VPid, APid1, APid2, DPid1, DPid2, true)
|
||||||
{
|
{
|
||||||
@ -628,23 +628,27 @@ int ReadFrame(int f, uchar *b, int Length, int Max)
|
|||||||
|
|
||||||
// --- cPlayBuffer ---------------------------------------------------------
|
// --- cPlayBuffer ---------------------------------------------------------
|
||||||
|
|
||||||
class cPlayBuffer : public cRingBuffer {
|
class cPlayBuffer : public cRingBufferFrame {
|
||||||
protected:
|
protected:
|
||||||
cDvbApi *dvbApi;
|
cDvbApi *dvbApi;
|
||||||
int videoDev, audioDev;
|
int videoDev, audioDev;
|
||||||
FILE *dolbyDev;
|
FILE *dolbyDev;
|
||||||
int blockInput, blockOutput;
|
int blockInput, blockOutput;
|
||||||
bool paused, fastForward, fastRewind;
|
bool still, paused, fastForward, fastRewind;
|
||||||
|
int readIndex, writeIndex;
|
||||||
|
bool canDoTrickMode;
|
||||||
bool canToggleAudioTrack;
|
bool canToggleAudioTrack;
|
||||||
uchar audioTrack;
|
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:
|
public:
|
||||||
cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
|
cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
|
||||||
virtual ~cPlayBuffer();
|
virtual ~cPlayBuffer();
|
||||||
virtual void Pause(void) {}
|
virtual void Pause(void);
|
||||||
virtual void Play(void) = 0;
|
virtual void Play(void);
|
||||||
virtual void Forward(void) {}
|
virtual void Forward(void);
|
||||||
virtual void Backward(void) {}
|
virtual void Backward(void);
|
||||||
virtual int SkipFrames(int Frames) { return -1; }
|
virtual int SkipFrames(int Frames) { return -1; }
|
||||||
virtual void SkipSeconds(int Seconds) {}
|
virtual void SkipSeconds(int Seconds) {}
|
||||||
virtual void Goto(int Position, bool Still = false) {}
|
virtual void Goto(int Position, bool Still = false) {}
|
||||||
@ -654,14 +658,16 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev)
|
cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev)
|
||||||
:cRingBuffer(VIDEOBUFSIZE)
|
:cRingBufferFrame(VIDEOBUFSIZE)
|
||||||
{
|
{
|
||||||
dvbApi = DvbApi;
|
dvbApi = DvbApi;
|
||||||
videoDev = VideoDev;
|
videoDev = VideoDev;
|
||||||
audioDev = AudioDev;
|
audioDev = AudioDev;
|
||||||
dolbyDev = NULL;
|
dolbyDev = NULL;
|
||||||
blockInput = blockOutput = false;
|
blockInput = blockOutput = false;
|
||||||
paused = fastForward = fastRewind = false;
|
still = paused = fastForward = fastRewind = false;
|
||||||
|
readIndex = writeIndex = -1;
|
||||||
|
canDoTrickMode = false;
|
||||||
canToggleAudioTrack = false;
|
canToggleAudioTrack = false;
|
||||||
audioTrack = 0xC0;
|
audioTrack = 0xC0;
|
||||||
if (cDvbApi::AudioCommand()) {
|
if (cDvbApi::AudioCommand()) {
|
||||||
@ -677,18 +683,136 @@ cPlayBuffer::~cPlayBuffer()
|
|||||||
pclose(dolbyDev);
|
pclose(dolbyDev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cPlayBuffer::Clear(bool Block)
|
void cPlayBuffer::Output(void)
|
||||||
{
|
{
|
||||||
cRingBuffer::Clear();
|
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(videoDev, VIDEO_CLEAR_BUFFER));
|
||||||
CHECK(ioctl(audioDev, AUDIO_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)
|
void cPlayBuffer::ToggleAudioTrack(void)
|
||||||
{
|
{
|
||||||
if (CanToggleAudioTrack()) {
|
if (CanToggleAudioTrack()) {
|
||||||
audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0;
|
audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0;
|
||||||
Clear();
|
Empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -698,27 +822,19 @@ class cReplayBuffer : public cPlayBuffer {
|
|||||||
private:
|
private:
|
||||||
cIndexFile *index;
|
cIndexFile *index;
|
||||||
cFileName fileName;
|
cFileName fileName;
|
||||||
int fileOffset;
|
|
||||||
int replayFile;
|
int replayFile;
|
||||||
bool eof;
|
bool eof;
|
||||||
int lastIndex, stillIndex, playIndex;
|
|
||||||
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
|
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
|
||||||
void Clear(bool Block = false);
|
|
||||||
void Close(void);
|
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);
|
void DisplayFrame(uchar *b, int Length);
|
||||||
int Resume(void);
|
int Resume(void);
|
||||||
bool Save(void);
|
bool Save(void);
|
||||||
protected:
|
protected:
|
||||||
virtual void Input(void);
|
virtual void Input(void);
|
||||||
virtual void Output(void);
|
|
||||||
public:
|
public:
|
||||||
cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName);
|
cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName);
|
||||||
virtual ~cReplayBuffer();
|
virtual ~cReplayBuffer();
|
||||||
virtual void Pause(void);
|
|
||||||
virtual void Play(void);
|
|
||||||
virtual void Forward(void);
|
|
||||||
virtual void Backward(void);
|
|
||||||
virtual int SkipFrames(int Frames);
|
virtual int SkipFrames(int Frames);
|
||||||
virtual void SkipSeconds(int Seconds);
|
virtual void SkipSeconds(int Seconds);
|
||||||
virtual void Goto(int Position, bool Still = false);
|
virtual void Goto(int Position, bool Still = false);
|
||||||
@ -730,10 +846,8 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
|
|||||||
,fileName(FileName, false)
|
,fileName(FileName, false)
|
||||||
{
|
{
|
||||||
index = NULL;
|
index = NULL;
|
||||||
fileOffset = 0;
|
|
||||||
replayFile = fileName.Open();
|
replayFile = fileName.Open();
|
||||||
eof = false;
|
eof = false;
|
||||||
lastIndex = stillIndex = playIndex = -1;
|
|
||||||
if (!fileName.Name())
|
if (!fileName.Name())
|
||||||
return;
|
return;
|
||||||
// Create the index file:
|
// Create the index file:
|
||||||
@ -745,6 +859,7 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
|
|||||||
delete index;
|
delete index;
|
||||||
index = NULL;
|
index = NULL;
|
||||||
}
|
}
|
||||||
|
canDoTrickMode = index != NULL;
|
||||||
dvbApi->SetModeReplay();
|
dvbApi->SetModeReplay();
|
||||||
Start();
|
Start();
|
||||||
}
|
}
|
||||||
@ -762,22 +877,23 @@ void cReplayBuffer::Input(void)
|
|||||||
{
|
{
|
||||||
dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid());
|
dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid());
|
||||||
|
|
||||||
int ResumeIndex = Resume();
|
readIndex = Resume();
|
||||||
if (ResumeIndex >= 0)
|
if (readIndex >= 0)
|
||||||
isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, IndexToHMSF(ResumeIndex, true));
|
isyslog(LOG_INFO, "resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true));
|
||||||
|
|
||||||
int lastIndex = -1;
|
|
||||||
int brakeCounter = 0;
|
|
||||||
uchar b[MAXFRAMESIZE];
|
uchar b[MAXFRAMESIZE];
|
||||||
while (Busy() && (blockInput || NextFile())) {
|
while (Busy() && (blockInput || NextFile())) {
|
||||||
if (!blockInput && stillIndex < 0) {
|
if (blockInput) {
|
||||||
|
if (blockInput > 1)
|
||||||
|
blockInput = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!still) {
|
||||||
int r = 0;
|
int r = 0;
|
||||||
if (fastForward && !paused || fastRewind) {
|
if (fastForward && !paused || fastRewind) {
|
||||||
int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset);
|
|
||||||
uchar FileNumber;
|
uchar FileNumber;
|
||||||
int FileOffset, Length;
|
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
|
int Index = index->GetNextIFrame(readIndex, fastForward, &FileNumber, &FileOffset, &Length);
|
||||||
Index = index->GetNextIFrame(Index, fastForward, &FileNumber, &FileOffset, &Length);
|
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
if (!NextFile(FileNumber, FileOffset))
|
if (!NextFile(FileNumber, FileOffset))
|
||||||
break;
|
break;
|
||||||
@ -787,31 +903,23 @@ void cReplayBuffer::Input(void)
|
|||||||
Play();
|
Play();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
lastIndex = Index;
|
readIndex = Index;
|
||||||
playIndex = -1;
|
|
||||||
r = ReadFrame(replayFile, b, Length, sizeof(b));
|
r = ReadFrame(replayFile, b, Length, sizeof(b));
|
||||||
StripAudioPackets(b, r);
|
|
||||||
}
|
}
|
||||||
else if (index) {
|
else if (index) {
|
||||||
lastIndex = -1;
|
|
||||||
playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset);
|
|
||||||
uchar FileNumber;
|
uchar FileNumber;
|
||||||
int FileOffset, Length;
|
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;
|
break;
|
||||||
r = ReadFrame(replayFile, b, Length, sizeof(b));
|
r = ReadFrame(replayFile, b, Length, sizeof(b));
|
||||||
StripAudioPackets(b, r, audioTrack);
|
|
||||||
}
|
}
|
||||||
else // allows replay even if the index file is missing
|
else // allows replay even if the index file is missing
|
||||||
r = read(replayFile, b, sizeof(b));
|
r = read(replayFile, b, sizeof(b));
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
uchar *p = b;
|
cFrame *frame = new cFrame(b, r, readIndex);
|
||||||
while (r > 0 && Busy() && !blockInput) {
|
while (Busy() && !blockInput && !Put(frame))
|
||||||
int w = Put(p, r);
|
;
|
||||||
p += w;
|
|
||||||
r -= w;
|
|
||||||
usleep(1); // this keeps the CPU load low
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (r == 0)
|
else if (r == 0)
|
||||||
eof = true;
|
eof = true;
|
||||||
@ -820,50 +928,16 @@ void cReplayBuffer::Input(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else//XXX
|
||||||
usleep(1); // this keeps the CPU load low
|
usleep(1); // this keeps the CPU load low
|
||||||
if (blockInput > 1)
|
|
||||||
blockInput = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dsyslog(LOG_INFO, "input thread ended (pid=%d)", getpid());
|
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)
|
void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)
|
||||||
{
|
{
|
||||||
|
if (canDoTrickMode) {
|
||||||
for (int i = 0; i < Length - 6; i++) {
|
for (int i = 0; i < Length - 6; i++) {
|
||||||
if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
|
if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
|
||||||
uchar c = b[i + 3];
|
uchar c = b[i + 3];
|
||||||
@ -908,6 +982,7 @@ void cReplayBuffer::StripAudioPackets(uchar *b, int Length, uchar Except)
|
|||||||
XXX*/
|
XXX*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void cReplayBuffer::DisplayFrame(uchar *b, int Length)
|
void cReplayBuffer::DisplayFrame(uchar *b, int Length)
|
||||||
{
|
{
|
||||||
@ -918,85 +993,11 @@ void cReplayBuffer::DisplayFrame(uchar *b, int Length)
|
|||||||
CHECK(ioctl(videoDev, VIDEO_STILLPICTURE, &sp));
|
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)
|
void cReplayBuffer::Close(void)
|
||||||
{
|
{
|
||||||
if (replayFile >= 0) {
|
if (replayFile >= 0) {
|
||||||
fileName.Close();
|
fileName.Close();
|
||||||
replayFile = -1;
|
replayFile = -1;
|
||||||
fileOffset = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1017,7 +1018,7 @@ int cReplayBuffer::Resume(void)
|
|||||||
bool cReplayBuffer::Save(void)
|
bool cReplayBuffer::Save(void)
|
||||||
{
|
{
|
||||||
if (index) {
|
if (index) {
|
||||||
int Index = index->Get(fileName.Number(), fileOffset);
|
int Index = writeIndex;
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
Index -= RESUMEBACKUP;
|
Index -= RESUMEBACKUP;
|
||||||
if (Index > 0)
|
if (Index > 0)
|
||||||
@ -1046,8 +1047,8 @@ int cReplayBuffer::SkipFrames(int Frames)
|
|||||||
void cReplayBuffer::SkipSeconds(int Seconds)
|
void cReplayBuffer::SkipSeconds(int Seconds)
|
||||||
{
|
{
|
||||||
if (index && Seconds) {
|
if (index && Seconds) {
|
||||||
Clear(true);
|
Empty(true);
|
||||||
int Index = index->Get(fileName.Number(), fileOffset);
|
int Index = writeIndex;
|
||||||
if (Index >= 0) {
|
if (Index >= 0) {
|
||||||
if (Seconds < 0) {
|
if (Seconds < 0) {
|
||||||
int sec = index->Last() / FRAMESPERSEC;
|
int sec = index->Last() / FRAMESPERSEC;
|
||||||
@ -1059,10 +1060,9 @@ void cReplayBuffer::SkipSeconds(int Seconds)
|
|||||||
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 (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0)
|
readIndex = writeIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) - 1; // Input() will first increment it!
|
||||||
NextFile(FileNumber, FileOffset);
|
|
||||||
}
|
}
|
||||||
Clear(false);
|
Empty(false);
|
||||||
Play();
|
Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1070,7 +1070,7 @@ void cReplayBuffer::SkipSeconds(int Seconds)
|
|||||||
void cReplayBuffer::Goto(int Index, bool Still)
|
void cReplayBuffer::Goto(int Index, bool Still)
|
||||||
{
|
{
|
||||||
if (index) {
|
if (index) {
|
||||||
Clear(true);
|
Empty(true);
|
||||||
if (paused)
|
if (paused)
|
||||||
CHECK(ioctl(videoDev, VIDEO_CONTINUE));
|
CHECK(ioctl(videoDev, VIDEO_CONTINUE));
|
||||||
if (++Index <= 0)
|
if (++Index <= 0)
|
||||||
@ -1079,28 +1079,27 @@ void cReplayBuffer::Goto(int Index, bool Still)
|
|||||||
int FileOffset, Length;
|
int FileOffset, Length;
|
||||||
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
|
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
|
||||||
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
|
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
|
||||||
stillIndex = Index;
|
still = true;
|
||||||
playIndex = -1;
|
|
||||||
uchar b[MAXFRAMESIZE];
|
uchar b[MAXFRAMESIZE];
|
||||||
int r = ReadFrame(replayFile, b, Length, sizeof(b));
|
int r = ReadFrame(replayFile, b, Length, sizeof(b));
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
DisplayFrame(b, r);
|
DisplayFrame(b, r);
|
||||||
fileOffset += Length;
|
|
||||||
paused = true;
|
paused = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
stillIndex = playIndex = -1;
|
still = false;
|
||||||
Clear(false);
|
readIndex = writeIndex = Index;
|
||||||
|
Empty(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
||||||
{
|
{
|
||||||
if (index) {
|
if (index) {
|
||||||
if (stillIndex >= 0)
|
if (still)
|
||||||
Current = stillIndex;
|
Current = readIndex;
|
||||||
else {
|
else {
|
||||||
Current = index->Get(fileName.Number(), fileOffset);
|
Current = writeIndex;
|
||||||
if (SnapToIFrame) {
|
if (SnapToIFrame) {
|
||||||
int i1 = index->GetNextIFrame(Current + 1, false);
|
int i1 = index->GetNextIFrame(Current + 1, false);
|
||||||
int i2 = index->GetNextIFrame(Current, true);
|
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)
|
bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
|
||||||
{
|
{
|
||||||
if (FileNumber > 0) {
|
if (FileNumber > 0)
|
||||||
fileOffset = FileOffset;
|
|
||||||
replayFile = fileName.SetOffset(FileNumber, FileOffset);
|
replayFile = fileName.SetOffset(FileNumber, FileOffset);
|
||||||
}
|
|
||||||
else if (replayFile >= 0 && eof) {
|
else if (replayFile >= 0 && eof) {
|
||||||
Close();
|
Close();
|
||||||
replayFile = fileName.NextFile();
|
replayFile = fileName.NextFile();
|
||||||
@ -1131,12 +1128,6 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
|
|||||||
|
|
||||||
class cDVDplayBuffer : public cPlayBuffer {
|
class cDVDplayBuffer : public cPlayBuffer {
|
||||||
private:
|
private:
|
||||||
cCondVar ready4input;
|
|
||||||
cMutex inputMutex;
|
|
||||||
|
|
||||||
cCondVar ready4output;
|
|
||||||
cMutex outputMutex;
|
|
||||||
|
|
||||||
uchar audioTrack;
|
uchar audioTrack;
|
||||||
|
|
||||||
cDVD *dvd;//XXX necessary???
|
cDVD *dvd;//XXX necessary???
|
||||||
@ -1186,7 +1177,7 @@ private:
|
|||||||
int lpcm_count;
|
int lpcm_count;
|
||||||
int is_nav_pack(unsigned char *buffer);
|
int is_nav_pack(unsigned char *buffer);
|
||||||
void Close(void);
|
void Close(void);
|
||||||
void Clear(bool Block = false);
|
virtual void Empty(bool Block = false);
|
||||||
int decode_packet(unsigned char *sector, int iframe);
|
int decode_packet(unsigned char *sector, int iframe);
|
||||||
int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType);
|
int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType);
|
||||||
bool PacketStart(uchar **Data, int len);
|
bool PacketStart(uchar **Data, int len);
|
||||||
@ -1201,14 +1192,9 @@ private:
|
|||||||
void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }
|
void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }
|
||||||
protected:
|
protected:
|
||||||
virtual void Input(void);
|
virtual void Input(void);
|
||||||
virtual void Output(void);
|
|
||||||
public:
|
public:
|
||||||
cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title);
|
cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title);
|
||||||
virtual ~cDVDplayBuffer();
|
virtual ~cDVDplayBuffer();
|
||||||
virtual void Pause(void);
|
|
||||||
virtual void Play(void);
|
|
||||||
virtual void Forward(void);
|
|
||||||
virtual void Backward(void);
|
|
||||||
virtual int SkipFrames(int Frames);
|
virtual int SkipFrames(int Frames);
|
||||||
virtual void SkipSeconds(int Seconds);
|
virtual void SkipSeconds(int Seconds);
|
||||||
virtual void Goto(int Position, bool Still = false);
|
virtual void Goto(int Position, bool Still = false);
|
||||||
@ -1224,6 +1210,41 @@ public:
|
|||||||
#define cOUTPACK 5
|
#define cOUTPACK 5
|
||||||
#define cOUTFRAMES 6
|
#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 cDVDplayBuffer::getAudioStream(unsigned int StreamId)
|
||||||
{
|
{
|
||||||
unsigned int trackID;
|
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,
|
* 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
|
* and sometimes we incorrectly think that valid other packs are NAV packs. I
|
||||||
@ -1317,15 +1304,13 @@ void cDVDplayBuffer::Input(void)
|
|||||||
|
|
||||||
doplay = true;
|
doplay = true;
|
||||||
while (Busy() && doplay) {
|
while (Busy() && doplay) {
|
||||||
inputMutex.Lock();
|
if (blockInput) {
|
||||||
while (blockInput) {
|
|
||||||
if (blockInput > 1)
|
if (blockInput > 1)
|
||||||
blockInput = 1;
|
blockInput = 1;
|
||||||
ready4input.Wait(inputMutex);
|
continue;
|
||||||
}
|
}
|
||||||
inputMutex.Unlock();
|
|
||||||
|
|
||||||
//BEGIN: riped from play_title
|
//BEGIN: ripped from play_title
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Playback by cell in this pgc, starting at the cell for our chapter.
|
* 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);
|
// 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());
|
dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
|
||||||
@ -1761,6 +1744,7 @@ int cDVDplayBuffer::SendPCM(int size)
|
|||||||
while (p_size) {
|
while (p_size) {
|
||||||
if (ac3outp != ac3inp) { // data in the buffer
|
if (ac3outp != ac3inp) { // data in the buffer
|
||||||
buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder
|
buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder
|
||||||
|
// XXX there is no 'swab' here??? (kls)
|
||||||
p_size--;
|
p_size--;
|
||||||
length++;
|
length++;
|
||||||
ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
|
ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
|
||||||
@ -1791,18 +1775,9 @@ int cDVDplayBuffer::SendPCM(int size)
|
|||||||
|
|
||||||
length += 6;
|
length += 6;
|
||||||
|
|
||||||
inputMutex.Lock();
|
cFrame *frame = new cFrame(buffer, length);
|
||||||
while (Free() < length && Busy() && !blockInput)
|
while (Busy() && !blockInput && !Put(frame))
|
||||||
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();
|
|
||||||
}
|
|
||||||
size -= MAXSIZE;
|
size -= MAXSIZE;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1834,7 +1809,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
|
|||||||
uchar *osect = sector;
|
uchar *osect = sector;
|
||||||
#endif
|
#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) {
|
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]);
|
esyslog(LOG_ERR, "ERROR: got unexpected packet: %x %x %x %x", sector[0], sector[1], sector[2], sector[3]);
|
||||||
return -1;
|
return -1;
|
||||||
@ -1885,7 +1860,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
|
|||||||
sector += 6;
|
sector += 6;
|
||||||
//we are now at the beginning of the payload
|
//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;
|
ac3datalen -= 13;
|
||||||
if (audioTrack == *sector) {
|
if (audioTrack == *sector) {
|
||||||
sector +=4;
|
sector +=4;
|
||||||
@ -1933,154 +1908,23 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
|
|||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inputMutex.Lock();
|
cFrame *frame = new cFrame(sector, r);
|
||||||
while (Free() < r && Busy() && !blockInput)
|
while (Busy() && !blockInput && !Put(frame))
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
playDecodedAC3();
|
playDecodedAC3();
|
||||||
return pt;
|
return pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDVDplayBuffer::Output(void)
|
void cDVDplayBuffer::Empty(bool Block)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if (!(blockInput || blockOutput)) {
|
if (!(blockInput || blockOutput)) {
|
||||||
blockInput = blockOutput = 2;
|
cPlayBuffer::Empty(true);
|
||||||
ready4input.Broadcast();
|
|
||||||
ready4output.Broadcast();
|
|
||||||
time_t t0 = time(NULL);
|
|
||||||
while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2)
|
|
||||||
usleep(1);
|
|
||||||
Lock();
|
|
||||||
cPlayBuffer::Clear();
|
|
||||||
ac3stat = AC3_START;
|
ac3stat = AC3_START;
|
||||||
ac3outp = ac3inp;
|
ac3outp = ac3inp;
|
||||||
}
|
}
|
||||||
if (!Block) {
|
if (!Block)
|
||||||
blockInput = blockOutput = 0;
|
cPlayBuffer::Empty(false);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cDVDplayBuffer::Close(void)
|
void cDVDplayBuffer::Close(void)
|
||||||
@ -2116,13 +1960,13 @@ void cDVDplayBuffer::SkipSeconds(int Seconds)
|
|||||||
int newchapid = Seconds > 0 ? chapid + 1 : chapid - 1;
|
int newchapid = Seconds > 0 ? chapid + 1 : chapid - 1;
|
||||||
|
|
||||||
if (newchapid >= 0 && newchapid < tt_srpt->title[titleid].nr_of_ptts) {
|
if (newchapid >= 0 && newchapid < tt_srpt->title[titleid].nr_of_ptts) {
|
||||||
Clear(true);
|
Empty(true);
|
||||||
chapid = newchapid;
|
chapid = newchapid;
|
||||||
NextState(cOPENCHAPTER);
|
NextState(cOPENCHAPTER);
|
||||||
if (ac3stat != AC3_STOP)
|
if (ac3stat != AC3_STOP)
|
||||||
ac3stat = AC3_START;
|
ac3stat = AC3_START;
|
||||||
ac3outp = ac3inp;
|
ac3outp = ac3inp;
|
||||||
Clear(false);
|
Empty(false);
|
||||||
Play();
|
Play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2139,7 +1983,7 @@ void cDVDplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
|
|||||||
|
|
||||||
// --- cTransferBuffer -------------------------------------------------------
|
// --- cTransferBuffer -------------------------------------------------------
|
||||||
|
|
||||||
class cTransferBuffer : public cRingBuffer {
|
class cTransferBuffer : public cRingBufferLinear {
|
||||||
private:
|
private:
|
||||||
cDvbApi *dvbApi;
|
cDvbApi *dvbApi;
|
||||||
int fromDevice, toDevice;
|
int fromDevice, toDevice;
|
||||||
@ -2155,7 +1999,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid)
|
cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid)
|
||||||
:cRingBuffer(VIDEOBUFSIZE, true)
|
:cRingBufferLinear(VIDEOBUFSIZE, true)
|
||||||
,remux(VPid, APid, 0, 0, 0)
|
,remux(VPid, APid, 0, 0, 0)
|
||||||
{
|
{
|
||||||
dvbApi = DvbApi;
|
dvbApi = DvbApi;
|
||||||
|
7
menu.c
7
menu.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: 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"
|
#include "menu.h"
|
||||||
@ -2438,11 +2438,10 @@ eOSState cReplayControl::ProcessKey(eKeys Key)
|
|||||||
// Positioning:
|
// Positioning:
|
||||||
case kUp: dvbApi->Play(); break;
|
case kUp: dvbApi->Play(); break;
|
||||||
case kDown: dvbApi->Pause(); break;
|
case kDown: dvbApi->Pause(); break;
|
||||||
case kLeft: dvbApi->Backward(); break;
|
|
||||||
case kRight: dvbApi->Forward(); break;
|
|
||||||
case kLeft|k_Release:
|
case kLeft|k_Release:
|
||||||
|
case kLeft: dvbApi->Backward(); break;
|
||||||
case kRight|k_Release:
|
case kRight|k_Release:
|
||||||
dvbApi->Play(); break;
|
case kRight: dvbApi->Forward(); break;
|
||||||
case kGreen|k_Repeat:
|
case kGreen|k_Repeat:
|
||||||
case kGreen: dvbApi->SkipSeconds(-60); break;
|
case kGreen: dvbApi->SkipSeconds(-60); break;
|
||||||
case kYellow|k_Repeat:
|
case kYellow|k_Repeat:
|
||||||
|
304
ringbuffer.c
304
ringbuffer.c
@ -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.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"
|
#include "ringbuffer.h"
|
||||||
@ -41,108 +41,42 @@ cRingBuffer::cRingBuffer(int Size, bool Statistics)
|
|||||||
{
|
{
|
||||||
size = Size;
|
size = Size;
|
||||||
statistics = Statistics;
|
statistics = Statistics;
|
||||||
buffer = NULL;
|
|
||||||
inputThread = NULL;
|
inputThread = NULL;
|
||||||
outputThread = NULL;
|
outputThread = NULL;
|
||||||
maxFill = 0;
|
|
||||||
busy = false;
|
busy = false;
|
||||||
if (size > 1) { // 'size - 1' must not be 0!
|
maxFill = 0;
|
||||||
buffer = new uchar[size];
|
|
||||||
if (!buffer)
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cRingBuffer::~cRingBuffer()
|
cRingBuffer::~cRingBuffer()
|
||||||
{
|
{
|
||||||
delete inputThread;
|
delete inputThread;
|
||||||
delete outputThread;
|
delete outputThread;
|
||||||
delete buffer;
|
|
||||||
if (statistics)
|
if (statistics)
|
||||||
dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
|
dsyslog(LOG_INFO, "buffer stats: %d (%d%%) used", maxFill, maxFill * 100 / (size - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int cRingBuffer::Available(void)
|
void cRingBuffer::WaitForPut(void)
|
||||||
{
|
{
|
||||||
mutex.Lock();
|
putMutex.Lock();
|
||||||
int diff = head - tail;
|
readyForPut.Wait(putMutex);
|
||||||
mutex.Unlock();
|
putMutex.Unlock();
|
||||||
return (diff >= 0) ? diff : size + diff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cRingBuffer::Clear(void)
|
void cRingBuffer::WaitForGet(void)
|
||||||
{
|
{
|
||||||
mutex.Lock();
|
getMutex.Lock();
|
||||||
head = tail = 0;
|
readyForGet.Wait(getMutex);
|
||||||
mutex.Unlock();
|
getMutex.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
int cRingBuffer::Put(const uchar *Data, int Count)
|
void cRingBuffer::EnablePut(void)
|
||||||
{
|
{
|
||||||
if (Count > 0) {
|
readyForPut.Broadcast();
|
||||||
mutex.Lock();
|
|
||||||
int rest = size - head;
|
|
||||||
int diff = tail - head;
|
|
||||||
mutex.Unlock();
|
|
||||||
int free = (diff > 0) ? diff - 1 : size + diff - 1;
|
|
||||||
if (statistics) {
|
|
||||||
int fill = size - free - 1 + Count;
|
|
||||||
if (fill >= size)
|
|
||||||
fill = size - 1;
|
|
||||||
if (fill > maxFill) {
|
|
||||||
maxFill = fill;
|
|
||||||
int percent = maxFill * 100 / (size - 1);
|
|
||||||
if (percent > 75)
|
|
||||||
dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (free <= 0)
|
|
||||||
return 0;
|
|
||||||
if (free < Count)
|
|
||||||
Count = free;
|
|
||||||
if (Count > maxFill)
|
|
||||||
maxFill = Count;
|
|
||||||
if (Count >= rest) {
|
|
||||||
memcpy(buffer + head, Data, rest);
|
|
||||||
if (Count - rest)
|
|
||||||
memcpy(buffer, Data + rest, Count - rest);
|
|
||||||
head = Count - rest;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy(buffer + head, Data, Count);
|
|
||||||
head += Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int cRingBuffer::Get(uchar *Data, int Count)
|
void cRingBuffer::EnableGet(void)
|
||||||
{
|
{
|
||||||
if (Count > 0) {
|
readyForGet.Broadcast();
|
||||||
mutex.Lock();
|
|
||||||
int rest = size - tail;
|
|
||||||
int diff = head - tail;
|
|
||||||
mutex.Unlock();
|
|
||||||
int cont = (diff >= 0) ? diff : size + diff;
|
|
||||||
if (rest <= 0)
|
|
||||||
return 0;
|
|
||||||
if (cont < Count)
|
|
||||||
Count = cont;
|
|
||||||
if (Count >= rest) {
|
|
||||||
memcpy(Data, buffer + tail, rest);
|
|
||||||
if (Count - rest)
|
|
||||||
memcpy(Data + rest, buffer, Count - rest);
|
|
||||||
tail = Count - rest;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memcpy(Data, buffer + tail, Count);
|
|
||||||
tail += Count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cRingBuffer::Start(void)
|
bool cRingBuffer::Start(void)
|
||||||
@ -178,3 +112,213 @@ void cRingBuffer::Stop(void)
|
|||||||
DELETENULL(outputThread);
|
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);
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
esyslog(LOG_ERR, "ERROR: illegal size for ring buffer (%d)", Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
cRingBufferLinear::~cRingBufferLinear()
|
||||||
|
{
|
||||||
|
delete buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cRingBufferLinear::Available(void)
|
||||||
|
{
|
||||||
|
Lock();
|
||||||
|
int diff = head - tail;
|
||||||
|
Unlock();
|
||||||
|
return (diff >= 0) ? diff : Size() + diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRingBufferLinear::Clear(void)
|
||||||
|
{
|
||||||
|
Lock();
|
||||||
|
head = tail = 0;
|
||||||
|
Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
int cRingBufferLinear::Put(const uchar *Data, int Count)
|
||||||
|
{
|
||||||
|
if (Count > 0) {
|
||||||
|
Lock();
|
||||||
|
int rest = Size() - head;
|
||||||
|
int diff = tail - head;
|
||||||
|
Unlock();
|
||||||
|
int free = (diff > 0) ? diff - 1 : Size() + diff - 1;
|
||||||
|
if (statistics) {
|
||||||
|
int fill = Size() - free - 1 + Count;
|
||||||
|
if (fill >= Size())
|
||||||
|
fill = Size() - 1;
|
||||||
|
if (fill > maxFill) {
|
||||||
|
maxFill = fill;
|
||||||
|
int percent = maxFill * 100 / (Size() - 1);
|
||||||
|
if (percent > 75)
|
||||||
|
dsyslog(LOG_INFO, "buffer usage: %d%%", percent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (free <= 0)
|
||||||
|
return 0;
|
||||||
|
if (free < Count)
|
||||||
|
Count = free;
|
||||||
|
if (Count > maxFill)
|
||||||
|
maxFill = Count;
|
||||||
|
if (Count >= rest) {
|
||||||
|
memcpy(buffer + head, Data, rest);
|
||||||
|
if (Count - rest)
|
||||||
|
memcpy(buffer, Data + rest, Count - rest);
|
||||||
|
head = Count - rest;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(buffer + head, Data, Count);
|
||||||
|
head += Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cRingBufferLinear::Get(uchar *Data, int Count)
|
||||||
|
{
|
||||||
|
if (Count > 0) {
|
||||||
|
Lock();
|
||||||
|
int rest = Size() - tail;
|
||||||
|
int diff = head - tail;
|
||||||
|
Unlock();
|
||||||
|
int cont = (diff >= 0) ? diff : Size() + diff;
|
||||||
|
if (rest <= 0)
|
||||||
|
return 0;
|
||||||
|
if (cont < Count)
|
||||||
|
Count = cont;
|
||||||
|
if (Count >= rest) {
|
||||||
|
memcpy(Data, buffer + tail, rest);
|
||||||
|
if (Count - rest)
|
||||||
|
memcpy(Data + rest, buffer, Count - rest);
|
||||||
|
tail = Count - rest;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memcpy(Data, buffer + tail, Count);
|
||||||
|
tail += Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- cFrame ----------------------------------------------------------------
|
||||||
|
|
||||||
|
cFrame::cFrame(const uchar *Data, int Count, int Index)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
head = Frame->next = Frame;
|
||||||
|
}
|
||||||
|
currentFill += Frame->Count();
|
||||||
|
Unlock();
|
||||||
|
EnableGet();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
WaitForPut();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cFrame *cRingBufferFrame::Get(bool Wait)
|
||||||
|
{
|
||||||
|
Lock();
|
||||||
|
cFrame *p = head ? head->next : NULL;
|
||||||
|
Unlock();
|
||||||
|
if (!p && Wait)
|
||||||
|
WaitForGet();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cRingBufferFrame::Delete(const cFrame *Frame)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
85
ringbuffer.h
85
ringbuffer.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: 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
|
#ifndef __RINGBUFFER_H
|
||||||
@ -24,25 +24,24 @@ private:
|
|||||||
cRingBufferInputThread *inputThread;
|
cRingBufferInputThread *inputThread;
|
||||||
cRingBufferOutputThread *outputThread;
|
cRingBufferOutputThread *outputThread;
|
||||||
cMutex mutex;
|
cMutex mutex;
|
||||||
int size, head, tail;
|
cCondVar readyForPut, readyForGet;
|
||||||
uchar *buffer;
|
cMutex putMutex, getMutex;
|
||||||
int maxFill;
|
int size;
|
||||||
bool busy;
|
bool busy;
|
||||||
bool statistics;
|
|
||||||
protected:
|
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 Lock(void) { mutex.Lock(); }
|
||||||
void Unlock(void) { mutex.Unlock(); }
|
void Unlock(void) { mutex.Unlock(); }
|
||||||
int Available(void);
|
int Size(void) { return size; }
|
||||||
int Free(void) { return size - Available() - 1; }
|
|
||||||
bool Busy(void) { return busy; }
|
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;
|
virtual void Input(void) = 0;
|
||||||
// Runs as a separate thread and shall continuously read data from
|
// Runs as a separate thread and shall continuously read data from
|
||||||
// a source and call Put() to store the data in the ring buffer.
|
// a source and call Put() to store the data in the ring buffer.
|
||||||
@ -57,4 +56,60 @@ public:
|
|||||||
void Stop(void);
|
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
|
#endif // __RINGBUFFER_H
|
||||||
|
12
thread.c
12
thread.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: 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"
|
#include "thread.h"
|
||||||
@ -26,15 +26,15 @@ cCondVar::~cCondVar()
|
|||||||
pthread_cond_destroy(&cond);
|
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);
|
pthread_cond_broadcast(&cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void cCondVar::Signal(void)
|
void cCondVar::Signal(void)
|
||||||
{
|
{
|
||||||
pthread_cond_signal(&cond);
|
pthread_cond_signal(&cond);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// --- cMutex ----------------------------------------------------------------
|
// --- cMutex ----------------------------------------------------------------
|
||||||
|
|
||||||
|
8
thread.h
8
thread.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: 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
|
#ifndef __THREAD_H
|
||||||
@ -21,10 +21,10 @@ private:
|
|||||||
public:
|
public:
|
||||||
cCondVar(void);
|
cCondVar(void);
|
||||||
~cCondVar();
|
~cCondVar();
|
||||||
bool Wait(cMutex &_mutex);
|
bool Wait(cMutex &Mutex);
|
||||||
//bool TimedWait(cMutex &_mutex, unsigned long tmout);
|
//bool TimedWait(cMutex &Mutex, unsigned long tmout);
|
||||||
void Broadcast(void);
|
void Broadcast(void);
|
||||||
void Signal(void);
|
//void Signal(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
class cMutex {
|
class cMutex {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user