高级会员
- 积分
- 948
- 金钱
- 948
- 注册时间
- 2022-4-20
- 在线时间
- 356 小时
|
本帖最后由 驭剑的秘密 于 2024-3-11 10:23 编辑
此篇文为记录与分享。
2024.03.11更改:今天登上来看,发现原本写进本篇文章的内容在发表之后莫名其妙少了,导致看得云里雾里的
在年前曾经询问论坛的大佬们如何拉流[H7如何接收海康威视监控摄像头的视频流?]
当时拿到代码后尝试了一下,能有反应,但是没有调通。过完年之后,立马投入了研究,查找了多方资料。
【流媒体协议之RTSP详解】——这一篇文章帮助我完成了RTSP握手阶段 【后方将简称此处为①】
【RTP协议全解(H264码流和PS流)】——这一篇文章帮助我完成了RTP包的解析 【后方将简称此处为②】
【使用VLC播放UDP流】——这一篇文章帮助我完成了解析后的验证步骤 【后方将简称此处为③】
在每个阶段都有一些坑,容我细细道来
一、RTSP握手阶段
第一个阶段中,首先的要点就是要确认拉流的地址是否正确,以下是海康威视拉流地址的格式示例:
rtsp://username:password@ip:port/codec/ch/type/av_stream
username: 用户名
password: 密码
ip: 摄像头的IP地址
port: 端口号,默认是554
codec:我的摄像头可设置的模式只有h264和h265
ch: 通道号,起始为1
type: 码流类型,主码流为main,辅码流为sub
例如,请求海康摄像机通道1的主码流,Url如下
主码流:
rtsp://admin:12345@192.168.0.64:554/h264/ch1/main/av_stream
rtsp://admin:12345@192.168.0.64:554/h265/ch1/main/av_stream
在明确了这个地址之后,就来到了最重要验证环节,我在这里花费的时间是相对于久的:
当与摄像头取得通信后,根据①处的文章的步骤,会收到以下内容
- RTSP/1.0 401 Unauthorized
- CSeq: 2
- WWW-Authenticate: Digest realm="IP Camera(F8582)", nonce="07a4249696c5e1235b317066497db7d1", stale="FALSE"
- Date: Fri, Mar 08 2024 16:06:00 GMT
复制代码 此时,需要将nonce和realm的内容与用户名和密码进行一系列MD5校验后发送给摄像头服务端,接下来,我将以前文中的url地址为例进行解释。
第一步,先将用户名、realm、密码按照顺序,组成字符串,并以冒号":"做间隔,获取MD5值,例如:
- 合并后的字符串数组A[] = "admin:IP Camera(F8582):12345";
复制代码 接着把这个字符串A进行MD5校验,url也要存储为字符串进行MD5校验
这里假设你的MD5函数是md5_one(char * str);参数是一个字符串,返回值也是一个字符串。
url的内容是:rtsp://192.168.0.64:554/h264/ch1/main/av_stream,注:这里不需要包含用户名和密码:
- md5_url = md5_one(url);
- md5_A = md5_one(A);
复制代码
然后将md5_A、nonce、md5_url 再次按照顺序组成字符串,以冒号:隔开后,获取MD5值,例如:
- 合并后的字符串数组HB[] = "md5_A字符串的内容:IP Camera(F8582):md5_url字符串的内容";
- md5_HB = md5_one(HB);
复制代码
最后,就可以拿着md5_HB字符串的内容,以①处文章所提到的回复格式进行回复,就会验证通过。
再接着就是按照RTSP协议内容,向服务端发送开始推流的指令[PLAY],然后在程序内设置好接收RTP包的回调函数用于接收就好了。
二、RTP接收阶段
当初次到达这个阶段的时候,我以为可以不需要解析就能播放,因为一开始我猜想:使用VLC通过RTSP流播放的时候,VLC接收到的数据应当和我接收到的RTP包数据一样的。
所以我直接就想用VLC播放器进行播放,但是失败了。我也不是开发这个播放器的作者,所以我也不太清楚为什么。好在查阅了一番资料过后,发现VLC支持播放由UDP发送的H264裸数据流,这才有了RTP解析的步骤。
参考②处的内容,我对RTP包进行了解析,由于有点愚钝,没有深刻理解到RTP填充标志和分片包的含义,所以在这里卡了好几天,现在略作解释:
根据文章内容,发现如果RTP包的填充标志位为1的话,那么在获取RTP有效数据的时候,需要将尾部的填充数据去除,去除的数据长度由尾部的最后一个字节决定。
当将RTP包头和填充数据去除之后,就得到了真正的RTP有效数据,再对这些数据进行解析。
而获取到的这段RTP有效数据也存在包头,其指示了本包的类型,其余的数据才是有效的H264裸数据流。
[20240311注]原本此处有图和一些解释,发表后消失,现在补充:
通过解析这段RTP有效数据,可以获悉这一段数据的类型是H264的单包还是分片包,具体内容请参考②处文章,明确解释了如何通过包头判断包的类型。
在这里我只简单表述一下我对单包和分片包的理解。
*单包和分片包的区别:
当是单包的时候,十分简单,根据H264的协议内容得知,直接在单包的有效数据前方添加四个字节"0x00, 0x00, 0x00, 0x01".则可使之成为真正可用的H264裸数据流。
当是分片包的时候,为了携带更多信息,包头扩展为了2个字节,具体的内容在②处文章内有说明。
其实可以简单的理解为:单包数据量过大的时候,就有了分片包,发送方会将单包拆分为多次发送,那么就必须告诉接收方何时为此包的起始,何时为此包的结束。
所以在包头存在着包的起始标志位和结束标志位,例如:
某个包内容是[ABCDEFGHI]
分片包将其分为了[*ABC][*DEF][*GHI]三个包进行发送,星号*代表着含有标志位的包头
那么在第一个包[*ABC]中,起始标志位和结束标志位的值为10,第二个包[*DEF]中为00,第三个包[*GHI]中为01.
知晓了这一点,就能知道,把所有分片包去除包头之后就是有效的H264裸数据流,只是在起始包的前方需要添加四个字节"0x00, 0x00, 0x00, 0x01".
三、RTP解析的正确性的验证阶段
验证的方法还是很多的,我选择的是直接使用VLC播放器对解析后的数据流进行播放来验证正确性。由于在第二个阶段我已经获取了H264的裸数据流,所以我选择直接将每次解析出来的裸数据流使用UDP发送到某个IP地址的端口中
然后通过VLC的UDP播放功能来验证,现在假设我UDP发送的目标IP地址是192.168.0.111,端口是5201,那么在VLC端就可以输入:
- udp/h264://@192.168.0.111:5201 (其中的含义相信一眼就能明了)
复制代码
以上就是我的整个过程,用于记录和分享,谢谢大家!
|
|