diff options
Diffstat (limited to 'dxr3syncbuffer.c')
-rw-r--r-- | dxr3syncbuffer.c | 420 |
1 files changed, 420 insertions, 0 deletions
diff --git a/dxr3syncbuffer.c b/dxr3syncbuffer.c new file mode 100644 index 0000000..8ea8ccd --- /dev/null +++ b/dxr3syncbuffer.c @@ -0,0 +1,420 @@ +/* + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +/* + ToDo: + - cDxr3SyncBuffer::Push: XXX This is only a workaround until a sufficient control algorithm is implemented +*/ + +#include <unistd.h> +#include "dxr3syncbuffer.h" +#include "dxr3memcpy.h" + +const int DXR3_MAX_VIDEO_FRAME_LENGTH = 4096; +const int DXR3_MAX_AUDIO_FRAME_LENGTH = 4096; + +// ================================== +cFixedLengthFrame::cFixedLengthFrame(uint32_t length) : +m_count(0), m_length(length), m_pts(0), m_type(ftUnknown) { + + m_pData = new uint8_t[length]; + if (!m_pData) + { + cLog::Instance() << "Failed to allocate memory in cFixedLengthFrame (m_pData) - will stop now"; + exit(1); + } + + m_audioChannelCount = UNKNOWN_CHANNEL_COUNT; + m_audioDataRate = UNKNOWN_DATA_RATE; + m_videoAspectRatio = UNKNOWN_ASPECT_RATIO; +} + +// ================================== +cFixedLengthFrame::~cFixedLengthFrame() +{ + if (m_pData) + { + delete[] m_pData; + } +} + +// ================================== +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; + dxr3_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; + + + + +// ================================== +cDxr3SyncBuffer::cDxr3SyncBuffer(int frameCount, int frameLength, cDxr3Interface& dxr3Device) : cRingBuffer(frameCount, true), m_dxr3Device(dxr3Device) +{ + m_pBuffer = new cFixedLengthFrame[frameCount](frameLength); + + if (!m_pBuffer) + { + cLog::Instance() << "Failed to allocate memory in cDxr3SyncBuffer (m_pBuffer) - will stop now"; + exit(1); + } + + 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; + Lock(); + ret = m_count; + Unlock(); + 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(); + m_bPollSync = true; + 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))) + { + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + } + 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; + + 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)) + { + m_bPutBlock = true; + EnableGet(); + m_bWaitPts = false; + WaitForPut(); + } + + Lock(); + 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) + { + cLog::Instance() << "Buffer overrun\n"; +// cLog::Instance() << "cDxr3SyncBuffer::Push m_demuxMode: " << (int)m_demuxMode << endl; +// cLog::Instance() << "cDxr3SyncBuffer::Push Available(): " << Available() << endl; +// cLog::Instance() << "cDxr3SyncBuffer::Push Size(): " << Size() << endl; + + 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; + } + } + Unlock(); + break; + } + + return &m_pBuffer[lastIndex]; +} + +// ================================== +void cDxr3SyncBuffer::Pop(void) +{ + Lock(); + 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(); + Unlock(); +} + +// ================================== +cFixedLengthFrame* cDxr3SyncBuffer::Get(void) +{ + cFixedLengthFrame* pRet = 0; + + if (!m_bStopped) + { + while (!Available() || !m_bStartReceiver) + { + m_bGetBlock = true; + ReceiverStopped(); + WaitForGet(); + } + + Lock(); + if (m_nextFree != m_next) + { + pRet = &m_pBuffer[m_next]; + } + Unlock(); + } + else + { + WaitForGet(); + } + + return pRet; +} + +// ================================== +void cDxr3SyncBuffer::Clear(void) +{ + Lock(); + 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(); + Unlock(); +} + +// ================================== +void cDxr3SyncBuffer::WaitForSysClock(uint32_t pts, uint32_t delta) +{ + m_waitPts = pts; + m_waitDelta = delta; + if (!m_bPutBlock) + { + Lock(); + m_bWaitPts = true; + Unlock(); + 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) +{ + Lock(); + 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; + } + } + } + Unlock(); +} + +// ================================== +void cDxr3SyncBuffer::WaitForReceiverStopped(void) +{ + if (!m_bGetBlock) + { + receiverStoppedMutex.Lock(); + receiverStopped.Wait(receiverStoppedMutex); + receiverStoppedMutex.Unlock(); + } +} + +// ================================== +void cDxr3SyncBuffer::ReceiverStopped(void) +{ + receiverStopped.Broadcast(); +} |