首页 > 其他分享 >如何在轻量级RTSP服务支持H.264扩展SEI发送接收自定义数据?

如何在轻量级RTSP服务支持H.264扩展SEI发送接收自定义数据?

时间:2023-08-05 23:32:56浏览次数:34  
标签:H.264 handle 定义数据 rtsp server HANDLE NT UINT32 轻量级

为什么开发轻量级RTSP服务?

开发轻量级RTSP服务的目的是为了解决在某些场景下用户或开发者需要单独部署RTSP或RTMP服务的问题。这种服务的优势主要有以下几点:

  1. 便利性:通过轻量级RTSP服务,用户无需配置单独的服务器,降低了部署和配置的复杂性(无论是走RTMP还是GB28181,均需要平台服务支撑)。
  2. 可扩展性:该服务支持同时创建多个RTSP服务,便于根据需求扩展或缩减服务规模(在性能没问题的情况下,启动多个服务,支撑多路流数据并发)。
  3. 并发性:能满足内网无纸化/电子教室等场景中的低并发需求,对并发要求不高的场景也适用(低并发解决大问题)。
  4. 兼容性:支持H.264/H.265视频编码,以及RTSP鉴权、RTSP会话数查看、单播、组播模式。

总的来说,轻量级RTSP服务的目标是提供一种便捷、可扩展且能满足低并发需求的服务,特别适合在内网环境下使用。

如何在轻量级RTSP服务扩展SEI发送接收?

大牛直播SDK支持推送端通过H.264 SEI信息扩展,实时传输文本/二进制数据信息,播放端做相应解析和回显。

适用场景:

  1. 公告广播:推送将相对/绝对时间戳/时间/公告内容发到播放端,播放端实时接收消息并做相应的逻辑处理。
  2. 冲顶大会:推流端实时将题目分发到播放端,借助于大牛直播SDK低延迟特性,轻松实现“音-画-题”同步接收;
  3. 会议教育类直播:推流端将字幕等分发到播放端,播放端实时绘制出相关内容;
  4. 应急指挥/单兵:推送端将GIS信息/现场采集到的数据实时写入并分发到播放端;
  5. 在线教育:推流端将激光笔和涂鸦操作分发到播放端,播放端实时划圈划线,实现特定特效。

尽管Windows、Linux、Android和iOS平台,我们都支持了H.264扩展SEI发送和接收的模块,本文先以Windows平台为例,介绍下关键的接口设计思路:

如何在轻量级RTSP服务支持H.264扩展SEI发送接收自定义数据?_H.264 SEI

本文以Windows平台轻量级RTSP服务为例,数据源采集计时器窗体,然后,启动RTSP服务,发布RTSP流,发布后,自动发送自定义数据,播放端接收并回显轻量级RTSP服务发过来的自定义数据。上图可以看到,整体延迟在毫秒级(200多毫秒)。

先说启动停止轻量级RTSP服务关键接口设计:

		/*+++rtsp server操作接口+++*/

		/*
		* 创建一个rtsp server 
		* pRtspServerHandle: rtsp server 句柄
		* reserve:保留参数传0
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *OpenRtspServer)(NT_PHANDLE pRtspServerHandle, NT_INT32 reserve);

		/*
		* 设置rtsp server 监听端口, 在StartRtspServer之前必须要设置端口
		* rtsp_server_handle: rtsp server 句柄
		* port: 端口号,可以设置为554,或者是1024到65535之间,其他值返回失败
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtspServerPort)(NT_HANDLE rtsp_server_handle, NT_INT32 port);

		/*
		* 设置rtsp server 鉴权用户名和密码, 这个可以不设置,只有需要鉴权的再设置
		* rtsp_server_handle: rtsp server 句柄
		* user_name: 用户名,必须是英文
		* password:密码,必须是英文
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtspServerUserNamePassword)(NT_HANDLE rtsp_server_handle, NT_PCSTR user_name, NT_PCSTR password);


		/*
		* 设置rtsp server 组播, 如果server设置成组播就不能单播,组播和单播只能选一个, 一般来说单播网络设备支持的好,wifi组播很多路由器不支持
		* rtsp_server_handle: rtsp server 句柄
		* is_multicast: 是否组播, 1为组播, 0为单播, 其他值接口返回错误, 默认是单播
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtspServerMulticast)(NT_HANDLE rtsp_server_handle, NT_INT32 is_multicast);


		/*
		* 设置rtsp server 组播组播地址 
		* rtsp_server_handle: rtsp server 句柄
		* multicast_address: 组播地址
		* 如果设置的不是组播地址, 将返回错误
		* 组播地址范围说明: [224.0.0.0, 224.0.0.255] 为组播预留地址, 不能设置. 可设置范围为[224.0.1.0, 239.255.255.255], 其中SSM地址范围为[232.0.0.0, 232.255.255.255]
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtspServerMulticastAddress)(NT_HANDLE rtsp_server_handle, NT_PCSTR multicast_address);


		/*
		* 获取rtsp server当前的客户会话数, 这个接口必须在StartRtspServer之后再调用
		* rtsp_server_handle: rtsp server 句柄
		* session_numbers: 会话数
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *GetRtspServerClientSessionNumbers)(NT_HANDLE rtsp_server_handle, NT_INT32* session_numbers);


		/*
		* 启动rtsp server
		* rtsp_server_handle: rtsp server 句柄
		* reserve: 保留参数传0
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *StartRtspServer)(NT_HANDLE rtsp_server_handle, NT_INT32 reserve);

		/*
		* 停止rtsp server
		* rtsp_server_handle: rtsp server 句柄
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *StopRtspServer)(NT_HANDLE rtsp_server_handle);

		/*
		* 关闭rtsp server
		* 调用这个接口之后rtsp_server_handle失效,
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32 (NT_API *CloseRtspServer)(NT_HANDLE rtsp_server_handle);


		/*---rtsp server操作接口---*/

再说发布RTSP流相关接口设计:

		/*+++发布rtsp流相关接口+++*/

		/*
		* 设置rtsp的流名称
		* stream_name: 流程名称,不能为空字符串,必须是英文
		* 这个作用是: 比如rtsp的url是:rtsp://192.168.0.111/test, test就是设置下去的stream_name
		* 成功返回 NT_ERC_OK
		*/
		NT_UINT32(NT_API *SetRtspStreamName)(NT_HANDLE handle, NT_PCSTR stream_name);

		/*
		* 给要发布的rtsp流设置rtsp server, 一个流可以发布到多个rtsp server上,rtsp server的创建启动请参考OpenRtspServer和StartRtspServer接口
		* handle: 推送实例句柄
		* rtsp_server_handle:rtsp server句柄 
		* reserve: 保留参数,传0
		*/
		NT_UINT32(NT_API *AddRtspStreamServer)(NT_HANDLE handle, NT_HANDLE rtsp_server_handle, NT_INT32 reserve);

		
		/*
		* 清除设置的rtsp server
		*/
		NT_UINT32(NT_API *ClearRtspStreamServer)(NT_HANDLE handle);


		/*
		启动rtsp流
		reserve: 保留参数,传0
		*/
		NT_UINT32(NT_API *StartRtspStream)(NT_HANDLE handle, NT_INT32 reserve);

		
		/*
		停止rtsp流
		*/
		NT_UINT32(NT_API *StopRtspStream)(NT_HANDLE handle);


		/*---发布rtsp流相关接口---*/

发送自定义数据相关接口设计:

		/*++++发送用户自定义数据相关接口++++*/
		/*
		* 1. 目前使用sei机制发送用户自定数据到播放端
		* 2. 这种机制有可能会丢失数据, 所以这种方式不保证接收端一定能收到
		* 3. 优势:能和视频保持同步,虽然有可能丢失,但一般的需求都满足了
		* 4. 目前提供两种发送方式 第一种发送二进制数据, 第二种发送 utf8字符串
		*/

		/*
		* 设置发送队列大小,为保证实时性,默认大小为3, 必须设置一个大于0的数
		* 如果数据超过队列大小,将丢掉队头数据
		* 这个接口请在 StartPublisher 之前调用
		*/
		NT_UINT32(NT_API *SetPostUserDataQueueMaxSize)(NT_HANDLE handle, NT_INT32 max_size, NT_INT32 reserve);


		/*
		* 清空用户数据队列, 有些情况可能会用到,比如发送队列里面有4条消息再等待发送,又想把最新的消息快速发出去, 可以 
		* 先清除掉正在排队消息, 再调用PostUserXXX  
		*
		*/
		NT_UINT32(NT_API *ClearPostUserDataQueue)(NT_HANDLE handle);

		/*
		* 发送二进制数据
		* data: 二进制数据
		* size:数据大小
		* 注意: 1.目前数据大小限制在256个字节以内,太大可能会影响视频传输,如果有特殊需求,需要增大限制,请联系我们
		* 2. 如果积累的数据超过了设置的队列大小,之前的队头数据将被丢弃
		* 3. 必须再调用StartPublisher之后再发送数据
		*/
		NT_UINT32(NT_API *PostUserData)(NT_HANDLE handle, const NT_BYTE* data, NT_UINT32 size, NT_INT32 reserve);

		/*
		* 发送utf8字符串
		* utf8_str: utf8字符串
		* 注意: 1. 字符串长度不能超过256, 太大可能会影响视频传输,如果有特殊需求,需要增大限制,请联系我们
		* 2. 如果积累的数据超过了设置的队列大小,之前的队头数据将被丢弃
		* 3. 必须再调用StartPublisher之后再发送数据
		*/
		NT_UINT32(NT_API *PostUserUTF8StringData)(NT_HANDLE handle, NT_PCSTR utf8_str, NT_INT32 reserve);


		/*----发送用户自定义数据相关接口----*/

播放端接收用户自定义数据接口:

设置用户数据回调:

	player_api_.SetUserDataCallBack(player_handle_, GetSafeHwnd(), NT_SP_SDKUserDataHandle);

回调实现:

extern "C" NT_VOID NT_CALLBACK NT_SP_SDKUserDataHandle(NT_HANDLE handle, NT_PVOID user_data,
	NT_INT32  data_type,
	NT_PVOID  data,
	NT_UINT32 size,
	NT_UINT64 timestamp,
	NT_UINT64 reserve1,
	NT_INT64  reserve2,
	NT_PVOID  reserve3)
{
	if ( 1 == data_type )
	{
		std::wostringstream oss;
		oss << L"userdata ";

		const NT_BYTE* byte_data = reinterpret_cast<const NT_BYTE*>(data);
		if ( byte_data != nullptr && size > 0 )
		{
			oss << L" byte data size=" << size;
		}

		std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;

		oss << L" t:" << timestamp << L"\r\n";

		OutputDebugStringW(oss.str().c_str());
	}
	else if ( 2 == data_type )
	{
		const NT_CHAR* str_data = reinterpret_cast<const NT_CHAR*>(data);
		if (str_data != nullptr && size > 0)
		{
			std::unique_ptr<std::string> s(new std::string(str_data, str_data + size));

			// oss << L" utf8 string:" << conv.from_bytes(*s);
			// oss << L" size=" << size;

			if ( !s->empty() )
			{
				HWND hwnd = reinterpret_cast<HWND>(user_data);
				if ( hwnd != nullptr && ::IsWindow(hwnd) )
				{
					::PostMessage(hwnd, WM_USER_SDK_SP_RECV_USER_DATA, (WPARAM)s.release(), (LPARAM)timestamp);
				}
			}
		}
	}

}

事件处理:

LRESULT CSmartPlayerDlg::OnSDKRecvUserData(WPARAM wParam, LPARAM lParam)
{
	std::unique_ptr<std::string> str((std::string*)(wParam));

	if (str && !str->empty())
	{
		auto timestamp = (NT_UINT64)(lParam);

		std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;

		auto w_str = conv.from_bytes(*str);

		std::wostringstream wss;

		wss << L"收到推送端消息:[ " << w_str << L" ] t:" << timestamp;

		edit_player_msg_.SetWindowTextW(wss.str().c_str());
	}

	return S_OK;
}

总结

需要注意的是,无论是轻量级RTSP服务还是RTMP推送设计,因为是通过H.264扩展SEI发送和接收自定义数据,会存在数据或消息丢失的情况,很难实现可靠传输,当然,也可以在多帧数据携带数据,确保消息多次重传达到防止部分数据丢失的目的。

标签:H.264,handle,定义数据,rtsp,server,HANDLE,NT,UINT32,轻量级
From: https://blog.51cto.com/daniusdk/6979040

相关文章

  • K3s vs K8s:轻量级和全功能的对决
    Kubernetes,通常缩写为K8s,是领先的容器编排工具。该开源项目最初由Google开发,帮助塑造了现代编排的定义。该系统包括了部署和运行容器化系统所需的一切。社区供应商基于Kubernetes创建了适用于不同用例的独立发行版。K3s[1] 是由Rancher创建的一种kubernetes流行发行版,现......
  • nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发,
    nps  nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发,可支持任何tcp、udp上层协议(访问内网网站、本地支付接口调试、ssh访问、远程桌面,内网dns解析等等……),此外还支持内网http代理、内网socks5代理、p2p等,并带有功能强大的web管理端。背景做微......
  • redis stream做轻量级消息队列的可行性
    背景对于消息数量很少的场景,尝试使用redisstream来做消息队列.为什么要用redis的stream,redis的其他数据结构可以吗?参考文章1:https://www.zhihu.com/question/43688764?sort=created参考文章2:https://www.cnblogs.com/williamjie/p/11201654.htmlredis有一些机制有队......
  • MQTT:轻量级消息传输协议在物联网中的应用
    随着物联网技术的发展,越来越多的设备需要进行实时通信和数据交换。在这样的背景下,MQTT(MessageQueuingTelemetryTransport)作为一种轻量级的消息传输协议,逐渐成为物联网领域的热门选择。本文将介绍MQTT协议的基本概念、特点以及在物联网中的应用,同时通过代码实例演示如何使用MQTT......
  • 一种轻量级定时任务实现
    现在市面上有各式各样的分布式定时任务,每个都有其独特的特点,我们这边的项目因为一开始使用的是分布式开源调度框架TBSchedule,但是这个框架依赖ZK,由于ZK的不稳定性和项目老旧无人维护,导致我们的定时任务会偶发出现异常,比如:任务停止、任务项丢失、任务不执行等;每逢618大促,在单量很......
  • VisionOn 一款集流程图、思维导图、白板于一体的轻量级在线制图工具
    VisionOn一款集流程图、思维导图、白板于一体的轻量级在线图形工具在工作和学习过程中,通过可视化的图形,有助于清晰高效地表达我们的灵感、想法、思想。工欲善其事,必先利其器。目前,思维导图软件已经有Xmind、Mindnode、MindMeister、亿图图示、Gitmind,流程图软件包括Microso......
  • 一种轻量级定时任务实现 | 京东云技术团队
    现在市面上有各式各样的分布式定时任务,每个都有其独特的特点,我们这边的项目因为一开始使用的是分布式开源调度框架TBSchedule,但是这个框架依赖ZK,由于ZK的不稳定性和项目老旧无人维护,导致我们的定时任务会偶发出现异常,比如:任务停止、任务项丢失、任务不执行等;每逢618大促,在单量很大......
  • 使用轻量级 CDC debezium-server-databend 构建实时数据同步
    作者:韩山杰DatabendCloud研发工程师https://github.com/hantmacDebeziumServerDatabend是一个基于DebeziumEngine自研的轻量级CDC项目,用于实时捕获数据库更改并将其作为事件流传递最终将数据写入目标数据库Databend。它提供了一种简单的方式来监视和捕获关系型数......
  • 轻量级的工作流引擎:提质增效+灵活简便+拖拽式设计
    低代码开发市场现在正是蓬勃发展的时期,由于低代码技术平台能够为当代企业节省很多宝贵时间,实现提质增效的办公效率,因此获得了大家的认可与喜爱。其中,工作流引擎是当中的主要功能,其拖拽式设计、易操作等优势特点也深受大家的喜爱。今天,我们就一起来聊聊这轻量级的工作流引擎是如何......
  • 基于C++11的轻量级网络框架-实现大并发网络IO
    完整资料进入【数字空间】查看——搜索"writebug"项目特点基于C++11开发,避免使用裸指针,代码稳定可靠;同时跨平台移植简单方便,代码清晰简洁。使用epoll+线程池+异步网络IO模式开发,并发性能优越。代码经过大量的稳定性、性能测试,可满足商用服务器项目。支持linux、macos、ios、android......