乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

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

       gljin_cn 2016-06-24

      RTMP服務(wù)器(一)


      :chunk_header/rtmp_header

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

         

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

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

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

      擴(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ù)類(lèi)型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 //塊類(lèi)型2

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

      }ChunkHeader;

       

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

      類(lèi)型0 

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

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

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

      類(lèi)型1 

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

                

      類(lèi)型2

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

              

      類(lèi)型3

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

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

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

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

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

                   對(duì)于類(lèi)型0或類(lèi)型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.              

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

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

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

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

       

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

      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出來(lái)后新增的數(shù)據(jù)類(lèi)型,這種類(lèi)型數(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類(lèi)型和對(duì)應(yīng)的ObjValue大小整理如下,詳細(xì)的ObjType的數(shù)據(jù)在本文的最下面列出:

      類(lèi)型說(shuō)明(ObjType)        數(shù)據(jù)  dataSize

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

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

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

      CORE_NUMBER   0x00   8字節(jié)

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

      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ā)送的開(kāi)銷(xiāo)。

      塊大小是可配置的。最大塊是65535字節(jié),最小塊是128字節(jié)。塊越大CPU使用率越低,但是也導(dǎo)致大的寫(xiě)入,在低帶寬下產(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包,無(wú)論是命令或數(shù)據(jù)。

       

      四:flv發(fā)包處理

      這里需要解析flv流。

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

      然后分析各個(gè)tag類(lèi)型,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;              //編解碼類(lèi)型: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)志位,表明是否依賴(lài)于corecoder = 0

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

       

      }Audio_ASC;

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

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

      2:收包:

      收包的時(shí)候,首先將分片的包組成完整的包,然后根據(jù)上面結(jié)構(gòu)解析出視頻:sps,pps。音頻采樣率,樣本,聲道等,如果是aac填寫(xiě)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:開(kāi)始向服務(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ù)器開(kāi)始向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í)候說(shuō)明服務(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中的不同類(lèi)型,如:

      #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之前填寫(xiě)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)購(gòu)買(mǎi)等信息,謹(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)論公約

        類(lèi)似文章 更多