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

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

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

启动RTSP服务:

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

ini 复制代码
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服务?

typescript 复制代码
//发布/停止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。

ini 复制代码
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流:

ini 复制代码
//停止发布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:

arduino 复制代码
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的会话链接数:

java 复制代码
//获取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);
			}
		}
	};

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

相关推荐
iOStanhaitao11 小时前
6.第一个c++安卓程序编译运行
音视频开发
音视频牛哥8 天前
不只是等待 IDR:SmartMediaKit 播放器对 H.264 GDR 码流的完整适配实践
音视频开发·视频编码·直播
三木彤15 天前
语音转文本python
音视频开发
鹧鸪晏19 天前
Android GLSurfaceView 完全指南
android·音视频开发
ltlovezh22 天前
AAC 元数据:ADTS 与 ASC 的区别、转换和常见坑
后端·ffmpeg·音视频开发
深念Y22 天前
我明白为什么B站没法在浏览器开直播了——Windows Chrome推流踩坑全记录
前端·chrome·webrtc·浏览器·srs·直播·flv
深念Y23 天前
仿B站直播功能技术选型:为什么必须用SRS而不是WebRTC P2P?
webrtc·srs·直播·推流·b站·多媒体·obs
MonkeyKing24 天前
iOS 音频实战:边播边缓存、预加载与断点续播完整实现
音视频开发
11年老程序猿在线搬砖24 天前
2026年语聊APP开发费用深度拆解:从MVP到百万并发的预算清单
音视频开发·创业·技术选型·社交app开发·语聊app·开发费用
深念Y1 个月前
网络多播与广播:到底能不能节省带宽和流量?
网络·直播·p2p·点对点·多播·流量·单播