天天看點

使用Intel media SDK h264編碼後的資料幀分析及用vlc播放不出原因分析

使用Intel media SDK寫死H264資料然後儲存成264檔案,用vlc播放失敗。

預設編碼是第一幀有IDR幀,後續都沒有I幀,這裡打開儲存的264檔案分析資料幀時發現其資料幀如下

使用Intel media SDK h264編碼後的資料幀分析及用vlc播放不出原因分析
使用Intel media SDK h264編碼後的資料幀分析及用vlc播放不出原因分析

從上圖中可以看到,第一個00 00 00 01 09可以判斷出是分界符的類型,第二個00 00 00 01 27是SPS,第三個00 00 00 01 28是PPS,第四個00 00 00 01 06是SEI,第五個00 00 01 25才是IDR。判斷類型補充如下,參考https://blog.csdn.net/jefry_xdz/article/details/8461343

我們還是接着看最上面圖的碼流對應的資料來層層分析,以00 00 00 01分割之後的下一個位元組就是NALU類型,将其轉為二進制資料後,解讀順序為從左往右算,如下:
(1)第1位禁止位,值為1表示文法出錯
(2)第2~3位為參考級别
(3)第4~8為是nal單元類型

例如上面00000001後有67,68以及65

其中0x67的二進制碼為:
0110 0111
4-8為00111,轉為十進制7,參考第二幅圖:7對應序列參數集SPS

其中0x68的二進制碼為:
0110 1000
4-8為01000,轉為十進制8,參考第二幅圖:8對應圖像參數集PPS

其中0x65的二進制碼為:
0110 0101
4-8為00101,轉為十進制5,參考第二幅圖:5對應IDR圖像中的片(I幀)
           

接着是後面的非IDR幀資料,如下圖

使用Intel media SDK h264編碼後的資料幀分析及用vlc播放不出原因分析

依次分别是0x00 00 00 01 09(分隔符)|| 0x00 00 00 01 28(PPS)|| 0x00 00 00 01 06(SEI)|| 0x00 00 01 21(非IDR)。

是以用vlc播放失敗的原因就在于這個分隔符,必須去掉這個分隔符才行。

Intel media SDK裡有個sample_encode指令行程式,在執行sample_encode.exe h264 -i out.yuv -o out.264 -w 544 -h 960 -PicTimingSEI:off的時候,發現仍然沒有去掉這個0x00 00 00 01 09(分隔符),通過參考https://blog.jianchihu.net/intel-media-sdk-remove-unused.html,發現在代碼裡pipeline_encode.cpp檔案裡添加m_CodingOption.AUDelimiter = MFX_CODINGOPTION_OFF;能去掉分隔符,如下:

//-PicTimingSEI:off添加這個選項pInParams->nPicTimingSEI就會為true
if (pInParams->nPicTimingSEI || pInParams->nNalHrdConformance || pInParams->nVuiNalHrdParameters)
    {
        //隻有進入到這裡通過設定bCodingOption為true,m_CodingOption的配置才能生效
        m_CodingOption.PicTimingSEI = pInParams->nPicTimingSEI;
        m_CodingOption.NalHrdConformance = pInParams->nNalHrdConformance;
        m_CodingOption.VuiNalHrdParameters = pInParams->nVuiNalHrdParameters;
        
        //這行代碼才是關鍵,很奇怪的是在inter media sdk說明文檔裡對這個測試程式的附加選項中沒有這個值的對應選項,目前隻能在代碼裡設定,不能通過指令行來設定
        m_CodingOption.AUDelimiter = MFX_CODINGOPTION_OFF;
        bCodingOption = true;
    }
    if (bCodingOption)
    {
        m_EncExtParams.push_back((mfxExtBuffer *)&m_CodingOption);
    }