网站设计怎么做链接,域名注册查询入口,凡科互联网科技股份有限公司,专门做水果的网站1、 rtsp 工具
1 vlc 必备工具 2 wireshark 必备工具 3 自己制作的工具 player 使用tcp 拉流#xff0c;不自己写的话#xff0c;使用ffmpeg 去写一个播放器就行 4 live555 编译好live555#xff0c; 将live555的参数修改以下#xff0c;主要是缓存大小
文章使用c 来写一…1、 rtsp 工具
1 vlc 必备工具 2 wireshark 必备工具 3 自己制作的工具 player 使用tcp 拉流不自己写的话使用ffmpeg 去写一个播放器就行 4 live555 编译好live555 将live555的参数修改以下主要是缓存大小
文章使用c 来写一个server目的主要是为了gb28181 接收ps流 主动拉rtsp 流经过AI 算法以后 再将AI 结果 转成wsflv 和 rtsp 流。为了对比live555的过程编译live555本身live是一个非常好的服务端和客户端测试非常方便。这里AI 使用libtorch。整个协议都使用原始的代码编写最重要的是要支持投屏协议可以将结果直接投送到大屏上包含的协议比较多综合比较强因此准备使用多篇文章分开来写。
解码依然使用ffmpeg来解码尽量使用ffmpeg的硬解码 如果有可能尽量使用vulkan。
最后生成rtsp server 只支撑tcp 协议因为有可能要穿到外网部署。同时支持分布式推送ps流。各位读者不要觉得复杂这个是真的需求。
2、rtsp 抓包
如下黑体加粗的是客户端紧接着的是服务端。 OPTIONS rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0 RTSP/1.0 CSeq: 2 User-Agent: LibVLC/3.0.18 (LIVE555 Streaming Media v2016.11.28) RTSP/1.0 401 Unauthorized CSeq: 2 WWW-Authenticate: Digest realm“Login to 6FEF45758F9C6A42”,nonce“fa305e83-5897-4eaa-a787-1395d12bac9b” OPTIONS rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0 RTSP/1.0 CSeq: 3 Authorization: Digest username“admin”, realm“Login to 6FEF45758F9C6A42”, nonce“fa305e83-5897-4eaa-a787-1395d12bac9b”, uri“rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0”, response“3e64ebc6b330912aa130ed02dc7fb46b” User-Agent: LibVLC/3.0.18 (LIVE555 Streaming Media v2016.11.28) RTSP/1.0 200 OK CSeq: 3 Public: OPTIONS, DESCRIBE, ANNOUNCE, SETUP, PLAY, PAUSE, TEARDOWN, GET_PARAMETER, SET_PARAMETER, REDIRECT, RECORD Server: Rtsp Server/3.0 DESCRIBE rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0 RTSP/1.0 CSeq: 4 Authorization: Digest username“admin”, realm“Login to 6FEF45758F9C6A42”, nonce“fa305e83-5897-4eaa-a787-1395d12bac9b”, uri“rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0”, response“83a27a943b70d6094e8f27612f2fc026” User-Agent: LibVLC/3.0.18 (LIVE555 Streaming Media v2016.11.28) Accept: application/sdp RTSP/1.0 200 OK CSeq: 4 Content-Base: rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0/ Content-Type: application/sdp x-Accept-Dynamic-Rate: 1 Cache-Control: must-revalidate Content-Length: 477 v0 o- 2229913047 2229913047 IN IP4 0.0.0.0 sMedia Server cIN IP4 0.0.0.0 t0 0 acontrol:* apacketization-supported:DH artppayload-supported:DH arange:nptnow- mvideo 0 RTP/AVP 96 acontrol:trackID0 aframerate:25.000000 artpmap:96 H264/90000 afmtp:96 packetization-mode1;profile-level-id4D0029;sprop-parameter-setsZ00AKZY1QPAET8s3BQEFQAAAAwBAAAAMoQA,aO4xsgA arecvonly maudio 0 RTP/AVP 8 acontrol:trackID1 artpmap:8 PCMA/8000 arecvonly SETUP rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0/trackID0 RTSP/1.0 CSeq: 5 Authorization: Digest username“admin”, realm“Login to 6FEF45758F9C6A42”, nonce“fa305e83-5897-4eaa-a787-1395d12bac9b”, uri“rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0/”, response“0eae62d04ad69162488d27765b8c0078” User-Agent: LibVLC/3.0.18 (LIVE555 Streaming Media v2016.11.28) Transport: RTP/AVP;unicast;client_port60860-60861 RTSP/1.0 200 OK CSeq: 5 Session: 2667172900 Transport: RTP/AVP;unicast;client_port60860-60861;server_port2000-2001;ssrc8c70b4ab x-Dynamic-Rate: 1 SETUP rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0/trackID1 RTSP/1.0 CSeq: 6 Authorization: Digest username“admin”, realm“Login to 6FEF45758F9C6A42”, nonce“fa305e83-5897-4eaa-a787-1395d12bac9b”, uri“rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0/”, response“0eae62d04ad69162488d27765b8c0078” User-Agent: LibVLC/3.0.18 (LIVE555 Streaming Media v2016.11.28) Transport: RTP/AVP;unicast;client_port60862-60863 Session: 2667172900 RTSP/1.0 200 OK CSeq: 6 Session: 2667172900 Transport: RTP/AVP;unicast;client_port60862-60863;server_port2002-2003;ssrc99bb5969 x-Dynamic-Rate: 1 PLAY rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0/ RTSP/1.0 CSeq: 7 Authorization: Digest username“admin”, realm“Login to 6FEF45758F9C6A42”, nonce“fa305e83-5897-4eaa-a787-1395d12bac9b”, uri“rtsp://192.168.0.108:554/cam/realmonitor?channel1subtype0/”, response“ea485ad09bc4e5cd23ae7bfdbd1dccd8” User-Agent: LibVLC/3.0.18 (LIVE555 Streaming Media v2016.11.28) Session: 2667172900 Range: npt0.000- RTSP/1.0 200 OK CSeq: 7 Session: 2667172900 Range: npt0.000- RTP-Info: urltrackID0;seq1;rtptime0,urltrackID1;seq1;rtptime0 整个交互过程确实一目了然rtsp 协议是非常简单明了
3、使用vlc 拉流
注意点 使用vlc时要注意一点就是拉流如果是用tcp方式把vlc里面设置以下打开的速度会很快不然他会尝试udp方式最后才打开tcp会使用很长时间 可以从界面上看到实际上vlc使用的是live555 来制作的rtsp client。
输入输出的时间戳问题
接收到的流分为两种一种是ps流一种是rtsp流对于ps流我们需要首先要建立RTPserver 解析然后将ps 转成标准的RTP协议。 标准的RTP协议的时间戳以90000为基而wsflv流也就是websocket流必须以普通的时间戳为准因此里面需要转换时间戳。
GB28181 收流后接收到的时间戳直接给RTP也就是RTSP 协议里直接可以使用因为ps流的时间戳是以90000为基的而转到websocket flv 流必须变成正常的时间公式应该是
1/90000 * pts * 1000, 比如 4500 的RTP时间戳对应的时间应该为 4500* 1000 / 90000 50, 4500 这个数值我们如果敏感的话其实就是一秒钟为20帧 也就是 时间戳为 0 50 100 150而对应的RTP 时间戳为 0 4500 9000 13500 …
接收ps流
暂时先做一个ps server over udp 先不做tcp 这样容易出成果
void PsServer(int listenPort)
{int sock_fd socket(AF_INET, SOCK_DGRAM, 0);if(sock_fd -1){printf(Socket init error\n);exit(-1);}struct sockaddr_in addr_s; memset(addr_s, 0, sizeof(addr_s));addr_s.sin_family AF_INET;addr_s.sin_port htons(listenPort);addr_s.sin_addr.s_addr htonl(INADDR_ANY);/* 绑定socket */ if(bind(sock_fd, (struct sockaddr *)addr_s, sizeof(addr_s)) 0) { perror(bind error:); exit(1); } char ipbuf[20];int n, len;char recv_buf[MAX_BUFF_SIZE]; struct sockaddr_in addr_c;memset(addr_c, 0, sizeof(addr_c));while(1) { n recvfrom(sock_fd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *)addr_c, (socklen_t *)len); if(n 0) {perror(recvfrom error:); exit(1); }// bzero(ipbuf,sizeof(ipbuf));// inet_ntop(AF_INET,addr_c.sin_addr.s_addr,ipbuf,sizeof(ipbuf));if(n 12){uint32_t ssrc;memcpy((uint8_t*)ssrc, (uint8_t*)recv_buf 8, 4);ssrc htonl(ssrc);RtpSource* rtp getRtpSource(ssrc);memcpy(rtp-data, (uint8_t*)recv_buf, n);rtp-len n;m_rtpFactory.parserRtpData(rtp);}}
}收到流以后要解封包ps变成es 流然后 解码使用libtorch 做AI 识别最后将画面编码成es 流再交给rtsp server我们一点点来先讲一下解码后用torch 识别下一次讲如何解封包ps流
拉取流后解码调用
#include iostream
#include torch/script.h
#include torch/torch.h
using namespace std;int main() {//加载pytorch模型torch::jit::script::Module module torch::jit::load(./model.pt);//注意检查路径//是否支持GPU加速if(!torch::cuda::is_available())exit(0);torch::DeviceType device_type; //设置Device类型device_type torch::kCUDA; //torch::kCUDA and torch::kCPUtorch::Device device(device_type, 0);//模型转到GPU中去module.to(device);// Create a vector of inputs.std::vectortorch::jit::IValue inputs;inputs.push_back(torch::ones({1, 3, 46, 224}).to(device));// Execute the model and turn its output into a tensor.for (int i 0; i 100; i) {at::Tensor output module.forward(inputs).toTensor();std::cout output.slice(/*dim*/1, /*start*/0, /*end*/5) \n;}
}下一节继续