Loop buffer, 主要是获取到的播放数据进行缓存。对于HLS播放器的播放数据的处理有比较多的处理模式,如映射文件、LoopBuffer、切片存储等。就要看具体需要了。
现在来看这是我自定的LoopBuffer类
class CLoopBuffer
{
private:
CRITICAL_SECTION m_mutex;
__int64 m_iBufferSize; /*当前数据管理缓冲区的大小 */
__int64 m_iVaildLength; /*当前数据缓冲区中有效数据长度*/
unsigned char *m_pBuffer;
unsigned char *m_pBufTail;
unsigned char *m_pCurRead;
unsigned char *m_pCurWrite;
bool m_bInterrupt;
HANDLE hMutex;
bool m_downloadEnd_flag;
bool m_isRead; // 阅读判断符
bool m_isStop; // 强制终止标记
public:
CLoopBuffer(__int64 iBufferSize);
~CLoopBuffer();
__int64 _buffer_read(unsigned char* pData, __int64 iDataLen, bool bForceEnough);
void _buffer_write(unsigned char* pData, __int64 iDataLen);
void _buffer_interrupt();
void _buffer_reset();
void _buffer_reset_readBegin();
__int64 _buffer_getVaildLength(); //获取剩余量
void _buffer_setReadPos(__int64 pos); //设置播放位置
__int64 _buffer_readLength();
void _buffer_stopRead(); //停止读取工作
};
其中最重要就是标记位置的四个指针:
m_pBuffer: 缓存的头指针
m_pBufTail: 缓存的尾指针
m_pCurRead: 读取位置指针
m_pCurWrite: 写入位置指针
现在针对特殊的几个函数进行分析:
1、__int64CLoopBuffer::_buffer_read(unsigned char* pData, __int64 iDataLen, bool bForceEnough) 读取LoopBuffer缓存数据函数
入参分析:
unsigned char* pData :待填充的Buffer
_int64 iDataLen : 需要存储的数据大小
boolbForceEnough:是否满填充,true 表示必须填充iDataLen大小的数据,false 反之
分析:
1、设定可提供的数据量。如果bForceEnough = true,则表示满数据量填充。不足则需要等待
2、拷贝数据到pData中。如果m_pCurRead到m_pBufTail的数据量小于可读取量,则需要取到尾部数据,和头部到剩余大小的数据。
注意: 等待数据足够时,小心死循环了。其中应该有强制退出标记。
__int64 CLoopBuffer::_buffer_read(unsigned char* pData, __int64 iDataLen, bool bForceEnough)
{
if (NULL == m_pBuffer)
{
return 0;
}
__int64 iActualReadLen = iDataLen;
__int64 iCurrToEndLen = 0;
//1、得到需要提供的数据的长度
if(true == bForceEnough)
{
//必须等待有足够的数据可读
while(m_iVaildLength < iDataLen)
{
......
Sleep(50);
}
}
else
{
// 能满足条件尽量满足条件,不满足条件时有多少数据读多少数据
if(m_iVaildLength < iDataLen)
{
iActualReadLen = m_iVaildLength;
}
}
WaitForSingleObject(hMutex, 1L);
//2、根据实际情况Copy数据
//得到当前位置距离队列尾的长度
iCurrToEndLen = (__int64)(m_pBufTail - m_pCurRead);
if(iCurrToEndLen >= iActualReadLen)
{
//如果剩余长度足够,则直接copy并返回
memcpy(pData,m_pCurRead, iActualReadLen);
m_pCurRead += iActualReadLen;
}
else
{
//Step 1:有多少读多少
memcpy(pData, m_pCurRead, iCurrToEndLen);
//Step 2:移动到头部继续读剩余的数据
memcpy(pData+iCurrToEndLen, m_pBuffer, iActualReadLen-iCurrToEndLen);
m_pCurRead = m_pBuffer + (iActualReadLen - iCurrToEndLen);
}
//3、减少当前Buf的长度
EnterCriticalSection(&m_mutex);
m_iVaildLength -= iActualReadLen;
LeaveCriticalSection(&m_mutex);
return iActualReadLen;
}
2、void CLoopBuffer::_buffer_write(unsigned char* pData, __int64 iDataLen) 写入数据到Loop buffer中
不细说了,和读取有些道理相通的。
void CLoopBuffer::_buffer_write(unsigned char* pData, __int64 iDataLen)
{
__int64 iActualWriteLen = iDataLen;
__int64 iCurrToEndLen = 0;
//判断写入数据长度有效性
if(iActualWriteLen > m_iBufferSize)
{
return;
}
//等待有足够空间可用于写数据
while( (m_iBufferSize - m_iVaildLength) < iDataLen)
{
.....
Sleep(100);
}
//将数据Copy到Buffer中
iCurrToEndLen = (__int64)(m_pBufTail - m_pCurWrite);
if(iCurrToEndLen >= iDataLen )
{
//如果剩余长度足够,则直接copy并返回
memcpy(m_pCurWrite, pData, iDataLen);
m_pCurWrite += iDataLen;
}
else
{
// Step 1:能填充多少数据先填充多少数据
memcpy(m_pCurWrite, pData, iCurrToEndLen);
// Step 2:移动到头部继续填充剩余的数据
memcpy(m_pBuffer, pData+iCurrToEndLen, iDataLen-iCurrToEndLen);
m_pCurWrite = m_pBuffer + (iDataLen-iCurrToEndLen);
}
//增加当前buf的长度
EnterCriticalSection(&m_mutex);
m_iVaildLength += iDataLen;
LeaveCriticalSection(&m_mutex);
}
其他的函数只要起到控制功能、清空数据等处理。
大家一定要注意别出现死循环了。其中有一些While循环,特别关照它呀!