GB28181学习(十六)——基于jrtplib实现tcp被动和主动收流

前言

GB/T28181-2022实时流的传输方式介绍:https://blog.csdn.net/www_dong/article/details/134255185

tcp passive收流

流程图

在这里插入图片描述

注意:

  • m字段指定传输方式为TCP/RTP/AVP;
  • sdp信息中增加"a=setup:passive";
  • SIP服务器启动端口监听,设备发起tcp连接请求;

设计

  1. 创建socket、bind、listen,启动数据接收线程;
// TcpServer为封装的socket类int CGBTcpServerStreamReceiver::Start()
{if (m_localIP.empty() || m_localPort <= 0)return -1;if (m_tcpServer.get())return 0;m_tcpServer = std::make_shared<TcpServer>(TcpDataCB, this);if (!m_tcpServer.get())return -1;if (0 != m_tcpServer->TcpCreate() || 0 != m_tcpServer->TcpBind(m_localPort) || 0 != m_tcpServer->TcpListen(5))return -1;m_thread = std::thread(TcpDataThread, this);return 0;
}
  1. 在线程内等待连接,连接成功后接收数据并回调至应用层处理
void CGBTcpServerStreamReceiver::TcpDataWorker()
{bool bAccept = false;uint8_t payload;while (m_running){if (!bAccept){// 等待设备连接if (0 == m_tcpServer->TcpAccept()){bAccept = true;// 连接成功后,初始化rtp参数if (0 != InitRtpSession_()){break;}}continue;}Poll();BeginDataAccess();// 开始接收数据if (GotoFirstSourceWithData()){do{RTPPacket* packet = nullptr;while (nullptr != (packet = GetNextPacket())){payload = packet->GetPayloadType();if (0 == payload){DeletePacket(packet);continue;}struct rtp_packet_tcp data;data.mark = packet->HasMarker();data.pts = packet->GetTimestamp();data.seq = packet->GetSequenceNumber();data.data = packet->GetPayloadData();data.len = (int)packet->GetPayloadLength();m_payload = payload;if (m_lastSeq < 0){m_lastSeq = data.seq - 1;}if (m_lastSeq = data.seq - 1){PackData_(data.data, data.len);}DeletePacket(packet);}} while (GotoNextSourceWithData());}EndDataAccess();Sleep(30);}Destroy();
}
  1. 初始化rtp参数
int CGBTcpServerStreamReceiver::InitRtpSession_()
{const int packSize = 45678;RTPSessionParams sessionParams;sessionParams.SetProbationType(RTPSources::NoProbation);sessionParams.SetOwnTimestampUnit(90000.0 / 25.0);sessionParams.SetMaximumPacketSize(packSize + 64);m_rtpTcpTransmitter = new RTPTCPTransmitter(nullptr);m_rtpTcpTransmitter->Init(true);m_rtpTcpTransmitter->Create(65535, 0);if (0 != Create(sessionParams, m_rtpTcpTransmitter))return -1;if (0 != AddDestination(RTPTCPAddress(m_tcpServer->GetClientSocket())))return -1;return 0;
}

注意:RTP over TCP模式比RTP over UDP模式多了两字节的长度字段。

tcp active收流

流程图

在这里插入图片描述

注意:

  • m字段指定传输方式为TCP/RTP/AVP;
  • sdp信息中增加"a=setup:active";
  • 设备返回200 OK,报文的SDP信息中包含tcp监听端口;
  • SIP服务器根据设备监听端口发起TCP连接请求;

设计

  1. 创建socket、connect、初始化rtp,启动数据接收线程
// TcpClient为封装的客户端socket类int CGBTcpClientStreamReceiver::Start(int streamType)
{if (m_localIP.empty() || m_localPort <= 0)return -1;if (m_tcpClient.get())return 0;// 创建socketm_tcpClient = std::make_shared<TcpClient>(TcpDataCB, this);if (!m_tcpClient.get() || 0 != m_tcpClient->TcpCreate())return -1;// connectint ret = m_tcpClient->TcpConnectByTime(m_localIP.c_str(), m_localPort, 5);if (0 != ret)return -1;// 初始化rtp sessionif (0 != InitRtpSession_())return -1;// 启动接收线程m_thread = std::thread(TcpDataThread, this);
}
  1. 初始化rtp参数
int CGBTcpClientStreamReceiver::InitRtpSession_()
{const int packSize = 45678;RTPSessionParams sessionParams;sessionParams.SetProbationType(RTPSources::NoProbation);sessionParams.SetOwnTimestampUnit(90000.0 / 25.0);sessionParams.SetMaximumPacketSize(packSize + 64);m_rtpTcpTransmitter = new RTPTCPTransmitter(nullptr);m_rtpTcpTransmitter->Init(true);m_rtpTcpTransmitter->Create(65535, 0);if (0 != Create(sessionParams, m_rtpTcpTransmitter))return -1;// 添加客户端socketif (0 != AddDestination(RTPTCPAddress(m_tcpClient->GetClientSocket())))return -1;return 0;
}
  1. 在线程内等待连接,连接成功后接收数据并回调至应用层处理

同tcp passive收流流程。

rtp解包工具

基于qt+ireader库实现tcp解包(ps封装+264载荷)

解包流程

  1. 打开文件,创建解码器
void RtpUnpackDlg::StartRtpUnpack()
{if (m_thread.joinable())return;QString filePath = ui.le_filePath->text();if (filePath.isEmpty()){QMessageBox::critical(this, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("文件路径为空"), QMessageBox::Ok);return;}m_rtpPayloadParam.payload = 100;m_rtpPayloadParam.encoding = "PS";m_rtpPayloadParam.frtp = fopen(filePath.toStdString().c_str(), "rb");if (!m_rtpPayloadParam.frtp){QMessageBox::critical(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("打开输入文件失败"), QMessageBox::Ok);return;}m_rtpPayloadParam.fout = fopen(outFilePath.toStdString().c_str(), "wb");if (!m_rtpPayloadParam.fout){QMessageBox::critical(this, QString::fromLocal8Bit("警告"), QString::fromLocal8Bit("打开输出文件失败"), QMessageBox::Ok);return;}struct rtp_payload_t handler;handler.alloc = RtpPacketAlloc;handler.free = RtpPacketFree;handler.packet = RtpDecodePacket;m_rtpPayloadParam.decoder = rtp_payload_decode_create(100, "PS", &handler, this);m_thread = std::thread(DataReadThread, this);
}
  1. 读数据
void RtpUnpackDlg::RtpDataReadWorker()
{while (m_running){// 先读两个字节的头unsigned char s2[2];if (2 != fread(s2, 1, 2, m_rtpPayloadParam.frtp))break;m_rtpPayloadParam.size = (s2[0] << 8) | s2[1];assert(ctx.size < sizeof(ctx.packet));if (m_rtpPayloadParam.size != (int)fread(m_rtpPayloadParam.packet, 1, m_rtpPayloadParam.size, m_rtpPayloadParam.frtp))break;// 塞数据if (m_rtpPayloadParam.packet[1] < RTCP_FIR || m_rtpPayloadParam.packet[1] > RTCP_LIMIT)rtp_payload_decode_input(m_rtpPayloadParam.decoder, m_rtpPayloadParam.packet, m_rtpPayloadParam.size);}fclose(m_rtpPayloadParam.frtp);fclose(m_rtpPayloadParam.fout);
}
  1. 解包
int RtpUnpackDlg::DecodePacket(const void* packet, int bytes, uint32_t timestamp, int flags)
{static const unsigned char start_code[4] = { 0, 0, 0, 1 };static unsigned char buffer[2 * 1024 * 1024] = {0, };size_t size = 0;if (0 == strcmp("H264", m_rtpPayloadParam.encoding) || 0 == strcmp("H265", m_rtpPayloadParam.encoding)|| 0 == strcmp("PS", m_rtpPayloadParam.encoding)){memcpy(buffer, start_code, sizeof(start_code));size += sizeof(start_code);}memcpy(buffer + size, packet, bytes);size += bytes;fwrite(buffer, 1, size, m_rtpPayloadParam.fout);// 新增界面播放功能if (m_playWidget)m_playWidget->AddData(CODEC_VIDEO_H264, (void*)buffer, size);return 0;
}

界面示例

在这里插入图片描述

参考:https://github.com/ireader中的demo示例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/146200.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AWS实战(一)-创建S3 存储桶

1&#xff09;登录AWS账号&#xff0c;选择服务—>存储—>S3。 2&#xff09;查看存储桶列表 3&#xff09;点击"创建存储桶"创建bucket。 4&#xff09;设置跨域 点击编辑&#xff0c;修改跨域设置即可。

关于Ultra HDR Image的那些事

一、什么是Ultra HDR Image 2023年10月初&#xff0c;google正式发布了Android 14。该版本中引入了一个新的功能Ultra HDR Image&#xff0c;被誉为”图像技术的未来”。之前Android版本各手机厂商或许有自己的HDR图片技术&#xff0c;本文这里重点分析下Android14上google的实…

在test用户下创建test1表并插入数据,然后将tes1t表的查询权限授予test2用户

文章目录 1、以 test 用户登录2、创建 test1 表3、插入数据4、查看数据5、授予权限创建用户test2以 test 用户登录并授予权限&#xff1a;使用test2用户登录查询&#xff0c;测试结果 1、以 test 用户登录 首先&#xff0c;您需要以 test 用户登录到数据库 sqlplus test/1232…

腾讯云4核8G服务器配置价格表,轻量和CVM标准型S5实例

腾讯云4核8G服务器S5和轻量应用服务器优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云…

Linux下向Github仓库推送

文章目录 Git 与 Github安装git在github下创建项目下载项目到本地Git三板斧第一板斧 git add第二板斧 git commit第三板斧 git push Git 与 Github Git是目前从开发人员到设计人员的版本控制技术。gitee是国内社交代码托管平台。这是一个你可以玩和实验的地方。在这里你可以找…

注解方式优雅的实现 Redisson 分布式锁

1前言 日常开发中&#xff0c;难免遇到一些并发的场景&#xff0c;为了保证接口执行的一致性&#xff0c;通常采用加锁的方式&#xff0c;因为服务是分布式部署模式&#xff0c;本地锁Reentrantlock和Synchnorized这些就先放到一边了&#xff0c;Redis的setnx锁存在无法抱保证…

创建具有负载平衡和集群的可扩展 Node.js 应用程序

创建具有负载平衡和集群的可扩展 Node.js 应用程序 负载平衡是提高应用程序性能、可扩展性和可用性的一项重要技术。当客户端向负载均衡器发出请求时&#xff0c;负载均衡器根据预定义的规则将请求分发到不同的实例。 可以使用cluster集群模块或 PM2 等工具根据负载均衡器的流…

[PHP]关联和操作MySQL数据库然后将数据库部署到ECS

在Mac电脑上使用VS Code进行PHP开发并关联操作MySQL数据库&#xff0c;然后将数据库部署到ECS。 1.安装PHP和MySQL 确保你的Mac上已经安装了PHP和MySQL。你可以使用Homebrew来安装它们&#xff1a; $ brew install php $ brew install mysql 安装mysql完成后记住这一句: …

城市网吧视频智能监控方案,实现视频远程集中监控

网吧环境较为复杂&#xff0c;电脑设备众多且人员流动性大&#xff0c;极易发生人员或消防事故&#xff0c;亟需改变&#xff0c;TSINGSEE青犀AI智能网吧视频监管方案可以帮助实现对网吧环境和用户活动的实时监控和管理。 1、视频监控系统 在网吧内部布置高清摄像头&#xff0…

反转字符串中的单词

给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;输入字符串 s中可能会存在前导空格、尾随空格…

笔记54:门控循环单元 GRU

本地笔记地址&#xff1a;D:\work_file\DeepLearning_Learning\03_个人笔记\3.循环神经网络\第9章&#xff1a;动手学深度学习~现代循环神经网络 a a a a a a a

Bulk RNA-seq上下游分析

Bulk-RNA-seq上下游分析还是相对简单的&#xff0c;这次我以mouse为例&#xff0c;进行Bulk-RNA-seq上下游分析&#xff0c;并进行对应的图片绘制。 上游分析 1.软件准备 #安装所需软件 sudo apt install fastqc sudo apt install hisat2 sudo apt install cutadapt sudo ap…

腾讯云4核8G服务器性能如何多少钱一年?

腾讯云服务器4核8G配置优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云百科txybk.com分…

Spring Security OAuth2.0 实现分布式系统的认证和授权

Spring Security OAuth2.0 实现分布式系统的认证和授权 1. 基本概念1.1 什么是认证&#xff1f;1.2 什么是会话&#xff1f;1.2.1 基于 session 的认证方式1.2.2 基于 token 的认证方式 1.3 什么是授权&#xff1f;1.3.1 授权的数据模型 1.4 RBAC 介绍 2. Spring Security2.1 S…

鸿蒙4.0开发笔记之DevEco Studio如何使用Previewer窗口预览器(一)

一、预览器作用 DevEco Studio预览器概况在HarmonyOS应用开发过程中&#xff0c;通过使用预览器&#xff0c;可以查看应用的UI效果&#xff0c;方便开发者实时查看应用的运行效果&#xff0c;随时调整代码。 二、打开Previewer预览器 1、正常启动 打开预览器的位置在DevEco…

Spring Boot - devtools 热部署

spring-boot-devtools是Spring Boot提供的一组开发工具&#xff0c;它旨在提高开发体验。这些工具包括应用程序的自动重新启动、自动刷新和远程调试等功能。下面是将spring-boot-devtools整合到Spring Boot应用程序中的步骤&#xff1a; 0、启用"Build project automatic…

4核8G服务器价格选择轻量还是CVM合适?

腾讯云服务器4核8G配置优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;轻量应用服务器4核8G12M带宽一年446元、529元15个月&#xff0c;腾讯云百科txybk.com分…

【论文阅读】A Survey on Video Diffusion Models

视频扩散模型&#xff08;Video Diffusion Model&#xff09;最新综述GitHub 论文汇总-A Survey on Video Diffusion Models。 paper&#xff1a;[2310.10647] A Survey on Video Diffusion Models (arxiv.org) 0. Abstract 本文介绍了AIGC时代视频扩散模型的全面回顾。简要介…

Redis7.2.3集群安装,新增节点,删除节点,分配哈希槽,常见问题

概念&#xff1a; 【Redis】高可用之三&#xff1a;集群&#xff08;cluster&#xff09; - 知乎 实操&#xff1a; Redis集群三种模式 主从模式 优势&#xff1a; 主节点可读可写 从节点只能读&#xff08;从节点从主节点同步数据&#xff09; 缺点&#xff1a; 当主节点…

基于java web的中小型人力资源管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…