首页 > 其他分享 >Android平台轻量级RTSP服务模块如何实现一个服务发布多路RTSP流?

Android平台轻量级RTSP服务模块如何实现一个服务发布多路RTSP流?

时间:2023-09-25 19:04:43浏览次数:33  
标签:RTSP handle libPublisher rtsp TAG publisherHandle Android 轻量级

我们在做Android平台轻量级RTSP服务和内网RTSP网关的时候,遇到过这样的问题,如何同时发布多路RTSP流出去?

回答这个问题,实际上不难,大牛直播SDK在设计这个模块的时候,考虑到了一个Service带多路流的情况,以下是大概的技术实现:

Android平台轻量级RTSP服务模块如何实现一个服务发布多路RTSP流?_RTSP转发

启动RTSP服务:

启动RTSP服务的时候,你可以注意到OpenRtspServer()会返回rtsp_handle_,这个句柄对应一个RTSP Service。

	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拉流URL)?

实际上,只要确保,每个发布的RTSP流,对应一个publisherHandle,音视频数据投递,也是传递这个publisherHandle。

	private boolean StartRtspStream(long publisherHandle, String rtsp_stream_name)
	{
		if (isRTSPPublisherRunning)
			return false;

		libPublisher.SetRtspStreamName(publisherHandle, rtsp_stream_name);
		libPublisher.AddRtspStreamServer(publisherHandle, rtsp_handle_, 0);

		if (libPublisher.StartRtspStream(publisherHandle, 0) != 0)
		{
			Log.e(TAG, "调用发布rtsp流接口失败!");

			if (!isPushing)
			{
				libPublisher.SmartPublisherClose(publisherHandle);
				publisherHandle = 0;
			}

			return false;
		}

		isRTSPPublisherRunning = true;
		return true;
	}

停止发布RTSP流:

	//停止发布RTSP流
	private void stopRtspPublisher(long publisherHandle)
	{
		if(!isRTSPPublisherRunning)
			return;

		isRTSPPublisherRunning = false;

		if (null == libPublisher || 0 == publisherHandle)
			return;

		libPublisher.StopRtspStream(publisherHandle);

		if (!isPushing && !isRTSPServiceRunning)
		{
			releasePublisherHandle();
		}
	}

每一路发布的RTSP流,都对应一个event回调,回上来外部可以拉流的RTSP URL:

	class EventHandlePublisherV2 implements NTSmartEventCallbackV2 {
		@Override
		public void onNTSmartEventCallbackV2(long handle, int id, long param1, long param2, String param3, String param4, Object param5) {

			Log.i(TAG, "EventHandlePublisherV2: handle=" + handle + " id:" + id);

			String publisher_event = "";

			switch (id) {
				...
				case NTSmartEventID.EVENT_DANIULIVE_ERC_PUBLISHER_RTSP_URL:
					publisher_event = "RTSP服务URL: " + param3;
					break;
        ...
			}
		}
	}

如果需要获取单个Service的会话链接数:

	//获取RTSP会话数
	class ButtonGetRtspSessionNumbersListener implements OnClickListener {
		public void onClick(View v) {
			if (libPublisher != null && rtsp_handle_ != 0) {
				int session_numbers = libPublisher.GetRtspServerClientSessionNumbers(rtsp_handle_);

				Log.i(TAG, "GetRtspSessionNumbers: " + session_numbers);

				PopRtspSessionNumberDialog(session_numbers);
			}
		}
	};

以上是大概的设计思路,感兴趣的开发者可以参考。

标签:RTSP,handle,libPublisher,rtsp,TAG,publisherHandle,Android,轻量级
From: https://blog.51cto.com/daniusdk/7598069

相关文章

  • Android使用webview缓存
    //StringcacheDirPath=context.getFilesDir().getAbsolutePath()+"cache/";//getSettings().setAppCachePath(cacheDirPath);//1.设置缓存路径//getSettings().setAppCacheMaxSize(500*1024*1024);//2.设置缓存大小//getSettings().setAppCache......
  • Android EditText显示图标
    实现了要给带清除按钮的ClearEditText,但是无法显示图标<androidx.constraintlayout.widget.ConstraintLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center">......
  • WPF中以MVVM方式,实现RTSP视频播放
    前言视频播放在上位机开发中经常会遇到,基本上是两种常见的解决方案1.采用厂家提供的sdk和前端控件进行展示,常见的海康/大华都提供了相关sdk及文档2.开启相机onvif协议,捅过rtsp视频流进行播放,前端可以采用web方式,或者wpf中的视频控件进行展示。项目需求,决定了最终采用开启相机on......
  • Android 多选下拉框的简单实现
    1、布局文件(activity_dropdown.xml)<?xmlversion="1.0"encoding="utf-8"?><RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"to......
  • android驱动模块实现文件重定位
    编写驱动模块进行sys_call_tablehook替换sys_open和sys_openat系统调用为自定义函数,需要注意sys_call_table是只读的,修改前需要前修改其内存属性为可写。直接修改内核源码,并编写驱动模块实现filterfunction进行过滤。sys_call_tablehook只能对系统调用函数进行hook。而第......
  • R3300L, Q7 ATV Android9固件
    R3300L,Q7ATVAndroid9固件固件来源https://www.znds.com/tv-1239603-1-1.html之前在恩山上发布过1080p安卓6固件https://www.right.com.cn/forum/thread-1761250-1-1.html,这个固件的不足之处就是没有GoogleServiceFramework,只能通过SmartYoutube之类的第三方APP......
  • Android 9关机流程
    一、整体关机流程framework->init->kernel二、关机流程(代码)本文基于Android9,梳理下正常power键触发的关机流程。涉及的相关代码路径如下://frameworkframeworks\base\core\res\res\values\config.xmlframeworks\base\services\core\java\com\android\server\policy\LegacyG......
  • 过来Android码农提醒,不要有面试就去,可能会白跑一趟
    前言亲身经历!!面试失败总结(它失败,我也不想要的那种)正值毕业季,毕业生开始走向求职之路,大量求职者随之而来。再加上现在正值金九银十招聘的火热阶段。找工作的都知道,工作成功的最后一步是面试,所以很多求职者都选择有面试就去,这是不可取的。就拿本人最近的面试来说,通勤一个小时,明明之前......
  • Android程序员35岁的职业出路:寻找新的舞台
    前言转眼间已经到了奔四的年纪,岁月匆匆,时光荏苒,转眼间已经在Android行业干了8年,当前项目组也陆陆续续进入了不少00后,80后已经不见踪影,90后正在逐渐淡出,而我,也要开始迎接程序员35岁这个坎,心里还是想要继续做技术这条路,但是也给自己思索了一些转行之路,在此跟大家交流交流。为什么35岁......
  • Android DataBinding——导入以及生成的绑定类
    导入DataBinding库提供了导入、变量和include等功能。导入可以方便在引用布局文件中引用类;变量允许您描述可在绑定表达式中使用的属性;Includes允许您在整个应用程序中重用复杂的布局。ImportsImports允许您轻松地在布局文件中的引用类,就像在代码中一样。data元素内部可以使用零个或......