Live555
对于LIVE555和RTSP,相信看到这篇博文的朋友应该很熟悉了,分享一些皮毛,大家尽量吐槽:
首先说一下做的功能:利用live555是里面的一个live555mediaserver来作为媒体服务器,然后利用里面的TestRTSPClient来取得码流,当然官网上说了:RTSPClient只是个测试程序,如果用作产品还需要进行优化,不过可以作为参考,我也是用他来作为一个队LIVE555入门的东西,看了一下里面的流程,好了不说废话了,这里主要讲的利用RTSP来从媒体服务器中取得码流,如下:
1.首先下载LIVE555源码,然后进行编译(我的环境是ubuntu11.10),得到源码即可编译通过,然后里面有个媒体服务器目录进去运行
./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.
- 1
- 2
- 3
- 4
得到上面这一串字符,我们可以看到有一个是rtsp://192.168.1.06/<filename>
,这个就是我们在利用rtsp编写代码的时候需要用的url;现在你可以进入上层目录下testProgs,执行:./testRTSPClient rtsp://192.168.1.106/<filename>
,然后就可以看到有码流过来了,这些码流就是文件名文件,当然这个文件是在媒体服务器当前目录中存在的,当你运行前你可以尝试用抓包工具看到码流申请的流程;这里我用的是VLC来代替这一步
2.当第一步证实我们的mediaServer是可用的了,接下来的步骤就是在vlc中找到打开网路流 - >然后把上面的rtsp url输入vlc中,然后开启网络抓包工具,单击播放,通过抓包工具可以清楚的看到码流申请的流程:
1.
==> vlc-> mediaserver请求
选项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 //注意与上面的一样
日期:星期六,六月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)
接受:application / sdp //这段表示我们请求得到回复的数据应该是sdp(关于sdp请百度)
==> mediaserver-> vlc回复
RTSP / 1.0 200 OK
CSeq:3
日期:星期六,六月08 2013 14:01:34 GMT
Content-Base:rtsp://192.168.1.106/client.264/
Content-Type:application / sdp
内容长度:521 v = 0 o = - 1370699986662940 1 IN IP4 192.168.1.106 s = H.264视频,由LIVE555媒体服务器流式传输i = client.264 t = 0 0 a =工具:LIVE555流媒体v2012.11.30 a =类型:广播a =控制:* a =范围:npt = 0- a = x-qt-text-nam:H.264视频,由LIVE555媒体服务器流式传输a = x-qt-text-inf:client .264 m =视频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)
传输:RTP / AVP / TCP;单播; interleaved = 0-1 //传输协议TCP RTP单播,interleaved这个字段跟解rtp包有关系,具体还不是很清楚,如果是udp的话,这里商量的是端口的问题,tcp直接使用当前端口发送
==> mediaserver-> vlc回复//回应请求,表示已经知道如何发送,往哪里发送,并返回一个会话ID
RTSP / 1.0 200 OK
CSeq:4
日期:星期六,2013年6月8日14:01:34 GMT传输:\ RTP / AVP / TCP;单播;目的地= 192.168.1.105;源= 192.168.1.106;交错= 0-1会话:CFB1212D //这个是表示是这一次会话的标示
4.
这里我们可以申请进行传输码流了==> vlc-> mediaserver请求PLAY rtsp://192.168.1.106/client.264/ RTSP / 1.0 //请求播放播放CSeq:5用户代理:LibVLC / 2.0 .1(LIVE555流媒体v2011.12.23)会话:CFB1212D //带上会话ID,否则会返回未找到错误范围:npt = 0.000- //这个跟时间有关系==> mediaserver-> vlc回复RTSP / 1.0 200 OK CSeq:5日期:星期六,2013年6月8日14:01:34 GMT范围:npt = 0.000-会话:CFB1212D // sessionID RTP-Info:url = rtsp://192.168.1.106/client.264/track1; seq = 54219; rtptime = 2695045868
到此,你可以通过vlc看到视频,或者听到音频了;上面是通过vlc抓包得到的流程,淡然可能还需要进行其他的请求,比如上面公共:中的TEARDOWN,PAUSE,GET_PARAMETER,SET_PARAMETER这些方法,分别是:关闭流,暂停,获取流参数,设置参数,然后我们可以通过编码来实现这些,然后保存发送过来的RTP码流包,如果需要保存裸流的话,需要对RTP包进行解析,后续会找时间对博文进行更新!下面是代码片段,仅供参考,转载请注明出处!
首先当然是建立连接,得到插座,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)
{
//失败处理
}
- 1
- 2
- 3
- 4
- 五
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
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
- 1
- 2
- 3
- 4
- 五
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
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;
}
- 1
- 2
- 3
- 4
- 五
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
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)
{
//失败处理
}
- 1
- 2
- 3
- 4
- 五
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
//这里需要注意的是:很可能码流比200 OK先接收到,需要专门进行处理
至此就完成了所有的到码流流程,当然当你不需要码流的时候应该发送TEARDOWN请求,记得带上会话ID,类似的,这里就不贴出来了,然后断开连接
本人也是学到一点皮毛并进行了实践,希望大家多多指针和分享经验
<link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css">
</div>
上一篇: RTSP协议的实现
下一篇: ElasticSearch