=====================================================
RTMPdump(libRTMP) 源代碼分析系列文章:
RTMPdump 源代碼分析?1: main()函數(shù)
RTMPDump (libRTMP) 源代碼分析2:解析RTMP地址——RTMP_ParseURL()
RTMPdump (libRTMP) 源代碼分析3: AMF編碼
RTMPdump (libRTMP) 源代碼分析4: 連接第一步——握手 (HandShake)
RTMPdump (libRTMP) 源代碼分析5: 建立一個(gè)流媒體連接 ?(NetConnection部分)
RTMPdump (libRTMP) 源代碼分析6: 建立一個(gè)流媒體連接 ?(NetStream部分 1)
RTMPdump (libRTMP) 源代碼分析7: 建立一個(gè)流媒體連接 ?(NetStream部分 2)
RTMPdump (libRTMP) 源代碼分析8: 發(fā)送消息 (Message)
RTMPdump (libRTMP) 源代碼分析9: 接收消息 (Message) ?(接收視音頻數(shù)據(jù))
RTMPdump (libRTMP) 源代碼分析10: 處理各種消息 (Message)
=====================================================
函數(shù)調(diào)用結(jié)構(gòu)圖
RTMPDump (libRTMP)的整體的函數(shù)調(diào)用結(jié)構(gòu)圖如下圖所示。
單擊查看大圖
詳細(xì)分析
前文已經(jīng)分析了?RTMPdump中建立一個(gè)NetConnection的過程:RTMPdump 源代碼分析 5: 建立一個(gè)流媒體連接 (NetConnection部分)
多余的話不多說,下面先來看看RTMP_ConnectStream(),該函數(shù)主要用于在NetConnection基礎(chǔ)上建立一個(gè)NetStream。
RTMP_ConnectStream()
[cpp]?view plaincopy
?? int?? RTMP_ConnectStream(RTMP?*r,?int?seekTime)?? {?? ??RTMPPacket?packet?=?{?0?};?? ?? ??? ? ?? ??if?(seekTime?>?0)?? ????r->Link.seekTime?=?seekTime;?? ?? ??r->m_mediaChannel?=?0;?? ?? ??while?(!r->m_bPlaying?&&?RTMP_IsConnected(r)?&&?RTMP_ReadPacket(r,?&packet))?? ????{?? ??????if?(RTMPPacket_IsReady(&packet))?? ????{?? ??????if?(!packet.m_nBodySize)?? ????????continue;?? ??????if?((packet.m_packetType?==?RTMP_PACKET_TYPE_AUDIO)?||?? ??????????(packet.m_packetType?==?RTMP_PACKET_TYPE_VIDEO)?||?? ??????????(packet.m_packetType?==?RTMP_PACKET_TYPE_INFO))?? ????????{?? ??????????RTMP_Log(RTMP_LOGWARNING,?"Received?FLV?packet?before?play()!?Ignoring.");?? ??????????RTMPPacket_Free(&packet);?? ??????????continue;?? ????????}?? ???????? ???????? ??????r->dlg->AppendCInfo("建立網(wǎng)絡(luò)流:處理收到的數(shù)據(jù)。開始處理收到的數(shù)據(jù)");?? ???????? ??????RTMP_ClientPacket(r,?&packet);?? ???????? ??????r->dlg->AppendCInfo("建立網(wǎng)絡(luò)流:處理收到的數(shù)據(jù)。處理完畢,清除數(shù)據(jù)。");?? ???????? ??????RTMPPacket_Free(&packet);?? ????}?? ????}?? ?? ??return?r->m_bPlaying;?? }??
乍一看,這個(gè)函數(shù)的代碼量好像挺少的,實(shí)際上不然,其復(fù)雜度還是挺高的。我覺得比RTMP_Connect()要復(fù)雜不少。
其關(guān)鍵就在于這個(gè)While()循環(huán)。首先,循環(huán)的三個(gè)條件都滿足,就能進(jìn)行循環(huán)。只有出錯(cuò)或者建立網(wǎng)絡(luò)流(NetStream)的步驟完成后,才能跳出循環(huán)。
在這個(gè)函數(shù)中有兩個(gè)函數(shù)尤為重要:
RTMP_ReadPacket()
RTMP_ClientPacket()
第一個(gè)函數(shù)的作用是讀取通過Socket接收下來的消息(Message)包,但是不做任何處理。第二個(gè)函數(shù)則是處理消息(Message),并做出響應(yīng)。這兩個(gè)函數(shù)結(jié)合,就可以完成接收消息然后響應(yīng)消息的步驟。
下面來開一下RTMP_ReadPacket():
[cpp]?view plaincopy
?? int?? RTMP_ReadPacket(RTMP?*r,?RTMPPacket?*packet)?? {?? ?????? ?????? ??uint8_t?hbuf[RTMP_MAX_HEADER_SIZE]?=?{?0?};?? ?????? ??char?*header?=?(char?*)hbuf;?? ??int?nSize,?hSize,?nToRead,?nChunk;?? ??int?didAlloc?=?FALSE;?? ?? ??RTMP_Log(RTMP_LOGDEBUG2,?"%s:?fd=%d",?__FUNCTION__,?r->m_sb.sb_socket);?? ???? ??if?(ReadN(r,?(char?*)hbuf,?1)?==?0)?? ????{?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?read?RTMP?packet?header",?__FUNCTION__);?? ??????return?FALSE;?? ????}?? ???? ??packet->m_headerType?=?(hbuf[0]?&?0xc0)?>>?6;?? ???? ??packet->m_nChannel?=?(hbuf[0]?&?0x3f);?? ??header++;?? ???? ??if?(packet->m_nChannel?==?0)?? ????{?? ??????if?(ReadN(r,?(char?*)&hbuf[1],?1)?!=?1)?? ????{?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?read?RTMP?packet?header?2nd?byte",?? ??????????__FUNCTION__);?? ??????return?FALSE;?? ????}?? ???????? ??????packet->m_nChannel?=?hbuf[1];?? ??????packet->m_nChannel?+=?64;?? ??????header++;?? ????}?? ???? ??else?if?(packet->m_nChannel?==?1)?? ????{?? ??????int?tmp;?? ??????if?(ReadN(r,?(char?*)&hbuf[1],?2)?!=?2)?? ????{?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?read?RTMP?packet?header?3nd?byte",?? ??????????__FUNCTION__);?? ??????return?FALSE;?? ????}?? ??????tmp?=?(hbuf[2]?<<?8)?+?hbuf[1];?? ???????? ??????packet->m_nChannel?=?tmp?+?64;?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s,?m_nChannel:?%0x",?__FUNCTION__,?packet->m_nChannel);?? ??????header?+=?2;?? ????}?? ???? ??nSize?=?packetSize[packet->m_headerType];?? ?? ??if?(nSize?==?RTMP_LARGE_HEADER_SIZE)???? ????packet->m_hasAbsTimestamp?=?TRUE;?????? ?? ??else?if?(nSize?<?RTMP_LARGE_HEADER_SIZE)?? ????{????????????????? ??????if?(r->m_vecChannelsIn[packet->m_nChannel])?? ????memcpy(packet,?r->m_vecChannelsIn[packet->m_nChannel],?? ???????????sizeof(RTMPPacket));?? ????}?? ?? ??nSize--;?? ?? ??if?(nSize?>?0?&&?ReadN(r,?header,?nSize)?!=?nSize)?? ????{?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?read?RTMP?packet?header.?type:?%x",?? ??????__FUNCTION__,?(unsigned?int)hbuf[0]);?? ??????return?FALSE;?? ????}?? ?? ??hSize?=?nSize?+?(header?-?(char?*)hbuf);?? ?? ??if?(nSize?>=?3)?? ????{?? ?????? ??????packet->m_nTimeStamp?=?AMF_DecodeInt24(header);?? ?? ???????? ?????? ??????if?(nSize?>=?6)?? ????{?? ??????packet->m_nBodySize?=?AMF_DecodeInt24(header?+?3);?? ??????packet->m_nBytesRead?=?0;?? ??????RTMPPacket_Free(packet);?? ?????? ??????if?(nSize?>?6)?? ????????{?? ???????????? ??????????packet->m_packetType?=?header[6];?? ???????????? ??????????if?(nSize?==?11)?? ????????packet->m_nInfoField2?=?DecodeInt32LE(header?+?7);?? ????????}?? ????}?? ???????? ??????if?(packet->m_nTimeStamp?==?0xffffff)?? ????{?? ??????if?(ReadN(r,?header?+?nSize,?4)?!=?4)?? ????????{?? ??????????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?read?extended?timestamp",?? ??????????__FUNCTION__);?? ??????????return?FALSE;?? ????????}?? ??????packet->m_nTimeStamp?=?AMF_DecodeInt32(header?+?nSize);?? ??????hSize?+=?4;?? ????}?? ????}?? ?? ??RTMP_LogHexString(RTMP_LOGDEBUG2,?(uint8_t?*)hbuf,?hSize);?? ?? ??if?(packet->m_nBodySize?>?0?&&?packet->m_body?==?NULL)?? ????{?? ??????if?(!RTMPPacket_Alloc(packet,?packet->m_nBodySize))?? ????{?? ??????RTMP_Log(RTMP_LOGDEBUG,?"%s,?failed?to?allocate?packet",?__FUNCTION__);?? ??????return?FALSE;?? ????}?? ??????didAlloc?=?TRUE;?? ??????packet->m_headerType?=?(hbuf[0]?&?0xc0)?>>?6;?? ????}?? ?? ??nToRead?=?packet->m_nBodySize?-?packet->m_nBytesRead;?? ??nChunk?=?r->m_inChunkSize;?? ??if?(nToRead?<?nChunk)?? ????nChunk?=?nToRead;?? ?? ???? ??if?(packet->m_chunk)?? ????{?? ??????packet->m_chunk->c_headerSize?=?hSize;?? ??????memcpy(packet->m_chunk->c_header,?hbuf,?hSize);?? ??????packet->m_chunk->c_chunk?=?packet->m_body?+?packet->m_nBytesRead;?? ??????packet->m_chunk->c_chunkSize?=?nChunk;?? ????}?? ?? ??if?(ReadN(r,?packet->m_body?+?packet->m_nBytesRead,?nChunk)?!=?nChunk)?? ????{?? ??????RTMP_Log(RTMP_LOGERROR,?"%s,?failed?to?read?RTMP?packet?body.?len:?%lu",?? ??????__FUNCTION__,?packet->m_nBodySize);?? ??????return?FALSE;?? ????}?? ?? ??RTMP_LogHexString(RTMP_LOGDEBUG2,?(uint8_t?*)packet->m_body?+?packet->m_nBytesRead,?nChunk);?? ?? ??packet->m_nBytesRead?+=?nChunk;?? ?? ???? ??if?(!r->m_vecChannelsIn[packet->m_nChannel])?? ????r->m_vecChannelsIn[packet->m_nChannel]?=?(RTMPPacket?*)?malloc(sizeof(RTMPPacket));?? ??memcpy(r->m_vecChannelsIn[packet->m_nChannel],?packet,?sizeof(RTMPPacket));?? ???? ??if?(RTMPPacket_IsReady(packet))?? ????{?? ???????? ??????if?(!packet->m_hasAbsTimestamp)?? ????packet->m_nTimeStamp?+=?r->m_channelTimestamp[packet->m_nChannel];??? ?? ??????r->m_channelTimestamp[packet->m_nChannel]?=?packet->m_nTimeStamp;?? ?? ???????? ???????? ??????r->m_vecChannelsIn[packet->m_nChannel]->m_body?=?NULL;?? ??????r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead?=?0;?? ??????r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp?=?FALSE;????? ????}?? ??else?? ????{?? ??????packet->m_body?=?NULL;??? ????}?? ?? ??return?TRUE;?? }??
在這里要注意的是,接收下來的實(shí)際上是塊(Chunk)而不是消息(Message),因?yàn)橄?#xff08;Message)在網(wǎng)絡(luò)上傳播的時(shí)候,實(shí)際上要分割成塊(Chunk)。
這里解析的就是塊(Chunk)
可參考:RTMP規(guī)范簡單分析
具體的解析代碼我就不多說了,直接參考RTMP協(xié)議規(guī)范就可以了,一個(gè)字節(jié)一個(gè)字節(jié)的解析就OK了。
rtmpdump源代碼(Linux):http://download.csdn.net/detail/leixiaohua1020/6376561
rtmpdump源代碼(VC 2005 工程):http://download.csdn.net/detail/leixiaohua1020/6563163
總結(jié)
以上是生活随笔為你收集整理的RTMPdump(libRTMP) 源代码分析 6: 建立一个流媒体连接 (NetStream部分 1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。