給公司的直播推流框架加上了攜帶SEI的功能偏序,做完了記錄一下
這個(gè)東西使用場(chǎng)景挺廣的,比如直播中的動(dòng)畫(huà)效果,直接渲染到畫(huà)面上可能會(huì)引起性能消耗吩案,不如通過(guò)SEI告訴給觀眾,由觀眾端做出UI響應(yīng)帝簇,既能保持直播畫(huà)面和效果同步出現(xiàn)徘郭,又能減少主播端的性能消耗,其次丧肴,對(duì)于音頻視頻文件資源残揉,可以通過(guò)SEI在視頻中埋入版權(quán)等信息。
H264編碼由兩個(gè)部分組成(VCL和NAL)
畫(huà)面幀首先要經(jīng)過(guò) 視頻編碼層面(VCL) 被編碼層切割成宏塊芋浮,這不是本篇記錄的重點(diǎn)抱环,不展開(kāi)講
之后這些塊會(huì)被 網(wǎng)絡(luò)抽象層面(NAL) 分割成多個(gè)NALU塊
NAL | NAL | NAL | NAL | ... |
---|
這些NAL塊里一部分是裝著上面切割的畫(huà)面數(shù)據(jù),一部分裝著描述這個(gè)視頻的參數(shù)數(shù)據(jù)(輸序列參數(shù)集和圖像參數(shù)集等等)
接著拆
每個(gè)NAL又可以拆成NAL Header和RBSP
NAL Header | RBSP | NAL Header | RBSP | ... |
---|
其中NAL Header描述了這個(gè)NAL的類型及攜帶了什么樣的參數(shù)纸巷,RBSP則是這個(gè)NAL攜帶的內(nèi)容
NAL Header的位圖如下
1江醇、F(forbiden):禁止位,占用NAL頭的第一個(gè)位何暇,當(dāng)禁止位值為1時(shí)表示語(yǔ)法錯(cuò)誤陶夜;
2、NRI:參考級(jí)別裆站,占用NAL頭的第二到第三個(gè)位条辟;值越大黔夭,該NAL越重要。
3羽嫡、Type:Nal單元數(shù)據(jù)類型本姥,也就是標(biāo)識(shí)該NAL單元的數(shù)據(jù)類型是哪種,占用NAL頭的第四到第8個(gè)位杭棵;
(摘自go_str博客)
其中我們比較關(guān)注的是其中的后5位婚惫,即NAL Type
其中Type = 6 表示該NAL攜帶的是輔助增強(qiáng)信息(SEI)
由上面NAL Header的位圖可知,Type=6時(shí)魂爪,NAL Header的 頭是
00 00 00 01 06
___________ __
NAL起始(start code) NAL Type
接下來(lái)是SEL的參數(shù)先舷,SEI信息包含幾個(gè)主要要素
· SEI payload type (該SEI遵循的語(yǔ)法)
· SEI payload size (該SEI所攜帶信息的長(zhǎng)度)
這里我們只討論SEI payloadType = 5的情況,即遵循user_data_unregistered()語(yǔ)法的SEI信息
· SEI payload uuid (SEI)
· SEI payload content
以及作為結(jié)尾的
· rbsp trailing bits (0x80)
一個(gè)個(gè)來(lái)講滓侍,首先是SEI payload type
他的解析方式為蒋川,持續(xù)讀取8bit,直到非0xff為止撩笆,然后把讀取的數(shù)值累加捺球,累加值即為SEI payload type。
接在SEI payload type 后面的夕冲,即SEI payload size氮兵,讀取SEI payload size和payload type邏輯類似,仍然是讀取到非0xff為止歹鱼,這樣可以支持任意長(zhǎng)度的SEI payload添加泣栈。
那么按照以上邏輯,再拼上start code和NAL Type
00 00 00 01 06 05 12
___________ __ —— __
NAL起始(start code) NAL Type SEIPayloadType SEIPayloadSize
即 00 00 00 01 06 05
以上就是一個(gè)遵循user_data_unregistered()語(yǔ)法醉冤、payloadContent長(zhǎng)度為18byte的SEI參數(shù)定義
定義好參數(shù)接下來(lái)就是內(nèi)容部分
首先user_data_unregistered()語(yǔ)法要求在SEI payload size之后的16byte作為SEI payload uuid秩霍,該uuid由用戶自定義篙悯,可以作為業(yè)務(wù)的標(biāo)識(shí)參數(shù)
01 02 03 04 01 02 03 04 01 02 03 04 01 02 03 04
因?yàn)閡uid固定為16蚁阳,所以SEI payload size的長(zhǎng)度必須大于等于16
然后就是SEI payload content,自由發(fā)揮鸽照,不要超過(guò)(content size - 16)即可螺捐,以0x00作為字符串結(jié)尾,
05 00
因?yàn)樯厦娑x的size = 18 ,所以這里只有2byte作為content
最后再給這條NAL拼上結(jié)束標(biāo)示
80
綜上所致矮燎,該條NAL的完整樣式即為
00 00 00 01 06 05 12 01
02 03 04 01 02 03 04 01
02 03 04 01 02 03 04 05
00 80
到這里本篇的學(xué)習(xí)記錄就結(jié)束了
接下來(lái)要做的事就是把這條NAL在h.264編碼過(guò)程中混進(jìn)碼流里定血,然后塞進(jìn)RTMP,變成Message诞外,再切成Chunk澜沟,發(fā)出去就完事了……
至于接受端如何解析,我司有大佬修改ijkPlayer已經(jīng)實(shí)現(xiàn)了SEI信息的解析峡谊,本人暫時(shí)沒(méi)有研究到(太忙唉……)茫虽,排上日程刊苍,抽時(shí)間去拜讀一下源碼
很久沒(méi)有寫(xiě)文章了,感謝閱讀濒析,歡迎各位交流雅正
參考引用:
1.go_str的博客 入門理解H264編碼
2.金山云的博客 FFmpeg從入門到精通——進(jìn)階篇正什,SEI那些事兒