1. 程式人生 > >播放器接收緩衝區的設計思路

播放器接收緩衝區的設計思路

編者:李國帥

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正在播放//如果全部播放就需要重新緩衝