將h.264視頻流封裝成flv格式文件

1、flv 格式

本文轉自:http://blog.csdn.net/yeyumin89/article/details/7932368 對其文章的格式稍作調整,並修改了部分 type error.

flv 文件的格式其實網上資料仍是很多,可是怎麼封裝成 flv 卻很少。看了很多資料,找到了一個以爲還比較靠譜的: html

http://www.cnblogs.com/chef/archive/2012/07/18/2597279.html 數組

其實 flv 仍是挺簡單的一個視頻格式,下面就來先談一談 FLV 的格式吧。 ide

FLV 是一個二進制文件,簡單來講,其是由一個文件頭(FLV header)和不少 tag 組成(FLV body)。tag 又能夠分紅三類: audio, video, script,分別表明音頻流,視頻流,腳本流,而每一個 tag 又由 tag header 和 tag data 組成。 工具

文件頭由 9 bytes 組成 學習

 

前3個 bytes 是文件類型,老是「FLV」,也就是(0x46 0x4C 0x56)。第4 btye 是版本號,目前通常是 0x01。第5 byte 是流的信息,倒數第一 bit 是1表示有視頻(0x01),倒數第三 bit 是1表示有音頻(0x4),有視頻又有音頻就是 0x01 | 0x04(0x05),其餘都應該是 0。最後 4 bytes 表示 FLV 頭的長度,3+1+1+4 = 9 測試

FLV header 後面就是 FLV body,FLV body 由若干個 tag 組成。每個 tag 第一部分是 tag header,tag header 長度爲 11 bytes,可是每一個 tag header 前面有 4 bytes 記錄着上一個 tag 的長度,此待會兒再說。tag header 的第1個 byte 爲記錄着 tag 的類型,音頻(0x8),視頻(0x9),腳本(0x12);第2到4 bytes 是數據區的長度,也就是 tag data 的長度;再後面3個 bytes 是時間戳,單位是毫秒,類型爲0x12則時間戳爲0,時間戳控制着文件播放的速度,能夠根據音視頻的幀率類設置;時間戳後面一個 byte 是擴展時間戳,時間戳不夠長的時候用;最後3 bytes 是 streamID,可是總爲0,再後面就是數據區了(tag data),也便是h264的裸流,tag header 長度爲1+3+3+1+3=11。 spa

0x12 前面的 00 00 00 00 就是剛剛說的記錄着上一個 tag 的長度的4 bytes,這裏由於前面沒有tag,因此爲0。 .net

tag data 若是是音頻數據,第一個 byte 記錄 audio 信息: 設計

前 4 bits 表示音頻格式(所有格式請看官方文檔): code

·0 -- 未壓縮

·1 -- ADPCM

·2 -- MP3

·4 -- Nellymoser 16-kHz mono

·5 -- Nellymoser 8-kHz mono

·10 -- AAC

下面兩個 bits 表示 samplerate:

·0 -- 5.5KHz

·1 -- 11kHz

·2 -- 22kHz

·3 -- 44kHz

下面1 bit 表示採樣長度:

·0 -- snd8Bit

·1 -- snd16Bit

下面1 bit 表示類型:

·0 -- sndMomo

·1 -- sndStereo

以後是數據。

若是是視頻數據,第一個 byte 記錄 video 信息:

前4 bits 表示類型:

·1-- keyframe

·2 -- inner frame

·3 -- disposable inner frame (h.263 only)

·4 -- generated keyframe

後4 bits 表示解碼器 ID:

·2 -- seronson h.263

·3 -- screen video

·4 -- On2 VP6

·5 -- On2 VP6 with alpha channel

·6 -- Screen video version 2

·7 -- AVC (h.264)

以後是數據。


若是是 AAC 和 AVC 的音視頻,則在放入數據前有一個音頻和視頻的配置信息須要寫入前兩個 tag,等會再說。以前說每一個 tag 前面會有一個記錄上個 tag 長度的4個bytes(previous tag size),整個的 flv 文件實際上是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。第一個 previous tag size 由於前面沒有 tag,因此爲0,其餘的老是記錄着前面一個 tag 長度(tag data size + tag header size)。

 

若是 tag data 是腳本數據,Script Tag Data,該類型 Tag 又一般被稱爲Metadata(元數據) Tag,會放一些關於 FLV 視頻和音頻的參數信息,如duration、width、height等。一般該類型 Tag 會跟在 File Header 後面做爲第一個 Tag 出現,並且只有一個。通常來講,該 Tag Data 結構包含兩個 AMF 包。AMF(Action Message Format)是 Adobe 設計的一種通用數據封裝格式,在Adobe 的不少產品中應用,簡單來講,AMF 將不一樣類型的數據用統一的格式來描述。第一個 AMF 包封裝字符串類型數據,用來裝入一個「onMetaData」標誌,這個標誌與 Adobe 的一些 API 調用有,在此不細述。第二個 AMF 包封裝一個數組類型,這個數組中包含了音視頻信息項的名稱和值。具體說明以下,你們能夠參照圖片上的數據進行理解

第一個 AMF 包:

第1個字節表示 AMF 包類型,通常老是0x02,表示字符串,其餘值表示意義請查閱文檔。

第2-3個字節爲 UI16 類型值,表示字符串的長度,通常老是 0x000A(「onMetaData」長度)。

後面字節爲字符串數據,通常總爲「onMetaData」。

第二個AMF包:

 第1個字節表示 AMF 包類型,通常老是 0x08,表示數組。

 第2-5個字節爲 UI32 類型值,表示數組元素的個數。

 後面即爲各數組元素的封裝,數組元素爲元素名稱和值組成的對。表示方法以下:

   第1-2個字節表示元素名稱的長度,假設爲L。

   後面跟着爲長度爲L的字符串。

   第L+3個字節表示元素值的類型。

  後面跟着爲對應值,佔用字節數取決於值的類型

 

到此flv格式的解析就差很少了,若有寫錯的地方請指出。

附上一個網友寫的flv的查看工具:
http://download.csdn.net/detail/yeyumin89/4534822 

2、開始動手

前面寫了 flv 文件的解析,有 h264 裸流的話就開始封裝吧。網上大多數都是用ffmeg 庫來作這個工做的,哎,學習資料少學不會,仍是本身動手吧。

封裝前要先了解下 h.264 格式,只須要知道一點點就能夠了,我看了 h.264 官方文檔,我靠,3百多頁,還全是中文,什麼,是中文?既然是中文的我就勉強看下吧,我靠,看起來還很複雜的,果斷不看了,不須要,也沒時間,我又不作解碼,這東西具體步驟資料又少,基本都是那一兩篇轉來轉去,這還要感謝我上一篇提到的那個鏈接的兄弟,記錄下過程,否則之後就忘乾淨了。
 
h264 是一個個 NALU 單元組成的,每一個單元以 00 00 01 或者 00 00 00 01分隔開來,每2個 00 00 00 01 之間就是一個 NALU 單元。咱們實際上就是將一個個 NALU 單元封裝進 FLV 文件
 

每一個NALU單元開頭第一個 byte 的低5 bits 表示着該單元的類型,即  NAL nal_unit_type:
#define NALU_TYPE_SLICE 1
#define NALU_TYPE_DPA 2
#define NALU_TYPE_DPB 3
#define NALU_TYPE_DPC 4
#define NALU_TYPE_IDR 5
#define NALU_TYPE_SEI 6          
#define NALU_TYPE_SPS 7
#define NALU_TYPE_PPS 8
#define NALU_TYPE_AUD 9

#define NALU_TYPE_EOSEQ 10
#define NALU_TYPE_EOSTREAM 11

#define NALU_TYPE_FILL 12


每一個 NALU 第一個 byte & 0x1f  就能夠得出它的類型,好比上圖第一個 NALU:67 & 0x1f = 7,則此單元是 SPS,第三個:68 & 0x1f = 8,則此單元是 PPS。
 
前一章說到若是數據是 AAC 或者 AVC 的話,則有一個音頻和視頻的配置信息須要寫入前兩個 tag(metadata 以後),AAC 音頻就不說了,在 ISO-14496-3 Audio 中有描述,給一張圖。
 
說下 AVC 視頻流的 configuretion,ISO-14496-15 AVC file format 有詳細描述,先給兩張圖,一張是說明,一張是實際截圖。
 

這個例子是對應我第一個截圖來的,通常 h264 數據最開始的兩個 NALU 就是 SPS 和 PPS,可是我如今尚未明白爲何個人那個 h264 裸流在開始的時候會有兩個 SPS、PPS,並且以後數據還會不時的出現,可是我沒有管這個,依然只各弄了一個進去,其餘的忽略掉了,反正多餘的我都忽略了,也沒發現有什麼錯。反正首先把音視頻的配置信息封進 metadata 以後的 tag,而後就能夠封數據了。再說下元數據,flv header 以後就是它了,再以後就是音視頻配置信息,再後面就是音視頻數據,元數據前一章說了是 AMF 格式的,按格式封就好了,測試其實沒有元數據視頻也能夠正常播放,等會再簡單說下 AMF吧。

 
 

如今開始封裝 h264 數據吧,前一章提到了 flv 關於 AVC 的格式,除開元數據,其餘數據是:一個 byte 的 video 信息 + 一個 byte 的 AVCPacket type + 3 個 bytes 的無用數據(composition time,當 AVC 時無用,全是 0)+ 4 個bytes 的 NALU 單元長度 + N 個bytes 的 NALU 數據,因此包頭數據長度信息是剛纔提到的信息的總和長度。要強調下,當音視頻配置信息 tag 的時候,是沒有 4 個 bytes 的 NALU 單元長度的


AVC 的配置信息時,先上一個圖,


17 -- 高4 bits:1,keyframe。 低4 bits:7,表明 AVC。 後面一個 byte 0x00,AVCPacket type,表明 AVC sequence header。後 3 個 bytes 無心義,以後就是 decoder configuration record 的內容了。 圖中綠色後面 00 00 00 28 就是前面 tag 的總長度

 
當 NALU 第一個 byte xx & 0x1f == 5 的時候,說明該單元是一個 I frame,關鍵幀

17 -- 和上面的同樣。 01 -- AVC NALU。藍色框內的 4 個 bytes 記錄後面 NALU 數據的長度。65 & 0x1f == 5.
 
若是 NALU 第一個 byte xx & 0x1f != 5 的時候,就不是一個 I frame

27 -- 高4 bits:2,inter frame ,P frame。 低4 bits:7,AVC NALU。其餘都同樣。圖中綠色後面 00 00 00 28 就是前面 tag 的總長度。
 
 
整個的flv文件實際上是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。

  1. tag1 是 metadata,記錄視頻的一些信息;
  2. tag2 是視頻配置信息(AVC decoder configuration record),
  3. tag3 是音頻配置信息(若是沒有音頻則去掉此項),
  4. tag4以及以後的tag就是音視頻數據了。

每個結構怎麼封都說清楚了,安上面的步驟一個一個NALU封就好了。
 

封包的時候要特別注意一下包頭裏面的時間戳,由於這個控制着播放的速度,若是不填,全是 0 的話,播放會至關快,通常按視頻幀率來設置。我這個 h264 流是 8 幀的,因此我每一個 tag 的時間間隔是 125ms 左右。


注意了,flv裏面的數據都是大端模式,放數據進去要轉換一下,若是你是一般的小端的機器的話。
 
 
到這裏應該差很少了吧,我是一個 NALU 單元封裝成一個 tag,我也是剛接觸,不知道上述還有哪些地方不合理,不過測試沒有發現問題。我也才接觸這東西,若是有知情人,望解釋一下爲何有多個 PPS SPS,謝謝
相關文章
相關標籤/搜索