summaryrefslogtreecommitdiff
path: root/dvbapi.c
diff options
context:
space:
mode:
authorKlaus Schmidinger <vdr@tvdr.de>2001-08-05 12:23:24 +0200
committerKlaus Schmidinger <vdr@tvdr.de>2001-08-05 12:23:24 +0200
commitc2ed9b5daf19b86823b27a06799d7d43d476f654 (patch)
treee7c24b75e4cd2b181ebc9e88ad22bb888960c39d /dvbapi.c
parent614113cdcb1ebb176891664426e9c0cc2bb63c9d (diff)
downloadvdr-c2ed9b5daf19b86823b27a06799d7d43d476f654.tar.gz
vdr-c2ed9b5daf19b86823b27a06799d7d43d476f654.tar.bz2
New ringbuffer for frames
Diffstat (limited to 'dvbapi.c')
-rw-r--r--dvbapi.c712
1 files changed, 278 insertions, 434 deletions
diff --git a/dvbapi.c b/dvbapi.c
index 1be6db34..cb2f85c5 100644
--- a/dvbapi.c
+++ b/dvbapi.c
@@ -6,7 +6,7 @@
*
* 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
@@ -448,7 +448,7 @@ int cFileName::NextFile(void)
// --- cRecordBuffer ---------------------------------------------------------
-class cRecordBuffer : public cRingBuffer {
+class cRecordBuffer : public cRingBufferLinear {
private:
cDvbApi *dvbApi;
cFileName fileName;
@@ -471,7 +471,7 @@ public:
};
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)
,remux(VPid, APid1, APid2, DPid1, DPid2, true)
{
@@ -628,23 +628,27 @@ int ReadFrame(int f, uchar *b, int Length, int Max)
// --- cPlayBuffer ---------------------------------------------------------
-class cPlayBuffer : public cRingBuffer {
+class cPlayBuffer : public cRingBufferFrame {
protected:
cDvbApi *dvbApi;
int videoDev, audioDev;
FILE *dolbyDev;
int blockInput, blockOutput;
- bool paused, fastForward, fastRewind;
+ bool still, paused, fastForward, fastRewind;
+ int readIndex, writeIndex;
+ bool canDoTrickMode;
bool canToggleAudioTrack;
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:
cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev);
virtual ~cPlayBuffer();
- virtual void Pause(void) {}
- virtual void Play(void) = 0;
- virtual void Forward(void) {}
- virtual void Backward(void) {}
+ virtual void Pause(void);
+ virtual void Play(void);
+ virtual void Forward(void);
+ virtual void Backward(void);
virtual int SkipFrames(int Frames) { return -1; }
virtual void SkipSeconds(int Seconds) {}
virtual void Goto(int Position, bool Still = false) {}
@@ -654,14 +658,16 @@ public:
};
cPlayBuffer::cPlayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev)
-:cRingBuffer(VIDEOBUFSIZE)
+:cRingBufferFrame(VIDEOBUFSIZE)
{
dvbApi = DvbApi;
videoDev = VideoDev;
audioDev = AudioDev;
dolbyDev = NULL;
blockInput = blockOutput = false;
- paused = fastForward = fastRewind = false;
+ still = paused = fastForward = fastRewind = false;
+ readIndex = writeIndex = -1;
+ canDoTrickMode = false;
canToggleAudioTrack = false;
audioTrack = 0xC0;
if (cDvbApi::AudioCommand()) {
@@ -677,18 +683,136 @@ cPlayBuffer::~cPlayBuffer()
pclose(dolbyDev);
}
-void cPlayBuffer::Clear(bool Block)
+void cPlayBuffer::Output(void)
{
- cRingBuffer::Clear();
- CHECK(ioctl(videoDev, VIDEO_CLEAR_BUFFER));
- CHECK(ioctl(audioDev, AUDIO_CLEAR_BUFFER));
+ 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(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)
{
if (CanToggleAudioTrack()) {
audioTrack = (audioTrack == 0xC0) ? 0xC1 : 0xC0;
- Clear();
+ Empty();
}
}
@@ -698,27 +822,19 @@ class cReplayBuffer : public cPlayBuffer {
private:
cIndexFile *index;
cFileName fileName;
- int fileOffset;
int replayFile;
bool eof;
- int lastIndex, stillIndex, playIndex;
bool NextFile(uchar FileNumber = 0, int FileOffset = -1);
- void Clear(bool Block = false);
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);
int Resume(void);
bool Save(void);
protected:
virtual void Input(void);
- virtual void Output(void);
public:
cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const char *FileName);
virtual ~cReplayBuffer();
- virtual void Pause(void);
- virtual void Play(void);
- virtual void Forward(void);
- virtual void Backward(void);
virtual int SkipFrames(int Frames);
virtual void SkipSeconds(int Seconds);
virtual void Goto(int Position, bool Still = false);
@@ -730,10 +846,8 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
,fileName(FileName, false)
{
index = NULL;
- fileOffset = 0;
replayFile = fileName.Open();
eof = false;
- lastIndex = stillIndex = playIndex = -1;
if (!fileName.Name())
return;
// Create the index file:
@@ -745,6 +859,7 @@ cReplayBuffer::cReplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, const
delete index;
index = NULL;
}
+ canDoTrickMode = index != NULL;
dvbApi->SetModeReplay();
Start();
}
@@ -762,22 +877,23 @@ void cReplayBuffer::Input(void)
{
dsyslog(LOG_INFO, "input thread started (pid=%d)", getpid());
- int ResumeIndex = Resume();
- if (ResumeIndex >= 0)
- isyslog(LOG_INFO, "resuming replay at index %d (%s)", ResumeIndex, IndexToHMSF(ResumeIndex, true));
+ readIndex = Resume();
+ if (readIndex >= 0)
+ isyslog(LOG_INFO, "resuming replay at index %d (%s)", readIndex, IndexToHMSF(readIndex, true));
- int lastIndex = -1;
- int brakeCounter = 0;
uchar b[MAXFRAMESIZE];
while (Busy() && (blockInput || NextFile())) {
- if (!blockInput && stillIndex < 0) {
+ if (blockInput) {
+ if (blockInput > 1)
+ blockInput = 1;
+ continue;
+ }
+ if (!still) {
int r = 0;
if (fastForward && !paused || fastRewind) {
- int Index = (lastIndex >= 0) ? lastIndex : index->Get(fileName.Number(), fileOffset);
uchar FileNumber;
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
- Index = index->GetNextIFrame(Index, fastForward, &FileNumber, &FileOffset, &Length);
+ int Index = index->GetNextIFrame(readIndex, fastForward, &FileNumber, &FileOffset, &Length);
if (Index >= 0) {
if (!NextFile(FileNumber, FileOffset))
break;
@@ -787,126 +903,85 @@ void cReplayBuffer::Input(void)
Play();
continue;
}
- lastIndex = Index;
- playIndex = -1;
+ readIndex = Index;
r = ReadFrame(replayFile, b, Length, sizeof(b));
- StripAudioPackets(b, r);
}
else if (index) {
- lastIndex = -1;
- playIndex = (playIndex >= 0) ? playIndex + 1 : index->Get(fileName.Number(), fileOffset);
uchar FileNumber;
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;
r = ReadFrame(replayFile, b, Length, sizeof(b));
- StripAudioPackets(b, r, audioTrack);
}
else // allows replay even if the index file is missing
r = read(replayFile, b, sizeof(b));
if (r > 0) {
- uchar *p = b;
- while (r > 0 && Busy() && !blockInput) {
- int w = Put(p, r);
- p += w;
- r -= w;
- usleep(1); // this keeps the CPU load low
- }
+ cFrame *frame = new cFrame(b, r, readIndex);
+ while (Busy() && !blockInput && !Put(frame))
+ ;
}
- else if (r ==0)
+ else if (r == 0)
eof = true;
else if (r < 0 && errno != EAGAIN) {
LOG_ERROR;
break;
}
}
- else
+ else//XXX
usleep(1); // this keeps the CPU load low
- if (blockInput > 1)
- blockInput = 1;
}
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)
{
- for (int i = 0; i < Length - 6; i++) {
- if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
- uchar c = b[i + 3];
- int l = b[i + 4] * 256 + b[i + 5] + 6;
- switch (c) {
- case 0xBD: // dolby
- if (Except && dolbyDev) {
- int written = b[i + 8] + 9; // skips the PES header
- int n = l - written;
- while (n > 0) {
- int w = fwrite(&b[i + written], 1, n, dolbyDev);
- if (w < 0) {
- LOG_ERROR;
- break;
+ if (canDoTrickMode) {
+ for (int i = 0; i < Length - 6; i++) {
+ if (b[i] == 0x00 && b[i + 1] == 0x00 && b[i + 2] == 0x01) {
+ uchar c = b[i + 3];
+ int l = b[i + 4] * 256 + b[i + 5] + 6;
+ switch (c) {
+ case 0xBD: // dolby
+ if (Except && dolbyDev) {
+ int written = b[i + 8] + 9; // skips the PES header
+ int n = l - written;
+ while (n > 0) {
+ int w = fwrite(&b[i + written], 1, n, dolbyDev);
+ if (w < 0) {
+ LOG_ERROR;
+ break;
+ }
+ n -= w;
+ written += w;
}
- n -= w;
- written += w;
- }
- }
- // continue with deleting the data - otherwise it disturbs DVB replay
- case 0xC0 ... 0xC1: // audio
- if (c == 0xC1)
- canToggleAudioTrack = true;
- if (!Except || c != Except) {
- int n = l;
- for (int j = i; j < Length && n--; j++)
- b[j] = 0x00;
- }
- break;
- case 0xE0 ... 0xEF: // video
- break;
- default:
- //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c);
- l = 0;
- }
- if (l)
- i += l - 1; // the loop increments, too!
+ }
+ // continue with deleting the data - otherwise it disturbs DVB replay
+ case 0xC0 ... 0xC1: // audio
+ if (c == 0xC1)
+ canToggleAudioTrack = true;
+ if (!Except || c != Except) {
+ int n = l;
+ for (int j = i; j < Length && n--; j++)
+ b[j] = 0x00;
+ }
+ break;
+ case 0xE0 ... 0xEF: // video
+ break;
+ default:
+ //esyslog(LOG_ERR, "ERROR: unexpected packet id %02X", c);
+ l = 0;
+ }
+ if (l)
+ i += l - 1; // the loop increments, too!
+ }
+ /*XXX
+ else
+ esyslog(LOG_ERR, "ERROR: broken packet header");
+ XXX*/
}
- /*XXX
- else
- esyslog(LOG_ERR, "ERROR: broken packet header");
- XXX*/
- }
+ }
}
void cReplayBuffer::DisplayFrame(uchar *b, int Length)
@@ -918,85 +993,11 @@ void cReplayBuffer::DisplayFrame(uchar *b, int Length)
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)
{
if (replayFile >= 0) {
fileName.Close();
replayFile = -1;
- fileOffset = 0;
}
}
@@ -1017,7 +1018,7 @@ int cReplayBuffer::Resume(void)
bool cReplayBuffer::Save(void)
{
if (index) {
- int Index = index->Get(fileName.Number(), fileOffset);
+ int Index = writeIndex;
if (Index >= 0) {
Index -= RESUMEBACKUP;
if (Index > 0)
@@ -1046,8 +1047,8 @@ int cReplayBuffer::SkipFrames(int Frames)
void cReplayBuffer::SkipSeconds(int Seconds)
{
if (index && Seconds) {
- Clear(true);
- int Index = index->Get(fileName.Number(), fileOffset);
+ Empty(true);
+ int Index = writeIndex;
if (Index >= 0) {
if (Seconds < 0) {
int sec = index->Last() / FRAMESPERSEC;
@@ -1059,10 +1060,9 @@ void cReplayBuffer::SkipSeconds(int Seconds)
Index = 1; // not '0', to allow GetNextIFrame() below to work!
uchar FileNumber;
int FileOffset;
- if (index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) >= 0)
- NextFile(FileNumber, FileOffset);
+ readIndex = writeIndex = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset) - 1; // Input() will first increment it!
}
- Clear(false);
+ Empty(false);
Play();
}
}
@@ -1070,7 +1070,7 @@ void cReplayBuffer::SkipSeconds(int Seconds)
void cReplayBuffer::Goto(int Index, bool Still)
{
if (index) {
- Clear(true);
+ Empty(true);
if (paused)
CHECK(ioctl(videoDev, VIDEO_CONTINUE));
if (++Index <= 0)
@@ -1079,28 +1079,27 @@ void cReplayBuffer::Goto(int Index, bool Still)
int FileOffset, Length;
Index = index->GetNextIFrame(Index, false, &FileNumber, &FileOffset, &Length);
if (Index >= 0 && NextFile(FileNumber, FileOffset) && Still) {
- stillIndex = Index;
- playIndex = -1;
+ still = true;
uchar b[MAXFRAMESIZE];
int r = ReadFrame(replayFile, b, Length, sizeof(b));
if (r > 0)
DisplayFrame(b, r);
- fileOffset += Length;
paused = true;
}
else
- stillIndex = playIndex = -1;
- Clear(false);
+ still = false;
+ readIndex = writeIndex = Index;
+ Empty(false);
}
}
void cReplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
{
if (index) {
- if (stillIndex >= 0)
- Current = stillIndex;
+ if (still)
+ Current = readIndex;
else {
- Current = index->Get(fileName.Number(), fileOffset);
+ Current = writeIndex;
if (SnapToIFrame) {
int i1 = index->GetNextIFrame(Current + 1, false);
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)
{
- if (FileNumber > 0) {
- fileOffset = FileOffset;
+ if (FileNumber > 0)
replayFile = fileName.SetOffset(FileNumber, FileOffset);
- }
else if (replayFile >= 0 && eof) {
Close();
replayFile = fileName.NextFile();
@@ -1131,12 +1128,6 @@ bool cReplayBuffer::NextFile(uchar FileNumber, int FileOffset)
class cDVDplayBuffer : public cPlayBuffer {
private:
- cCondVar ready4input;
- cMutex inputMutex;
-
- cCondVar ready4output;
- cMutex outputMutex;
-
uchar audioTrack;
cDVD *dvd;//XXX necessary???
@@ -1186,7 +1177,7 @@ private:
int lpcm_count;
int is_nav_pack(unsigned char *buffer);
void Close(void);
- void Clear(bool Block = false);
+ virtual void Empty(bool Block = false);
int decode_packet(unsigned char *sector, int iframe);
int ScanVideoPacket(const uchar *Data, int Count, uchar *PictureType);
bool PacketStart(uchar **Data, int len);
@@ -1201,14 +1192,9 @@ private:
void NextState(int State) { prevcycle = cyclestate; cyclestate = State; }
protected:
virtual void Input(void);
- virtual void Output(void);
public:
cDVDplayBuffer(cDvbApi *DvbApi, int VideoDev, int AudioDev, cDVD *DvD, int title);
virtual ~cDVDplayBuffer();
- virtual void Pause(void);
- virtual void Play(void);
- virtual void Forward(void);
- virtual void Backward(void);
virtual int SkipFrames(int Frames);
virtual void SkipSeconds(int Seconds);
virtual void Goto(int Position, bool Still = false);
@@ -1224,6 +1210,41 @@ public:
#define cOUTPACK 5
#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 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,
* and sometimes we incorrectly think that valid other packs are NAV packs. I
@@ -1317,15 +1304,13 @@ void cDVDplayBuffer::Input(void)
doplay = true;
while (Busy() && doplay) {
- inputMutex.Lock();
- while (blockInput) {
- if (blockInput > 1)
- blockInput = 1;
- ready4input.Wait(inputMutex);
- }
- inputMutex.Unlock();
+ if (blockInput) {
+ if (blockInput > 1)
+ blockInput = 1;
+ continue;
+ }
- //BEGIN: riped from play_title
+ //BEGIN: ripped from play_title
/**
* 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);
- if (blockInput > 1)
- blockInput = 1;
}
dsyslog(LOG_INFO, "output thread ended (pid=%d)", getpid());
@@ -1761,6 +1744,7 @@ int cDVDplayBuffer::SendPCM(int size)
while (p_size) {
if (ac3outp != ac3inp) { // data in the buffer
buffer[(length + 6) ^ 1] = ac3data[ac3outp]; // swab because ac3dec delivers wrong byteorder
+ // XXX there is no 'swab' here??? (kls)
p_size--;
length++;
ac3outp = (ac3outp + 1) % AC3_BUFFER_SIZE;
@@ -1791,18 +1775,9 @@ int cDVDplayBuffer::SendPCM(int size)
length += 6;
- inputMutex.Lock();
- while (Free() < length && Busy() && !blockInput)
- 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();
- }
+ cFrame *frame = new cFrame(buffer, length);
+ while (Busy() && !blockInput && !Put(frame))
+ ;
size -= MAXSIZE;
}
return 0;
@@ -1834,7 +1809,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
uchar *osect = sector;
#endif
- //make sure we got an PS packet header
+ //make sure we got a PS packet header
if (!PacketStart(&sector, 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]);
return -1;
@@ -1885,7 +1860,7 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
sector += 6;
//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;
if (audioTrack == *sector) {
sector +=4;
@@ -1933,154 +1908,23 @@ int cDVDplayBuffer::decode_packet(unsigned char *sector, int trickMode)
return pt;
}
}
- inputMutex.Lock();
- while (Free() < r && Busy() && !blockInput)
- 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();
- }
+ cFrame *frame = new cFrame(sector, r);
+ while (Busy() && !blockInput && !Put(frame))
+ ;
playDecodedAC3();
return pt;
}
-void cDVDplayBuffer::Output(void)
-{
- 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)
+void cDVDplayBuffer::Empty(bool Block)
{
if (!(blockInput || blockOutput)) {
- blockInput = blockOutput = 2;
- ready4input.Broadcast();
- ready4output.Broadcast();
- time_t t0 = time(NULL);
- while ((blockInput > 1 || blockOutput > 1) && time(NULL) - t0 < 2)
- usleep(1);
- Lock();
- cPlayBuffer::Clear();
+ cPlayBuffer::Empty(true);
ac3stat = AC3_START;
ac3outp = ac3inp;
}
- if (!Block) {
- blockInput = blockOutput = 0;
- 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);
+ if (!Block)
+ cPlayBuffer::Empty(false);
}
void cDVDplayBuffer::Close(void)
@@ -2116,13 +1960,13 @@ void cDVDplayBuffer::SkipSeconds(int Seconds)
int newchapid = Seconds > 0 ? chapid + 1 : chapid - 1;
if (newchapid >= 0 && newchapid < tt_srpt->title[titleid].nr_of_ptts) {
- Clear(true);
+ Empty(true);
chapid = newchapid;
NextState(cOPENCHAPTER);
if (ac3stat != AC3_STOP)
- ac3stat=AC3_START;
+ ac3stat = AC3_START;
ac3outp = ac3inp;
- Clear(false);
+ Empty(false);
Play();
}
}
@@ -2139,7 +1983,7 @@ void cDVDplayBuffer::GetIndex(int &Current, int &Total, bool SnapToIFrame)
// --- cTransferBuffer -------------------------------------------------------
-class cTransferBuffer : public cRingBuffer {
+class cTransferBuffer : public cRingBufferLinear {
private:
cDvbApi *dvbApi;
int fromDevice, toDevice;
@@ -2155,7 +1999,7 @@ public:
};
cTransferBuffer::cTransferBuffer(cDvbApi *DvbApi, int ToDevice, int VPid, int APid)
-:cRingBuffer(VIDEOBUFSIZE, true)
+:cRingBufferLinear(VIDEOBUFSIZE, true)
,remux(VPid, APid, 0, 0, 0)
{
dvbApi = DvbApi;