播放器接收缓冲区的设计思路

编者:李国帅

qq:9611153 微信lgs9611153

时间:2013-2-28 8:39:15

背景原因:

旧时文档,当时编写播放器时的设计思路

 

设计思路:

 

1、使用大块的内存,然后使用环形存储,以前使用过

                   申请8M内存

                   添加不同大小的数据帧,比如1K,5K等等,每次写入一帧读取一帧。

                   每一帧的头部若干个字节是一个结构体,说明当前帧的序号,长度,在大内存中的位置等等。

                   也可以建立一个数据帧的索引,每个索引包含一个结构体,结构体里面对数据进行索引和定位。

                   这个设计最关键的部分在于读写到内存结尾处,怎么返回头部进行读写。读取速度大于写入速度该如何处理等等。

 

                   优点是占用内存少,没有内存碎片。

                   缺点是:逻辑复杂,容易出错。

2、当前方法:申请独立的内存

                   申请一个固定的索引结构体数组

                            m_pFrameQueue = new FrameNode[m_nMaxQueueLen];

                            typedef struct  _tagFrameNode

                            {

                                     LONG                          nFrameType;             //BYTE

                                     LONG                          nIndex;                       //

                                     REFERENCE_TIME   lTimestamp;              // frame's timestamp

                                     _tagFrameNode*    prev;                            // point to next node

                                     _tagFrameNode*    next;                            // point to next node

                                     LONG                          lSize;                            // frame's size of pDataBuffer

                                     PBYTE                         pDataBuffer;   // frame's data

                            }FrameNode;//描述了客户端在接收到数据组成的帧格式,缓存队列以此结点存储。

                   把结构体首尾串联起来

                            m_pReadPos = m_pWritePos = m_pFrameQueue;

                            FrameNode *p = m_pFrameQueue;

                            p->prev = m_pFrameQueue+(m_nMaxQueueLen-1);

                            p->nIndex = 0;

                            for(UINT i = 1; i < m_nMaxQueueLen; i++)

                            {

                                     p->nIndex = i;

                                     p->pDataBuffer= NULL;

                                     p->lSize = 0;

 

                                     p->next    = m_pFrameQueue + i;

                                     p = p->next;

                                     p->prev = m_pFrameQueue + i-1;

                            }

                            p->next = m_pFrameQueue;

                   为所有的结构体数据指针分配内存

                            p = m_pFrameQueue;

                            for(UINT i = 0; i < m_nMaxQueueLen; i++)

                            {

                                     p->pDataBuffer= (BYTE*)malloc(m_nMaxFrameSize);

                                     if(p->pDataBuffer!=NULL)m_nAllocCount++;

                                     p = p->next;

                            }

                   添加数据

                            m_pWritePos->lTimestamp = pFrameNode->lTimestamp;

                            m_pWritePos->nFrameType = pFrameNode->nFrameType;

                            m_pWritePos->lSize = pFrameNode->lSize;

                            memcpy(m_pWritePos->pDataBuffer, pFrameNode->pDataBuffer, m_pWritePos->lSize);

 

                            m_nCounts++;

                            m_pWritePos = m_pWritePos->next;

                   读取数据

                            pFrameNode = m_pReadPos;

                            m_pReadPos = m_pReadPos->next;

                            m_nCounts--;

 

                   优点是:逻辑简单,速度快。

                   缺点是:无效内存太多。如果播放器较多,内存耗费量大。每帧数据大小不一,比如cif和高清数据帧大小不一,这时候会存在兼容性浪费。

                  

3、可以使用共享内存(综合以上两种方法)

                   但是没有必要使用真正操作系统意义上的共享内存,而只是整个应用程序能够使用的共享内存。

                   只要把应用程序做成一个单件,那么就可能让所有的模块或者实例来使用它。

                   需要很多时间,并且需要很多的调试,暂时不使用这样的改造。

 

                   如果大家都从一个地方获取资源,那么怎么处理只用不还的问题?这就变成了吃大锅饭。

                   每个人自己管理自己的资源才能够更加有效的实现整个资源的优化管理。

                   发现把内存集中起来更不好控制。

 

                   尝试不能成功的关键还是没有做好帧的控制,导致解码出现问题,directshow中pin的deliver函数阻塞。

                            如果缓冲区满,后面所有的帧都不能添加。如果缓冲区中腾出了空间,应该找到一个关键帧放进去,而不是遇到一个放一个。

                            如果缓冲区满,可以把非关键帧丢掉,直到遇到一个关键帧再播放。

                            不能因为这个帧过大而把它丢掉,因为这个可能是个关键帧,丢掉之后后面的p帧很难进行解码。

                           

附加

                   一个不成熟的逻辑,缓冲区必须缓冲一定数量数据的时候才能播放。0正在缓冲,1正在播放//如果全部播放就需要重新缓冲

 

猜你喜欢

转载自blog.csdn.net/lgs790709/article/details/84838347
今日推荐