關於利用live555,RTSP取流

對於live555和RTSP,相信看到這篇博文的朋友應該很熟悉了,分享一些皮毛,大家儘量吐槽:
首先說一下做的功能:利用live555裏面的一個live555mediaserver來作爲媒體服務器,然後利用裏面的TestRTSPClient來取得碼流,當然官網上說了:RTSPClient只是個測試程序,如果用作產品還需要進行優化,不過可以作爲參考,我也是用他來作爲一個隊live555入門的東西,看了一下里面的流程,好了不說廢話了,這裏主要講的利用RTSP來從媒體服務器中取得碼流,如下:

1.首先下載live555源碼,然後進行編譯(我的環境是ubuntu11.10),得到源碼即可編譯通過,然後裏面有個mediaServer目錄進去運行

./live555MediaServer
Play streams from this server using the URL
rtsp://192.168.1.106/<filename> //這裏假設我們的文件名是:VideoFile.h264;
where <filename> is a file present in the current directory.

得到上面這一串字符,我們可以看到有一個是rtsp://192.168.1.06/<filename>,這個就是我們在利用rtsp編寫代碼的時候需要用的url;現在你可以進入上層目錄下testProgs,執行:
./testRTSPClient rtsp://192.168.1.106/<filename>,然後就可以看到有碼流過來了,這些碼流就是filename文件,當然這個文件是在mediaServer當前目錄中存在的,當你運行前你可以嘗試用抓包工具看到碼流申請的流程;這裏我用的是vlc來代替這一步

2.當第一步證實我們的mediaServer是可用的了,接下來的步驟就是在vlc中找到打開網路流–>然後把上面的rtsp url輸入vlc中,然後開啓網絡抓包工具,單擊播放,通過抓包工具可以清楚的看到碼流申請的流程:

1.
==>vlc—>mediaserver 請求
OPTIONS rtsp://192.168.1.106/client.264 RTSP/1.0 //OPTIONS請求,最後面的RTSP/1.0是rtsp版本
CSeq: 2 //這個是會話的序號,回覆的序號跟這個必須一致,並且應該是遞增的
User-Agent: LibVLC/2.0.1 (LIVE555 Streaming Media v2011.12.23)//可以不用管
==> mediaserver–>vlc 回覆
RTSP/1.0 200 OK //200 OK 表示我們求的OPTIONS請求成功
CSeq: 2 //注意與上面的一樣
Date: Sat, Jun 08 2013 14:01:34 GMT //服務器當前時間
//服務器支持的方法,也就是說我們可以發送下面的這些請求過去
Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMET

2.
==>vlc—>mediaserver 請求
DESCRIBE rtsp://192.168.1.106/client.264 RTSP/1.0 //DESCRIBE請求
CSeq: 3 //序號遞增
User-Agent: LibVLC/2.0.1 (LIVE555 Streaming Media v2011.12.23)
Accept: application/sdp //這段表示我們請求得到回覆的數據應該是sdp(關於sdp請百度)
==> mediaserver–>vlc 回覆
RTSP/1.0 200 OK
CSeq: 3
Date: Sat, Jun 08 2013 14:01:34 GMT
Content-Base: rtsp://192.168.1.106/client.264/
Content-Type: application/sdp
Content-Length: 521 v=0 o=- 1370699986662940 1 IN IP4 192.168.1.106 s=H.264 Video, streamed by the LIVE555 Media Server i=client.264 t=0 0 a=tool:LIVE555 Streaming Media v2012.11.30 a=type:broadcast a=control:* a=range:npt=0- a=x-qt-text-nam:H.264 Video, streamed by the LIVE555 Media Server a=x-qt-text-inf:client.264 m=video 0 RTP/AVP 96 c=IN IP4 0.0.0.0 b=AS:500 a=rtpmap:96 H264/90000 a=fmtp:96 packetization-mode=1;profile-level-id=42C033;sprop-parameter \
-sets=Z0LAM5p0CwS0IAAAAwAgAAAGUeMGVA==,aM48gA== a=control:track1
//回覆了一串很長的sdp信息,其中有很多字段對我們請求碼流是比較重要,比如
a=control:track1 //這個是一個標誌,具體比如對應ipc可能是通道的概念,我們後面需要這個字段
a=rtpmap:96 H264/90000 //h264的碼流 SDP信息本人也還沒有全部弄懂,可以在需要的時候進行百度瞭解

3.
==>vlc—>mediaserver 請求
SETUP rtsp://192.168.1.106/client.264/track1 RTSP/1.0 //SETUP請求,告訴服務器怎麼發送給我們
CSeq: 4
User-Agent: LibVLC/2.0.1 (LIVE555 Streaming Media v2011.12.23)
Transport: RTP/AVP/TCP;unicast;interleaved=0-1 //傳輸協議TCP RTP 單播, interleaved這個字段跟解rtp包有關係,具體還不是很清楚,如果是udp的話,這裏商量的是端口的問題,tcp直接使用當前端口發送
==> mediaserver–>vlc 回覆 //迴應請求,表示已經知道如何發送,往哪裏發送,並返回一個session ID
RTSP/1.0 200 OK
CSeq: 4
Date: Sat, Jun 08 2013 14:01:34 GMT Transport: \RTP/AVP/TCP;unicast;destination=192.168.1.105;source=192.168.1.106;interleaved=0-1 Session: CFB1212D //這個是表示是這一次會話的標示

4.
這裏我們可以申請進行傳輸碼流了 ==>vlc—>mediaserver 請求 PLAY rtsp://192.168.1.106/client.264/ RTSP/1.0 //請求播放 PLAY CSeq: 5 User-Agent: LibVLC/2.0.1 (LIVE555 Streaming Media v2011.12.23) Session: CFB1212D //帶上sessionID,否則會返回Not Found錯誤 Range: npt=0.000- //這個跟時間有關係 ==> mediaserver–>vlc 回覆 RTSP/1.0 200 OK CSeq: 5 Date: Sat, Jun 08 2013 14:01:34 GMT Range: npt=0.000- Session: CFB1212D //sessionID RTP-Info: url=rtsp://192.168.1.106/client.264/track1;seq=54219;rtptime=2695045868

到此,你可以通過vlc看到視頻,或者聽到音頻了;上面是通過vlc抓包得到的流程,淡然可能還需要進行其他的請求,比如上面Public:中的TEARDOWN, PAUSE, GET_PARAMETER, SET_PARAMETER這些方法,分別是:關閉流,暫停,獲取流參數,設置參數,然後我們可以通過編碼來實現這些,然後保存發送過來的RTP碼流包,如果需要保存裸流的話,需要對RTP包進行解析,後續會找時間對博文進行更新!下面是代碼片段,僅供參考,轉載請註明出處!
首先當然是建立連接,得到socket,rtsp默認端口是554,這裏省去這些步驟
GetLineString()是自己封裝的一個字符解析的函數

1. OPTIONS
 std::string sOptions;
 sOptions = sOptions + "OPTIONS rtsp://" + m_SerIp + "/client.264" +" RTSP/1.0\r\n";
 char cSeq[8] = {0};
 sprintf(cSeq, "%d", m_icSeq);
 m_icSeq++;
 sOptions = sOptions + std::string("CSeq: ") + std::string(cSeq) + "\r\n";
 sOptions = sOptions + "User-Agent: " + std::string("TestRtsp\r\n\r\n");
 char cRecvBuf[512] = {0}; 
 send(m_RtspSocket, sOptions.c_str(), sOptions.length(), 0);
 recv(m_RtspSocket, cRecvBuf, 512, 0);
 if(std::string(cRecvBuf).find("200 OK") == std::string::npos)
 {
     //失敗處理
 }
2. DESCRIBE
 std::string sDesc;
 sDesc += "DESCRIBE rtsp://" + m_SerIp + "/client.264" + " RTSP/1.0\r\n";
 char cSeq[8] = {0};
 sprintf(cSeq, "%d", m_icSeq);
 m_icSeq++;
 sDesc += std::string("CSeq: ") + cSeq + "\r\n";
 sDesc += "User-Agent: RtspTest\r\n";
 sDesc += "Accept: application/sdp\r\n\r\n";
 Send(m_RtspSocket, sDesc.c_str(), sDesc.length(), 0) ;
 Recv(m_RtspSocket, cRecvBuf, 512, 0) ;
 if(std::string(cRecvBuf).find("200 OK") == std::string::npos)
     continue;
    //a=control:track1
    std::string reString;
    GetLineString(cRecvBuf, "a=control: ", reString); //獲取a=control:track1中track1
    m_sChannel = reString; //保存track1
3.SETUP
 std::string sSetup;
 sSetup += "SETUP rtsp://" + m_SerIp + "/client.264/" + m_sChannel + "  RTSP/1.0\r\n";
 char cSeq[8] = {0};
 sprintf(cSeq, "%d", m_icSeq);
 m_icSeq++;
 sSetup += std::string("CSeq: ") + cSeq + "\r\n";
 sSetup += "User-Agent: RtspTest\r\n";
 sSetup += "Transport: RTP/AVP/TCP;unicast;interleaved=0-1\r\n\r\n";
 Send(m_RtspSocket, sSetup.c_str(), sSetup.length(), 0) ;
 Recv(m_RtspSocket, cRecvBuf, 512, 0) ;
if(std::string(cRecvBuf).find("200 OK") == std::string::npos)
{//獲取sessionID並保存
    //Session: 223333
    std::string reString ;
    GetLineString(cRecvBuf, "Session: ", reString);
    m_Session = reString;
}
4.PLAY
 std::string sPlay;
 sPlay += "PLAY rtsp://" + m_SerIp + "/client.264/" + " RTSP/1.0\r\n";
 char cSeq[8] = {0};
 sprintf(cSeq, "%d", m_icSeq);
 m_icSeq++;
 sPlay += std::string("CSeq: ") + cSeq + "\r\n";
 sPlay += "User-Agent: RtspTest\r\n";
 sPlay += "Session: " + m_Session + "\r\n";
 sPlay += "Range: npt=0.000-\r\n\r\n";
 Send(m_RtspSocket, sPlay.c_str(), sPlay.length(), 0) ;
 Recv(m_RtspSocket, cRecvBuf, 512, 0) ;
 if(std::string(cRecvBuf).find("200 OK") == std::string::npos)
{
  //失敗處理
}

//這裏需要注意的是:很可能碼流比200 OK先接收到,需要專門進行處理
至此就完成了所有的到碼流流程,當然當你不需要碼流的時候應該發送TEARDOWN請求,記得帶上sessionID,類似的,這裏就不貼出來了,然後斷開連接

本人也是學到一點皮毛並進行了實踐,希望大家多多指針和分享經驗

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