关于利用live555,RTSP取流

来源:互联网 发布:淘宝网店怎么装修视频 编辑:程序博客网 时间:2024/06/11 14:32

对于live555和RTSP,相信看到这篇博文的朋友应该很熟悉了,分享一些皮毛,大家尽量吐槽:
首先说一下做的功能:利用live555里面的一个live555mediaserver来作为媒体服务器,然后利用里面的TestRTSPClient来取得码流,当然官网上说了:RTSPClient只是个测试程序,如果用作产品还需要进行优化,不过可以作为参考,我也是用他来作为一个队live555入门的东西,看了一下里面的流程,好了不说废话了,这里主要讲的利用RTSP来从媒体服务器中取得码流,如下:

1.首先下载live555源码,然后进行编译(我的环境是ubuntu11.10),得到源码即可编译通过,然后里面有个mediaServer目录进去运行

./live555MediaServerPlay streams from this server using the URLrtsp://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,类似的,这里就不贴出来了,然后断开连接

本人也是学到一点皮毛并进行了实践,希望大家多多指针和分享经验

0 0