h264檢測是I幀還是P幀,解決錄影第一幀有馬賽克問題
最近使用h264碼流資料進行錄影,但是錄出來的第一幀有馬賽克,究其原因是錄影的第一幀不是關鍵幀,所以需要錄影是需要判斷第一幀是否是關鍵幀,方法有兩種,第一種是原碼流的基礎上查詢,第二種是將原碼流傳遞給ffmpeg讓ffmpeg判斷key_frame,第二種相對簡單,但是由於這樣一來錄影和解碼視訊切合的太緊密,之後修改比較麻煩,所以選擇第一種方案,檢視註釋1可以明白如何檢測h264碼流的關鍵幀,下面是我擷取原碼流的關鍵幀和p幀
0000000 :是sps
0000000 : 是pps
0000000 : 是幀型別
關鍵幀型別:
-
<span style="color:#FF0000;"><span style=
- 0000010: a</span><span style="color:#3366FF;">000 0000 0168 ce38 80</span>00 0000 01<span style="color:#000000;">65</span> 8880 .....h.8.....e..
-
0000020: 4001 8231 2000 4f11 d84d 5fff fb3b c28a @..1 .O..M_..;..
- 0000030: 00bc fc83 03db b3e3 8603 9c59 fa0f a82c ...........Y...,
- 0000040: df55 fdf6 8414 032a e766 bd4b fbea 05af .U.....*.f.K....</span>
- </span>
P幀型別:
- 0000000: <span style="color:#C0C0C0;">0000 0001 6742 401f 9654 0501 ed00 f39e [email protected]......
-
0000010: a</span><span style="color:#3366FF;">000 0000 0168 ce38 80</span>00 0000 01<span style=
- 0000020: 0586 7cb9 9125 5788 8f90 7f1f 1930 7eef ..|..%W......0~.
- 0000030: 6383 bebd 2cc5 3627 92c3 390b 46dc d4a5 c...,.6'..9.F...
- 0000040: 774b 3484 57f8 9840 fba3 1dd6 800f 2242 wK4.W..@......"B
- 0000050: 8816 080f 8f8d 84c6 09aa cda6 363d 00da ............6=..
- 0000060: b563 4392 bc65 93e2 63bb 6d30 472e 3ef1 .cC..e..c.m0G.>.
- 0000070: 545d 6a3f 36c3 2f7d 6b1e 3c91 d15d d687 T]j?6./}k.<..]..
所以在程式碼中需要檢索第29個位元組,來判斷是65還是41,
- public static String byteToHexString(byte src){
- StringBuilder stringBuilder = new StringBuilder("");
- int v = src & 0xFF;
- String hv = Integer.toHexString(v);
- if (hv.length() < 2) {
- stringBuilder.append(0);
- }
- stringBuilder.append(hv);
- return stringBuilder.toString();
- }
- private boolean isFirstIFrame = true;
- private String IFrame = "65";//關鍵幀是0x65
- //<span style="font-size:16px"></span>bArrayImage是存放h264原碼流位元組陣列
- if (是在錄影) {
- if (isFirstIFrame) {
- String type = byteToHexString(bArrayImage[29]);
- if (type.equals(IFrame)) { //第29個字元是判斷幀的型別
- isFirstIFrame = false;
- ShootingVideoData(bArrayImage, Video_Data_iVideoLen);//錄製第一幀:關鍵幀
- }
- }else {
- ShootingVideoData(bArrayImage, Video_Data_iVideoLen);
- }
- }
這樣在錄製出的第一幀錄影就沒有馬賽克了。
註釋1:檢測h264中I幀,P幀
今天在網上找了一些資料,知道了如何檢測h264中的幀型別,在這裡記錄下來。
首先,貼出nal單元型別定義(圖從《新一代視訊壓縮編碼標準H.264》摘錄):
假設一段h264的碼流為:00 00 00 01 41 E6 60……
其中的00 00 00 01為起始碼,而起始碼之後的下一個位元組就可以檢測出這一幀的型別。
在上面的碼流中起始碼之後的位元組位 0x41,換算成二進位制為 0100 0001。
注:我解讀順序為從左往右算。
(1)第1位禁止位,值為1表示語法出錯
(2)第2~3位為參考級別
(3)第4~8為是nal單元型別,在此處為 0 0001換算成十進位制為1。根據上圖可知道這段碼流是【不分割槽、非IDR影象的片】,在baseline的檔次中就是P幀,因為baseline沒有B幀。
如果是另一段碼流:00 00 00 01 65 E8……
那麼根據0x65位元組(0110 0101)根據後5位換算十進位制為5,也就是【IDR影象中的片】,即I幀。
用程式碼的方式可以這樣寫,int type = 0x65 & 0x1f,然後根據type在表中查詢即可獲得需要的結果。