生活随笔
收集整理的這篇文章主要介紹了
librtmp协议分析---RTMP_SendPacket函数
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
接下來我們分析RTMP_SendPacket函數(shù)。我們先了解一下rtmp的消息格式chunk。
RTMP的head組成
RTMP的head在協(xié)議中的表現(xiàn)形式是chunk head,前面已經(jīng)說到一個(gè)Message + head可以分成一個(gè)和多個(gè)chunk,為了區(qū)分這些chunk,肯定是需要一個(gè)chunk head的,具體的實(shí)現(xiàn)就把Message ?head的信息和chunk head的信息合并在一起以chunk head的形式表現(xiàn)。? ? ? ? ? 一個(gè)完整的chunk的組成如下圖所示
Chunk basic header:? 該字段包含chunk的stream ID和 type 。chunk的Type決定了消息頭的編碼方式。該字段的長度完全依賴于stream ID,該字段是一個(gè)可變長的字段。?
Chunk Msg Header:0, 3 ,7, 11? 該字段包含了將要發(fā)送的消息的信息(或者是一部分,一個(gè)消息拆成多個(gè)chunk的情況下是一部分)該字段的長度由chunk basic header中的type決定。
Extend Timestamp: 0 ,4 bytes 該字段發(fā)送的時(shí)候必須是正常的時(shí)間戳設(shè)置成0xffffff時(shí),當(dāng)正常時(shí)間戳不為0xffffff時(shí),該字段不發(fā)送。當(dāng)時(shí)間戳比0xffffff小該字段不發(fā)送,當(dāng)時(shí)間戳比0xffffff大時(shí)該字段必須發(fā)送,且正常時(shí)間戳設(shè)置成0xffffff。
Chunk Data 實(shí)際數(shù)據(jù)(Payload),可以是信令,也可以是媒體數(shù)據(jù)。
總結(jié)如下圖所示:
6.1.2 塊消息頭 有四種格式的塊消息ID,供塊流基本頭中的fmt 字段選擇。一個(gè)實(shí)現(xiàn)應(yīng)該使用最緊致的方式來表示塊消息頭。
6.1.2.1 類型0 0 類型的塊長度為11 字節(jié)。在一個(gè)塊流的開始和時(shí)間戳返回的時(shí)候必須有這種塊。
時(shí)間戳:3 字節(jié) 對于0 類型的塊。消息的絕對時(shí)間戳在這里發(fā)送。如果時(shí)間戳大于或等于16777215(16 進(jìn)制0x00ffffff),該值必須為16777215,并且擴(kuò)展時(shí)間戳必須出現(xiàn)。否則該值就是整個(gè)的時(shí)間戳。
6.1.2.2. 類型1 類型1 的塊占7 個(gè)字節(jié)長。消息流ID 不包含在本塊中。塊的消息流ID 與先前的塊相同。具有可變大小消息的流,在第一個(gè)消息之后的每個(gè)消息的第一個(gè)塊應(yīng)該使用這個(gè)格式。
6.1.2.3. 類型2 類型2 的塊占3 個(gè)字節(jié)。既不包含流ID 也不包含消息長度。本塊使用的流ID 和消息長度與先前的塊相同。具有固定大小消息的流,在第一個(gè)消息之后的每個(gè)消息的第一個(gè)塊應(yīng)該使用這個(gè)格式。
6.1.2.4 類型3 類型3 的塊沒有頭。流ID,消息長度,時(shí)間戳都不出現(xiàn)。這種類型的塊使用與先前塊相同的數(shù)據(jù)。當(dāng)一個(gè)消息被分成多個(gè)塊,除了第一塊以外,所有的塊都應(yīng)使用這種類型。示例可參考6.2.2 節(jié)中的例2 。由相同大小,流ID,和時(shí)間間隔的流在類型2 的塊之后應(yīng)使用這種塊。示例可參考6.2.1 節(jié)中的例1 。如果第一個(gè)消息和第二個(gè)消息的時(shí)間增量與第一個(gè)消息的時(shí)間戳相同,那么0類型的塊之后必須是3 類型的塊而,不需要類型2 的塊來注冊時(shí)間增量。如果類型3 的塊在類型0 的塊之后,那么類型3 的時(shí)間戳增量與0 類型的塊的時(shí)間戳相同。
時(shí)間戳增量:3 字節(jié) 對于類型1 的塊和類型2 的塊,本字段表示先前塊的時(shí)間戳與當(dāng)前塊的時(shí)間戳的差值。如果增量大于等于1677215(16 進(jìn)制0x00ffffff),這個(gè)值必須是16777215 ,并且擴(kuò)展時(shí)間戳必須出現(xiàn)。否則這個(gè)值就是整個(gè)的增量。
消息長度:3 字節(jié) 對于類型0 或類型1 的塊本字段表示消息的長度。注意,這個(gè)值通常與負(fù)載長度是不相同的。The chunk payload length is the?maximum chunk size for all but the last chunk, and the remainder (which may be?the entire length, for small messages) for the last chunk.
消息類型ID:1 字節(jié) 對于0 類型和1 類型的塊,本字段發(fā)送消息類型。
消息流ID:4 字節(jié) 對于0 類型的塊,本字段存儲(chǔ)消息流ID。通常,在一個(gè)塊流中的消息來自于同一個(gè)消息流。雖然,由于不同的消息可能復(fù)用到一個(gè)塊流中而使頭壓縮無法有效實(shí)施。但是,如果一個(gè)消息流關(guān)閉而另一個(gè)消息流才打開,那么通過發(fā)送一個(gè)新的0 類型的塊重復(fù)使用一個(gè)存在的塊流也不是不可以。
6.1.3. 擴(kuò)展時(shí)間戳 只有當(dāng)塊消息頭中的普通時(shí)間戳設(shè)置為0x00ffffff 時(shí),本字段才被傳送。如果普通時(shí)間戳的值小于0x00ffffff,那么本字段一定不能出現(xiàn)。如果時(shí)間戳字段不出現(xiàn)本字段也一定不能出現(xiàn)。類型3 的塊一定不能含有本字段。本字段在塊消息頭之后,塊時(shí)間之前。
代碼分析如下:
[cpp] ?view plaincopy print?
int ?RTMP_SendPacket(RTMP?*r,?RTMPPacket?*packet,? int ?queue)?? {?? ????const ?RTMPPacket?*prevPacket?=?r->m_vecChannelsOut[packet->m_nChannel];?? ????uint32_t?last?=?0;?? ????int ?nSize;?? ????int ?hSize,?cSize;?? ????char ?*header,?*hptr,?*hend,?hbuf[RTMP_MAX_HEADER_SIZE],?c;?? ????uint32_t?t;?? ????char ?*buffer,?*tbuf?=?NULL,?*toff?=?NULL;?? ????int ?nChunkSize;?? ????int ?tlen;?? ?? ?????? ?????? ????? ? ? ? ?? ????if ?(prevPacket?&&?packet->m_headerType?!=?RTMP_PACKET_SIZE_LARGE)?? ????{?? ?????????? ?????????? ?????????? ?????????? ?????????? ????????if ?(prevPacket->m_nBodySize?==?packet->m_nBodySize&&?prevPacket->m_packetType?==?packet->m_packetType?? ????????&&?packet->m_headerType?==?RTMP_PACKET_SIZE_MEDIUM)?? ????????????packet->m_headerType?=?RTMP_PACKET_SIZE_SMALL;?? ?? ?????????? ?????????? ????????if ?(prevPacket->m_nTimeStamp?==?packet->m_nTimeStamp?&&?packet->m_headerType?==?RTMP_PACKET_SIZE_SMALL)?? ????????????packet->m_headerType?=?RTMP_PACKET_SIZE_MINIMUM;?? ????????last?=?prevPacket->m_nTimeStamp;?? ????}?? ?? ?????? ????if ?(packet->m_headerType?>?3)? ?? ????{?? ????????RTMP_Log(RTMP_LOGERROR,?"sanity?failed!!?trying?to?send?header?of?type:?0x%02x." ,?(unsigned? char )packet->m_headerType);?? ????????return ?FALSE;?? ????}?? ?? ?????? ?????? ?????? ????nSize?=?packetSize[packet->m_headerType];?? ????hSize?=?nSize;?? ????cSize?=?0;?? ?????? ????t?=?packet->m_nTimeStamp?-?last;?? ?? ????if ?(packet->m_body)?? ????{?? ?????????? ????????header?=?packet->m_body?-?nSize;?? ?????????? ????????hend?=?packet->m_body;?? ?????????? ????}?? ????else ?? ????{?? ????????header?=?hbuf?+?6;?? ????????hend?=?hbuf?+?sizeof (hbuf);?? ????}?? ?? ????if ?(packet->m_nChannel?>?319) ?? ????????cSize?=?2;?? ????else ? if ?(packet->m_nChannel?>?63) ?? ????????cSize?=?1;?? ?????? ????if ?(cSize)?? ????{?? ????????header?-=?cSize;?? ????????hSize?+=?cSize;?? ????}?? ?? ?????? ?????? ????if ?(nSize?>?1?&&?t?>=?0xffffff)?? ????{?? ????????header?-=?4;?? ????????hSize?+=?4;?? ????}?? ?? ????hptr?=?header;?? ????c?=?packet->m_headerType?<<?6;?? ?? ?????? ????switch ?(cSize)?? ????{?? ????case ?0: ?? ????????c?|=?packet->m_nChannel;?? ????????break ;?? ????case ?1: ?? ????????break ;?? ????case ?2: ?? ????????c?|=?1;?? ????????break ;?? ????}?? ????*hptr++?=?c;?? ?? ?????? ????if ?(cSize)?? ????{?? ????????int ?tmp?=?packet->m_nChannel?-?64; ?? ????????*hptr++?=?tmp?&?0xff;?? ????????if ?(cSize?==?2) ?? ????????????*hptr++?=?tmp?>>?8;?? ????}?? ?? ????if ?(nSize?>?1) ?? ????{?? ?????????? ????????hptr?=?AMF_EncodeInt24(hptr,?hend,?t?>?0xffffff???0xffffff?:?t);?? ????}?? ?? ????if ?(nSize?>?4) ?? ????{?? ?????????? ????????hptr?=?AMF_EncodeInt24(hptr,?hend,?packet->m_nBodySize);?? ????????*hptr++?=?packet->m_packetType;?? ????}?? ?????? ????if ?(nSize?>?8)?? ????????hptr?+=?EncodeInt32LE(hptr,?packet->m_nInfoField2);?? ?? ????if ?(nSize?>?1?&&?t?>=?0xffffff) ?? ????????hptr?=?AMF_EncodeInt32(hptr,?hend,?t);?? ?? ?????? ?????? ????nSize?=?packet->m_nBodySize;?? ????buffer?=?packet->m_body;?? ????nChunkSize?=?r->m_outChunkSize;?? ?? ????RTMP_Log(RTMP_LOGDEBUG2,?"%s:?fd=%d,?size=%d" ,?__FUNCTION__,?r->m_sb.sb_socket,?nSize);?? ?????? ????if ?(r->Link.protocol?&?RTMP_FEATURE_HTTP)?? ????{?? ?????????? ?????????? ?????????? ?????????? ????????int ?chunks?=?(nSize?+?nChunkSize?-?1)?/?nChunkSize;?? ????????if ?(chunks?>?1) ?? ????????{?? ?????????????? ?????????????? ?????????????? ?????????????? ????????????tlen?=?chunks?*?(cSize?+?1)?+?nSize?+?hSize;?? ????????????tbuf?=?malloc(tlen);?? ????????????if ?(!tbuf)?? ????????????????return ?FALSE;?? ????????????toff?=?tbuf;?? ????????}?? ????}?? ?? ?????? ????while ?(nSize?+?hSize)?? ????{?? ????????int ?wrote;?? ?? ????????if ?(nSize?<?nChunkSize) ?? ????????????nChunkSize?=?nSize;?? ?? ????????RTMP_LogHexString(RTMP_LOGDEBUG2,?(uint8_t?*)header,?hSize);?? ????????RTMP_LogHexString(RTMP_LOGDEBUG2,?(uint8_t?*)buffer,?nChunkSize);?? ?????????? ?????????? ????????if ?(tbuf)?? ????????{?? ?????????????? ?????????????? ????????????memcpy(toff,?header,?nChunkSize?+?hSize);?? ????????????toff?+=?nChunkSize?+?hSize;?? ????????}?? ????????else ?? ????????{?? ?????????????? ????????????wrote?=?WriteN(r,?header,?nChunkSize?+?hSize);?? ????????????if ?(!wrote)?? ????????????????return ?FALSE;?? ????????}?? ????????nSize?-=?nChunkSize;?? ????????buffer?+=?nChunkSize;?? ????????hSize?=?0;?? ?? ?????????? ????????if ?(nSize?>?0)?? ????????{?? ????????????header?=?buffer?-?1;?? ????????????hSize?=?1;?? ????????????if ?(cSize)?? ????????????{?? ????????????????header?-=?cSize;?? ????????????????hSize?+=?cSize;?? ????????????}?? ????????????*header?=?(0xc0?|?c);?? ????????????if ?(cSize)?? ????????????{?? ????????????????int ?tmp?=?packet->m_nChannel?-?64;?? ????????????????header[1]?=?tmp?&?0xff;?? ????????????????if ?(cSize?==?2)?? ????????????????????header[2]?=?tmp?>>?8;?? ????????????}?? ????????}?? ????}?? ????if ?(tbuf)?? ????{?? ????????int ?wrote?=?WriteN(r,?tbuf,?toff?-?tbuf);?? ????????free(tbuf);?? ????????tbuf?=?NULL;?? ????????if ?(!wrote)?? ????????????return ?FALSE;?? ????}?? ?? ?????? ????if ?(packet->m_packetType?==?0x14)?? ????{?? ????????AVal?method;?? ????????char ?*ptr;?? ????????ptr?=?packet->m_body?+?1;?? ????????AMF_DecodeString(ptr,?&method);?? ????????RTMP_Log(RTMP_LOGDEBUG,?"Invoking?%s" ,?method.av_val);?? ?????????? ????????if ?(queue)?? ????????{?? ????????????int ?txn;?? ????????????ptr?+=?3?+?method.av_len;?? ????????????txn?=?(int )AMF_DecodeNumber(ptr);?? ????????????AV_queue(&r->m_methodCalls,?&r->m_numCalls,?&method,?txn);?? ????????}?? ????}?? ?? ????if ?(!r->m_vecChannelsOut[packet->m_nChannel])?? ????r->m_vecChannelsOut[packet->m_nChannel]?=?malloc(sizeof (RTMPPacket));?? ????memcpy(r->m_vecChannelsOut[packet->m_nChannel],?packet,?sizeof (RTMPPacket));?? ????return ?TRUE;?? }??
總結(jié)
以上是生活随笔 為你收集整理的librtmp协议分析---RTMP_SendPacket函数 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。