欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Live555

程序员文章站 2022-07-01 09:54:44
...

对于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

上一篇: RTSP协议的实现

下一篇: ElasticSearch