ffmpeg拉RTSP流转推RTMP服务器

整体设计

1. 拉流:通过RTSP|RTMP直播播放SDK的数据回调接口,拿到音视频数据;

2. 转推:通过RTMP直播推送SDK的编码后数据输入接口,把回调上来的数据,传给RTMP直播推送模块,实现RTSP|RTMP数据流到RTMP服务器的转发;

3. 录像:如果需要录像,借助RTSP|RTMP直播播放SDK,拉到音视频数据后,直接存储MP4文件即可;

4. 快照:如果需要实时快照,拉流后,解码调用播放端快照接口,生成快照,因为快照涉及到video数据解码.

Demo主要实现了以下几个功能点展示:

1. 设置RTMP、RTSP拉流的URL;

2. 设置转推RTMP的URL;

3. 实时播放|录像过程中,实时静音、实施快照;

4. 实时播放;

5. 实时录像;

6. 拉取的流数据,实时转推,对应“开始推流”;

7. 拉取的流数据,注入轻量级RTSP服务,启动服务后,发布RTSP流,对外提供可访问的RTSP URL。

注意:以上播放、录像、转推RTMP、注入轻量级RTSP服务四者是可单独工作,也可随时启动或停止相关功能,互不影响。

相关代码实现

开始拉流

拉流的目的,主要是启动数据回调,注意:拉流并不是直接播放出来窗口,只是拿数据,如果需要本地预览拉流数据,可以点击“开始播放”。

注意:“开始推流”和“发布RTSP流”之前,一定要先“开始拉流”,拿到音视频数据。

private boolean StartPull()
	{
		if ( isPulling )
			return false;

		if (!OpenPullHandle())
			return false;

		libPlayer.SmartPlayerSetAudioDataCallback(playerHandle, new PlayerAudioDataCallback());
		libPlayer.SmartPlayerSetVideoDataCallback(playerHandle, new PlayerVideoDataCallback());

		int is_pull_trans_code  = 1;
		libPlayer.SmartPlayerSetPullStreamAudioTranscodeAAC(playerHandle, is_pull_trans_code);

		int startRet = libPlayer.SmartPlayerStartPullStream(playerHandle);

		if (startRet != 0) {
			Log.e(TAG, "Failed to start pull stream!");

			if(!isPlaying && !isRecording && isPushing && !isRTSPPublisherRunning)
			{
				libPlayer.SmartPlayerClose(playerHandle);
				playerHandle = 0;
			}

			return false;
		}

		isPulling = true;
		return true;
	}

这里调到OpenPullHandle()封装,其实就是启动调研Player的Open()接口,获取到player handle,然后设置一下基础数据接口,比如event callback,buffer time,TCP/UDP模式、拉流的URL等;


private boolean OpenPullHandle()
	{
		if (playerHandle != 0) {
			return true;
		}

		playbackUrl = "rtsp://admin:daniulive12345@192.168.0.120:554/h265/ch1/main/av_stream";

		if (playbackUrl == null) {
			Log.e(TAG, "playback URL with NULL...");
			return false;
		}

		playerHandle = libPlayer.SmartPlayerOpen(myContext);

		if (playerHandle == 0) {
			Log.e(TAG, "playerHandle is nil..");
			return false;
		}

		libPlayer.SetSmartPlayerEventCallbackV2(playerHandle,
				new EventHandePlayerV2());

		libPlayer.SmartPlayerSetBuffer(playerHandle, playBuffer);

		// set report download speed
		// libPlayer.SmartPlayerSetReportDownloadSpeed(playerHandle, 1, 5);

		//设置RTSP超时时间
		int rtsp_timeout = 12;
		libPlayer.SmartPlayerSetRTSPTimeout(playerHandle, rtsp_timeout);

		//设置RTSP TCP/UDP模式自动切换
		int is_auto_switch_tcp_udp

停止拉流

private void StopPull()
	{
		if ( !isPulling )
			return;

		libPlayer.SmartPlayerStopPullStream(playerHandle);

		if ( !isPlaying && !isRecording && !isPushing && !isRTSPPublisherRunning)
		{
			libPlayer.SmartPlayerClose(playerHandle);
			playerHandle = 0;
		}

		isPulling = false;
	}

开始播放


private boolean StartPlay()
	{
		if (!OpenPullHandle())
			return false;

		// 如果第二个参数设置为null,则播放纯音频
		libPlayer.SmartPlayerSetSurface(playerHandle, sSurfaceView);

		libPlayer.SmartPlayerSetRenderScaleMode(playerHandle, 1);

		// External Render test
		// libPlayer.SmartPlayerSetExternalRender(playerHandle, new
		// RGBAExternalRender());
		// libPlayer.SmartPlayerSetExternalRender(playerHandle, new
		// I420ExternalRender());

		libPlayer.SmartPlayerSetFastStartup(playerHandle, isFastStartup ? 1 : 0);

		libPlayer.SmartPlayerSetAudioOutputType(playerHandle, 1);

		if (isMute) {
			libPlayer.SmartPlayerSetMute(playerHandle, isMute ? 1
					: 0);
		}

		if (isHardwareDecoder)
		{
			int isSupportHevcHwDecoder = libPlayer.SetSmartPlayerVideoHevcHWDecoder(playerHandle, 1);

			int isSupportH264HwDecoder = libPlayer
					.SetSmartPlayerVideoHWDecoder(playerHandle, 1);

			Log.i(TAG, "isSupportH264HwDecoder: " + isSupportH264HwDecoder + ", isSupportHevcHwDecoder: " + isSupportHevcHwDecoder);
		}

		libPlayer.SmartPlayerSetLowLatencyMode(playerHandle, isLowLatency ? 1
				: 0);

		libPlayer.SmartPlayerSetRotation(playerHandle, rotate_degrees);

		int iPlaybackRet = libPlayer
				.SmartPlayerStartPlay(playerHandle);

		if (iPlaybackRet != 0) {
			Log.e(TAG, "StartPlay failed!");

			if ( !isPulling && !isRecording && !isPushing && !isRTSPPublisherRunning)
			{
				libPlayer.SmartPlayerClose(playerHandle);
				playerHandle = 0;
			}

			return false;
		}

		isPlaying = true;
		return true;
	}

停止播放

private void StopPlay()
	{
		if ( !isPlaying )
			return;

		isPlaying = false;

		libPlayer.SmartPlayerStopPlay(playerHandle);

		if ( !isPulling && !isRecording && !isPushing && !isRTSPPublisherRunning)
		{
			libPlayer.SmartPlayerClose(playerHandle);
			playerHandle = 0;
		}
	}

开始录像


private boolean StartRecorder()
	{
		if (!OpenPullHandle())
			return false;

		ConfigRecorderFuntion();

		int iRecRet = libPlayer
				.SmartPlayerStartRecorder(playerHandle);

		if (iRecRet != 0) {
			Log.e(TAG, "StartRecorder failed!");

			if ( !isPulling &&!isPlaying && !isPushing && !isRTSPPublisherRunning)
			{
				libPlayer.SmartPlayerClose(playerHandle);
				playerHandle = 0;
			}

			return false;
		}

		isRecording = true;
		return true;
	}停止录像	private void StopRecorder()
	{
		if ( !isRecording )
			return;

		isRecording = false;

		libPlayer.SmartPlayerStopRecorder(playerHandle);

		if ( !isPlaying && !isPulling && !isPushing && !isRTSPPublisherRunning)
		{
			libPlayer.SmartPlayerClose(playerHandle);
			playerHandle = 0;
		}
	}

开始推流



private boolean StartPush()
	{
		if (isPushing)
			return false;

		relayStreamUrl = "rtmp://192.168.0.211:1935/hls/stream1";

		if (relayStreamUrl == null) {
			Log.e(TAG, "StartPush URL is null...");
			return false;
		}

		if (!OpenPushHandle())
			return false;

		if ( libPublisher.SmartPublisherSetURL(publisherHandle, relayStreamUrl) != 0 )
		{
			Log.e(TAG, "StartPush failed!");
		}

		int startRet = libPublisher.SmartPublisherStartPublisher(publisherHandle);
		if( startRet != 0)
		{
			Log.e(TAG, "Failed to call StartPublisher!");

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

			return false;
		}

		isPushing = true;

		return true;
	}

开始推流调到了OpenPushHandle()封装,具体代码如下:

private boolean OpenPushHandle()
	{
		if(publisherHandle != 0)
		{
			return true;
		}

		int audio_opt = 2;
		int video_opt = 2;

		int videoWidth = 640;
		int videoHeight  = 480;

		publisherHandle = libPublisher.SmartPublisherOpen(myContext, audio_opt

停止推流

public void StopPush()
	{
		if (!isPushing)
			return;

		isPushing = false;

		libPublisher.SmartPublisherStopPublisher(publisherHandle);

		if(!isRTSPPublisherRunning && !isRTSPServiceRunning)
		{
			libPublisher.SmartPublisherClose(publisherHandle);
			publisherHandle = 0;
		}
	}

启动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);

				//一般来说单播网络设备支持的好,wifi组播

停止RTSP服务

//停止RTSP服务
	private void stopRtspService() {
		if(!isRTSPServiceRunning)
			return;

		if (libPublisher != null && rtsp_handle_ != 0) {
			libPublisher.StopRtspServer(rtsp_handle_);
			libPublisher.CloseRtspServer(rtsp_handle_);
			rtsp_handle_ = 0;
		}

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

		isRTSPServiceRunning = false;
	}

开始发布RTSP



private boolean StartRtspStream()
	{
		if (isRTSPPublisherRunning)
			return false;

		String rtsp_stream_name = "stream1";
		libPublisher.SetRtspStreamName(publisherHandle, rtsp_stream_name);
		libPublisher.ClearRtspStreamServer(publisherHandle);

		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()
	{
		if(!isRTSPPublisherRunning)
			return;

		if (libPublisher != null) {
			libPublisher.StopRtspStream(publisherHandle);
		}

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

		isRTSPPublisherRunning = 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();
	}
//获取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);
			}
		}
	};




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值