当前位置: 首页 > article >正文

音视频学习(十九)——rtsp收流(tcp方式)

前言

本文主要介绍以tcp方式实现rtsp拉流。

流程图

在这里插入图片描述

流程说明:

  1. 客户端发起tcp请求,如向真实相机设备请求,端口一般默认554;
  2. tcp连接成功,客户端与服务端开始rtsp信令交互;
  3. 客户端收到play命令响应后,开启线程等待接收数据,同时开启定时器,定时向服务端发送命令用于心跳保活
  4. 服务端向客户端发送音视频数据;
  5. 客户端接收rtp数据并进行解复用;

设计

  • 发送tcp请求
    • 创建socket
    • connect
    • 设置非阻塞
    • 设置tcp超时时间
// 建立tcp连接
m_tcpClient = std::make_shared<TcpClient>(nullptr, this);
if (!m_tcpClient.get()
    || 0 != m_tcpClient->TcpCreate()
    || 0 != m_tcpClient->TcpConnectByTime(ip.c_str(), port, 5)
    || 0 != m_tcpClient->TcpSetNoBlock(true)
    || 0 != m_tcpClient->TcpRecvTimeout(10))
    break;
  • rtsp信令交互
// 创建command类
m_command = std::make_shared<CRtspCommand>(RTSP_TRANSPORT_RTP_TCP, m_tcpClient, m_func, m_user);
if (!m_command.get())
    break;

// 创建rtsp client
if(!m_command->CreateRtspClient(m_rtspUrl, username, userpasswd))
    break;

// 发送describe
int ret = m_command->SendDescribe();
if (0 != ret)
    break;
  • 补充:创建rtsp client,发送describe后根据回调进行后续命令操作(使用开源库ireader/librtsp进行rtsp信令交互)
bool CRtspCommand::CreateRtspClient(const std::string& uri, const std::string& username, const std::string& userpasswd)
{
	if (uri.empty() || username.empty() || userpasswd.empty())
		return false;

	rtsp_client_handler_t handler;
	handler.send = SendCallback;
	handler.rtpport = RtpPortCallcback;
	handler.onannounce = AnnounceCallback;
	handler.ondescribe = DescribeCallback;
	handler.onsetup = SetupCallback;
	handler.onplay = PlayCallback;
	handler.onpause = PauseCallback;
	handler.onteardown = TeardownCallback;
	handler.onrtp = RtpDataCallback;

	m_rtsp = rtsp_client_create(uri.c_str(), username.c_str(), userpasswd.c_str(), &handler, this);
	if (!m_rtsp)
		return false;

	return true;
}
  • 启动线程等待接收数据
#define RECV_DATA_SIZE (64*1024*1024)

void CRtsp::RtspWorker()
{
	std::shared_ptr<char> dataPacket(new char[RECV_DATA_SIZE], std::default_delete<char[]>());
	memset(dataPacket.get(), 0x00, RECV_DATA_SIZE);
	int recvLen = 0;

	while (m_running)
	{
		recvLen = m_tcpClient->TcpRecv(dataPacket.get(), RECV_DATA_SIZE);
		if (recvLen <= 0)       // 数据接收失败
		{
			break;
		}

		if (0 != m_command->InputData(dataPacket.get(), recvLen))
		{
			break;
		}

		memset(dataPacket.get(), 0x00, STREAM_DATA_SIZE);
	}
}
  • 启动定时器进行心跳保活(tcp方式需要
// 创建定时器
m_timer = std::make_shared<ZDTimer>(10, 1000);
m_timer->Start();

// 开启定时器
m_timer->AddTask(10000, [this]() {
    // 10s发送一次get parameter命令
    int count = rtsp_client_media_count((rtsp_client_t*)m_rtsp);
    if (count > 0)
        rtsp_client_get_parameter(m_rtsp, 0, NULL);
});

// 停止定时器
if (m_timer.get())
{
    m_timer->Stop();
    m_timer.reset();
}
  • 接收视频数据并解复用(使用开源库ireader/librtp库进行rtp数据解复用)
// 1.创建解复用器
m_demuxer = rtp_demuxer_create(100, profile ? profile->frequency : 90000, payload, encoding.c_str(), RtpPacketCallback, this);

// 2. 塞数据
rtp_demuxer_input(m_demuxer, data, len);

// 3. 数据回调
static int RtpPacketCallback (void* param, const void* packet, int bytes, uint32_t timestamp, int flags)
{
   	// 裸流数据处理
}

// 4. 销毁
rtp_demuxer_destroy(&m_demuxer);

效果

在这里插入图片描述


http://www.kler.cn/news/148300.html

相关文章:

  • django 新建流程
  • Flask Session 登录认证模块
  • Python小技巧:探索函数调用为何加速代码执行
  • 力扣23. 合并 K 个升序链表(java,最小堆解法)
  • vivado产生报告阅读分析27
  • 前端相关免查整合-vue、es、工具类等
  • 计算机丢失vcomp140.dll是什么意思,如何解决与修复(附教程)
  • 代码随想录算法训练营 ---第四十二天
  • ubuntu 使用快照启动polygon主网
  • C语言——数组转换
  • 野火霸天虎 STM32F407 学习笔记(六)系统时钟详解
  • 亚信科技AntDB数据库与库瀚存储方案完成兼容性互认证
  • frp内网穿透
  • 4-docker-compose介绍(部署flask案例、yaml文件、启动)、新建flask项目、编写Dockerfile(用于构建flask项目的镜像)、
  • 头发的方向图(2D和3D)与合成
  • 【Mybatis】预编译/即时sql 数据库连接池
  • linux进入telnet和推出telnet
  • 零基础在ubuntu上搭建rtmp服务器-srs
  • 关于Redis底层的两个问题
  • 18、Android 组件化
  • C++中的map和set的使用
  • 【Spark入门】基础入门
  • facebook引流软件需要具备什么功能
  • 相关性分析和作图
  • php高级工程师范文模板
  • 完美解决:Nginx访问PHP出现File not found.
  • 逆向扒cocosjs安卓包教程-破解加密的js源码
  • vue+elementUI的tabs与table表格联动固定与滚动位置
  • 【JUC】十二、CompletableFuture(上)
  • Java 之 lambda 表达式(二)---- Stream 操作 API