序言
關於1078實時監控的另一種做法,就是自己編碼處理音視頻裸流.這種形式需要了解更多的音視頻基礎知識,因爲之前的處理過程是JavaCV幫我們做了很多東西.本文只是做個準備工作,先了解一些基礎知識在,然後才能知道該方案的可行性
參考資料:
- https://blog.csdn.net/u013008311/article/details/80249586
- https://blog.csdn.net/u013008311/article/details/80251479
- https://blog.csdn.net/jefry_xdz/article/details/8461343
- https://www.cnblogs.com/wainiwann/p/7477794.html
- https://blog.csdn.net/bsplover/article/details/7426511
- https://blog.csdn.net/byxdaz/article/details/53993791
H264/AVC
視頻編解碼技術有兩套標準:
- 國際電聯(ITU-T)的標準H.263、H.263+等;
- ISO 的MPEG標準Mpeg1、Mpeg2、Mpeg4等等。
H.264/AVC是兩大組織集合H.263+和Mpeg4的優點聯合推出的最新標準,最具價值的部分無疑是更高的數據壓縮比。在同等的圖像質量條件下,H.264的數據壓縮比能比H.263高2倍,比MPEG-4高1.5倍。 所以說H264和AVC 其實是指同一個東西.
H.264/AVC標準是由ITU-T和ISO/IEC聯合開發的,定位於覆蓋整個視頻應用領域,包括:低碼率的無線應用、標準清晰度和高清晰度的電視廣播應用、Internet上的視頻流應用,傳輸高清晰度的DVD視頻以及應用於數碼相機的高質量視頻應用等等。
ITU-T給這個標準命名爲H.264(以前叫做H.26L),而ISO/IEC稱它爲MPEG-4 高級視頻編碼(Advanced Video Coding,AVC),並且它將成爲MPEG-4標準的第10部分。既然AVC是當前MPEG-4標準的拓展,那麼它必然將受益於MPEG-4開發良好的基礎結構(比如系統分層和音頻等)。很明顯,作爲MPEG-4高級簡潔框架(Advanced Simple Profile,ASP)的MPEG-4 AVC將會優於當前的MPEG-4視頻壓縮標準,它將主要應用在具有高壓縮率和分層次質量需求的方向。
H264原始碼流是一個接一個的NALU(網絡抽象層單元)租成的,每個單元之間是由 0x00 0x00 0x00 0x01 或者 0x00 0x00 0x01分割而成的,緊接着就是NALU的單元頭和數據體.(注意這裏的NALU是很重要的,因爲後面我會一定要現貨區NALU才能進行編碼操作與封裝操作[email protected],注意這裏的分隔符~~很重要,我們在收到終端的推流數據的時候就會遇到)
NAL
在H.264/AVC視頻編碼標準中,整個系統框架被分爲了兩個層面:
- 視頻編碼層面(VCL):負責有效表示視頻數據的內容
- 網絡抽象層面(NAL):負責格式化數據並提供頭信息,保證數據適合各種信道和存儲介質上的傳輸(這個是我們要關注的重點)
因此我們平時的每幀數據就是一個NAL單元(SPS與PPS除外)。在實際的H264數據幀中,往往幀前面帶有00 00 00 01 或 00 00 01分隔符,一般來說編碼器編出的首幀數據爲PPS與SPS,接着爲I幀…… 注意這裏的分隔符[email protected]
SPS(參數集合)
SPS即Sequence Paramater Set,又稱作序列參數集。SPS中保存了一組編碼視頻序列(Coded video sequence)的全局參數。所謂的編碼視頻序列即原始視頻的一幀一幀的像素數據經過編碼之後的結構組成的序列。而每一幀的編碼後數據所依賴的參數保存於圖像參數集中。一般情況SPS和PPS的NAL Unit通常位於整個碼流的起始位置。但在某些特殊情況下,在碼流中間也可能出現這兩種結構,主要原因可能爲:(這個特殊情況不考慮)
- 解碼器需要在碼流中間開始解碼;
- 編碼器在編碼的過程中改變了碼流的參數(如圖像分辨率等)
PPS(參數集合)
除了序列參數集SPS之外,H.264中另一重要的參數集合爲圖像參數集Picture Paramater Set(PPS)。通常情況下,PPS類似於SPS,在H.264的裸碼流中單獨保存在一個NAL Unit中,只是PPS NAL Unit的nal_unit_type值爲8;而在封裝格式中,PPS通常與SPS一起,保存在視頻文件的文件頭中。(這個是我們的1078的環境,不考慮真實環境)
解析H264數據
最上面圖的碼流對應的數據來層層分析,以00 00 00 01分割之後的下一個字節就是NALU類型,將其轉爲二進制數據後,解讀順序爲從左往右算,如下:
- 第1位禁止位,值爲1表示語法出錯
- 第2~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幀)
所以判斷是否爲I幀的算法爲: (NALU類型 & 0001 1111) = 5 即 NALU類型 & 31 = 5
FLV封裝格式
FLV文件是由 FLV文件頭(FLV header)和 FLV文件體(FLV body)組成的。
FLV body又是由 (previous tag size 和 flv tag)* N 組成的。
Flv Header
FLV header 中包含的信息有: 文件類型、 FLV版本 、stream信息、 FLV header 長度。這個Header長度一般都是固定的9個字節:(注意這個頭信息需要搞明白,因爲後面我們的推流會要自己寫入頭信息,根據你的數據情況[email protected])
Flv Body(這個數據的生成過程其實不復雜,但是需要先搞清楚它原始的數據結構,比較耗費時間--心累)
FLV body中包含很多個FLV tag,tag的分類有三種:0x8音頻、0x9視頻、0x12腳本。(後面會對着3中類型的數據分別講解,每個類型的tag的作用不一樣音頻和視頻很容易區分,主要是腳本的作用)
每個tag中包含tag頭和tag體.
每個tag前面還有一個previous size包. 記錄着上一個tag的數據的長度(這個長度就是header 和 body 的長度總和)
Tag Header
Tag Body---0x12腳本
腳本tag 0x12(script tag),腳本tag描述了媒體信息,比如視頻的width 和 height ,幀率等等信息. (看到這感覺崩潰,不知道後面是否需要自己寫入腳本信息, 非常希望終端推送的數據已經包含了腳本[email protected])
圖中爲一個腳本tag的數據截圖,腳本tag在tag頭後面的tag數據中一般會包含兩個AMF包,AMF是Adobe設計的一種通用數據封裝格式。在第一個AMF包中有一個字符串類型的值,該值爲onMetaDate。第二個AMF包封裝一個“數據組”,每一組數據都有自己的元素名、元素類型、元素值、這裏不詳細描述(現在又引出了AMF的封裝格式---------痛哭流涕,這個後面空了在研究)
Tag Body---0x9視頻
視頻tag 0x9 視頻tag頭都是一樣的,1byte Tag類型,3bytes數據長度記錄,3bytes時間戳,一個擴展時間戳bype,3bytes StreamID。(後面跟了一個字節用於區分視頻的數據類型)
視頻tag頭後面的第一byte 的4bit表示視頻數據的類型,後4bit表示視頻的編碼器ID( 跟在這後面的纔是視頻幀的數據,如:I幀, P幀,B幀 等等---等等很牽強)
數據類型:1<->keyframe、2<->innerframe、3<->disposable inner frame(h.263)、4<->generated keyframe
編碼器ID:2<->h.263、3<->screen video、4<->On2 VP6、5<->On2 VP6 with alpha channel、6<->Screen video version、7<->AVC/h264 (注意這裏的 avc h264 其實是一個編碼器的不同稱呼-----希望終端推送的流數據中包含了~~~ =.=)
Tag Body---0x8音頻(這裏的音頻格式我們用的是G711A)
音頻tag0x8 和 視頻相比tagtype爲0x8 tag header 都是一樣的後面跟着的 tag數據類型,後續就是音頻的數據了。
音頻tag佔1byte 前4bit表示音頻格式(比如MP3),接着2bit表示採樣率,接着1bit表示採樣長度接着1bit表示音頻類型
音頻格式:0<->未壓縮、1<->ADPCM、2<->MP3、4<->Nellymoser 16-Hz mono、5<->Nellymoser 8-kHz mono、10<->AAC (竟然缺少了我們的G711A的編碼格式,但是字典表中肯定有的)
採樣率: 0<->5.5kHz、1<->11kHz、2<->22kHz、3<->44kHz (缺少了8kHz,字典表中肯定有的)
採樣位數:0<->snd8bit、1<->16bit(這個使我們要的)
音配類型:0<->sndMono(單聲道) 1<->sndStereo(立體聲)
稍微詳細一點的FLV文件格式說明
FLV-Header(這裏的UI標識bit,後面的數字標識幾個bit, ub就是ui數組)
- Signature: FLV 文件的前3個字節爲固定的‘F’‘L’‘V’,用來標識這個文件是flv格式的.在做格式探測的時候,
- 如果發現前3個字節爲“FLV”,就認爲它是flv文件.
- Version: 第4個字節表示flv版本號.
- Flags: 第5個字節中的第0位和第2位,分別表示 video 與 audio 存在的情況.(1表示存在,0表示不存在)
- DataOffset : 最後4個字節表示FLV header 長度.
Field | Type | Comment |
Signature | UI8 | Signature byte always 'F' (0x46) |
Signature | UI8 | Signature byte always 'L' (0x4C) |
Signature | UI8 | Signature byte always 'V' (0x56) |
Version | UI8 | File version (for example, 0x01 for FLV version 1) |
TypeFlagsReserved | UB [5] | Shall be 0 |
TypeFlagsAudio | UB [1] | 1 = Audio tags are present |
TypeFlagsReserved | UB [1] | Shall be 0 |
TypeFlagsVideo | UB [1] | 1 = Video tags are present |
DataOffset | UI32 | The length of this header in bytes |
The FLV File Body
FLV header之後,就是 FLV File Body.
FLV File Body是由一連串的back-pointers + tags構成.back-pointers就是4個字節數據,表示前一個tag的size.
所以第一個PreviousTagSize0 是 Flv Header的長度.
Field | Type | Comment |
PreviousTagSize0 | UI32 | Always 0 |
Tag1 | FLVTAG | First tag |
PreviousTagSize1 | UI32 |
Size of previous tag, including its header, in bytes. For FLV version1, this value is 11 plus the DataSize of the previous tag. |
Tag2 | FLVTAG | Second tag |
... | ... | ... |
PreviousTagSizeN-1 | UI32 | Size of second-to-last tag, including its header, in bytes. |
TagN | FLVTAG | Last tag |
PreviousTagSizeN | UI32 | Size of last tag, including its header, in bytes |
FLVTAG
- TagType: TAG中第1個字節中的前5位表示這個TAG中包含數據的類型,8 = audio,9 = video,18 = script data.
- DataSize:StreamID之後的數據長度.
- Timestamp和TimestampExtended組成了這個TAG包數據的PTS信息,記得剛開始做FVL demux的時候,並沒有考慮TimestampExtended的值,直接就把Timestamp默認爲是PTS,後來發生的現 象就是畫面有跳幀的現象,後來才仔細看了一下文檔發現真正數據的PTS是PTS= Timestamp | TimestampExtended<<24.
- StreamID之後的數據就是每種格式的情況不一樣了,接下格式進行詳細的介紹.
Field | Type | Comment |
Reserved | UB [2] | Reserved for FMS, should be 0 |
Filter | UB [1] | Indicates if packets are filtered. 0 = No pre-processing required. 1 = Pre-processing (such as decryption) of the packet is required before it can be rendered. Shall be 0 in unencrypted files, and 1 for encrypted tags. See Annex F. FLV Encryption for the use of filters. |
TagType | UB [5] |
Type of contents in this tag. The following types are |
DataSize | UI24 | Length of the message. Number of bytes after StreamID to end of tag (Equal to length of the tag – 11) |
Timestamp | UI24 | Time in milliseconds at which the data in this tag applies. This value is relative to the first tag in the FLV file, which always has a timestamp of 0. |
TimestampExtended | UI8 | Extension of the Timestamp field to form a SI32 value. This field represents the upper 8 bits, while the previous Timestamp field represents the lower 24 bits of the time in milliseconds. |
StreamID | UI24 | Always 0. |
AudioTagHeader | IF TagType == 8 AudioTagHeader |
|
VideoTagHeader | IF TagType == 9 VideoTagHeader |
|
EncryptionHeader | IF Filter == 1 EncryptionTagHeader |
|
FilterParams | IF Filter == 1 FilterParams |
|
Data | IF TagType == 8 AUDIODATA IF TagType == 9 VIDEODATA IF TagType == 18 SCRIPTDATA |
Data specific for each media type. |
Audio Tags
Field | Type | Comment |
SoundFormat | UB [4] | Format of SoundData. The following values are defined: 0 = Linear PCM, platform endian 1 = ADPCM 2 = MP3 3 = Linear PCM, little endian 4 = Nellymoser 16 kHz mono 5 = Nellymoser 8 kHz mono 6 = Nellymoser 7 = G.711 A-law logarithmic PCM 8 = G.711 mu-law logarithmic PCM 9 = reserved 10 = AAC 11 = Speex 14 = MP3 8 kHz 15 = Device-specific sound Formats 7, 8, 14, and 15 are reserved. AAC is supported in Flash Player 9,0,115,0 and higher. Speex is supported in Flash Player 10 and higher. |
SoundRate | UB [2] | Sampling rate. The following values are defined: 0 = 5.5 kHz 1 = 11 kHz 2 = 22 kHz 3 = 44 kHz |
SoundSize | UB [1] |
Size of each audio sample. This parameter only pertains to |
SoundType | UB [1] | Mono or stereo sound 0 = Mono sound 1 = Stereo sound |
AACPacketType | IF SoundFormat == 10 UI8 |
The following values are defined: 0 = AAC sequence header 1 = AAC raw |
Video Tags
Field | Type | Comment |
Frame Type | UB [4] | Type of video frame. The following values are defined: 1 = key frame (for AVC, a seekable frame) 2 = inter frame (for AVC, a non-seekable frame) 3 = disposable inter frame (H.263 only) 4 = generated key frame (reserved for server use only) 5 = video info/command frame |
CodecID | UB [4] | Codec Identifier. The following values are defined: 2 = Sorenson H.263 3 = Screen video 4 = On2 VP6 5 = On2 VP6 with alpha channel 6 = Screen video version 2 7 = AVC |
AVCPacketType | IF CodecID == 7 UI8 |
The following values are defined: |
CompositionTime | IF CodecID == 7 SI24 |
IF AVCPacketType == 1 Composition time offset ELSE 0 See ISO 14496-12, 8.15.3 for an explanation of composition times. The offset in an FLV file is always in milliseconds. |
Script Tags
Field | Type | Comment |
Type | UI8 | Type of the ScriptDataValue. The following types are defined: 0 = Number 1 = Boolean 2 = String 3 = Object 4 = MovieClip (reserved, not supported) 5 = Null 6 = Undefined 7 = Reference 8 = ECMA array 9 = Object end marker 10 = Strict array 11 = Date 12 = Long string |
ScriptDataValue | IF Type == 0 DOUBLE IF Type == 1 UI8 IF Type == 2 SCRIPTDATASTRING IF Type == 3 SCRIPTDATAOBJECT IF Type == 7 UI16 IF Type == 8 SCRIPTDATAECMAARRAY IF Type == 10 SCRIPTDATASTRICTARRAY IF Type == 11 SCRIPTDATADATE IF Type == 12 SCRIPTDATALONGSTRING |
Script data value. The Boolean value is (ScriptDataValue ≠ 0). |