OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 1431|回复: 2

STM32H7通过RTSP拉流海康威视摄像头

[复制链接]

54

主题

347

帖子

0

精华

高级会员

Rank: 4

积分
948
金钱
948
注册时间
2022-4-20
在线时间
356 小时
发表于 2024-3-8 17:37:52 | 显示全部楼层 |阅读模式
本帖最后由 驭剑的秘密 于 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

在明确了这个地址之后,就来到了最重要验证环节,我在这里花费的时间是相对于久的:
当与摄像头取得通信后,根据①处的文章的步骤,会收到以下内容
  1. RTSP/1.0 401 Unauthorized
  2. CSeq: 2
  3. WWW-Authenticate: Digest realm="IP Camera(F8582)", nonce="07a4249696c5e1235b317066497db7d1", stale="FALSE"
  4. Date:  Fri, Mar 08 2024 16:06:00 GMT
复制代码
此时,需要将nonce和realm的内容与用户名和密码进行一系列MD5校验后发送给摄像头服务端,接下来,我将以前文中的url地址为例进行解释。
第一步,先将用户名、realm、密码按照顺序,组成字符串,并以冒号":"做间隔,获取MD5值,例如:

  1. 合并后的字符串数组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,注:这里不需要包含用户名和密码:



  1. md5_url = md5_one(url);
  2. md5_A = md5_one(A);
复制代码




然后将md5_A、nonce、md5_url 再次按照顺序组成字符串,以冒号:隔开后,获取MD5值,例如:

  1. 合并后的字符串数组HB[] = "md5_A字符串的内容:IP Camera(F8582):md5_url字符串的内容";
  2. md5_HB = md5_one(HB);
复制代码


最后,就可以拿着md5_HB字符串的内容,以①处文章所提到的回复格式进行回复,就会验证通过。

再接着就是按照RTSP协议内容,向服务端发送开始推流的指令[PLAY],然后在程序内设置好接收RTP包的回调函数用于接收就好了。


二、RTP接收阶段


当初次到达这个阶段的时候,我以为可以不需要解析就能播放,因为一开始我猜想:使用VLC通过RTSP流播放的时候,VLC接收到的数据应当和我接收到的RTP包数据一样的。
所以我直接就想用VLC播放器进行播放,但是失败了。我也不是开发这个播放器的作者,所以我也不太清楚为什么。好在查阅了一番资料过后,发现VLC支持播放由UDP发送的H264裸数据流,这才有了RTP解析的步骤。
参考②处的内容,我对RTP包进行了解析,由于有点愚钝,没有深刻理解到RTP填充标志和分片包的含义,所以在这里卡了好几天,现在略作解释:
QQ截图20240308164918.png
根据文章内容,发现如果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端就可以输入:


  1. udp/h264://@192.168.0.111:5201      (其中的含义相信一眼就能明了)
复制代码



以上就是我的整个过程,用于记录和分享,谢谢大家!



又菜又爱指点
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

17

主题

161

帖子

0

精华

高级会员

Rank: 4

积分
955
金钱
955
注册时间
2022-7-21
在线时间
446 小时
发表于 2024-3-10 15:20:54 | 显示全部楼层
回复 支持 反对

使用道具 举报

3

主题

88

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
447
金钱
447
注册时间
2014-3-7
在线时间
49 小时
发表于 2024-3-12 14:00:48 | 显示全部楼层
会不会装上LINUX 编程序容易点。   
STM32?步进电机开发板
http://yonyon.taobao.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-22 16:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表