1. 程式人生 > >rtmplib rtmp協議過程分析

rtmplib rtmp協議過程分析

寫的很好,收藏如下,向作者致敬!

沒事碰到了librtmp庫,這個庫是ffmpeg的依賴庫,用來接收,釋出RTMP協議格式的資料。

程式碼在這裡:git clone git://git.ffmpeg.org/rtmpdump

先看一段通過librtmp.so庫下載RTMP源釋出的資料的例子,從rtmpdump中抽取出來。使用的大體流程如下:

  1. RTMP_Init主要就初始化了一下RTMP*rtmp變數的成員。
  2. RTMP_SetupURL 函式將rtmp源地址的埠,app,等url引數進行解析,設定到rtmp變數中。比如這樣的地址: rtmp://host[:port]/path swfUrl=url tcUrl=url 。
  3. RTMP_SetBufferMS 函式設定一下緩衝大小;
  4. RTMP_Connect函式完成了連線的建立,一級RTMP協議層的應用握手,待會介紹。
  5. RTMP_ConnectStream總的來說,完成了一個流的建立,以及開啟,觸發服務端傳送資料過來,返回後,服務端應該就開始傳送資料了。
  6. Download 其實是RTMP_Read函式的封裝,後者讀取服務端的資料返回。
  1. RTMP_Init(&rtmp);//初始化RTMP引數  
  2. //指定了-i 引數,直接設定URL  
  3. if (RTMP_SetupURL(&rtmp, fullUrl.av_val) == FALSE) {  
  4.     RTMP_Log(RTMP_LOGERROR, "Couldn't parse URL: %s", fullUrl.av_val);  
  5.     return RD_FAILED;  
  6. }  
  7. rtmp.Link.timeout = timeout ;  
  8. /* Try to keep the stream moving if it pauses on us */  
  9. if (!bLiveStream )  
  10.     rtmp.Link.lFlags |= RTMP_LF_BUFX;  
  11. while (!RTMP_ctrlC)  
  12. {  
  13.     RTMP_Log(RTMP_LOGDEBUG, "Setting buffer time to: %dms", DEF_BUFTIME);  
  14.     RTMP_SetBufferMS(&rtmp, DEF_BUFTIME);//告訴伺服器幫我快取多久  
  15.     RTMP_LogPrintf("Connecting ...\n");  
  16.     if (!RTMP_Connect(&rtmp, NULL)) {//建立連線,傳送"connect"  
  17.         nStatus = RD_NO_CONNECT;  
  18.         break;  
  19.     }  
  20.     RTMP_Log(RTMP_LOGINFO, "Connected...");  
  21.     //處理服務端返回的各種控制訊息包,比如收到connect的result後就進行createStream,以及傳送play(test)訊息  
  22.     if (!RTMP_ConnectStream(&rtmp, 0)) {//一旦返回,表示服務端開始傳送資料了.可以play了  
  23.         nStatus = RD_FAILED;  
  24.         break;  
  25.     }  
  26.     nStatus = Download(&rtmp, file, bStdoutMode, bLiveStream );  
  27.     if (nStatus != RD_INCOMPLETE || !RTMP_IsTimedout(&rtmp) || bLiveStream)  
  28.         break;  
  29. }  


一、建立協議連線

下面來詳細介紹下RTMP_Connect函式的工作。

先看程式碼,下面RTMP_Connect的工作是連線對端,進行握手,並且傳送”connect” 控制訊息,附帶一些app,tcurl等引數。其實時呼叫了2個函式完成工作的:RTMP_Connect0, RTMP_Connect1 。

  1. int  RTMP_Connect(RTMP *r, RTMPPacket *cp)  
  2. {//連線對端,進行握手,並且傳送"connect" 控制訊息,附帶一些app,tcurl等引數  
  3.     struct sockaddr_in service;  
  4.     if (!r->Link.hostname.av_len)  
  5.         return FALSE;  
  6.     memset(&service, 0, sizeof(struct sockaddr_in));  
  7.     service.sin_family = AF_INET;  
  8.     if (r->Link.socksport)  
  9.     {  
  10.         /* Connect via SOCKS */  
  11.         if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))  
  12.             return FALSE;  
  13.     }  
  14.     else  
  15.     {  
  16.         /* Connect directly */  
  17.         if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))  
  18.             return FALSE;  
  19.     }  
  20.     if (!RTMP_Connect0(r, (struct sockaddr *)&service))//建立一個socket連線  
  21.         return FALSE;  
  22.     r->m_bSendCounter = TRUE;  
  23.     return RTMP_Connect1(r, cp);//進行C0-2/S0-2協議握手,傳送connect命令  
  24. }  

其中RTMP_Connect0 函式比較簡單,標準的socket, conect 流程,另外設定了一下TCP_NODELAY選項,方便小包傳送等。以及SO_RCVTIMEO讀超時,這部分屬於基本的TCP層面的連線;

RTMP_Connect1 函式則完成類似HTTP層面的RTMP協議的連線建立過程。首先是HandShake 握手。RTMP的握手是通過客戶端跟服務端互相傳送資料包來完成的,每人3個數據包,名之為C0,C1,C2 以及S0,S1, S2。其傳送資料有嚴格的限制的。因為互相依賴。這個在官方文件中有詳細的介紹,不多說。

對於librtmp來說,可能的一種流程是:

CLIENT                          SERVER

C0,C1             —>

<—         S0, S1,S2

C2                    –>

具體看一下程式碼,比較長。

  1. static int HandShake(RTMP *r, int FP9HandShake)  
  2. {//C0,C1 -- S0, S1, S2 -- C2 訊息握手協議  
  3.     int i;  
  4.     uint32_t uptime, suptime;  
  5.     int bMatch;  
  6.     char type;  
  7.     char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;  
  8.     char serversig[RTMP_SIG_SIZE];  
  9.     clientbuf[0] = 0x03;//C0, 一個位元組。03代表協議版本號為3     /* not encrypted */  
  10.     uptime = htonl(RTMP_GetTime());//這是一個時間戳,放在C1訊息頭部  
  11.     memcpy(clientsig, &uptime, 4);  
  12.     memset(&clientsig[4], 0, 4);//後面放4個位元組的空資料然後就是隨機資料  
  13.     //後面是隨機資料,總共1536位元組的C0訊息  
  14. #ifdef _DEBUG  
  15.     for (i = 8; i <RTMP_SIG_SIZE; i++)  
  16.         clientsig[i] = 0xff;  
  17. #else  
  18.     for (i = 8; i <RTMP_SIG_SIZE; i++)  
  19.         clientsig[i] = (char)(rand() % 256);//傳送C0, C1訊息  
  20. #endif  
  21.     if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))  
  22.         return FALSE;  
  23.     //下面讀一個位元組也就是S0訊息,看協議是否一樣  
  24.     if (ReadN(r, &type, 1) != 1)    /* 0x03 or 0x06 */  
  25.         return FALSE;  
  26.     RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer   : %02X", __FUNCTION__, type);  
  27.     if (type != clientbuf[0])//C/S版本不一致  
  28.         RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",  __FUNCTION__, clientbuf[0], type);  
  29.     //讀取S1訊息,裡面有伺服器執行時間  
  30.     if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)  
  31.         return FALSE;  
  32.     /* decode server response */  
  33.     memcpy(&suptime, serversig, 4);  
  34.     suptime = ntohl(suptime);  
  35.     RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);  
  36.     RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version   : %d.%d.%d.%d", __FUNCTION__, serversig[4], serversig[5], serversig[6], serversig[7]);  
  37.     /* 2nd part of handshake */  
  38.     if (!WriteN(r, serversig, RTMP_SIG_SIZE))//傳送C2訊息,內容就等於S1訊息的內容。  
  39.         return FALSE;  
  40.     //讀取S2訊息  
  41.     if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)  
  42.         return FALSE;  
  43.     bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);  
  44.     if (!bMatch)//服務端返回的S2訊息必須跟C1訊息一致才行  
  45.     {  
  46.         RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);  
  47.     }  
  48.     return TRUE;  
  49. }  

握手的目的其實是互相溝通一下支援的協議版本號,伺服器時間戳等。確保連線的對端真的是RTMP支援的。

傳送請求給服務端。

然後就是SendConnectPacket的工作了。總結一句其功能是成一個“connect訊息以及其app,tcurl等引數,然後呼叫RTMP_SendPacket函式將其資料傳送出去。

到這裡連線建立完成了。

二、準備資料通道

RTMP_ConnectStream完成了通道的建立。其處理服務端返回的各種控制訊息包,比如收到connect的result後就進行createStream,以及傳送play(test)訊息。一旦返回,表示服務端開始傳送資料了.可以play了。

函式本身比較簡單,就是一個while迴圈,不斷的呼叫RTMP_ReadPacket讀取服務端傳送過來的資料包進行相應的處理。直到m_bPlaying變老變為TRUE為止,也就是可以播放的時候為止。資料包的處理函式為RTMP_ClientPacket。

  1. int RTMP_ConnectStream(RTMP *r, int seekTime)  
  2. {//迴圈讀取服務端傳送過來的各種訊息,比如window ack**, set peer bandwidth, set chunk size, _result等  
  3.     //直到接收到了play  
  4.     RTMPPacket packet = { 0 };  
  5.     /* seekTime was already set by SetupStream / SetupURL.  
  6.      * This is only needed by ReconnectStream.  
  7.      */  
  8.     if (seekTime > 0)  
  9.         r->Link.seekTime = seekTime;  
  10. 相關推薦

    rtmplib rtmp協議過程分析

    寫的很好,收藏如下,向作者致敬! 沒事碰到了librtmp庫,這個庫是ffmpeg的依賴庫,用來接收,釋出RTMP協議格式的資料。 程式碼在這裡:git clone git://git.ffmpeg.org/rtmpdump 先看一段通過librtm

    RTMP協議分析及推流過程

    簡介: 1.RTMP(實時訊息傳輸協議)是Adobe 公司開發的一個基於TCP的應用層協議。 2.RTMP協議中基本的資料單元稱為訊息(Message)。 3.當RTMP協議在網際網路中傳輸資料的時候,訊息會被拆分成更小的單元,稱為訊息塊(Chunk)。 RTMP 握手(

    rtmp 協議分析及互動過程

    本文描述了從開啟一個RTMP流媒體到視音訊資料開始播放的全過程。 注意:RTMP中的邏輯結構 RTMP協議規定,播放一個流媒體有兩個前提步驟:第一步,建立一個網路連線(NetConnection);第二步,建立一個網路流(NetStream)。其中,網路連線代表伺服器端應用程式和客戶端之間基礎的連通

    調試libRTMP代碼來分析RTMP協議

    bind 部分 字節 attribute err nco last esc command RTMP是Real Time Messaging Protocol(實時消息傳輸協議)的首字母縮寫。該協議基於TCP,是一個協議族,常用在視頻直播領域。RTMP協議的默認端口

    TCP協議三次握手過程分析

    fmt 圖1 同步 建立連接 協議 from pan mir 重置 TCP(Transmission Control Protocol) 傳輸控制協議。 TCP是主機對主機層的傳輸控制協議,提供可靠的連接服務,采用三次握手確認建立一個連接: 位碼即tcp標誌位,有6種標

    從wireshark抓包分析rtmp協議,並提取出H264視頻流

    tmp mage idt 進制 tro shark src 技術 wid 利用wireshark抓取rtmp流數據, 分析到rtmp流後,寫入過濾條件,如 tcp.stream eq 6導出tcp流保存16進制的數據為純文本格式一定要選擇 Hex轉儲,然後點擊 “Sava

    Tcp協議中的3次握手與4次揮手過程分析

    轉載https://blog.csdn.net/u012824097/article/details/52490091 客戶端與服務端的通訊中步驟 1建立Tcp連線 3次握手 2再進行資料傳輸 3資料傳輸完成後,斷開連線。

    RTMP協議分析

     一、RTMP包頭  RTMP協議 封包 參考Red5 RTMP協議封包 由一個包頭和一個包體組成,包頭可以是4種長度的任意一種:12, 8, 4,  1 byte(s).完整的RTMP包頭應該是12bytes,包含了時間戳,Head_Type,AMFSize,AMFT

    TCP協議四次揮手過程分析?為什麼握手三次揮手四次?

    1. 為什麼四次揮手? 為什麼連線的時候是三次握手,關閉的時候卻是四次握手? 答:因為當Server端收到Client端的SYN連線請求報文後,可以直接傳送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連線時,當Server端

    wireshark+rtmp協議分析

    使用wireshark抓包工具 如何使用wireshark中常見的過濾選項包括協議型別、埠號、stream eq、ip地址 通過wireshark,要學會如何重網路包中獲取視訊幀的資料,這裡主要針對rtmp協議。    抓取網路包 開啟wire

    RTMP協議播放流程的實現及抓包分析

         實時流協議(Real-TimeMessaging Protocol,RTMP)是用於網際網路上傳輸視音訊資料的網路協議。本API提供了支援RTMP, RTMPT,RTMPE, RTMP RTMPS以及以上幾種協議的變種(RTMPTE, RTMPTS)協議所需的大

    RTMP協議分析及H.264打包原理

    RTMP是Real Time Messaging Protocol(實時訊息傳輸協議)的首字母縮寫。該協議基於TCP,是一個協議族,包括RTMP基本協議及RTMPT/RTMPS/RTMPE等多種變種。RTMP是一種設計用來進行實時資料通訊的網路協議,主要用來在Flash/A

    視頻rtmp協議簡介

    png class 論文 smi false spa codec -i baidu 這篇論文裏講得非常詳細。下面說說我的理解。 server端:將視頻流按順序切割為視頻+音頻合成文件ts,每個ts是視頻流的一塊,並把ts信息存儲在m3u8文件中 client端:讀取m3u

    HTTP協議詳細分析

    就會 cat purpose 分隔 utf-8 tcp/ip 例如 握手 5.0 1、HTTP概述   1.1、什麽是HTTP?     它是Hyper Text Transfer Protocol的縮寫。超文本傳輸協議。     它是客戶瀏覽器和web服務器之間的

    【轉】Android 4.0 Launcher2源碼分析——啟動過程分析

    handler flag 這一 第一次啟動 asynctask pla size ontouch wait Android的應用程序的入口定義在AndroidManifest.xml文件中可以找出:[html] <manifest xmlns:android="htt

    STM32的flash數據頁轉存過程分析

    pty val 根據 mst else 系統 add ted ble stm32模擬eeprom要實現flash數據頁轉存,實現函數為 1 /** 2 * @brief Transfers last updated variables data from the fu

    Linux系統調用過程分析

    policy 用戶空間 抽象接口 保護 name ack for 內嵌 驅動程序 參考: 《Linux內核設計與實現》 0 摘要 linux的系統調用過程: 層次例如以下: 用戶程序------>C庫(即API):INT 0x80 ----->system_

    流媒體系統的RTMP協議

    RTMP協議 流媒體系統 AMF 什麽是RTMP協議 RTMP(Real-Time Messaging Protocol實時消息傳送協議)的縮寫,它是Adobe Systems公司為Flash播放器和服務器之間音頻、視頻和數據傳輸開發的協議。這是一個標準的,未加密

    推薦下:開源ckplayer 網頁播放器, 跨平臺(html5, mobile),flv, f4v, mp4, rtmp協議. webm, ogg, m3u8 !

    網頁播放器 get ... 默認 control firefox ckplayer 原本 auto 視頻播放, 原本是想h5 自帶視頻播放,使用很簡單,結果現實很骨感。 <video controls="controls" preload="auto" height

    X86架構下Linux啟動過程分析

    重要 ack csdn 檢查 point article span 註意 eap 1、X86架構下的從開機到Start_kernel啟動的整體過程 這個過程簡要概述為: 開機——>BIOS——>GRUB/LILO——>Linux Kernel