summaryrefslogtreecommitdiff
path: root/dxr3syncbuffer.c
diff options
context:
space:
mode:
authoraustriancoder <austriancoder>2005-08-15 17:28:49 +0000
committeraustriancoder <austriancoder>2005-08-15 17:28:49 +0000
commit290038f3de13b728cab6d3db7729078482903844 (patch)
treeb83287be6ad0602f7f73a91c11b36074e5062be0 /dxr3syncbuffer.c
parent8955b4dfa419698ecb853bb8f1cdc1fe96d206d6 (diff)
downloadvdr-plugin-dxr3-290038f3de13b728cab6d3db7729078482903844.tar.gz
vdr-plugin-dxr3-290038f3de13b728cab6d3db7729078482903844.tar.bz2
HEAD = 0.2.3 release, because i want to start my coding with this codebase
Diffstat (limited to 'dxr3syncbuffer.c')
-rw-r--r--dxr3syncbuffer.c496
1 files changed, 496 insertions, 0 deletions
diff --git a/dxr3syncbuffer.c b/dxr3syncbuffer.c
new file mode 100644
index 0000000..66be71b
--- /dev/null
+++ b/dxr3syncbuffer.c
@@ -0,0 +1,496 @@
+/*
+ * dxr3syncbuffer.c
+ *
+ * Copyright (C) 2002-2004 Kai Möller
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+/*
+ ToDo:
+ - cDxr3SyncBuffer::Push: XXX This is only a workaround until a
+ sufficient control algorithm is implemented
+*/
+
+#include <unistd.h>
+#include <sys/time.h>
+#include "dxr3syncbuffer.h"
+
+const int DXR3_MAX_VIDEO_FRAME_LENGTH = 4096;
+const int DXR3_MAX_AUDIO_FRAME_LENGTH = 4096;
+
+// ==================================
+//! constructor
+cFixedLengthFrame::cFixedLengthFrame() :
+ m_count(0), m_length(0), m_pts(0), m_type(ftUnknown)
+{
+
+ m_audioChannelCount = UNKNOWN_CHANNEL_COUNT;
+ m_audioDataRate = UNKNOWN_DATA_RATE;
+ m_videoAspectRatio = UNKNOWN_ASPECT_RATIO;
+}
+
+// ==================================
+cFixedLengthFrame::~cFixedLengthFrame()
+{
+ if (m_pData)
+ {
+ delete[] m_pData;
+ }
+}
+
+// ==================================
+// ! setup our frame
+void cFixedLengthFrame::Init(uint32_t lenght)
+{
+ m_length = lenght;
+ m_pData = new uint8_t[lenght];
+
+ // allocation ok?
+ if (!m_pData)
+ {
+ esyslog("dxr3: fatal: unable to allocate memory for new frame");
+ exit(1);
+ }
+}
+
+// ==================================
+void cFixedLengthFrame::CopyFrame(const uint8_t* pStart, int length,
+ uint32_t pts, eFrameType type)
+{
+ if (length > m_length)
+ {
+ delete[] m_pData;
+ m_pData = new uint8_t[length];
+ m_length = length;
+ }
+ m_type = type;
+ m_count = length;
+ m_pts = pts;
+ memcpy((void*) m_pData, (void*) pStart, length);
+}
+
+// ==================================
+uint8_t* cFixedLengthFrame::GetData(void)
+{
+ return m_pData;
+}
+
+// ==================================
+int cFixedLengthFrame::GetCount(void)
+{
+ return m_count;
+}
+
+// ==================================
+uint32_t cFixedLengthFrame::GetPts(void)
+{
+ return m_pts;
+}
+
+// ==================================
+void cFixedLengthFrame::SetPts(uint32_t pts)
+{
+ m_pts = pts;
+}
+
+// ==================================
+uint32_t cFixedLengthFrame::m_staticAudioChannelCount = 0;
+uint32_t cFixedLengthFrame::m_staticAudioDataRate = 0;
+
+
+// ==================================
+//! constructor
+cDxr3SyncBuffer::cDxr3SyncBuffer(int frameCount, int frameLength,
+ cDxr3Interface& dxr3Device) :
+ cRingBuffer(frameCount, true), m_dxr3Device(dxr3Device)
+{
+ m_pBuffer = new cFixedLengthFrame[frameCount];
+
+ // got we a valid m_pBuffer?
+ if (!m_pBuffer)
+ {
+ esyslog("dxr3: fatal: unable to allocate memory for new frame");
+ exit(1);
+ }
+
+ // init our new m_pBuffer;
+ for (int i = 0; i < frameCount; i++)
+ {
+ m_pBuffer[i].Init(frameLength);
+ }
+
+ // set some default values
+ m_count = 0;
+ m_nextFree = 0;
+ m_next = 0;
+ m_bWaitPts = false;
+ m_waitPts = 0;
+ m_waitDelta = 0;
+ m_lastPts = 0;
+ m_bPutBlock = false;
+ m_bGetBlock = false;
+ m_bStartReceiver = false;
+ m_bStopped = false;
+ m_demuxMode = DXR3_DEMUX_TV_MODE;
+ m_bPollSync = false;
+ SetTimeouts(1000, 10);
+}
+
+// ==================================
+cDxr3SyncBuffer::~cDxr3SyncBuffer()
+{
+ if (m_pBuffer)
+ {
+ delete[] m_pBuffer;
+ }
+}
+
+// ==================================
+int cDxr3SyncBuffer::Available(void)
+{
+ int ret = 0;
+#if VDRVERSNUM < 10313
+ Lock();
+#endif
+ ret = m_count;
+#if VDRVERSNUM < 10313
+ Unlock();
+#endif
+ return ret;
+}
+
+// ==================================
+const int BUFFER_LIMIT = 5;
+const int BUFFER_LIMIT_2 = 10;
+
+// ==================================
+bool cDxr3SyncBuffer::Poll(int TimeoutMs)
+{
+ bool retVal = true;
+ uint32_t currTime = m_dxr3Device.GetSysClock();
+ struct timeval tv_start, tv;
+ m_bPollSync = true;
+ gettimeofday(&tv_start, NULL);
+ if (m_demuxMode == DXR3_DEMUX_REPLAY_MODE)
+ {
+ if (Available() >= Size() - (Size()*BUFFER_LIMIT/100))
+ {
+ m_bPollSync = true;
+ while ((Available() >= Size() - (Size()*BUFFER_LIMIT_2)/100) &&
+ ((m_dxr3Device.GetSysClock() - currTime) <
+ ((uint32_t)TimeoutMs * (uint32_t)45)))
+ {
+ int d_s, d_us, ms;
+ m_bPutBlock = true;
+ EnableGet();
+ m_bWaitPts = false;
+ WaitForPut();
+ gettimeofday(&tv, NULL);
+ d_s = tv.tv_sec - tv_start.tv_sec;
+ d_us = tv.tv_usec - tv_start.tv_usec;
+ ms = d_s * 1000 + d_us / 1000;
+ if (ms > TimeoutMs * 2) {
+ esyslog("dxr3: sync: secondary timeout");
+ break;
+ }
+ }
+ if (Available() >= Size() - (Size()*BUFFER_LIMIT_2)/100)
+ {
+ retVal = false;
+ }
+ }
+ }
+
+ return retVal;
+}
+
+// ==================================
+cFixedLengthFrame* cDxr3SyncBuffer::Push(const uint8_t* pStart, int length, uint32_t pts, eFrameType type) throw (eSyncBufferException)
+{
+ int lastIndex = 0;
+ struct timeval tv_start, tv;
+ gettimeofday(&tv_start, NULL);
+
+ switch (m_demuxMode)
+ {
+ case DXR3_DEMUX_TRICK_MODE:
+ break;
+
+ case DXR3_DEMUX_TV_MODE:
+ case DXR3_DEMUX_REPLAY_MODE:
+ default:
+
+ while ((Available() >= Size() - (Size()*10)/100))
+ {
+ int d_s, d_us, ms;
+ m_bPutBlock = true;
+ EnableGet();
+ m_bWaitPts = false;
+ WaitForPut();
+ gettimeofday(&tv, NULL);
+ d_s = tv.tv_sec - tv_start.tv_sec;
+ d_us = tv.tv_usec - tv_start.tv_usec;
+ ms = d_s * 1000 + d_us / 1000;
+ if (ms > 2000) {
+ esyslog("dxr3: sync: push timeout");
+ return NULL;
+ }
+ }
+
+#if VDRVERSNUM < 10313
+ Lock();
+#endif
+ if (pts == m_lastPts)
+ {
+ pts = 0;
+ }
+ else
+ {
+ m_lastPts = pts;
+ }
+ lastIndex = m_nextFree;
+ m_pBuffer[m_nextFree].CopyFrame(pStart, length, pts, type);
+ m_pBuffer[m_nextFree].SetChannelCount(UNKNOWN_CHANNEL_COUNT);
+ m_pBuffer[m_nextFree].SetDataRate(UNKNOWN_DATA_RATE);
+ m_pBuffer[m_nextFree].SetAspectRatio(UNKNOWN_ASPECT_RATIO);
+ m_nextFree++;
+ m_count++;
+ m_nextFree %= Size();
+
+ if (m_nextFree == m_next)
+ {
+ esyslog("dxr3: sync: push buffer overrun");
+ Clear(); // XXX This is only a workaround until a sufficient control algorithm is implemented
+ throw(SYNC_BUFFER_OVERRUN);
+ }
+ if (!m_bWaitPts)
+ {
+ if (m_bStartReceiver)
+ {
+ EnableGet();
+ }
+ }
+ else
+ {
+ if (m_waitPts < m_dxr3Device.GetSysClock() ||
+ m_waitPts - m_dxr3Device.GetSysClock() < m_waitDelta)
+ {
+ EnableGet();
+ m_bWaitPts = false;
+ }
+ }
+#if VDRVERSNUM < 10313
+ Unlock();
+#endif
+ break;
+ }
+
+ return &m_pBuffer[lastIndex];
+}
+
+// ==================================
+void cDxr3SyncBuffer::Pop(void)
+{
+#if VDRVERSNUM < 10313
+ Lock();
+#endif
+ if (m_count)
+ {
+ uint32_t nextPts = 0;
+ uint32_t tmpBuffer = m_next;
+ for (int i = 0; i < m_count && nextPts == 0; ++i)
+ {
+ if (tmpBuffer) tmpBuffer = --tmpBuffer ? tmpBuffer : (Size() - 1);
+ nextPts = m_pBuffer[tmpBuffer].GetPts();
+ }
+ if (nextPts != 30)
+ {
+ cDxr3NextPts::Instance().SetNextPts(nextPts);
+ }
+
+ m_next++;
+ m_count--;
+ m_next %= Size();
+ if (m_next == m_nextFree)
+ {
+ m_next = m_nextFree = m_count = 0;
+ }
+ }
+ EnablePut();
+#if VDRVERSNUM < 10313
+ Unlock();
+#endif
+}
+
+// ==================================
+cFixedLengthFrame* cDxr3SyncBuffer::Get(void)
+{
+ cFixedLengthFrame* pRet = 0;
+
+ if (!m_bStopped)
+ {
+ while ((!Available() || !m_bStartReceiver) && !m_bStopped)
+ {
+ m_bGetBlock = true;
+ ReceiverStopped();
+ WaitForGet();
+ }
+
+#if VDRVERSNUM < 10313
+ Lock();
+#endif
+ if (m_nextFree != m_next)
+ {
+ pRet = &m_pBuffer[m_next];
+ }
+#if VDRVERSNUM < 10313
+ Unlock();
+#endif
+ }
+ else
+ {
+ WaitForGet();
+ }
+
+ return pRet;
+}
+
+// ==================================
+void cDxr3SyncBuffer::Clear(void)
+{
+#if VDRVERSNUM < 10313
+ Lock();
+#endif
+ m_next = 0;
+ m_nextFree = 0;
+ m_count = 0;
+ m_lastPts = 0;
+ m_bWaitPts = false;
+ m_bStartReceiver = false;
+ m_bPollSync = false;
+ if (m_bPutBlock)
+ {
+ EnablePut();
+ m_bPutBlock = false;
+ }
+ cFixedLengthFrame::Clear();
+ cDxr3NextPts::Instance().Clear();
+#if VDRVERSNUM < 10313
+ Unlock();
+#endif
+}
+
+// ==================================
+void cDxr3SyncBuffer::WaitForSysClock(uint32_t pts, uint32_t delta)
+{
+ m_waitPts = pts;
+ m_waitDelta = delta;
+ if (!m_bPutBlock)
+ {
+#if VDRVERSNUM < 10313
+ Lock();
+#endif
+ m_bWaitPts = true;
+#if VDRVERSNUM < 10313
+ Unlock();
+#endif
+ m_bGetBlock = true;
+ ReceiverStopped();
+ WaitForGet();
+ }
+ else
+ {
+ usleep(1); //* (pts - pSysClock->GetSysClock()));
+ }
+}
+
+// ==================================
+void cDxr3SyncBuffer::WaitForNextPut(void)
+{
+ if (!m_bPutBlock)
+ {
+ m_bGetBlock = true;
+ ReceiverStopped();
+ WaitForGet();
+ }
+ else
+ {
+ usleep(1);
+ }
+}
+
+// ==================================
+void cDxr3SyncBuffer::Start(void)
+{
+ m_bStartReceiver = true;
+ m_bStopped = false;
+ if (Available())
+ {
+ EnableGet();
+ }
+}
+
+// ==================================
+void cDxr3SyncBuffer::WakeUp(void)
+{
+#if VDRVERSNUM < 10313
+ Lock();
+#endif
+ if (m_bStartReceiver == true)
+ {
+ if (!m_bWaitPts)
+ {
+ EnableGet();
+ }
+ else
+ {
+ if (m_waitPts < m_dxr3Device.GetSysClock() ||
+ m_waitPts - m_dxr3Device.GetSysClock() < m_waitDelta)
+ {
+ EnableGet();
+ m_bWaitPts = false;
+ }
+ }
+ }
+#if VDRVERSNUM < 10313
+ Unlock();
+#endif
+}
+
+// ==================================
+void cDxr3SyncBuffer::WaitForReceiverStopped(void)
+{
+ if (!m_bGetBlock)
+ {
+ receiverStoppedMutex.Lock();
+ receiverStopped.Wait(receiverStoppedMutex);
+ receiverStoppedMutex.Unlock();
+ }
+}
+
+// ==================================
+void cDxr3SyncBuffer::ReceiverStopped(void)
+{
+ receiverStopped.Broadcast();
+}
+
+// Local variables:
+// mode: c++
+// c-file-style: "stroustrup"
+// c-file-offsets: ((inline-open . 0))
+// indent-tabs-mode: t
+// End: