一、前言
远程回放NVR或者服务器上的视频文件,一般有三种方式,第一种是调用厂家的SDK,这个功能最全,但是缺点明显就是每个厂家的设备都有自己的SDK,只兼容自家的设备,如果你的软件需要接入多个厂家的,那就意味着要写好多套SDK接入。而且一般厂家提供的SDK只有win的居多,少部分大厂还提供了linux的,但是基本上都是X86的,如果你要是国产系统或者硬件,那就全部歇菜。第二种方式用GB28181,就是监控行业的国家标准协议,能够回放和下载录像文件,这个最适合,毕竟是标准协议,按照协议来,通用任何平台,缺点就是比较复杂,而且也要做各种设备的兼容性测试,要做部分的调整。第三种就是通过rtsp协议来回放,这种实现起来最简单,按照厂家规约组合对应的rtsp回放视频地址就行,该地址带上开始时间和结束时间等参数,缺点就是只能回放和切换播放进度,如果需要下载的话,需要开启存储到本地才行,这个不可取,应该是要从服务器上下载录像文件的方式会更好。
现在各个监控大厂做的设备,基本上都会支持通过rtsp直接取流显示,而且做的比较好的还支持通过rtsp回放取流,基本上都会约定一个字符串的规则,每个厂家都是不一样的规则,比如回放对应的rtsp地址还要带上时间范围,回放肯定要指定一个开始时间和结束时间。这里需要特别提示的是,按道理rtsp是实时视频流,一般是没有时长的,而回放的rtsp视频流是带了时长的,所以可以通过seek来定位播放位置,这个就很方便用户在软件上任意拖动和切换播放位置,以前我一直以为rtsp实时视频流不可能有时长,原来是自己孤陋寡闻了,在通过一个老万音视频大佬的指点下才得知这个特性,这个特性当然需要设备厂家在后端实现支持。
有了回放可以切换播放进度位置这个特性,意味着回放这块不需要用GB28181国标去解析,直接构建对应的回放视频流字符串就可以,目前测试下来,正常播放和切换进度播放一点问题没有,唯独倍速播放有问题,目前看下来还是不支持倍速播放的,不知道是不是还有其他的机关要素控制比如参数啥的。其实取流回放的核心就是根据不同厂家拿到对应设备的rtsp字符串即可,解码那边要拿到时长,并当做文件处理,因为文件类型的可以切换播放进度。
视频地址:www.bilibili.com/video/BV13G…
二、效果图
三、体验地址
四、相关代码
QString UrlHelper::getRtspUrl(const UrlPara &urlPara)
{
QString url;
//头部地址格式完全一致
QString head = QString("rtsp://%1:%2@%3:554").arg(urlPara.userName).arg(urlPara.userPwd).arg(urlPara.deviceIP);
if (urlPara.companyType == CompanyType_HaiKang) {
//实时预览格式 rtsp://admin:12345@192.168.1.128:554/Streaming/Channels/101?transportmode=unicast
//视频回放格式 rtsp://admin:12345@192.168.1.128:554/Streaming/tracks/101?starttime=20120802t063812z&endtime=20120802t064816z
//流媒体视频流 rtsp://172.6.24.15:554/Devicehc8://172.6.22.106:8000:0:0?username=admin&password=12345
//日期时间格式 ISO 8601 表示Zulu(GMT) 时间 YYYYMMDD”T”HHmmSS.fraction”Z”,
//unicast表示单播,multicast表示多播,默认单播可以省略
//101解析: 1是通道号 01是通道的码流编号 也可以是02 03
QString startTimeISO = urlPara.dateTimeStart.toString(Qt::ISODate);
startTimeISO.replace("-", "");
startTimeISO.replace(":", "");
startTimeISO.toLower();
QString endTimeISO = urlPara.dateTimeEnd.toString(Qt::ISODate);
endTimeISO.replace("-", "");
endTimeISO.replace(":", "");
endTimeISO.toLower();
//通道号和码流编号
QString info = QString("%1%2%3").arg(urlPara.channel).arg(0).arg(urlPara.streamType + 1);
//回放时间范围
QString time = QString("starttime=%1z&endtime=%2z").arg(startTimeISO).arg(endTimeISO);
//实时和回放地址格式不同
if (urlPara.videoType == 0) {
url = QString("%1/Streaming/Channels/%2").arg(head).arg(info);
} else if (urlPara.videoType == 1) {
url = QString("%1/Streaming/tracks/%2?%3").arg(head).arg(info).arg(time);
}
} else if (urlPara.companyType == CompanyType_DaHua) {
//实时预览格式 rtsp://192.168.1.128:554/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif
//视频回放格式 rtsp://admin:12345@192.168.1.128:554/cam/playback?channel=1&subtype=0&starttime=2021_03_18_11_36_01&endtime=2021_03_18_12_05_01
QString startTimeStr = urlPara.dateTimeStart.toString("yyyy_MM_dd_HH_mm_ss");
QString endTimeStr = urlPara.dateTimeEnd.toString("yyyy_MM_dd_HH_mm_ss");
//通道号和码流编号
QString info = QString("channel=%1&subtype=%2").arg(urlPara.channel).arg(urlPara.streamType);
//回放时间范围
QString time = QString("starttime=%1&endtime=%2").arg(startTimeStr).arg(endTimeStr);
//实时和回放地址格式不同
if (urlPara.videoType == 0) {
url = QString("%1/cam/realmonitor?%2&unicast=true&proto=Onvif").arg(head).arg(info);
} else if (urlPara.videoType == 1) {
url = QString("%1/cam/playback?%2&%3").arg(head).arg(info).arg(time);
}
} else {
//实时预览格式 rtsp://admin:12345@192.168.1.128:554/live?channel=1&stream=1
//视频回放格式 rtsp://admin:12345@192.168.1.128:554/file?channel=1&start=1494485280&stop=1494485480
//先转换时间戳,1970年到该时间经过的秒数
qint64 startTimeSec = urlPara.dateTimeStart.toMSecsSinceEpoch() / 1000;
qint64 stopTimeSec = urlPara.dateTimeEnd.toMSecsSinceEpoch() / 1000;
//回放时间范围
QString time = QString("start=%1&stop=%2").arg(startTimeSec).arg(stopTimeSec);
//实时和回放地址格式不同
if (urlPara.videoType == 0) {
url = QString("%1/live?channel=%2&stream=%3").arg(head).arg(urlPara.channel).arg(urlPara.streamType);
} else if (urlPara.videoType == 1) {
url = QString("%1/file?channel=%2&%3").arg(head).arg(urlPara.channel).arg(time);
}
}
//还有一种通用格式 rtsp://admin:12345@192.168.1.128:554/0 0-主码流 1-子码流
return url;
}