H264 幀邊界識別簡介

http://blog.sina.com.cn/s/blog_76550fd70101gh1q.html


H.264 將構成一幀圖像所有nalu 的集合稱爲一個AU,幀邊界識別實際上就是識別AU。
因爲H.264 取消幀級語法,所以無法簡單地從碼流中獲取AU。解碼器只有在解碼的過
程中,通過某些語法元素的組合才能判斷一幀圖像是否結束。一般來說,解碼器必須在
完成一幀新圖像的第一個slice_header 語法解碼之後,才能知道前一幀圖像已經結束。
因此,最嚴謹的AU 識別步驟如下:
步驟 1 對碼流實施“去03 處理”。
步驟 2 解析nalu 語法。
步驟 3 解析slice_header 語法。
步驟 4 綜合判斷前後兩個nalu 以及對應的slice_header 中的若干個語法元素,看是否發生變化。
如果發生變化,則說明這兩個nalu 屬於不同的幀,否則說明這兩個nalu 屬於同一幀。
----結束
顯然,在解碼前完成上述的AU 識別消耗許多CPU 資源,因此不推薦使用AU 方式解碼
爲了提供一種簡單的AU 識別方案,H.264 規定一種類型爲09 的nalu,即編碼器在每次完成一個AU 編碼後,在碼流中插入一個類型爲09 的nalu,在這個前提下,解碼器只需要從碼流中搜索類型爲09 的nalu 即可獲得一個AU。
H.264 並不強制要求編碼器插入類型爲09 的nalu,因此並非所有的碼流都具備這種特徵。對於
編碼器和解碼器協同工作的應用場景,建議讓編碼器插入類型爲09 的nalu,這樣可以降低解碼
器識別AU 的代價。
爲了降低解碼器在解碼前識別AU 的代價,本文提出一種高效的AU 識別方法,其主要
思路是利用一幀圖像的第一個slice_header 中的語法元素first_mb_in_slice 一般等於0 這
個特徵(對於包含ASO 或者FMO 特性的碼流,這個條件不一定成立)。
typedef struct ParseContext{
    unsigned int FrameStartFound;
    unsigned int iFrameLength;
} ParseContext;
signed int DecLoadAU(unsigned char* pStream, unsigned int iStreamLen, ParseContext *pc)
    {
        unsigned int i;
        unsigned int state = 0xffffffff;
        if( NULL == pStream )
        {
            return -1;
        }
        for( i = 0; i < iStreamLen; i++)
        {
           
            if( (state & 0xFFFFFF1F) == 0x101 || (state & 0xFFFFFF1F) == 0x105 )
            {
                if (i >= iStreamLen)
                {
                    break;
                }if( pStream[i] & 0x80)
                {
                    if(pc->FrameStartFound)
                    {
                        pc->iFrameLength = i - 4;
                        pc->FrameStartFound = 0;
                        state = 0xffffffff;
                        return 0;
                    }
                    else
                    {
                        pc->FrameStartFound = 1;
                    }
                }
            }
            if (i < iStreamLen)
            {
                state = (state << 8) | pStream[i];
            }
        }
        pc->FrameStartFound = 0;
        return -1;
    }


解決了最關鍵的問題後, 下面就是將解碼完的數據送去播放的問題了, 可以啓動一個Timer, 定時去讀取一幀的數據送去解碼就可以。針對不同的幀率調整Timer的時間即可,當然最正規的做法是根據MP4或者AVI文件中的時間戳。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章