日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

RTMP服務(wù)器(一)(轉(zhuǎn))

 gljin_cn 2016-06-24

RTMP服務(wù)器(一)


:chunk_header/rtmp_header

  塊由頭和數(shù)據(jù)組成。塊頭由三部分組成:

   

塊基本頭:1到3 字節(jié)

本字段包含塊流ID和塊類型。塊類型決定編碼的消息頭的格式。長(zhǎng)度取決于塊流ID。塊流ID是可變長(zhǎng)字段。

塊消息頭:0,3,7或11字節(jié)。本字段編碼要發(fā)送的消息的信息。本字段的長(zhǎng)度,取決于塊頭中指定的塊類型。

擴(kuò)展時(shí)間戳:0個(gè)或4字節(jié)

本字段必須在發(fā)送普通時(shí)間戳(普通時(shí)間戳是指塊消息頭中的時(shí)間戳)設(shè)置為0xffffff時(shí)發(fā)送,正常時(shí)間戳為其他值時(shí)都不應(yīng)發(fā)送本值。當(dāng)普通時(shí)間戳的值小于0xffffff時(shí),本字段不用出現(xiàn),而應(yīng)當(dāng)使用正常時(shí)間戳字段。

//rtmp packet

typedef struct RtmpPacket

{

    ChunkHeader m_ChunkHeader;          //chunkheader 1-3字節(jié)

    //chunk msg header

    unsigned int m_TimeStamp;           //時(shí)間戳3字節(jié)                大端模式

    unsigned int m_MessageLenth;        //數(shù)據(jù)大小3個(gè)字節(jié)//amfsize  大端模式

    unsigned char m_MessageTypeID;      //數(shù)據(jù)類型1個(gè)字節(jié) //MessageTypeID

    unsigned int m_MessgageStreamID;    //流ID  4字節(jié)              端模式

    unsigned int m_ExtendTimeStamp;     //擴(kuò)展時(shí)間戳4字節(jié)           

                                        //則m_MessageLenth== 100,m_BytesRead == 50;   

    unsigned int m_hasAbsTimestamp;     //11字節(jié)的完整ChunkMsgHeader的TimeStamp是絕對(duì)值

    char * m_PacketData;                //包數(shù)據(jù)內(nèi)容

}RtmpPacket;

 

 

//chunk

typedef struct ChunkHeader

{

    unsigned char m_F0mt //塊類型2

    unsigned int  m_CsID/m_ChunkStreamId //編碼塊流ID 6位或字節(jié)位或字節(jié)位     大端模式

}ChunkHeader;

 

Rtmp可以衍生出21種packetheader,即ChunkHeader一個(gè)字節(jié),沒有擴(kuò)展時(shí)間戳,常用的4種分別為:

類型0 

0類型的塊長(zhǎng)度為11字節(jié)。在一個(gè)塊流的開始和時(shí)間戳返回的時(shí)候必須有這種塊。

             時(shí)間戳:3字節(jié)

           對(duì)于0類型的塊。消息的絕對(duì)時(shí)間戳在這里發(fā)送。如果時(shí)間戳大于或等于16777215(16進(jìn)制0x00ffffff),該值必須為16777215,并且擴(kuò)展時(shí)間戳必須出現(xiàn)。否則該值就是整個(gè)的時(shí)間戳。

類型1 

           類型1的塊占7個(gè)字節(jié)長(zhǎng)。消息流 ID不包含在本塊中。塊的消息流ID與先前的塊相同。具有可變大小消息的流,在第一個(gè)消息之后的每個(gè)消息的第一個(gè)塊應(yīng)該使用這個(gè)格式。

          

類型2

              類型2的塊占3個(gè)字節(jié)。既不包含流ID也不包含消息長(zhǎng)度。本塊使用的流ID和消息長(zhǎng)度與先前的塊相同。具有固定大小消息的流,在第一個(gè)消息之后的每個(gè)消息的第一個(gè)塊應(yīng)該使用這個(gè)格式。

        

類型3

   類型3的塊沒有頭。流ID,消息長(zhǎng)度,時(shí)間戳都不出現(xiàn)。這種類型的塊使用與先前塊相同的數(shù)據(jù)。當(dāng)一個(gè)消息被分成多個(gè)塊,除了第一塊以外,所有的塊都應(yīng)使用這種類型。由相同大小,流ID,和時(shí)間間隔的流在類型2的塊之后應(yīng)使用這種塊。

          如果第一個(gè)消息和第二個(gè)消息的時(shí)間增量與第一個(gè)消息的時(shí)間戳相同,那么0類型的塊之后必須是3類型的塊而,不需要類型2的塊來注冊(cè)時(shí)間增量。如果類型3的塊在類型0的塊之后,那么類型3的時(shí)間戳增量與0類型的塊的時(shí)間戳相同。

             時(shí)間戳增量:3字節(jié)

             對(duì)于類型1的塊和類型2的塊,本字段表示先前塊的時(shí)間戳與當(dāng)前塊的時(shí)間戳的差值。如果增量大于等于1677215(16進(jìn)制0x00ffffff),這個(gè)值必須是16777215 ,并且擴(kuò)展時(shí)間戳必須出現(xiàn)。否則這個(gè)值就是整個(gè)的增量。

             消息長(zhǎng)度:3字節(jié)

             對(duì)于類型0或類型1的塊本字段表示消息的長(zhǎng)度。

             注意,這個(gè)值通常與負(fù)載長(zhǎng)度是不相同的。The chunk payload length is themaximum chunk size for all but the last chunk, and the remainder (which maybe the entire length, for small messages) for the last chunk.              

             消息類型ID:1字節(jié)

             對(duì)于0類型和1類型的塊,本字段發(fā)送消息類型。

             消息流ID:4 字節(jié)

             對(duì)于0類型的塊,本字段存儲(chǔ)消息流ID。通常,在一個(gè)塊流中的消息來自于同一個(gè)消息流。雖然,由于不同的消息可能復(fù)用到一個(gè)塊流中而使頭壓縮無法有效實(shí)施。但是,如果一個(gè)消息流關(guān)閉而另一個(gè)消息流才打開,那么通過發(fā)送一個(gè)新的0類型的塊重復(fù)使用一個(gè)存在的塊流也不是不可以。

 

/* MessageTypeID -數(shù)據(jù)類型

0× Chunk Size  changes the chunk size for packets 

0× Unknown  

0× Bytes Read  send every x bytes read by both sides 

0× Ping  ping is a stream control message, hassubtypes 

0× Server BW  the servers downstream bw 

0× Client BW  the clients upstream bw 

0× Unknown  

0× Audio Data  packet containing audio 

0× Video Data  packet containing video data 

0x0A-0x0E Unknown   

0x0F FLEX_STREAM_SENDTYPE_FLEX_STREAM_SEND

0x10 FLEX_SHARED_OBJECT  TYPE_FLEX_SHARED_OBJECT 

0x11 FLEX_MESSAGE   TYPE_FLEX_MESSAGE  

0× Notify  an invoke which does not expect a reply 

0× Shared Object  has subtypes 

0× Invoke  like remoting call, used for stream actionstoo.

0× StreamData 這是FMS3出來后新增的數(shù)據(jù)類型,這種類型數(shù)據(jù)中包含AudioData和VideoData

*/

/*      RTMP_PACKET_TYPE_...                0x00 */

#define RTMP_PACKET_TYPE_CHUNK_SIZE         0x01

/*      RTMP_PACKET_TYPE_...                0x02 */

#define RTMP_PACKET_TYPE_BYTES_READ_REPORT  0x03

#define RTMP_PACKET_TYPE_CONTROL            0x04

#define RTMP_PACKET_TYPE_SERVER_BW          0x05

#define RTMP_PACKET_TYPE_CLIENT_BW          0x06

/*      RTMP_PACKET_TYPE_...                0x07 */

#define RTMP_PACKET_TYPE_AUDIO              0x08

#define RTMP_PACKET_TYPE_VIDEO              0x09

/*      RTMP_PACKET_TYPE_...                0x0A */

/*      RTMP_PACKET_TYPE_...                0x0B */

/*      RTMP_PACKET_TYPE_...                0x0C */

/*      RTMP_PACKET_TYPE_...                0x0D */

/*      RTMP_PACKET_TYPE_...                0x0E */

#define RTMP_PACKET_TYPE_FLEX_STREAM_SEND   0x0F

#define RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT 0x10

#define RTMP_PACKET_TYPE_FLEX_MESSAGE       0x11

#define RTMP_PACKET_TYPE_INFO               0x12

#define RTMP_PACKET_TYPE_SHARED_OBJECT      0x13

#define RTMP_PACKET_TYPE_INVOKE             0x14

/*      RTMP_PACKET_TYPE_...                0x15 */

#define RTMP_PACKET_TYPE_FLASH_VIDEO        0x16

 

二:amf結(jié)構(gòu)

/*

AMF數(shù)據(jù)由部分組成:ObjType加上ObjValue。ObjType的大小為一個(gè)字節(jié)。ObjValue的大小不固定,和ObjType相關(guān)。常用的ObjType類型和對(duì)應(yīng)的ObjValue大小整理如下,詳細(xì)的ObjType的數(shù)據(jù)在本文的最下面列出:

類型說明(ObjType)        數(shù)據(jù)  dataSize

CORE_String  0x02   2字節(jié)(2字節(jié)的數(shù)據(jù)紀(jì)錄了String的實(shí)際長(zhǎng)度)

CORE_Object   0x03  0字節(jié)(開始嵌套x00000009表示嵌套結(jié)束)

NULL     0x05 0字節(jié)空字節(jié)無意義

CORE_NUMBER   0x00   8字節(jié)

CORE_Map   0x08      4字節(jié)(開始嵌套)

CORE_BOOLEAN   0x01     1字節(jié)

 

ObjValue不一定是一個(gè)固定的大小,他可以包含另外一個(gè)AMF數(shù)據(jù),這另外一個(gè)AMF數(shù)據(jù)里面又有ObjType 加上ObjValue,也就是AMF數(shù)據(jù)的嵌套關(guān)系

AMF0數(shù)據(jù)的嵌套關(guān)系如下:

Object={ObjType + ObjValue}

CORE_BOOLEAN={Value(1 Byte)}

CORE_NUMBER={Value(8 Byte)}

CORE_String={StringLen(2Byte) + StringValue(StringLen Byte)}

CORE_DATE={value(10 Byte)}

CORE_Array={ArrayLen(4 Byte)+ Object}

CORE_Map={MapNum(4 Byte) +CORE_Object}

CORE_Object={CORE_String +Object}

*/

typedef enum

{

    AMF_NUMBER = 0, AMF_BOOLEAN,AMF_STRING, AMF_OBJECT,

   AMF_MOVIECLIP,       /* reserved, not used */

   AMF_NULL, AMF_UNDEFINED,AMF_REFERENCE, AMF_ECMA_ARRAY,AMF_OBJECT_END,

   AMF_STRICT_ARRAY, AMF_DATE, AMF_LONG_STRING,AMF_UNSUPPORTED,

   AMF_RECORDSET,       /* reserved, not used */

   AMF_XML_DOC, AMF_TYPED_OBJECT,

   AMF_AVMPLUS,     /* switch to AMF3 */

   AMF_INVALID = 0xff

} AMFDataType;

 

三:rtmp拆包組包

分塊使高層協(xié)議的大消息分割成小的消息,保證大的低優(yōu)先級(jí)消息不阻塞小的高優(yōu)先級(jí)消息。分塊把原本應(yīng)該消息中包含的信息壓縮在塊頭中減少了小塊消息發(fā)送的開銷。

塊大小是可配置的。最大塊是65535字節(jié),最小塊是128字節(jié)。塊越大CPU使用率越低,但是也導(dǎo)致大的寫入,在低帶寬下產(chǎn)生其他內(nèi)容的延遲。塊大小對(duì)每個(gè)方向都保持獨(dú)立。

1:拆包:即當(dāng)組成一個(gè)完整的rtmppacket有header和body,將此包分成小塊,一般發(fā)送第一個(gè)包時(shí)候需要完整的12字節(jié)頭或更多,剩下發(fā)送的包根據(jù)ChunkStreamId:編碼塊流ID匹配。

2:組包:即當(dāng)接收到rtmp分片包,根據(jù)ChunkStreamId:編碼塊流ID匹配組成一個(gè)完整的rtmp包,無論是命令或數(shù)據(jù)。

 

四:flv發(fā)包處理

這里需要解析flv流。

1:發(fā)包:首先:去掉9個(gè)字節(jié)的flv文件頭(如果是流不用去掉),

然后分析各個(gè)tag類型,flv有三種tag分別是Script,Video,Audio.

Script:里面存放的是flv流或文件的信息,寬高,文件長(zhǎng)度等等。

Video:存放的視頻數(shù)據(jù)(其中包含sps,pps ,用AvcC結(jié)構(gòu)表示),結(jié)構(gòu)如下

typedef struct Tag_Video_AvcC

{

    unsigned char configurationVersion;

    unsigned char AVCProfileIndication;

    unsigned char profile_compatibility;

    unsigned char AVCLevelIndication;

    unsigned char reserved_1;

    unsigned char lengthSizeMinusOne;

    unsigned char reserved_2;

    unsigned char numOfSequenceParameterSets //一般都是一個(gè)

    unsigned int sequenceParameterSetLength;   //sps長(zhǎng)度

    unsigned char * sequenceParameterSetNALUnit; //sps

    unsigned char numOfPictureParameterSets;   //一般都是一個(gè)

    unsigned int  pictureParameterSetLength;  //pps長(zhǎng)度

    unsigned char * pictureParameterSetNALUnit; //pps

    unsigned char reserved_3;

    unsigned char chroma_format;

    unsigned char reserved_4;

    unsigned char bit_depth_luma_minus8;

    unsigned char reserved_5;

    unsigned char bit_depth_chroma_minus8;

    unsigned char numOfSequenceParameterSetExt;

    unsigned int sequenceParameterSetExtLength;

    unsigned char * sequenceParameterSetExtNALUnit;

}Video_AvcC;

Audio: 存放的視頻數(shù)據(jù)(其中包含聲道,采樣率樣本等信息 ,用ASC結(jié)構(gòu)表示):結(jié)構(gòu)如下:

typedef struct Tag_Audio_ASC

{

    unsigned char audioObjectType;              //編解碼類型:AAC-LC = 0x02

    unsigned char samplingFrequencyIndex;       //采樣率44100 = 0x04

    unsigned char channelConfiguration;         //聲道= 2

    unsigned char framelengthFlag;              //標(biāo)志位,位于表明IMDCT窗口長(zhǎng)度= 0

    unsigned char dependsOnCoreCoder;           //標(biāo)志位,表明是否依賴于corecoder = 0

    unsigned char extensionFlag;                //選擇了AAC-LC = 0

 

}Audio_ASC;

發(fā)包的時(shí)候,根據(jù)獲取到的流信息://音頻(x08)、視頻(x09)和script data(x12),其它保留

填寫rtmppacket頭然后拆包發(fā)出去。

2:收包:

收包的時(shí)候,首先將分片的包組成完整的包,然后根據(jù)上面結(jié)構(gòu)解析出視頻:sps,pps。音頻采樣率,樣本,聲道等,如果是aac填寫7字節(jié)adts頭,然后一幀一幀的接收數(shù)據(jù)存入內(nèi)存或者渲染。

五:命令流程

以s代表服務(wù)器,c代表客戶端(publish或play)。

1:publish

 

Accept之后

c->s:c0c1

s->c:s0s1s2

c->s:c2

c->s:connect命令

s->c:windowacknowledgement size  set peer bandwidth   __result

c->s:windowacknowledgement size

s->c:onbwdone

c->s:checkbw

c->s:releasestream  fcpublish  createstream

s->c:__result

c->s:publish

s->c:onstatus;

c->s:開始向服務(wù)器發(fā)送數(shù)據(jù)

2:player

Accept之后

c->s:c0c1

s->c:s0s1s2

c->s:c2

c->s:connect命令

s->c:windowacknowledgement size  set peerbandwidth   __result

c->s:windowacknowledgement size

s->c:onbwdone

c->s:checkbw

c->s:createstream

s->c:__result

c->s:play

s->c:onstatus;

s->c:服務(wù)器開始向player發(fā)送數(shù)據(jù)

 

當(dāng)c向服務(wù)器發(fā)送命令,服務(wù)器給個(gè)響應(yīng),回復(fù)的命令對(duì)應(yīng)是用rtmp body中的mumber做對(duì)應(yīng)的。再有當(dāng)MessageTypeID /type id  == 0x14或0x11時(shí)候說明服務(wù)器給客戶端發(fā)送的命令完成。

 

 

即MessageTypeID /type id  ==  #define RTMP_PACKET_TYPE_INVOKE           0x14或

MessageTypeID/typeid == #define RTMP_PACKET_TYPE_FLEX_MESSAGE       0x11。

解釋下三個(gè)ID;

1: MessageTypeID:MessageTypeID中的不同類型,如:

#define RTMP_PACKET_TYPE_AUDIO              0x08

#define RTMP_PACKET_TYPE_VIDEO              0x09

2:chunkstream id :分片區(qū)分,如有個(gè)包大于128分包,當(dāng)傳輸?shù)诙€(gè)分片的時(shí)候要和第一個(gè)分片的chunk stream id相同才能判斷是一個(gè)包。

3:streamid :connectstream之前填寫0,之后為了區(qū)分flv/f4v流中多路流由server傳給client。

 

//注: AMF3 比AMF0 的 數(shù)據(jù)body前面多一個(gè)字節(jié)的“00”;

例如:

amf0:  (HandleInvoke(r,packet->m_body,packet->m_nBodySize)

Amf3: (HandleInvoke(r,packet->m_body + 1,packet->m_nBodySize - 1)

 

上面用以區(qū)分 amf0 和amf3。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多