rtmpdump代碼簡單分析

第一步——握手(Hand Shake)

代碼在 handshake.h文件中,
該文件中HandShake 函數是處理握手的。

第二 步-----建立連接NetConnection  在文件rtmp.cpp 中

RTMP_Connect():

其內部調用了 

RTMP_Connect0() 和  RTMP_Connect1()。

RTMP_Connect0() 主要是建立Socket連接

RTMP_Connect1() 建立RTMP連接.

第三步-----建立流 NetStream  代碼也在rtmp.cpp中

RTMP_ConnectStream

在這個函數中調用了

RTMP_ReadPacket()

RTMP_ClientPacket()

第一個函數的作用是讀取通過Socket接收下來的消息(Message)包,但是不做任何處理。第二個函數則是處理消息(Message),並做出響應。這兩個函數結合,就可以完成接收消息然後響應消息的步驟。

RTMP_ReadPacket 接收下來的是Chunk

RTMP_ClientPacket() 是用來處理消息,根據不同的消息,做不同的調用。

switch (packet->m_packetType)  
 {  
case 0x01:
break;
case 0x02:
break;
case 0x14:  
       
      if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)  
    bHasMediaPacket = 2;  
      break;  
......
}

消息類型爲0x14的消息,即消息類型ID爲20的消息,是AMF0編碼的命令消息,

依次調用

AMF_Decode(&obj, body, nBodySize, FALSE);  
 
  AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);  
  
(AVMATCH(&method, &av__result))  

三個命令,

針對不同的method,處理不同的命令。

這些命令有以下這些(不完整)

AVMATCH(&methodInvoked, &av_connect)
AVMATCH(&methodInvoked, &av_createStream)
AVMATCH(&methodInvoked, &av_play)
AVMATCH(&methodInvoked, &av_publish)
AVMATCH(&method, &av_onBWDone)
等等。

第四步------發送消息

消息是如何發送的?

  • 發送connect命令使用函數SendConnectPacket()
  • 發送createstream命令使用RTMP_SendCreateStream()
  • 發送realeaseStream命令使用SendReleaseStream()
  • 發送publish命令使用SendPublish()
  • 發送deleteStream的命令使用SendDeleteStream()
  • 發送pause命令使用RTMP_SendPause()

函數命名有兩種規律:RTMP_Send***()或者Send***(),其中*號代表命令的名稱


發送消息比較類似:
總體的思路是聲明一個RTMPPacket類型的結構體,然後設置各種屬性值,最後交給RTMP_SendPacket()進行發送。

RTMPPacket類型的結構體定義如下,一個RTMPPacket對應RTMP協議規範裏面的一個塊(Chunk)。


//Chunk信息
  typedef struct RTMPPacket
  {
    uint8_t m_headerType;//ChunkMsgHeader的類型(4種)
    uint8_t m_packetType;//Message type ID(1-7協議控制;8,9音視頻;10以後爲AMF編碼消息)
    uint8_t m_hasAbsTimestamp;    /* Timestamp 是絕對值還是相對值? */
    int m_nChannel;            //塊流ID
    uint32_t m_nTimeStamp;    // Timestamp
    int32_t m_nInfoField2;    /* last 4 bytes in a long header,消息流ID */
    uint32_t m_nBodySize;    //消息長度
    uint32_t m_nBytesRead;
    RTMPChunk *m_chunk;
    char *m_body;
  } RTMPPacket;

RTMP_SendPacket()
各種的RTMPPacket(即各種Chunk)都需要用這個函數進行發送。
這個函數 按照RTMP規範將數據編碼成符合規範的塊(Chunk),

在這裏需要注意一個函數:WriteN()。該函數完成了將數據發送出去的功能。


在這個函數里根據協議不同,調用相應的函數
  1. if (r->Link.protocol & RTMP_FEATURE_HTTP)  
  2.         nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);  
  3.       else  
  4.         nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);  

其中 RTMPSockBuf_Send()完成了數據發送的功能
在這個RTMPSockBuf_Send()函數中調用了系統Socket的send()函數完成了數據的發送功能

到此,發送消息能夠通過socket發送出去。


第五步------接收消息

RTMPdump中完成視音頻數據的接收的函數是:RTMP_Read()。

RTMP_Read()中實際讀取數據的函數是Read_1_Packet(),它的功能是從網絡上讀取一個RTMPPacket的數據,

Read_1_Packet()裏面實現從網絡中讀取視音頻數據的函數是RTMP_GetNextMediaPacket()。

RTMP_GetNextMediaPacket 裏會調用兩個函數:RTMP_ReadPacket()以及RTMP_ClientPacket()。這兩個函數中,前一個函數負責從網絡上讀取數據,後一個負責處理數據。

在RTMP_ReadPacket()函數裏完成從Socket中讀取數據的函數是ReadN(),

ReadN()中實現從Socket中接收數據的函數是RTMPSockBuf_Fill(),
RTMPSockBuf_Fill()函數中調用了系統Socket的recv()函數接收RTMP連接傳輸過來的數據。

第六步------處理各種消息

RTMPdump 的函數 RTMP_ClientPacket(), 主要完成了各種消息的處理。



消息ID
功能
調用函數

0x01
設置塊(Chunk)大小
HandleChangeChunkSize()

0x03
致謝
無函數

0x04
用戶控制
HandleCtrl

0x05
窗口致謝大小(Window Acknowledgement Size
HandleServerBW()

0x06
設置對等端帶寬(Set Peer Bandwidth)
HandleClientBW()

0x08
傳輸音頻


0x09
傳輸視頻


0x0f--11
傳輸AMF3編碼


0x12--14
傳輸AMF0編碼












發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章