之前写过两篇关于B接口以及GB28181的文章,近期遇到一个客户需求,需要通过B接口实现录像回放。我们先看下B接口2014部分的描述
在2014版本中,回放采用的是RTSP协议。我们再看看2019与2014的区别
在2019中,录像废除了RTSP协议,这个其实也是像GB28181看齐了,所以我说两个协议是相互借鉴学习的。当然在2014中,这个RTSP流协议,实际上也存在不合理之处,有点突兀,前面视频直播都是SIP+RTP,到回放时则变成了RTSP,所以2019废除也是明智之选。
本篇主要介绍2014版本的视频回放,这个功能用的少,所以最早我是直接编译了live555,这个已经涵盖了rtsp的流媒体点播服务,在给客户测试或者演示时,选择了RTP+裸h264的方式就可以了。只需要返回录像的RTSP地址,播流时交给live555即可。但是现在的客户是只支持ps+h264,这个live555就没法搞定了。
第一个方案,基于live555修改,开始研读live555的源代码,不读不知道,一读吓一跳,里面的继承关系十分复杂,且成员变量赋值也是有多处操作,比如存视频数据的fTo,看的头昏脑胀的。折腾了一两天,改了一下,不太容易改。就放弃了。
第二个方案,本来我自己的视频封装也包含了ps+264以及裸的264。无非就是缺少RTSP的信令解析,RTSP内部视频传输协议仍然是RTP/RTCP。我们只需要一个RTSP信令解析的功能就可以了,自己实现这个信令解析呢,其实也不难,花点时间。但是我们还是那个观点,站在巨人的肩膀上,经搜索,发现这个开源库很适用,稍微改造下即可。
https://gitcode.com/gh_mirrors/rt/RtspServer.git
在RTSP交互中,SETUP是含有了客户端接受的RTP流端口,报文示例如下
此处描述了rtp端口是4602,rtcp是4603
紧接着,我们会回复一个
此处我们将要传输流的端口是9228和9229,到此步骤为止,双方以及开始做传输准备了,只待下发PLAY指令即可。此处对应RtspServer的代码如下
/// RtspConnection.cpp
void RtspConnection::HandleCmdSetup()
{
if (auth_info_ != nullptr && !HandleAuthentication()) {
return;
}
int size = 0;
std::shared_ptr<char> res(new char[4096], std::default_delete<char[]>());
MediaChannelId channel_id = rtsp_request_->GetChannelId();
MediaSession::Ptr media_session = nullptr;
auto rtsp = rtsp_.lock();
if (rtsp) {
media_session = rtsp->LookMediaSession(session_id_);
}
if(!rtsp || !media_session) {
goto server_error;
}
if(media_session->IsMulticast()) {
std::string multicast_ip = media_session->GetMulticastIp();
if(rtsp_request_->GetTransportMode() == RTP_OVER_MULTICAST) {
uint16_t port = media_session->GetMulticastPort(channel_id);
uint16_t session_id = rtp_conn_->GetRtpSessionId();
if (!rtp_conn_->SetupRtpOverMulticast(channel_id, multicast_ip.c_str(), port)) {
goto server_error;
}
size = rtsp_request_->BuildSetupMulticastRes(res.get(), 4096, multicast_ip.c_str(), port, session_id);
}
else {
goto transport_unsupport;
}
}
else {
int rtpPort, rtcpPort;
uint16_t session_id = rtp_conn_->GetRtpSessionId();
/// TCP部分暂不考虑
if