一 socket拉取rtsp流。

先讲rtsp拉流的过程,如下是rtsp命令交互的过程。

OPTIONS rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0
CSeq: 2

RTSP/1.0 200 OK
CSeq: 2
Public: OPTIONS, DESCRIBE, PLAY, PAUSE, SETUP, TEARDOWN, SET_PARAMETER, GET_PARAMETER
Date:  Wed, Sep 02 2020 16:12:10 GMT

DESCRIBE rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0
CSeq: 3
Accept: application/sdp

RTSP/1.0 401 Unauthorized
CSeq: 3
WWW-Authenticate: Digest realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", stale="FALSE"
WWW-Authenticate: Basic realm="4419b635ea35"
Date:  Wed, Sep 02 2020 16:12:10 GMT

DESCRIBE rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0
CSeq: 4
Authorization: Digest username="admin", realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", uri="rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1", response="eebfce8371a4c20ba804694d9c19b9b7"
Accept: application/sdp

RTSP/1.0 200 OK
CSeq: 4
Content-Type: application/sdp
Content-Base: rtsp://192.168.31.29:554/0/0/101/
Content-Length: 951

v=0
o=- 1599063130018656 1599063130018656 IN IP6 ::
s=Media Presentation
e=NONE
b=AS:5100
t=0 0
a=control:rtsp://192.168.31.29:554/0/0/101/?transportmode=unicast&profile=Profile_1
m=video 0 RTP/AVP 96
c=IN IP6 ::
b=AS:5000
a=recvonly
a=x-dimensions:1280,720
a=control:rtsp://192.168.31.29:554/0/0/101/trackID=1?transportmode=unicast&profile=Profile_1
a=rtpmap:96 H264/90000
a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z00AH5WoFAFuhAAAHCAABX5AEA==,aO48gA==
m=audio 0 RTP/AVP 104
c=IN IP6 ::
b=AS:50
a=recvonly
a=control:rtsp://192.168.31.29:554/0/0/101/trackID=2?transportmode=unicast&profile=Profile_1
a=rtpmap:104 mpeg4-generic/8000/1
a=fmtp:104 profile-level-id=15; streamtype=5; mode=AAC-hbr; config=1588;SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1;
a=Media_header:MEDIAINFO=494D4B48010200000400000101200110401F0000007D000000000000000000000000000000000000;
a=appversion:1.0
SETUP rtsp://192.168.31.29:554/0/0/101/trackID=1?transportmode=unicast&profile=Profile_1 RTSP/1.0
CSeq: 5
Authorization: Digest username="admin", realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", uri="rtsp://192.168.31.29:554/0/0/101/", response="2749c91a6c28dd890d3e808cf60d0505"
Transport: RTP/AVP;unicast;client_port=20000-20001

RTSP/1.0 200 OK
CSeq: 5
Session:        924651277;timeout=60
Transport: RTP/AVP;unicast;client_port=20000-20001;server_port=8294-8295;ssrc=529a05f1;mode="play"
Date:  Wed, Sep 02 2020 16:12:10 GMT

PLAY rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0
CSeq: 6
Authorization: Digest username="admin", realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", uri="rtsp://192.168.31.29:554/0/0/101/", response="1bedb6f15e050eb6fbadcfa64a4be06a"
Session: 924651277
Range: npt=0.000-

RTSP/1.0 200 OK
CSeq: 6
Session:        924651277
RTP-Info: url=rtsp://192.168.31.29:554/0/0/101/trackID=1?transportmode=unicast&profile=Profile_1;seq=42160;rtptime=2465439958
Date:  Wed, Sep 02 2020 16:12:10 GMT

rtsp拉流的命令交互有四次,四个方法分别为:OPTIONS,DESCRIBE,SETUP,PLAY。

1. 先分离rtsp地址中的ip和端口。

比如:rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1

或者:rtsp://admin:admin123@192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1

rtsp有这两种形式的,第二种比第一种多了用户名和密码用于鉴权,这两种地址都可以用vlc直接播放,我们要做像vlc一样的功能。

剥离ip和端口为192.168.31.29:554,有用户名密码的也有解析记录下来。

2. tcp socket访问192.168.31.29:554建立连接。

3. 连接建立了,就开始发送命令了,每个命令的第一行的格式为:

METHOD URI VERSION

method是方法名,OPTIONS,DESCRIBE,SETUP,PLAY等。

uri是rtsp地址。

version是版本号,写RTSP/1.0就可以了。

先发送 OPTIONS命令获取rtsp服务所支持的方法。

OPTIONS rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0\r\n
CSeq: 2\r\n
\r\n

其中rtsp地址中有用户名密码的要先去掉,每一行都要以\r\n结尾,尾行要填充一个\r\n的空行。cseq是序列号,区分一应一答的对应关系。这个命令里cseq是2,那么响应消息里的cseq也是2.

接下来会收到服务器的应答。

RTSP/1.0 200 OK\r\n
CSeq: 2\r\n
Public: OPTIONS, DESCRIBE, PLAY, PAUSE, SETUP, TEARDOWN, SET_PARAMETER, GET_PARAMETER\r\n
Date:  Wed, Sep 02 2020 16:12:10 GMT\r\n
\r\n

应答消息体的首行格式是:版本号 状态码 状态描述

状态码为200时为成功,其他都是错误码。

4. 发送DESCRIBE,获取媒体信息。

DESCRIBE rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0\r\n
CSeq: 3\r\n
Accept: application/sdp\r\n
\r\n
RTSP/1.0 401 Unauthorized\r\n
CSeq: 3\r\n
WWW-Authenticate: Digest realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", stale="FALSE"\r\n
WWW-Authenticate: Basic realm="4419b635ea35"\r\n
Date:  Wed, Sep 02 2020 16:12:10 GMT\r\n
\r\n

跟上面类似,Accept: application/sdp 表示让服务器发送sdp格式的媒体信息。这里服务器应答了401错误,表示服务器需要鉴权。鉴权时使用md5的加密方式,加密方式可以使用openssl,后面代码里也有。

再次发送带有鉴权的消息就可以了。

DESCRIBE rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0\r\n
CSeq: 4\r\n
Authorization: Digest username="admin", realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", uri="rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1", response="eebfce8371a4c20ba804694d9c19b9b7"\r\n
Accept: application/sdp\r\n
\r\n
RTSP/1.0 200 OK\r\n
CSeq: 4\r\n
Content-Type: application/sdp\r\n
Content-Base: rtsp://192.168.31.29:554/0/0/101/\r\n
Content-Length: 951\r\n
\r\n
v=0\r\n
o=- 1599063130018656 1599063130018656 IN IP6 ::\r\n
s=Media Presentation\r\n
e=NONE\r\n
b=AS:5100\r\n
t=0 0\r\n
a=control:rtsp://192.168.31.29:554/0/0/101/?transportmode=unicast&profile=Profile_1\r\n
m=video 0 RTP/AVP 96\r\n
c=IN IP6 ::\r\n
b=AS:5000\r\n
a=recvonly\r\n
a=x-dimensions:1280,720\r\n
a=control:rtsp://192.168.31.29:554/0/0/101/trackID=1?transportmode=unicast&profile=Profile_1\r\n
a=rtpmap:96 H264/90000\r\n
a=fmtp:96 profile-level-id=420029; packetization-mode=1; sprop-parameter-sets=Z00AH5WoFAFuhAAAHCAABX5AEA==,aO48gA==\r\n
m=audio 0 RTP/AVP 104\r\n
c=IN IP6 ::\r\n
b=AS:50\r\n
a=recvonly\r\n
a=control:rtsp://192.168.31.29:554/0/0/101/trackID=2?transportmode=unicast&profile=Profile_1\r\n
a=rtpmap:104 mpeg4-generic/8000/1\r\n
a=fmtp:104 profile-level-id=15; streamtype=5; mode=AAC-hbr; config=1588;SizeLength=13; IndexLength=3; IndexDeltaLength=3; Profile=1;\r\n
a=Media_header:MEDIAINFO=494D4B48010200000400000101200110401F0000007D000000000000000000000000000000000000;\r\n
a=appversion:1.0\r\n
\r\n

应答中携带sdp消息体,sdp就不解释了,是一种媒体信息的格式。

从sdp中记录视频的uri。

5. SETUP

SETUP rtsp://192.168.31.29:554/0/0/101/trackID=1?transportmode=unicast&profile=Profile_1 RTSP/1.0\r\n
CSeq: 5\r\n
Authorization: Digest username="admin", realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", uri="rtsp://192.168.31.29:554/0/0/101/", response="2749c91a6c28dd890d3e808cf60d0505"\r\n
Transport: RTP/AVP;unicast;client_port=20000-20001\r\n
\r\n
RTSP/1.0 200 OK\r\n
CSeq: 5\r\n
Session:        924651277;timeout=60\r\n
Transport: RTP/AVP;unicast;client_port=20000-20001;server_port=8294-8295;ssrc=529a05f1;mode="play"\r\n
Date:  Wed, Sep 02 2020 16:12:10 GMT\r\n
\r\n

其中URI填写的是video媒体的Uri。记录下Session,后续交互需要。对视频传输进行设置,RTP/AVP表示UDP方式传输,client_port=20000-20001是本地视频交互的端口,第一个20000是h264传输的端口,20001是对视频控制的端口。server_port=8294-8295是服务端响应的视频传输与控制的端口。

6 PLAY

PLAY rtsp://192.168.31.29:554/0/0/101?transportmode=unicast&profile=Profile_1 RTSP/1.0\r\n
CSeq: 6\r\n
Authorization: Digest username="admin", realm="4419b635ea35", nonce="e82d275c2f0e6b2f433e85ccc87b6714", uri="rtsp://192.168.31.29:554/0/0/101/", response="1bedb6f15e050eb6fbadcfa64a4be06a"\r\n
Session: 924651277\r\n
Range: npt=0.000-\r\n
\r\n
RTSP/1.0 200 OK\r\n
CSeq: 6\r\n
Session:        924651277\r\n
RTP-Info: url=rtsp://192.168.31.29:554/0/0/101/trackID=1?transportmode=unicast&profile=Profile_1;seq=42160;rtptime=2465439958\r\n
Date:  Wed, Sep 02 2020 16:12:10 GMT\r\n
\r\n

应答200 OK后,服务器就开始推流了,在视频端口可以接收到视频流。