`
he91_com
  • 浏览: 376166 次
文章分类
社区版块
存档分类
最新评论

(HLS播放器之三)播放数据缓存机制之环形buffer

 
阅读更多

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循环,特别关照它呀!


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics