rtmp官方协议详解
生活随笔
收集整理的這篇文章主要介紹了
rtmp官方协议详解
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
標(biāo)準(zhǔn)規(guī)范學(xué)習(xí):
rtmp消息結(jié)構(gòu),包括幾個(gè)部分: 時(shí)戳:4 ?byte,單位毫秒。超過(guò)最大值后會(huì)翻轉(zhuǎn)。 長(zhǎng)度:消息負(fù)載的長(zhǎng)度。 類型ID:Type Id 一部分ID范圍用于rtmp的控制信令。還有一部分可以供上層使用,rtmp只是透?jìng)鳌_@樣可以方便的在rtmp上進(jìn)行擴(kuò)展。 消息流ID:Message Stream ID,用于區(qū)分不同流的消息。 兩個(gè)ID的區(qū)別: Message?stream:傳輸消息的邏輯通道。 Message?stream?ID:每個(gè)消息都有一個(gè)流id,用于指明屬于哪個(gè)流。 ? Chunk:是更底層的一個(gè)概念。Message有可能過(guò)大,需要分割成一個(gè)個(gè)碎片,chunk就是一個(gè)消息的部分碎片。 Chunk?stream:傳輸chunk的邏輯通道。
Chunk?stream?ID:用于標(biāo)示chunk屬于哪個(gè)邏輯通道。 message stream和chunk stream應(yīng)該屬于不同的層次,message屬于應(yīng)用層次消息,chunk屬于更底層rtmp協(xié)議層次。 一個(gè)chunk stream 上能夠跑多個(gè)message stream。message stream id在一個(gè)chunk stream下要不相等。 消息會(huì)切分成一個(gè)個(gè)小的塊進(jìn)行傳輸。 rtmp的時(shí)戳單位是毫秒。 連接握手流程圖: 握手過(guò)程:服務(wù)器和客戶端各自發(fā)送三個(gè)包:c0,c1,c2,s0,s1,s2,服務(wù)器必須在收到c0后才發(fā)送s0和s1,也可以等到c1才發(fā)送;服務(wù)端必須收到c1才能夠發(fā)送s2,客戶端必須收到s2才能夠發(fā)送c2 c0和s0就是一個(gè)字節(jié):表示協(xié)議版本號(hào)。現(xiàn)在是03。 01 234567 +-+-+-+-+-+-+-+-+ | ? ?version ?? | +-+-+-+-+-+-+-+-+ C0?and?S0?bits c1和s1長(zhǎng)度1536, 抓包發(fā)現(xiàn),zero字段不一定為0。 c2和s2的長(zhǎng)度也是1536 通過(guò)vlc和nginx rtmp抓的包發(fā)現(xiàn)和規(guī)范不對(duì)應(yīng)。安裝規(guī)范,time和time2應(yīng)該是為了計(jì)算帶寬和延遲。 交互過(guò)程: 一般客戶端一起發(fā)生c0和c1,然后服務(wù)器直接發(fā)送s0,1,2。客戶端收到后發(fā)送c2,握手完成。三次交互就可以了。 塊流:
一個(gè)連接可以傳輸多個(gè)塊流。每個(gè)塊流有不同的id來(lái)區(qū)分。 塊傳輸運(yùn)行將大的消息包切割為小的消息包。防止大的數(shù)據(jù)比如視頻阻塞連接,導(dǎo)致音頻和信令也無(wú)法傳遞。 小的消息也可以成本更加低的傳輸,包頭會(huì)壓縮. 塊流大小可以配置。有一個(gè)消息:set chunk size可以協(xié)商大小。大的塊可以降低cpu 負(fù)載,但是可能會(huì)阻塞重要消息;小的塊不利于傳輸,特別是在低帶寬的情況下。 塊允許 層協(xié)議將大的消息 解 更小的消息,例如,防 體積大的但優(yōu)先級(jí)小的消 息 (比如視頻) 阻礙體積較小但優(yōu)先級(jí)高的消息 (比如音頻或者控制命 )——傳送過(guò)程,音頻和控制的優(yōu)先級(jí)較高。 塊的大小是? 配置的 它? 使用一個(gè)設(shè)置塊大小的控制消息 行設(shè)置 (參考 5.4.1) 更大的塊大小? 降? CPU 開(kāi)銷(xiāo),但在? 寬 接時(shí)因 它的大量的寫(xiě)入也會(huì)延 ? 他內(nèi)容的傳遞 更小的塊不利于高比特率的流化 所 塊的大小設(shè)置 決于 體情況。——這是使用tcp必須要考慮的問(wèn)題。塊過(guò)大會(huì)影響音頻和控制的發(fā)送。過(guò)小會(huì)影響效率和比特率。 塊類型: 塊基本頭:
第一個(gè)字節(jié)都是這樣。其中fmt用來(lái)指示Message Header。 cs id: cs id是chunk stream id的縮寫(xiě)。范圍是3——65599。可變字節(jié),后面可以跟一個(gè)字節(jié),也可以跟兩個(gè)字節(jié)。跟幾個(gè)字節(jié)是有第一個(gè)字節(jié)的后面6位的值決定的。這一點(diǎn)中文翻譯寫(xiě)的不完整。 如果最后6位值為0,則表示后面只有一個(gè)字節(jié)。id范圍是64——319,其實(shí)就是0——255,最大和最小加64。 如果最后6位值為1,則表示后面只有兩個(gè)字節(jié)。id范圍是64 - 65599,其實(shí)就是0——65535,最大和最小加64。j 計(jì)算方法比較特殊:(第三 個(gè) 節(jié)) * 256 + 第二 個(gè) 節(jié) + 64 塊流id應(yīng)該是區(qū)分每一個(gè)流,比如,一個(gè)視頻通話,包括視頻和音頻兩個(gè)流。這里的意思應(yīng)該是一個(gè)連接可以傳遞多個(gè)流,通過(guò)塊流id進(jìn)行區(qū)分。 塊消息頭
塊消息頭格式由塊基本頭的fmt字段決定。共四種。 fmt: 四種類型:0 1 2 3 包頭必須盡可能的壓縮。 type 0:用在流開(kāi)始,或者時(shí)戳重置的時(shí)候。message header消息頭共11byte。 三字節(jié)時(shí)戳:表示范圍為0——16777215(0xffffff),如果大于等于16777215,則表示還有一個(gè)字節(jié)的擴(kuò)展時(shí)戳。chunk header的第三部分就是extend timestamp。這一本部分是否存在由三個(gè)字節(jié)的值決定。注意,這個(gè)是絕對(duì)時(shí)戳,而后面的幾種類型trunk都是時(shí)戳的增量;區(qū)分消息截止是根據(jù)消息的長(zhǎng)度來(lái)進(jìn)行的。那么輸入處理主動(dòng)丟棄包的情況? type 1:message header有7byte,比type 0少了4個(gè)字節(jié)的message stream id,使用上一個(gè)塊的id。大小可變的消息(比如視頻的每一幀數(shù)據(jù))往往會(huì)在第一幀(第一幀的第一個(gè)chunk需要用type0)后面的幀的第一個(gè)chunk中使用type1。為什么?因?yàn)榭勺償?shù)據(jù),必須有長(zhǎng)度信息記錄。 type2:只有三個(gè)字節(jié)。沒(méi)有message stream id和message 長(zhǎng)度。全部使用同一個(gè)chunk stream的上一個(gè)chunk的。適用于長(zhǎng)度不變的步伐傳輸。 type 3:0個(gè)字節(jié)的message header。時(shí)戳,長(zhǎng)度,消息流id全部使用同一個(gè)chunk stream的上一個(gè)chunk。當(dāng)一個(gè)消息切分后劃分到多個(gè)chunk的時(shí)候,除了帶個(gè)chunk,所有的其他chunk應(yīng)該使用type3。——如何判斷包結(jié)束?根據(jù)消息的長(zhǎng)度,第一個(gè)chunk中的長(zhǎng)度應(yīng)該是一個(gè)消息完成的長(zhǎng)度。 四種格式的使用: 第一個(gè)消息的第一個(gè)chunk 使用type0,攜帶全部的信息;后面的chunk使用type3; 第二個(gè)消息,如果是視頻消息,長(zhǎng)度可變,則第一個(gè)chunk使用type1,值丟棄message stream id即可。第二個(gè)消息的其他chunk使用type3。 如果是音頻,且長(zhǎng)度相同,則第一個(gè)消息用type0+type3,第二個(gè)消息用type2+type3。 如果音頻消息,長(zhǎng)度,消息間時(shí)戳增量(delta)都相同,則第一個(gè)消息可以用type0+type3,后面的所有消息全部用type3即可。這樣的話也要求第一個(gè)消息的時(shí)戳必須和消息間的時(shí)戳增量相同。 注意:除type0外,其他的全部是時(shí)戳的增量。而不是時(shí)戳絕對(duì)值。 從上面來(lái)看,音頻和視頻的chunk id應(yīng)該是不一樣的。否則無(wú)法區(qū)分。因?yàn)橛行K是沒(méi)有message stream id,只有chunk stream id的。 公共字段定義: 1、timestamp delta:表示的是上一個(gè)chunk 和當(dāng)前chunk的時(shí)戳差。不是消息的時(shí)間差。如果大于等于16777215,則表示還有一個(gè)字節(jié)的擴(kuò)展時(shí)戳。chunk header的第三部分就是extend timestamp。 2、消息長(zhǎng)度:消息的長(zhǎng)度。他和chunk的payload的大小是不同的。chunk size length是所有chunk的大小再加最后一個(gè)大小。——消息長(zhǎng)度是消息實(shí)際的大小。。 3、message?type?id:標(biāo)示消息類型,比如音頻,視頻,控制等。 4、message?stream?id:以小端序存儲(chǔ)。 Extended?Timestamp:當(dāng)時(shí)戳大于 play2:可以實(shí)現(xiàn)比特率的切換。 message length,chunk size,tcp分包和消息的切割
終于弄明白其中的原理了。本來(lái)這幾個(gè)概念和方法在規(guī)范中描述不是很清楚,結(jié)合抓包終于弄清楚 了。 message length:及時(shí)消息本身的大小。這個(gè)消息要在chunk中進(jìn)行傳輸。 chunk size:chunk的大小。chunk的大小默認(rèn)是128。可以通過(guò)消息設(shè)置chunk size 的最大值。每個(gè)chunk的大小最大不能夠超過(guò)max chunk size。 明白上面兩點(diǎn)后進(jìn)行分析: 1、如果message length小于等于max chunk size,則一個(gè)chunk中就包含著一個(gè)message。 2、如果message length大于max chunk size,則需要將這個(gè)message切分為多個(gè)chunk。前面幾個(gè)chunk size必須是max? size,最后一個(gè)就是剩余的大小。 tcp分包過(guò)程: 1、收到chunk,明確chunk stream id,對(duì)一個(gè)chunk stream的數(shù)據(jù)進(jìn)行處理。 2、判斷fmt類型,確定消息長(zhǎng)度。 3、如果長(zhǎng)度小于等于max chunk size,則這個(gè)chunk body的大小就是message length。 4、處理完這個(gè)chunk,跳過(guò)chunk header 和chunk body,就是下一個(gè)chunk。 5、如果長(zhǎng)度大于max chunk size,則chunk body的大小就是max chunk size。處理這一部分?jǐn)?shù)據(jù),然后跳過(guò)max chunk size找到下一個(gè)chunk的頭。有消息長(zhǎng)度減去max chunk size計(jì)算剩余的數(shù)據(jù)長(zhǎng)度,判斷剩余長(zhǎng)度是否大于max chunk size,如果大于,則表明這個(gè)chunk 大小還是max chunk size。以此類推,直到最后一個(gè)長(zhǎng)度小于等于max chunk size,那么這個(gè)長(zhǎng)度就是這個(gè)chunk的實(shí)際長(zhǎng)度,并且是這個(gè)消息的最后一個(gè)消息切片。然后把所有的有效切片拼接起來(lái),就是完整的消息。后面收到的將是另外一個(gè)消息。 協(xié)議控制消息:
RTMP使用1,2,3,4,5,6的message type id作為控制消息。控制協(xié)議的message stream id必須是0, chunk stream id必須是2(2的作用。0,1用來(lái)表示字節(jié)個(gè)數(shù),2是信令,3-6xxxx是實(shí)際的。)。控制信令一收到就生效——就是沒(méi)有協(xié)商過(guò)程。。。——時(shí)戳可以忽略。 set chunk size (1):設(shè)置chunk的最大size
message type id 為1。共四個(gè)字節(jié): 第一位必須為0。 默認(rèn)值是128,服務(wù)端和客戶端都可以設(shè)置chunk size。注意,一個(gè)交互中chunk size是相互獨(dú)立的,也就是,客戶端可以設(shè)置他發(fā)送過(guò)去的chunk size,服務(wù)端也可以設(shè)置他發(fā)送過(guò)去的chunk size。兩個(gè)是沒(méi)有影響的。 chunk size最小建議128,必須大于等于1。 chunk size的范圍是1到0x7fffffff(2147483647),但是因?yàn)閙essage header中message length只有三個(gè)字節(jié),所以chunk size的最大值是16777215? 如果大于此,就去他。 Abort?Message (2)
message type id為2,四個(gè)字節(jié),攜帶的內(nèi)容是chunk stream id。用于通知對(duì)端,如果這個(gè)chunk stream還有消息正在等待接收未到達(dá)的消息內(nèi)容,則停止,并丟棄原先接受的內(nèi)容。可以用在帶寬有限是優(yōu)先發(fā)送音頻和信令,丟棄視頻。 Acknowledgement?(3)?Window?Acknowledgement?Size?(5)
Window?Acknowledgement?Size用于設(shè)置窗口確認(rèn)大小,Acknowledgement是窗口確認(rèn)消息。 會(huì)話開(kāi)始時(shí),雙方都要先對(duì)端發(fā)送Window?Acknowledgement?Size,用于指明期望獲得確認(rèn)的大小。當(dāng)一端收到內(nèi)容大小超過(guò)Window?Acknowledgement?Size,就要像對(duì)方發(fā)送Acknowledgement。 1、會(huì)話開(kāi)始計(jì)算收到byte個(gè)數(shù)的時(shí)間點(diǎn)是收到Window?Acknowledgement?Size消息開(kāi)始。 2、byte size不包括tcp包頭,應(yīng)該是chunk的大小,即從tcp 的recv函數(shù)中獲得的內(nèi)容大小。 3、雙方都要向?qū)Ψ桨l(fā)送Window?Acknowledgement?Size和Acknowledgement。 4、發(fā)送端發(fā)送完Window?Acknowledgement?Size消息后,沒(méi)有收到Acknowledgement是不再發(fā)送進(jìn)一步的消息的——這樣會(huì)容易引起錯(cuò)誤,導(dǎo)致再也發(fā)送不出消息了。 Set?Peer?Bandwidth?(6)
設(shè)置對(duì)端輸出帶寬。對(duì)端是通過(guò)設(shè)置Window?Acknowledgement?Size來(lái)實(shí)現(xiàn)流量控制的。超過(guò)Window?Acknowledgement?Size后未確認(rèn)發(fā)送端將不再發(fā)送消息。所以對(duì)端收到set peer bandwidth后,如果之前發(fā)送的Window?Acknowledgement?Size和這里寫(xiě)的的Window?Acknowledgement?Size不一樣,一般會(huì)發(fā)送一個(gè)Window?Acknowledgement?Size。 message format
上面的協(xié)議控制消息的type id是1,2,3,5,6(這些是chunk stream的控制),沒(méi)有4。4是另外一個(gè)類型: User?Control?Messages?(4):用戶控制協(xié)議,是RTMP stream的控制協(xié)議。同樣,chunk stream id要設(shè)置為2,message stream id要設(shè)置為0。 消息體格式:兩個(gè)字節(jié)的event type,后面跟可變長(zhǎng)度的event data, RTMP?Command?Messages
客戶端和服務(wù)器之間可以發(fā)送的消息包括:音頻消息,視頻消息,數(shù)據(jù)消息,命令消息。命令消息采用AMF編碼。 command message type 20,17表示是命令消息。20表示使用AMF0編碼,17表示使用AMF3編碼。 命令消息包括connect,?createStream,?publish,?play,?pause ,響應(yīng)消息使用onstatus,result。 Data?Message?(18,?15):數(shù)據(jù)消息,用于傳輸Metadata或用戶數(shù)據(jù)。18表示AMF0,15是AMF3。 Shared?Object?Message?(19,?16):19表示AMF0,16是AMF3。 Audio?Message?(8):音頻消息 Video?Message?(9):視頻消息 Aggregate?Message?(22):一個(gè)消息中包含多個(gè)消息。 Types?of?Commands( 20,17)
netConnetion 命令: connect :請(qǐng)求連接到服務(wù)器的應(yīng)用實(shí)例。 call:請(qǐng)求一個(gè)遠(yuǎn)程調(diào)用。 creatStream:創(chuàng)建一個(gè)邏輯通道,用于客戶端來(lái)發(fā)送音頻,視頻,描述數(shù)據(jù)。netConnection是默認(rèn)通道,message stream id是0,creatStream使用0作為message stream id。 NetStream?Commands: 多個(gè)Netstream可以共用一個(gè)netconnection。但是stream的id是在什么時(shí)候確定的???——疑問(wèn) play2:切換到不同的比特率的流上,而不用更改播放時(shí)間。這是一個(gè)有用的功能。這個(gè)消息是在paly之后再發(fā)送。 deleteStream:刪除流。 receiveAudio:是否接受音頻。如果為false,服務(wù)器不用回復(fù)。如果為true,服務(wù)器回復(fù)兩個(gè)狀態(tài): NetStream.Seek.Notify?and?? NetStream.Play.Start receiveVideo:同樣。 publish:發(fā)布一個(gè)流到server。需要onStatus響應(yīng)。 seek:偏移。毫秒為單位。 pause:暫停。 example: 首先,connect是連接的服務(wù)器端的應(yīng)用(nginx rtmp有配置多個(gè)應(yīng)用。) 視頻裸數(shù)據(jù)是如何打包進(jìn)rtmp包的?
ffmpeg在flv和h264文件將的轉(zhuǎn)換是有問(wèn)題的。 視頻性格的數(shù)據(jù)包格式和flv的格式非常的像,基本上就是flv格式的變種。參考flv文件格式官方協(xié)議詳解。 視頻相關(guān)包包括:onMetaData,AVCDecoderConfigurationRecord,h264數(shù)據(jù)。和flv文件中的區(qū)別是flv文件用tag頭,rtmp中相關(guān)信息是放在rtmp頭中。至于內(nèi)部?jī)?nèi)容是一樣的。 AMF0編碼格式
*AMF數(shù)據(jù)類型:? ?*Type??????Byte?code? ?*Number????0x00? ?*Boolean???0x01? ?*String????0x02? ?*Object????0x03? ?*MovieClip?0x04? ?*Null??????0x05? ?*Undefined?0x06? ?*Reference?0x07? ?*MixedArray????0x08? ?*EndOfObject???0x09? ?*Array?????????0x0a? ?*Date??????????0x0b? ?*LongString????0x0c? ?*Unsupported???0x0d? ?*Recordset?????0x0e? ?*XML???????????0x0f? ?*TypedObject?(Class?instance)??0x10? ?*AMF3?data?0×11?
amf編碼:對(duì)個(gè)數(shù)據(jù)的合集,數(shù)據(jù)的邊界通過(guò)不同的類型,以及不同類型的長(zhǎng)度來(lái)區(qū)分。
第一個(gè)字節(jié)是數(shù)據(jù)類型,然后根據(jù)數(shù)據(jù)類型確定數(shù)據(jù)的長(zhǎng)度。其中,string是可變長(zhǎng)度,兩個(gè)字節(jié)長(zhǎng)度值。
如果是object,則object內(nèi)部是個(gè)字典,key是字符串,value是數(shù)據(jù),這里還要對(duì)數(shù)據(jù)根據(jù)類型對(duì)數(shù)據(jù)解析,同上。
rtmp消息結(jié)構(gòu),包括幾個(gè)部分: 時(shí)戳:4 ?byte,單位毫秒。超過(guò)最大值后會(huì)翻轉(zhuǎn)。 長(zhǎng)度:消息負(fù)載的長(zhǎng)度。 類型ID:Type Id 一部分ID范圍用于rtmp的控制信令。還有一部分可以供上層使用,rtmp只是透?jìng)鳌_@樣可以方便的在rtmp上進(jìn)行擴(kuò)展。 消息流ID:Message Stream ID,用于區(qū)分不同流的消息。 兩個(gè)ID的區(qū)別: Message?stream:傳輸消息的邏輯通道。 Message?stream?ID:每個(gè)消息都有一個(gè)流id,用于指明屬于哪個(gè)流。 ? Chunk:是更底層的一個(gè)概念。Message有可能過(guò)大,需要分割成一個(gè)個(gè)碎片,chunk就是一個(gè)消息的部分碎片。 Chunk?stream:傳輸chunk的邏輯通道。
Chunk?stream?ID:用于標(biāo)示chunk屬于哪個(gè)邏輯通道。 message stream和chunk stream應(yīng)該屬于不同的層次,message屬于應(yīng)用層次消息,chunk屬于更底層rtmp協(xié)議層次。 一個(gè)chunk stream 上能夠跑多個(gè)message stream。message stream id在一個(gè)chunk stream下要不相等。 消息會(huì)切分成一個(gè)個(gè)小的塊進(jìn)行傳輸。 rtmp的時(shí)戳單位是毫秒。 連接握手流程圖: 握手過(guò)程:服務(wù)器和客戶端各自發(fā)送三個(gè)包:c0,c1,c2,s0,s1,s2,服務(wù)器必須在收到c0后才發(fā)送s0和s1,也可以等到c1才發(fā)送;服務(wù)端必須收到c1才能夠發(fā)送s2,客戶端必須收到s2才能夠發(fā)送c2 c0和s0就是一個(gè)字節(jié):表示協(xié)議版本號(hào)。現(xiàn)在是03。 01 234567 +-+-+-+-+-+-+-+-+ | ? ?version ?? | +-+-+-+-+-+-+-+-+ C0?and?S0?bits c1和s1長(zhǎng)度1536, 抓包發(fā)現(xiàn),zero字段不一定為0。 c2和s2的長(zhǎng)度也是1536 通過(guò)vlc和nginx rtmp抓的包發(fā)現(xiàn)和規(guī)范不對(duì)應(yīng)。安裝規(guī)范,time和time2應(yīng)該是為了計(jì)算帶寬和延遲。 交互過(guò)程: 一般客戶端一起發(fā)生c0和c1,然后服務(wù)器直接發(fā)送s0,1,2。客戶端收到后發(fā)送c2,握手完成。三次交互就可以了。 塊流:
一個(gè)連接可以傳輸多個(gè)塊流。每個(gè)塊流有不同的id來(lái)區(qū)分。 塊傳輸運(yùn)行將大的消息包切割為小的消息包。防止大的數(shù)據(jù)比如視頻阻塞連接,導(dǎo)致音頻和信令也無(wú)法傳遞。 小的消息也可以成本更加低的傳輸,包頭會(huì)壓縮. 塊流大小可以配置。有一個(gè)消息:set chunk size可以協(xié)商大小。大的塊可以降低cpu 負(fù)載,但是可能會(huì)阻塞重要消息;小的塊不利于傳輸,特別是在低帶寬的情況下。 塊允許 層協(xié)議將大的消息 解 更小的消息,例如,防 體積大的但優(yōu)先級(jí)小的消 息 (比如視頻) 阻礙體積較小但優(yōu)先級(jí)高的消息 (比如音頻或者控制命 )——傳送過(guò)程,音頻和控制的優(yōu)先級(jí)較高。 塊的大小是? 配置的 它? 使用一個(gè)設(shè)置塊大小的控制消息 行設(shè)置 (參考 5.4.1) 更大的塊大小? 降? CPU 開(kāi)銷(xiāo),但在? 寬 接時(shí)因 它的大量的寫(xiě)入也會(huì)延 ? 他內(nèi)容的傳遞 更小的塊不利于高比特率的流化 所 塊的大小設(shè)置 決于 體情況。——這是使用tcp必須要考慮的問(wèn)題。塊過(guò)大會(huì)影響音頻和控制的發(fā)送。過(guò)小會(huì)影響效率和比特率。 塊類型: 塊基本頭:
第一個(gè)字節(jié)都是這樣。其中fmt用來(lái)指示Message Header。 cs id: cs id是chunk stream id的縮寫(xiě)。范圍是3——65599。可變字節(jié),后面可以跟一個(gè)字節(jié),也可以跟兩個(gè)字節(jié)。跟幾個(gè)字節(jié)是有第一個(gè)字節(jié)的后面6位的值決定的。這一點(diǎn)中文翻譯寫(xiě)的不完整。 如果最后6位值為0,則表示后面只有一個(gè)字節(jié)。id范圍是64——319,其實(shí)就是0——255,最大和最小加64。 如果最后6位值為1,則表示后面只有兩個(gè)字節(jié)。id范圍是64 - 65599,其實(shí)就是0——65535,最大和最小加64。j 計(jì)算方法比較特殊:(第三 個(gè) 節(jié)) * 256 + 第二 個(gè) 節(jié) + 64 塊流id應(yīng)該是區(qū)分每一個(gè)流,比如,一個(gè)視頻通話,包括視頻和音頻兩個(gè)流。這里的意思應(yīng)該是一個(gè)連接可以傳遞多個(gè)流,通過(guò)塊流id進(jìn)行區(qū)分。 塊消息頭
塊消息頭格式由塊基本頭的fmt字段決定。共四種。 fmt: 四種類型:0 1 2 3 包頭必須盡可能的壓縮。 type 0:用在流開(kāi)始,或者時(shí)戳重置的時(shí)候。message header消息頭共11byte。 三字節(jié)時(shí)戳:表示范圍為0——16777215(0xffffff),如果大于等于16777215,則表示還有一個(gè)字節(jié)的擴(kuò)展時(shí)戳。chunk header的第三部分就是extend timestamp。這一本部分是否存在由三個(gè)字節(jié)的值決定。注意,這個(gè)是絕對(duì)時(shí)戳,而后面的幾種類型trunk都是時(shí)戳的增量;區(qū)分消息截止是根據(jù)消息的長(zhǎng)度來(lái)進(jìn)行的。那么輸入處理主動(dòng)丟棄包的情況? type 1:message header有7byte,比type 0少了4個(gè)字節(jié)的message stream id,使用上一個(gè)塊的id。大小可變的消息(比如視頻的每一幀數(shù)據(jù))往往會(huì)在第一幀(第一幀的第一個(gè)chunk需要用type0)后面的幀的第一個(gè)chunk中使用type1。為什么?因?yàn)榭勺償?shù)據(jù),必須有長(zhǎng)度信息記錄。 type2:只有三個(gè)字節(jié)。沒(méi)有message stream id和message 長(zhǎng)度。全部使用同一個(gè)chunk stream的上一個(gè)chunk的。適用于長(zhǎng)度不變的步伐傳輸。 type 3:0個(gè)字節(jié)的message header。時(shí)戳,長(zhǎng)度,消息流id全部使用同一個(gè)chunk stream的上一個(gè)chunk。當(dāng)一個(gè)消息切分后劃分到多個(gè)chunk的時(shí)候,除了帶個(gè)chunk,所有的其他chunk應(yīng)該使用type3。——如何判斷包結(jié)束?根據(jù)消息的長(zhǎng)度,第一個(gè)chunk中的長(zhǎng)度應(yīng)該是一個(gè)消息完成的長(zhǎng)度。 四種格式的使用: 第一個(gè)消息的第一個(gè)chunk 使用type0,攜帶全部的信息;后面的chunk使用type3; 第二個(gè)消息,如果是視頻消息,長(zhǎng)度可變,則第一個(gè)chunk使用type1,值丟棄message stream id即可。第二個(gè)消息的其他chunk使用type3。 如果是音頻,且長(zhǎng)度相同,則第一個(gè)消息用type0+type3,第二個(gè)消息用type2+type3。 如果音頻消息,長(zhǎng)度,消息間時(shí)戳增量(delta)都相同,則第一個(gè)消息可以用type0+type3,后面的所有消息全部用type3即可。這樣的話也要求第一個(gè)消息的時(shí)戳必須和消息間的時(shí)戳增量相同。 注意:除type0外,其他的全部是時(shí)戳的增量。而不是時(shí)戳絕對(duì)值。 從上面來(lái)看,音頻和視頻的chunk id應(yīng)該是不一樣的。否則無(wú)法區(qū)分。因?yàn)橛行K是沒(méi)有message stream id,只有chunk stream id的。 公共字段定義: 1、timestamp delta:表示的是上一個(gè)chunk 和當(dāng)前chunk的時(shí)戳差。不是消息的時(shí)間差。如果大于等于16777215,則表示還有一個(gè)字節(jié)的擴(kuò)展時(shí)戳。chunk header的第三部分就是extend timestamp。 2、消息長(zhǎng)度:消息的長(zhǎng)度。他和chunk的payload的大小是不同的。chunk size length是所有chunk的大小再加最后一個(gè)大小。——消息長(zhǎng)度是消息實(shí)際的大小。。 3、message?type?id:標(biāo)示消息類型,比如音頻,視頻,控制等。 4、message?stream?id:以小端序存儲(chǔ)。 Extended?Timestamp:當(dāng)時(shí)戳大于 play2:可以實(shí)現(xiàn)比特率的切換。 message length,chunk size,tcp分包和消息的切割
終于弄明白其中的原理了。本來(lái)這幾個(gè)概念和方法在規(guī)范中描述不是很清楚,結(jié)合抓包終于弄清楚 了。 message length:及時(shí)消息本身的大小。這個(gè)消息要在chunk中進(jìn)行傳輸。 chunk size:chunk的大小。chunk的大小默認(rèn)是128。可以通過(guò)消息設(shè)置chunk size 的最大值。每個(gè)chunk的大小最大不能夠超過(guò)max chunk size。 明白上面兩點(diǎn)后進(jìn)行分析: 1、如果message length小于等于max chunk size,則一個(gè)chunk中就包含著一個(gè)message。 2、如果message length大于max chunk size,則需要將這個(gè)message切分為多個(gè)chunk。前面幾個(gè)chunk size必須是max? size,最后一個(gè)就是剩余的大小。 tcp分包過(guò)程: 1、收到chunk,明確chunk stream id,對(duì)一個(gè)chunk stream的數(shù)據(jù)進(jìn)行處理。 2、判斷fmt類型,確定消息長(zhǎng)度。 3、如果長(zhǎng)度小于等于max chunk size,則這個(gè)chunk body的大小就是message length。 4、處理完這個(gè)chunk,跳過(guò)chunk header 和chunk body,就是下一個(gè)chunk。 5、如果長(zhǎng)度大于max chunk size,則chunk body的大小就是max chunk size。處理這一部分?jǐn)?shù)據(jù),然后跳過(guò)max chunk size找到下一個(gè)chunk的頭。有消息長(zhǎng)度減去max chunk size計(jì)算剩余的數(shù)據(jù)長(zhǎng)度,判斷剩余長(zhǎng)度是否大于max chunk size,如果大于,則表明這個(gè)chunk 大小還是max chunk size。以此類推,直到最后一個(gè)長(zhǎng)度小于等于max chunk size,那么這個(gè)長(zhǎng)度就是這個(gè)chunk的實(shí)際長(zhǎng)度,并且是這個(gè)消息的最后一個(gè)消息切片。然后把所有的有效切片拼接起來(lái),就是完整的消息。后面收到的將是另外一個(gè)消息。 協(xié)議控制消息:
RTMP使用1,2,3,4,5,6的message type id作為控制消息。控制協(xié)議的message stream id必須是0, chunk stream id必須是2(2的作用。0,1用來(lái)表示字節(jié)個(gè)數(shù),2是信令,3-6xxxx是實(shí)際的。)。控制信令一收到就生效——就是沒(méi)有協(xié)商過(guò)程。。。——時(shí)戳可以忽略。 set chunk size (1):設(shè)置chunk的最大size
message type id 為1。共四個(gè)字節(jié): 第一位必須為0。 默認(rèn)值是128,服務(wù)端和客戶端都可以設(shè)置chunk size。注意,一個(gè)交互中chunk size是相互獨(dú)立的,也就是,客戶端可以設(shè)置他發(fā)送過(guò)去的chunk size,服務(wù)端也可以設(shè)置他發(fā)送過(guò)去的chunk size。兩個(gè)是沒(méi)有影響的。 chunk size最小建議128,必須大于等于1。 chunk size的范圍是1到0x7fffffff(2147483647),但是因?yàn)閙essage header中message length只有三個(gè)字節(jié),所以chunk size的最大值是16777215? 如果大于此,就去他。 Abort?Message (2)
message type id為2,四個(gè)字節(jié),攜帶的內(nèi)容是chunk stream id。用于通知對(duì)端,如果這個(gè)chunk stream還有消息正在等待接收未到達(dá)的消息內(nèi)容,則停止,并丟棄原先接受的內(nèi)容。可以用在帶寬有限是優(yōu)先發(fā)送音頻和信令,丟棄視頻。 Acknowledgement?(3)?Window?Acknowledgement?Size?(5)
Window?Acknowledgement?Size用于設(shè)置窗口確認(rèn)大小,Acknowledgement是窗口確認(rèn)消息。 會(huì)話開(kāi)始時(shí),雙方都要先對(duì)端發(fā)送Window?Acknowledgement?Size,用于指明期望獲得確認(rèn)的大小。當(dāng)一端收到內(nèi)容大小超過(guò)Window?Acknowledgement?Size,就要像對(duì)方發(fā)送Acknowledgement。 1、會(huì)話開(kāi)始計(jì)算收到byte個(gè)數(shù)的時(shí)間點(diǎn)是收到Window?Acknowledgement?Size消息開(kāi)始。 2、byte size不包括tcp包頭,應(yīng)該是chunk的大小,即從tcp 的recv函數(shù)中獲得的內(nèi)容大小。 3、雙方都要向?qū)Ψ桨l(fā)送Window?Acknowledgement?Size和Acknowledgement。 4、發(fā)送端發(fā)送完Window?Acknowledgement?Size消息后,沒(méi)有收到Acknowledgement是不再發(fā)送進(jìn)一步的消息的——這樣會(huì)容易引起錯(cuò)誤,導(dǎo)致再也發(fā)送不出消息了。 Set?Peer?Bandwidth?(6)
設(shè)置對(duì)端輸出帶寬。對(duì)端是通過(guò)設(shè)置Window?Acknowledgement?Size來(lái)實(shí)現(xiàn)流量控制的。超過(guò)Window?Acknowledgement?Size后未確認(rèn)發(fā)送端將不再發(fā)送消息。所以對(duì)端收到set peer bandwidth后,如果之前發(fā)送的Window?Acknowledgement?Size和這里寫(xiě)的的Window?Acknowledgement?Size不一樣,一般會(huì)發(fā)送一個(gè)Window?Acknowledgement?Size。 message format
上面的協(xié)議控制消息的type id是1,2,3,5,6(這些是chunk stream的控制),沒(méi)有4。4是另外一個(gè)類型: User?Control?Messages?(4):用戶控制協(xié)議,是RTMP stream的控制協(xié)議。同樣,chunk stream id要設(shè)置為2,message stream id要設(shè)置為0。 消息體格式:兩個(gè)字節(jié)的event type,后面跟可變長(zhǎng)度的event data, RTMP?Command?Messages
客戶端和服務(wù)器之間可以發(fā)送的消息包括:音頻消息,視頻消息,數(shù)據(jù)消息,命令消息。命令消息采用AMF編碼。 command message type 20,17表示是命令消息。20表示使用AMF0編碼,17表示使用AMF3編碼。 命令消息包括connect,?createStream,?publish,?play,?pause ,響應(yīng)消息使用onstatus,result。 Data?Message?(18,?15):數(shù)據(jù)消息,用于傳輸Metadata或用戶數(shù)據(jù)。18表示AMF0,15是AMF3。 Shared?Object?Message?(19,?16):19表示AMF0,16是AMF3。 Audio?Message?(8):音頻消息 Video?Message?(9):視頻消息 Aggregate?Message?(22):一個(gè)消息中包含多個(gè)消息。 Types?of?Commands( 20,17)
netConnetion 命令: connect :請(qǐng)求連接到服務(wù)器的應(yīng)用實(shí)例。 call:請(qǐng)求一個(gè)遠(yuǎn)程調(diào)用。 creatStream:創(chuàng)建一個(gè)邏輯通道,用于客戶端來(lái)發(fā)送音頻,視頻,描述數(shù)據(jù)。netConnection是默認(rèn)通道,message stream id是0,creatStream使用0作為message stream id。 NetStream?Commands: 多個(gè)Netstream可以共用一個(gè)netconnection。但是stream的id是在什么時(shí)候確定的???——疑問(wèn) play2:切換到不同的比特率的流上,而不用更改播放時(shí)間。這是一個(gè)有用的功能。這個(gè)消息是在paly之后再發(fā)送。 deleteStream:刪除流。 receiveAudio:是否接受音頻。如果為false,服務(wù)器不用回復(fù)。如果為true,服務(wù)器回復(fù)兩個(gè)狀態(tài): NetStream.Seek.Notify?and?? NetStream.Play.Start receiveVideo:同樣。 publish:發(fā)布一個(gè)流到server。需要onStatus響應(yīng)。 seek:偏移。毫秒為單位。 pause:暫停。 example: 首先,connect是連接的服務(wù)器端的應(yīng)用(nginx rtmp有配置多個(gè)應(yīng)用。) 視頻裸數(shù)據(jù)是如何打包進(jìn)rtmp包的?
ffmpeg在flv和h264文件將的轉(zhuǎn)換是有問(wèn)題的。 視頻性格的數(shù)據(jù)包格式和flv的格式非常的像,基本上就是flv格式的變種。參考flv文件格式官方協(xié)議詳解。 視頻相關(guān)包包括:onMetaData,AVCDecoderConfigurationRecord,h264數(shù)據(jù)。和flv文件中的區(qū)別是flv文件用tag頭,rtmp中相關(guān)信息是放在rtmp頭中。至于內(nèi)部?jī)?nèi)容是一樣的。 AMF0編碼格式
總結(jié)
以上是生活随笔為你收集整理的rtmp官方协议详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux下编译带x264的ffmpeg
- 下一篇: nginx 源码学习笔记(十)——基本容