Android MediaPlayer中的RTSP(一):RTSP简介

标签: rtsp  流媒体

背景:

我在最近的项目中遇到了使用Android的MediaPlayer来进行RTSP播放的场景。但对于RTSP这种流媒体协议,其实Android原生的播放器支持得不是很好,所以有许多需要修改的地方。

本文主要简单介绍RTSP协议及其在MediaPlayer中的层级,后续会记录下在项目中遇到的具体情况及对应的修改。

RTSP播放器架构

播放器的架构很清晰,
apk–>MediaPlayer->media_server–>厂商自己的Player(和NuPalyer/StagefrightPlayer一个层级)–>FFmpeg
如下图。
 RTSP播放器架构
因为走Android MediaPlayer的流程,拉流的部分是使用FFmpeg实现的,所以FFmpeg是最核心的部分,主要的修改,也即是针对FFmpeg里RTSP部分的修改,以适配项目的特殊性。

RTSP协议简介

1、简介

RTSP属于应用层协议,被用于控制媒体流的传输,它为多媒体服务扮演“网络远程控制”的角色,对流媒体提供了诸如暂停,快进等控制,而它本身并不传输数据。

因为RTSP的作用相当于流媒体服务器的远程控制,所以客户端需要和服务器进行命令交互,以到达建立/释放连接及远程控制的目的。命令连接基于TCP,一般使用554端口。而数据传输可以选择TCP或UDP来传送,这个需要看服务端的支持情况及客户端的选择。
RTSP负责建立和控制会话,RTP/TCP负责多媒体的传输,RTCP配合RTP做控制和流量统计,他们是合作的关系。
这里写图片描述

2、RTSP的消息

RTSP的消息有两大类,一是请求消息(request),一是回应消息(response),两种消息的格式不同。

请求消息格式:

方法 URI RTSP版本 CR LF
消息头 CR LF CR LF
消息体 CR LF
其中方法包括OPTIONS、SETUP、PLAY、TEARDOWN等待,URI是接收方(服务端)的地址,例如:rtsp://192.168.22.136:5000/v0,每行后面的CR LF表示回车换行,需要接收端有相应的解析,最后一个消息头需要有两个CR LF。

回应消息格式:

RTSP版本 状态码 解释 CR LF
消息头 CR LF CR LF
消息体 CR LF
其中RTSP版本一般都是RTSP/1.0,状态码是一个数值,200表示成功,解释是与状态码对应的文本解释。

状态码和HTTP差不多,由三位数组成,表示方法执行的结果,定义如下:

1XX:保留,将来使用;
2XX:成功,操作被接收、理解、接受(received,understand,accepted);
3XX:重定向,要完成操作必须进行进一步操作;
4XX:客户端出错,请求有语法错误或无法实现;
5XX:服务器出错,服务器无法实现合法的请求。

RTSP中定义的方法有:OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, SCALE, GET_PARAMETER ,SET_PARAMETER 。
在下面的交互流程中的例子中,会简单介绍这些方法的使用。

3 SDP各个参数简单介绍

这里写图片描述

注: “a=”字段描述节目时长。直播用 clock=表示,描述直播时移时长;点播用 ntp=表示 ,描述点播节目时长。具体参见 rfc 2326。

举例如下:
直播:直播时移时长为 1 小时
a=range:clock=20100817T000742.55Z-20100818T000742.55Z
点播: a=range:npt=0-246.655
注: “c=”字段表示连接描述,可使用组播地址;如果是组播地址,字段包含了媒体流的目的地址。也就是说,通过单播 rtsp 获取当前直播频道的组播地址,然后加入这个组播播放。具体参见 rfc 2326。例如: c=IN IP4 225.61.100.28/16
注: “m”字段表示负载类型(PT): RTP 信息包中的有效载荷域(Payload Type Field)的长度为 7位,因此 RTP 可支持 128 种不同的有效载荷类型。具体参见 rfc 3551。

SDP例子

DESCRIBE rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp?playtype=1&boid=001&backupagent=61.149.64.212:554&clienttype=1&time=20180510144608+08&life=172800&ifpricereqsnd=1&vcdnid=001&userid=09-20170912003-01&mediaid=ch11091521323921117877&ctype=5&TSTVTimeLife=604800&contname=&authid=0&UserLiveType=1&stbid=801100c8bb1d8e97&nodelevel=3&terminalflag=1&bitrate=3 RTSP/1.0
Accept: application/sdp
CSeq: 2

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
Cache-Control: no-cache
Content-Base: rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/
Content-Length: 267
Content-Type: application/sdp
CSeq: 2
Date: Thu, 10 May 2018 06:48:32 GMT
Expires: Thu, 10 May 2018 06:48:32 GMT

v=0
o=- 0 0 IN IP4 61.149.64.212
s=ZMSS RTSP Server
c=IN IP4 239.2.1.232/16 
b=AS:2500 
t=0 0
a=control:*
a=range:clock=20180503T064832.00Z-20180510T064832.00Z
m=video 8000 RTP/AVP 33
a=rtpmap:33 MP2T/90000
a=control:trackID=2
a=3GPP-Adaptation-Support:5

4、RTSP交互流程

一次基本的RTSP操作过程如下:

  1. 客户端连接到流服务器并发送一个RTSP描述命令(DESCRIBE)
  2. 流服务器通过一个SDP描述来进行反馈,反馈信息包括流数量、媒体类型等信息
  3. 客户端再分析该SDP描述,并为会话中的每一个流发送一个RTSP建立命令(SETUP),RTSP建立命令告诉服务器客户端用于接收媒体数据的端口
  4. 客户端发送一个播放命令(PLAY),服务器就开始在TCP/UDP上传送媒体流(RTP包)到客户端
  5. 在播放过程中客户端还可以向服务器发送命令来控制快进、快退和暂停等
  6. 最后,客户端可发送一个终止命令(TERADOWN)来结束流媒体会话

例子如下:

/*OPTIONS 主要功能:获取服务器/客户端支持的能力集,
关键字段:
Public:服务器支持的命令,在此例子中是用于获取服务器支持的命令,可以看到服务器回复我们支持DESCRIBE,OPTIONS,SETUP,TEARDOWN,PLAY,PAUSE,GET_PARAMETER,SET_PARAMETER
特殊说明:在一个RTSP交互流程中OPTIONS方法并不是必须的,前提是你知道服务器支持哪些命令
*/
OPTIONS rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp?playtype=1&boid=001&backupagent=61.149.64.212:554&clienttype=1&time=20180510144608+08&life=172800&ifpricereqsnd=1&vcdnid=001&userid=09-20170912003-01&mediaid=ch11091521323921117877&ctype=5&TSTVTimeLife=604800&contname=&authid=0&UserLiveType=1&stbid=801100c8bb1d8e97&nodelevel=3&terminalflag=1&bitrate=3 RTSP/1.0
CSeq: 1

RTSP/1.0 200 OK
Public: DESCRIBE,OPTIONS,SETUP,TEARDOWN,PLAY,PAUSE,GET_PARAMETER,SET_PARAMETER
Server: ZXUSS100 1.0 CSeq: 1

/*
DESCRIBE 主要功能:从服务器获取流媒体文件格式信息,从服务器获取流媒体文件传输信息
关键字段:
Content-Type:一般是SDP
Content-length:一般是SDP的长度
特殊说明:媒体信息通过SDP协议给出,例如这个例子中服务器回复range:clock=20180503T064832.00Z-20180510T064832.00Z,告诉客户端服务器的可时移range,并且是clock(绝对时间描述),也就是PLAY阶段请求的时间是ISO 8601时间戳标准
*/
DESCRIBE rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp?playtype=1&boid=001&backupagent=61.149.64.212:554&clienttype=1&time=20180510144608+08&life=172800&ifpricereqsnd=1&vcdnid=001&userid=09-20170912003-01&mediaid=ch11091521323921117877&ctype=5&TSTVTimeLife=604800&contname=&authid=0&UserLiveType=1&stbid=801100c8bb1d8e97&nodelevel=3&terminalflag=1&bitrate=3 RTSP/1.0
Accept: application/sdp
CSeq: 2

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
Cache-Control: no-cache
Content-Base: rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/
Content-Length: 267
Content-Type: application/sdp
CSeq: 2
Date: Thu, 10 May 2018 06:48:32 GMT
Expires: Thu, 10 May 2018 06:48:32 GMT

v=0
o=- 0 0 IN IP4 61.149.64.212
s=ZMSS RTSP Server
c=IN IP4 239.2.1.232/16 
b=AS:2500 
t=0 0
a=control:*
a=range:clock=20180503T064832.00Z-20180510T064832.00Z
m=video 8000 RTP/AVP 33
a=rtpmap:33 MP2T/90000
a=control:trackID=2
a=3GPP-Adaptation-Support:5

/*
SETUP 主要功能:与服务器协商流媒体传输方式,此过程中,建立RTP通道
关键字段:
Transport:指明服务器支持的传输方式及传输端口,地址等等信息。
在例子中参数MP2T/RTP/UDP指明服务器传输媒体数据将使用UDP传输;参数server_port=8000-8001;source=239.2.1.232指明了服务器的地址和端口号;destination=192.168.1.4指明客户端地址,这个例子中为内网地址,对于这种情况需要做NAT穿透。
特殊说明:需要注意的是,媒体服务器的地址source=239.2.1.232,为组播地址,需要加入RTP组播来拉流。(但在此例子中,我试过使用该地址拉流也没数据)
*/
SETUP rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/trackID=2 RTSP/1.0
Transport: MP2T/RTP/UDP;unicast;client_port=5000-5001
CSeq: 3

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
CSeq: 3
Date: Thu, 10 May 2018 06:48:32 GMT
Expires: Thu, 10 May 2018 06:48:32 GMT
Session: 65536595
Transport: MP2T/RTP/UDP;destination=192.168.1.4;client_port=5000-5001;server_port=8000-8001;source=239.2.1.232

/*
PLAY 主要功能:与服务器协商流媒体播放
关键字段:
Range:播放时间支持两种格式,Range: npt=0.0-end或者Range:clock=20100318T021919.35Z-20100318T031919.80Z
方法1 位置描述,相对时间描述——npt(normalplay time)
•beginning      节目起始点
•now            当前播放点
•end            节目结束点
•相对时间        媒体的相对时间
方法2 时间描述,绝对时间描述——clock,ISO 8601时间戳标准
•直接用数字形式表示与起始点的时间

Scale:播放速度 例如1倍速,Scale: 1.0
特殊说明:RTP-Info是前段回复我们的媒体服务器信息,可以看到这里和之前setup阶段前端回复的source地址并不一样。
(这才是媒体服务器的地址,这地方的冲突,可能是服务器写的不标准)
*/
PLAY rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/ RTSP/1.0
Range: clock=20180510T060000.00Z-
Scale: 1.0
CSeq: 4
Session: 65536595

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
CSeq: 4
Range: clock=20180510T060000.00Z-20180510T064832.93Z
Scale: 1.0
Session: 65536595
RTP-Info: url=rtsp://61.149.64.132:12370/live/ch11091521323921117877.sdp/trackID=2;seq=0;rtptime=841899578

/*
GET_PARAMETER 主要功能:1、从服务器获取参数,目前主要获取时间范围;2、保持RTSP连接(发送空的GET_PARAMETER)
在此例子中,是第二种用途,keep-alive
*/
GET_PARAMETER rtsp://61.149.64.212:554/live/ch11091521323921117877.sdp/ RTSP/1.0
CSeq: 5
Session: 65536595

RTSP/1.0 200 OK
Server: ZXUSS100 1.0
CSeq: 5
Session: 65536595

总结

本文介绍了一个相对简单清晰的RTSP交互实例,但是在实际情况中,因为项目使用的是FFmpeg的RTSP来进行拉流的,特别是整合到MediaPlayer中使用,还是有许多情况需要考虑并完善的:

1、SETUP阶段的协议选择:载流协议是UDP还是TCP,是否使用RTP承载,尝试一种载流协议不支持后的切换流程
2、重定向的完善:正常来说,一般在SETUP阶段后,就不会再有重定向了,因为这样需要重新断开再连接,但是实际使用中有些服务器是会在PLAY阶段去重定向的
3、NAT穿透: 使用UDP载流时,处于内网的客户端该如何进行NAT的打洞,以让服务器能将数据传送给客户端
4、与MediaPlayer的整合:PLAY中使用绝对时间描述时,该如何与MediaPlayer整合
5、媒体服务器的选择:即上面例子中提到的情况

这些是之前遇到的部分问题,我将在后续文章中说明这些问题。

版权声明:本文为myvest原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/myvest/article/details/80641799

智能推荐

spring cloud netflix (07) 服务的消费者(feign)

前言 完整知识点:spring cloud netflix 系列技术栈 Feign (同步通信 HTTP通信) feign是基于接口完成服务与服务之间的通信的 搭建Feign服务 项目结构 项目搭建 pom.xml application类 application.yml 使用feign完成服务与服务之间的通信 feign是基于接口完成服务与服务之间的通信的...

AtCoder Beginner Contest 174 E.Logs

AtCoder Beginner Contest 174 E.Logs 题目链接 到最后才发现是二分,菜菜的我/(ㄒoㄒ)/~~ 我们直接二分 [1,max{a[i]}][1,max\lbrace a[i]\rbrace][1,max{a[i]}] 即可,对每一个 midmidmid,每个数 a[i]a[i]a[i] 只需要切 a[i]−1mid\frac{a[i]-1}{mid}mi...

小程序基础与实战案例

小程序开发工具与基础 小程序开发准备: 申请小程序账号( appid ) 下载并安装微信开发者工具 具体步骤如下: 先进入 微信公众平台 ,下拉页面,把鼠标悬浮在小程序图标上 然后点击 小程序开发文档 照着里面给的步骤,就可以申请到小程序账号了。 然后就可以下载 开发者工具 了 下载完打开后的界面就是这个样子 下面让我们来新建一个小程序开发项目: 在AppID输入自己刚刚注册的AppID就可以,或...

VMware centOS7 下通过minikube部署Kubernetes

1、环境准备: VMware CentOS-7-x86_64 CPU:2*2core 内存:8G 宿主机和虚拟机需网络互通,虚拟机外网访问正常 Centos发行版版本查看:cat /etc/centos-release root用户操作 2、禁用swap分区 Kubernetes 1.8开始要求关闭系统的Swap,可暂时关闭或永久禁用, 使用 $ free -m 确认swap是否为开启状态 $ s...

逻辑回归与scikit-learn

欢迎关注本人的微信公众号AI_Engine LogisticRegression 算法原理 一句话概括:逻辑回归假设数据服从伯努利分布,通过极大化似然函数(损失函数)的方法,运用梯度下降或其他优化算法来求解参数,来达到将数据二分类的目的。 定义:逻辑回归(Logistic Regression)是一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性(不是概率)。比如某用户...

猜你喜欢

指针OR数组?用他们来表达字符串又有何不同?

cocowy的编程之旅 在学习C语言的过程中我们经常可以看到或者听到这样一句话:数组其实等价于指针,例如: 在这里可以轻松的看出输出后他们的值相等,其实在计算机内存里面,p为本地变量,有着他自己的作用域。而指针变量q保存着这个数组的首地址,通过*号指向这个地址保存的变量值。 然而我们再看一个例子: 这个时候计算机报错,这是为什么呢? 其实原因很简单,指针说指向的这个字符串的地址是位于计算机代码段地...

广度搜索

广度搜索的基本使用方法 广度搜索不同于深度搜索,是一种一步一步进行的过程,每一个点只记录一遍。需要用到队列记录每一步可以走到的位置,找到目标位置输出步数即可。 用到的知识:结构体、队列 如图 首先我们需要定义一个结构体来存储每个遍历到的点和步数 广搜不会用到递归,所以可以直接在主函数里写,这里需要定义一个结构体队列 初始化队列并将起始点入列 遍历 完整代码...

NIO Socket 编程实现tcp通信入门(二)

1、NIO简介 NIO面向通道和缓冲区进行工作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。可以双向传输数据,是同步非阻塞式IO。NIO还引入了选择器机制,从而实现了一个选择器监听多个底层通道,减少了线程并发数。用NIO实现socket的Tcp通信需要掌握下面三个知识点: Buffer 缓冲区 Channel 通道 Selector 选择器   2、java.nio.Buff...

[字节码系列]ObjectWeb ASM构建Method Monitor

      在前面的篇章中,我们看到Java Instrutment的强大能力,本篇,我们将介绍如何使用ObjectWeb ASM的字节码增强能力构建Method Monitor       1.什么是ObjectWeb ASM      ObjectWeb ...

Core Location 电子围栏:入门

原文:Geofencing with Core Location: Getting Started 作者:Andy Pereira 译者:kmyhy 更新说明:Andy Pereira 将本教程升级至 Xcode 9.3 和 Swift 4.1。 Geofencing 会在设备进入/离开指定的电子围栏时通知应用程序。它可以让你写出一些很酷的应用程序,当你从家里出来时触发通知,或者在附近出现最爱的商...