Android平台如何实现外部RTSP|RTMP流注入轻量级RTSP服务模块(内网RTSP网关)

news2024/9/21 20:51:05

技术背景

今天分享的是外部RTSP或RTMP流,拉取后注入到本地轻量级RTSP服务模块,供内网小并发场景下使用,这里我们叫做内网RTSP网关模块。

内网RTSP网关模块,系内置轻量级RTSP服务模块扩展,完成外部RTSP/RTMP数据拉取并注入到轻量级RTSP服务模块工作,多个内网客户端直接访问内网轻量级RTSP服务获取公网数据,无需部署单独的服务器,支持RTSP/RTMP H.265数据接入。

内置轻量级RTSP服务模块和内置RTSP网关模块共同点:

内置轻量级RTSP服务模块和内置RTSP网关模块,核心痛点是避免用户或者开发者单独部署RTSP或者RTMP服务,数据汇聚到内置RTSP服务,对外提供可供拉流的RTSP URL,适用于内网环境下,对并发要求不高的场景,支持H.264/H.265,支持RTSP鉴权、单播、组播模式,考虑到单个服务承载能力,我们支持同时创建多个RTSP服务,并支持获取当前RTSP服务会话连接数。

内置轻量级RTSP服务模块和内置RTSP网关模块不同点:数据来源不同

1. 内置轻量级RTSP服务模块,数据源来自摄像头、屏幕、麦克风等编码前数据,或者本地编码后的对接数据;

2. 内置RTSP网关模块,实际上是RTSP/RTMP拉流模块+内置轻量级RTSP服务模块组合出来的。数据源来自RTSP或RTMP网络流,拉流模块完成编码后的音视频数据回调,然后,汇聚到内置轻量级RTSP服务模块。

技术设计

本文以大牛直播SDK的转发demo基础设计为例,增加了内网RTSP网关模块,由于我们有非常稳定完善的RTSP、RTMP直播播放模块,内网RTSP网关模块,无非就是拉取到RTSP或RTMP流,把编码后的H.264/H.265数据回调上来,然后注入到轻量级RTSP服务模块即可,如下图所示:

先开始拉流,获取到拉流的RTSP或RTMP数据,实现如下:

		    //Author: daniusdk.com
            btnPullStream.setOnClickListener(new Button.OnClickListener() {

			// @Override
			public void onClick(View v) {

				if (isPulling)
				{
					if(isPushing || isRecording || isRTSPPublisherRunning)
					{
						Log.e(TAG, "please make sure pusher/recorder/rtsp server stopped first..");
						return;
					}

					StopPull();

					btnPullStream.setText("开始拉流");
					btnPushStream.setEnabled(false);
				}
				else {
					Log.i(TAG, "onClick StartPull Stream..");

					boolean is_pull_suc = StartPull();

					if(!is_pull_suc)
					{
						Log.e(TAG, "call StartPull() failed!");
						return;
					}

					btnPullStream.setText("停止拉流");
					btnPushStream.setEnabled(true);
				}
			}
		});

启动RTSP服务:

	//启动/停止RTSP服务
	class ButtonRtspServiceListener implements OnClickListener {
		public void onClick(View v) {
			if (isRTSPServiceRunning) {
				stopRtspService();

				btnRtspService.setText("启动RTSP服务");
				btnRtspPublisher.setEnabled(false);

				isRTSPServiceRunning = false;
				return;
			}

			if(!OpenPushHandle())
			{
				return;
			}

			Log.i(TAG, "onClick start rtsp service..");

			rtsp_handle_ = libPublisher.OpenRtspServer(0);

			if (rtsp_handle_ == 0) {
				Log.e(TAG, "创建rtsp server实例失败! 请检查SDK有效性");
			} else {
				int port = 8554;
				if (libPublisher.SetRtspServerPort(rtsp_handle_, port) != 0) {
					libPublisher.CloseRtspServer(rtsp_handle_);
					rtsp_handle_ = 0;
					Log.e(TAG, "创建rtsp server端口失败! 请检查端口是否重复或者端口不在范围内!");
				}

				//String user_name = "admin";
				//String password = "12345";
				//libPublisher.SetRtspServerUserNamePassword(rtsp_handle_, user_name, password);

				if (libPublisher.StartRtspServer(rtsp_handle_, 0) == 0) {
					Log.i(TAG, "启动rtsp server 成功!");
				} else {
					libPublisher.CloseRtspServer(rtsp_handle_);
					rtsp_handle_ = 0;
					Log.e(TAG, "启动rtsp server失败! 请检查设置的端口是否被占用!");
				}

				btnRtspService.setText("停止RTSP服务");
				btnRtspPublisher.setEnabled(true);

				isRTSPServiceRunning = true;
			}
		}
	}

发布RTSP流:

	//发布/停止RTSP流
	class ButtonRtspPublisherListener implements OnClickListener {
		public void onClick(View v) {
			if (isRTSPPublisherRunning) {
				stopRtspPublisher();

				btnRtspPublisher.setText("发布RTSP流");
				btnGetRtspSessionNumbers.setEnabled(false);
				btnRtspService.setEnabled(true);
			}
			else
			{
				Log.i(TAG, "onClick start rtsp publisher..");

				boolean startRet = StartRtspStream();

				if (!startRet) {
					Log.e(TAG, "Failed to call StartRtspStream().");
					return;
				}

				btnRtspPublisher.setText("停止RTSP流");
				btnGetRtspSessionNumbers.setEnabled(true);
				btnRtspService.setEnabled(false);
			}
		}
	};

如果需要获取到RTSP会话链接数:

	//当前RTSP会话数弹出框
	private void PopRtspSessionNumberDialog(int session_numbers) {
		final EditText inputUrlTxt = new EditText(this);
		inputUrlTxt.setFocusable(true);
		inputUrlTxt.setEnabled(false);

		String session_numbers_tag = "RTSP服务当前客户会话数: " + session_numbers;
		inputUrlTxt.setText(session_numbers_tag);

		AlertDialog.Builder builderUrl = new AlertDialog.Builder(this);
		builderUrl
				.setTitle("内置RTSP服务")
				.setView(inputUrlTxt).setNegativeButton("确定", null);
		builderUrl.show();
	}

如果需要预览:

		btnStartStopPlayback.setOnClickListener(new Button.OnClickListener() {

			// @Override
			public void onClick(View v) {

				if (isPlaying) {
					Log.i(TAG, "Stop playback stream++");

					StopPlay();

					btnStartStopPlayback.setText("开始播放 ");
					Log.i(TAG, "Stop playback stream--");
				} else {
					Log.i(TAG, "Start playback stream++");

					boolean startRet = StartPlay();

					if (!startRet) {
						Log.e(TAG, "Failed to call StartPlay().");
						return;
					}

					btnStartStopPlayback.setText("停止播放 ");

					Log.i(TAG, "Start playback stream--");
				}
			}
		});
	}

技术总结

内网RTSP网关,在小并发的环境下,不需要单独部署RTSP或RTMP服务,配合我们RTSP播放器,延迟毫秒级,优势非常明显,感兴趣的开发者可参考,如果需要测试,可测试看看,不止Android平台,Windows也有类似的实现。

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

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

相关文章

挖呀挖和ChatGPT-UMLChina建模知识竞赛第4赛季第1轮

DDD领域驱动设计批评文集>> 《软件方法》强化自测题集>> 《软件方法》各章合集>> 参考潘加宇在《软件方法》和UMLChina公众号文章中发表的内容作答。在本文下留言回答,先全部答对者得分,本轮总分为3分。 1. [单选] 以黄老师版“挖…

opengauss 的回归测试

目录 一、回归测试说明 二、单独执行测试用例(开发调试) 一、回归测试说明 opengauss/postgresql 的回归测试,通过执行SQL比较输出打印,判断代码修改是否改变了其它功能逻辑。 OG的回归测试大体上和PG类似,主要是通…

wordpress服务器搬家和更换域名的几个步骤

问题解说 其实wordpress换域名需要到数据库进行操作的,首先,你换域名也是有几种情况的; 换空间换域名 如果是上述问题,那么将FTP整站打包外,还需要将数据库里的所有数据表也打包,数据库是进phpmyadmin里打包的,两个都打包后,然后分别上传到新的空间ftp和数据库里,然…

什么是投入产出比(ROI)以及如何提升投入产出比?

投入产出比(ROI)是一种衡量企业或项目投资效益的指标,它可以帮助企业评估投资回报情况,并制定更加明智的投资决策。本文将为大家介绍什么是投入产出比(ROI)以及如何提升投入产出比。 一、什么是投入产出比&…

【计算机网络 - 第四章】网络层:数据平面

目录 一、网络层概述 1、主要作用 2、控制平面方法 3、网络层提供的两种服务 二、路由器工作原理 1、路由器总体结构 2、输入、输出端口处理 (1)输入端口 (2)输出端口 3、交换 (1)经内存交换 &…

后端实习产出--通过自定义注解、反射、进行切面编程实现一个转化工具

前置知识: 需要会自定义注解方法自定义注解字段AOP切面编程,反射等... 核心代码结构: 核心代码实现: package com.***.config;import cn.hutool.core.util.StrUtil; import com.google.common.collect.Maps; import com.***.co…

【pyq文案】可可爱爱の朋友圈文案

1.我在该生儿育女的年纪,选择了生椰拿铁 2.我妈年轻时候工资2000,我现在工资也2000,这就叫薪火相传 3.不要讨厌自己,有什么事怪星座生肖八字和mbti就好了 4.人是会和动物共情的,我开始理解急每天早起,然…

FL Studio2023最新中文免费版水果音乐制作软件

FL Studio(水果音乐制作软件)是一款强大的音乐制作编曲软件,非常容易上手。FL让你的计算机就像是全功能的录音室,漂亮的大混音盘,先进的创作工具,让你的音乐突破想象力的限制。一款强大的音乐制作软件,可以进行音乐编曲…

云计算期中测试

云计算期中测试 文章目录 云计算期中测试一、前言二、第一题1、命令方式2、java API方式 三、第二题1、创建CSV文件并将其上传到HDFS2、编写利用MapReduce框架的java代码3、打包java项目4、在Hadoop集群上提交jar文件来运行MapReduce作业 一、前言 在实验开始之前我们需要在虚…

MySQL高级_第05章_存储引擎

MySQL高级_第05章_存储引擎 1. 查看存储引擎 查看mysql提供什么存储引擎: show engines ; show engines \G ; 显式如下: *************************** 1. row *************************** Engine : InnoDB Support: DEFAULT Comment : Su…

企业管理OA系统在企业数字化转型中带来的变化,简直难以想象

目前企业管理面临到哪些痛点 1.信息孤岛:企业内部信息流动不畅,各部门数据独立,互相之间信息难以共享和沟通。 2.流程繁琐:企业业务流程较为繁琐,审批流程漫长,给业务员和经理带来不必要的工作压力。 3.…

Hbase入门篇03---Java API使用,HBase高可用配置和架构设计

Hbase入门篇03---Java API使用,HBase高可用配置和架构设计 需求环境搭建表的CRUD坑命令执行卡住不动 ?RegionServer只在本地127.0.0.1监听16020端口导致外网连接被拒RegionServer所在主机的/etc/hosts文件存在额外的回环地址映射信息,导致客户端拿到无法…

亚马逊云科技使用Inf2实例运行GPT-J-6B模型

在2019年的亚马逊云科技re:Invent上,亚马逊云科技发布了Inferentia芯片和Inf1实例这两个基础设施。Inferentia是一种高性能机器学习推理芯片,由亚马逊云科技定制设计,其目的是提供具有成本效益的大规模低延迟预测。时隔四年,2023年…

生成bean的注解@Component极其衍生和@ComponentScan@Configuration

Component Spring 2.5 以后,除了提供基本的 Component 注解之外,还提供了 Service Controller Repository 三个注解。在 Spring 源码中,后面三个注解都在开始部分引入了 Component 注解,除此以外这四个注解的源码内容没有任何区别…

Json介绍

文章目录 1. 什么是 JSON?2. JSON语法格式3. JSON在Java中的用途3.1 FastJSON1. FastJSON概述与下载2. FastJSON常用方法 3.2. Jackson1. Jackson下载与使用2. Jackson常用类与方法3. ObjectMapper类常用方法 1. 什么是 JSON? JSON:JavaScript Object N…

C语言函数大全-- _w 开头的函数(2)

C语言函数大全 本篇介绍C语言函数大全-- _w 开头的函数 1. _wexecl 1.1 函数说明 函数声明函数功能int _wexecl(const wchar_t *path, const wchar_t *arg0, ... /* , const wchar_t *arg1, ..., NULL */);它是一个 Windows 平台下的 C 标准库函数,用于在新进程…

〖大学生·技术人必学的职业规划白宝书 - 职业规划篇②〗- 进入职场前必须要考虑的问题

历时18个月,采访 850 得到的需求。 不管你是在校大学生、研究生、还是在职的小伙伴,该专栏有你想要的职业规划、简历、面试的答案。说明:该文属于 大学生技术人职业规划白宝书 专栏,购买任意白宝书体系化专栏可加入TFS-CLUB 私域社…

leecode106——使用中序遍历和后序遍历构造一棵二叉树

leecode106 中序遍历和后序遍历构造一棵二叉树 🔎中序遍历和后续遍历的性质 在后序遍历中,最后一个元素二叉树的根节点 在中序遍历序列中,根节点的左边为左子树,右边为右子树 🔎1.二叉树的还原过程描述 1.首先&am…

HTTP协议基本格式

HTTP协议基本格式 TCP/IP的分层管理HTTP的基本格式 TCP/IP的分层管理 TCP/IP协议族里重要的一点就是分层。TCP/IP协议族按层次分别分为5层: 应用层、传输层、网络层、数据链路层、物理层。 TCP/IP层次化的好处。 如果互联网只由一个协议统筹,某个地方需…

不动点定理的及其有趣应用

最近读高观点下的数学这本书,对书中介绍的布劳威尔不动点定理的有趣性质印象很深,原因是这个定理的某些性质能够解释我们生活中的一些常见现象,这里结合一个例题,聊以记录。 从一个数学题讲起: f(x)是定义在[0,1]上的…