低空经济与具身智能背后的“天眼”:超低延迟RTMP|RTSP播放技术全解析

50 阅读16分钟

摘要: 随着2024年“低空经济”首次写入政府工作报告,以及“具身智能”成为AI领域的下一个高地,实时视频传输技术正面临前所未有的挑战。无人机的高速巡检、机器人的远程遥操作(Teleoperation),都对视频流的延迟提出了毫秒级的苛刻要求。本文将结合行业趋势,深度剖析基于大牛直播SDK(SmartMediakit)的超低延迟RTMP/RTSP播放器技术,探讨如何在弱网环境下实现“所见即所得”的极致视觉反馈。

一、 引言:当“看见”成为控制的瓶颈

在传统的视频直播场景(如电商带货、赛事直播)中,3秒甚至5秒的延迟是可以被接受的。然而,在低空经济(无人机物流、应急救援)和具身智能(人形机器人、远程医疗)场景下,视频不仅仅是内容,更是传感器数据

​编辑

  • 无人机场景:当无人机以50km/h的速度飞行时,1秒的图像延迟意味着飞手看到的画面是14米之前的位置。这对于超视距飞行(BVLOS)是致命的安全隐患。

  • 具身智能场景:在远程操控机器人排爆或手术时,如果手部动作与视觉反馈不同步,操作者会产生严重的眩晕感(VR晕动症),且无法完成精细操作。

行业共识是:端到端延迟(Glass-to-Glass Latency)必须控制在200ms以内,甚至更低,才能满足实时操控的需求。

二、 通用协议的困境与大牛直播SDK的破局

目前主流的流媒体协议中,HLS/DASH延迟过高(10s+),WebRTC虽然延迟低但部署复杂且很难兼容传统的安防/广电架构。RTMPRTSP依然是目前工业界、安防界最成熟、兼容性最好的选择。

然而,开源播放器(如FFmpeg命令行、VLC、IJKPlayer默认配置)在处理这两个协议时,通常会有几秒的缓存。

大牛直播SDK(SmartPlayer)的核心价值在于:在保持RTMP/RTSP标准协议兼容性的前提下,通过自研的各种策略,将延迟压榨到了极致(100-200ms)。

核心技术点解析

  1. 极速Jitter Buffer策略 传统播放器为了抗抖动,会预设较大的Buffer。大牛直播SDK采用了动态Buffer策略,在网络良好的情况下,可以配置为0缓冲模式,数据收到即解码,解码即渲染,实现真正的实时播放。

  2. 多路H.265硬件解码 低空经济和机器人往往依赖4K甚至8K的高清图像来识别细节。SDK支持Android/iOS/Windows全平台的H.265硬解。不仅降低了CPU占用和设备发热(对电池供电的无人机至关重要),还能在同等画质下比H.264节省的带宽。

  3. 追帧与丢帧算法 在弱网环境下,累积延迟是最大的敌人。SDK内置了智能的追帧逻辑:当检测到网络拥塞导致缓存堆积时,播放器会策略性地丢弃非关键帧(P帧),加速解码播放,确保当前看到的画面是最新的,而不是几秒前的“历史”。

  4. RTSP的TCP/UDP自动切换 针对无人机图传经常面临的链路干扰,SDK支持RTSP over TCP(抗丢包,更稳定)和UDP(低延迟,更激进)模式,并支持组播技术,适应复杂的内网分发场景。

SmartMediakit 的设计理念总结

传统播放器

SmartPlayer

“内容播放”

“实时决策反馈”

稳定优先

延迟优先(在稳定范围内)

防卡顿靠加长缓存

防卡顿靠智能追帧与传输调优

默认直播配置

面向工业生产的实时渲染链路

一句话总结:

RTSP/RTMP 不是问题
播放器才是整个实时链路的命门
SmartPlayer,让它变成系统最坚实的一环

Windows平台 RTSP vs RTMP播放器延迟大比拼

三、 场景实战:低空经济与具身智能的落地

​编辑

1. 无人机城市空中交通(UAM)与巡检

在城市楼宇间穿梭的物流无人机,面临复杂的电磁干扰和遮挡。

  • 推流端:利用大牛直播SDK的轻量级RTSP/RTMP推送端,直接采集无人机机载摄像头(HDMI/SDI转IP)数据,进行H.265编码。

  • 播放端:地面站控制台集成SmartPlayer。

  • 关键配置:开启LowLatencyMode,设置缓冲时间为0。

  • 效果:飞手推杆加速,画面几乎同步发生变化,延迟感微乎其微。

2. 具身智能机器人的“千里眼”

假设我们在北京,需要操控一台位于深圳的数据中心巡检机器人。

  • 架构:机器人内部运行Linux ARM工控机,运行RTSP服务模块。

  • 传输:通过5G切片网络或SD-WAN回传。

  • 双向语音:大牛直播SDK不仅支持视频低延迟,还支持双向实时语音通话。操作员不仅能看到现场,还能听到现场设备的异响,并实时喊话指挥。这一特性对于具身智能的“交互性”至关重要。

3.为什么这类行业对播放器能力有“刚性依赖”

指标影响

UAM无人机

具身智能机器人

延迟偏高(300ms+)

误差增大 → 失控风险

指令滞后 → 机械臂危险动作

弱网抗性不足

花屏/卡顿 → 飞行风险

画面不同步 → 错误判断

无双向音视频能力

无法本地协作

无法反馈环境声学信息

SmartMediakit在这些核心指标上均提供工程化保障
确保遥操作不是“希望能行”,而是“必须能行”

Android平台RTSP播放器时延测试

四、 核心代码逻辑示例(Android端为例)

要实现超低延迟,单纯引入SDK是不够的,关键在于参数的配置。以下是基于大牛直播SDK实现低延迟播放的关键代码逻辑(Java):

onCreate()时,先new SmartPlayerJniV2():

/*
 * SmartPlayer.java
 * Author: daniusdk.com
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_smart_player);
	
	...

    libPlayer = new SmartPlayerJniV2();
    myContext = this.getApplicationContext();
}

开始播放、停止播放实现,开始播放的时候,调用InitAndSetConfig(),完成常规参数初始化,然后调用仅播放相关的其他接口。

btnStartStopPlayback.setOnClickListener(new Button.OnClickListener() {

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

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

			int iRet = libPlayer.SmartPlayerStopPlay(playerHandle);

			if (iRet != 0) {
				Log.e(TAG, "Call SmartPlayerStopPlay failed..");
				return;
			}

			btnHardwareDecoder.setEnabled(true);
			btnLowLatency.setEnabled(true);

			if (!isRecording) {
				btnPopInputUrl.setEnabled(true);
				btnSetPlayBuffer.setEnabled(true);
				btnFastStartup.setEnabled(true);

				btnRecoderMgr.setEnabled(true);
				libPlayer.SmartPlayerClose(playerHandle);
				playerHandle = 0;
			}

			isPlaying = false;
			btnStartStopPlayback.setText("开始播放 ");

			if (is_enable_hardware_render_mode && sSurfaceView != null) {
				sSurfaceView.setVisibility(View.GONE);
				sSurfaceView.setVisibility(View.VISIBLE);
			}

			Log.i(TAG, "Stop playback stream--");
		} else {
			Log.i(TAG, "Start playback stream++");

			if (!isRecording) {
				InitAndSetConfig();
			}

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

			libPlayer.SmartPlayerSetRenderScaleMode(playerHandle, 1);

			//int render_format = 1;
			//libPlayer.SmartPlayerSetSurfaceRenderFormat(playerHandle, render_format);

			//int is_enable_anti_alias = 1;
			//libPlayer.SmartPlayerSetSurfaceAntiAlias(playerHandle, is_enable_anti_alias);

			if (isHardwareDecoder && is_enable_hardware_render_mode) {
				libPlayer.SmartPlayerSetHWRenderMode(playerHandle, 1);
			}

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

			libPlayer.SmartPlayerSetUserDataCallback(playerHandle, new UserDataCallback());
			//libPlayer.SmartPlayerSetSEIDataCallback(playerHandle, new SEIDataCallback());

			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.SmartPlayerSetFlipVertical(playerHandle, is_flip_vertical ? 1 : 0);

			libPlayer.SmartPlayerSetFlipHorizontal(playerHandle, is_flip_horizontal ? 1 : 0);

			libPlayer.SmartPlayerSetRotation(playerHandle, rotate_degrees);

			libPlayer.SmartPlayerSetAudioVolume(playerHandle, curAudioVolume);

			int iPlaybackRet = libPlayer
					.SmartPlayerStartPlay(playerHandle);

			if (iPlaybackRet != 0) {
				Log.e(TAG, "Call SmartPlayerStartPlay failed..");
				return;
			}

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

			btnPopInputUrl.setEnabled(false);
			btnPopInputKey.setEnabled(false);
			btnSetPlayBuffer.setEnabled(false);
			btnLowLatency.setEnabled(false);
			btnFastStartup.setEnabled(false);
			btnRecoderMgr.setEnabled(false);

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

由于RTSP、RTMP播放模块,除了常规的直播播放外,也可能录像、或者实时拉流转发到RTMP服务器或轻量级RTSP服务,所以,和录像、转发相关的播放端基础参数配置,放到InitAndSetConfig()实现:

private void InitAndSetConfig() {
	playerHandle = libPlayer.SmartPlayerOpen(myContext);

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

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

	libPlayer.SmartPlayerSetBuffer(playerHandle, playBuffer);

	// set report download speed(默认2秒一次回调 用户可自行调整report间隔)
	libPlayer.SmartPlayerSetReportDownloadSpeed(playerHandle, 1, 2);

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

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

	//设置RTSP TCP/UDP模式自动切换
	int is_auto_switch_tcp_udp = 1;
	libPlayer.SmartPlayerSetRTSPAutoSwitchTcpUdp(playerHandle, is_auto_switch_tcp_udp);

	libPlayer.SmartPlayerSaveImageFlag(playerHandle, 1);

	// It only used when playback RTSP stream..
	// libPlayer.SmartPlayerSetRTSPTcpMode(playerHandle, 1);

	// playbackUrl = "rtmp://localhost:1935/live/stream1";

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

	libPlayer.SmartPlayerSetUrl(playerHandle, playbackUrl);
	// try_set_rtsp_url(playbackUrl);
}

EventHandle播放端事件回调处理,是底层状态反馈非常重要的媒介,除了网络状态、buffering状态回调外、还有录像状态、快照状态等回调:

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

		String player_event = "";

		switch (id) {
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:
				player_event = "开始..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:
				player_event = "连接中..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:
				player_event = "连接失败..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:
				player_event = "连接成功..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:
				player_event = "连接断开..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STOP:
				player_event = "停止播放..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:
				player_event = "分辨率信息: width: " + param1 + ", height: " + param2;
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:
				player_event = "收不到媒体数据,可能是url错误..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:
				player_event = "切换播放URL..";
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:
				player_event = "快照: " + param1 + " 路径:" + param3;

				if (param1 == 0)
					player_event = player_event + ", 截取快照成功";
				 else
					player_event = player_event + ", 截取快照失败";

				if (param4 != null && !param4.isEmpty())
					player_event += (", user data:" + param4);

				break;

			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:
				player_event = "[record]开始一个新的录像文件 : " + param3;
				break;
			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:
				player_event = "[record]已生成一个录像文件 : " + param3;
				break;

			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:
				Log.i(TAG, "Start Buffering");
				break;

			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:
				Log.i(TAG, "Buffering:" + param1 + "%");
				break;

			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:
				Log.i(TAG, "Stop Buffering");
				break;

			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:
				player_event = "download_speed:" + param1 + "Byte/s" + ", "
						+ (param1 * 8 / 1000) + "kbps" + ", " + (param1 / 1024)
						+ "KB/s";
				break;

			case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RTSP_STATUS_CODE:
				Log.e(TAG, "RTSP error code received, please make sure username/password is correct, error code:" + param1);
				player_event = "RTSP error code:" + param1;
				break;
		}

		if (player_event.length() > 0) {
			Log.i(TAG, player_event);
			Message message = new Message();
			message.what = PLAYER_EVENT_MSG;
			message.obj = player_event;
			handler.sendMessage(message);
		}
	}
}

如果RTSP、RTMP流需要录像:

btnStartStopRecorder.setOnClickListener(new Button.OnClickListener() {

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

		if (isRecording) {

			int iRet = libPlayer.SmartPlayerStopRecorder(playerHandle);

			if (iRet != 0) {
				Log.e(TAG, "Call SmartPlayerStopRecorder failed..");
				return;
			}

			if (!isPlaying) {
				btnPopInputUrl.setEnabled(true);
				btnSetPlayBuffer.setEnabled(true);
				btnFastStartup.setEnabled(true);
				btnRecoderMgr.setEnabled(true);

				libPlayer.SmartPlayerClose(playerHandle);
				playerHandle = 0;
			}

			btnStartStopRecorder.setText(" 开始录像");

			isRecording = false;
		} else {
			Log.i(TAG, "onClick start recorder..");

			if (!isPlaying) {
				InitAndSetConfig();
			}

			ConfigRecorderFunction();

			int startRet = libPlayer.SmartPlayerStartRecorder(playerHandle);

			if (startRet != 0) {
				Log.e(TAG, "Failed to start recorder.");
				return;
			}

			btnPopInputUrl.setEnabled(false);
			btnSetPlayBuffer.setEnabled(false);
			btnFastStartup.setEnabled(false);
			btnRecoderMgr.setEnabled(false);

			isRecording = true;
			btnStartStopRecorder.setText("停止录像");
		}
	}
});

其中,录像参数配置选项设置如下,除了下面演示接口外,还可以设置仅录视频或音频:

void ConfigRecorderFunction() {
	if (libPlayer != null) {
		int is_rec_trans_code = 1;
		libPlayer.SmartPlayerSetRecorderAudioTranscodeAAC(playerHandle, is_rec_trans_code);

		if (recDir != null && !recDir.isEmpty()) {
			int ret = libPlayer.SmartPlayerCreateFileDirectory(recDir);
			if (0 == ret) {
				if (0 != libPlayer.SmartPlayerSetRecorderDirectory(
						playerHandle, recDir)) {
					Log.e(TAG, "Set recoder dir failed , path:" + recDir);
					return;
				}

				if (0 != libPlayer.SmartPlayerSetRecorderFileMaxSize(
						playerHandle, 200)) {
					Log.e(TAG,
							"SmartPublisherSetRecorderFileMaxSize failed.");
					return;
				}

			} else {
				Log.e(TAG, "Create recorder dir failed, path:" + recDir);
			}
		}
	}
}

如需播放过程中实时截图:

btnCaptureImage.setOnClickListener(new Button.OnClickListener() {
	@SuppressLint("SimpleDateFormat")
	public void onClick(View v) {
		if (0 == playerHandle)
			return;

		if (null == capture_image_date_format_)
			capture_image_date_format_ = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS");

		String timestamp = capture_image_date_format_.format(new Date());
		String imageFileName = timestamp;

		String image_path = imageSavePath + "/" + imageFileName;

		int quality;
		boolean is_jpeg = true;
		if (is_jpeg) {
			image_path += ".jpeg";
			quality = 100;
		}
		else {
			image_path += ".png";
			quality = 100;
		}

		int capture_ret = libPlayer.CaptureImage(playerHandle,is_jpeg?0:1, quality, image_path, "test cix");
		Log.i(TAG, "capture image ret:" + capture_ret + ", file:" + image_path);
	}
});

如需对视频view做水平、垂直翻转或旋转:

btnFlipVertical.setOnClickListener(new Button.OnClickListener() {
	public void onClick(View v) {
		is_flip_vertical = !is_flip_vertical;

		if (is_flip_vertical) {
			btnFlipVertical.setText("取消反转");
		} else {
			btnFlipVertical.setText("垂直反转");
		}

		if (playerHandle != 0) {
			libPlayer.SmartPlayerSetFlipVertical(playerHandle,
					is_flip_vertical ? 1 : 0);
		}
	}
});

btnFlipHorizontal.setOnClickListener(new Button.OnClickListener() {
	public void onClick(View v) {
		is_flip_horizontal = !is_flip_horizontal;

		if (is_flip_horizontal) {
			btnFlipHorizontal.setText("取消反转");
		} else {
			btnFlipHorizontal.setText("水平反转");
		}

		if (playerHandle != 0) {
			libPlayer.SmartPlayerSetFlipHorizontal(playerHandle,
					is_flip_horizontal ? 1 : 0);
		}
	}
});

btnRotation.setOnClickListener(new Button.OnClickListener() {
	public void onClick(View v) {

		rotate_degrees += 90;
		rotate_degrees = rotate_degrees % 360;

		if (0 == rotate_degrees) {
			btnRotation.setText("旋转90度");
		} else if (90 == rotate_degrees) {
			btnRotation.setText("旋转180度");
		} else if (180 == rotate_degrees) {
			btnRotation.setText("旋转270度");
		} else if (270 == rotate_degrees) {
			btnRotation.setText("不旋转");
		}

		if (playerHandle != 0) {
			libPlayer.SmartPlayerSetRotation(playerHandle,
					rotate_degrees);
		}
	}
});

onDestroy() 的时候,停掉播放、录像、释放播放端实例句柄:

@Override
protected void onDestroy() {
	Log.i(TAG, "Run into activity destory++");

	if (playerHandle != 0) {
		if (isPlaying) {
			libPlayer.SmartPlayerStopPlay(playerHandle);
		}

		if (isRecording) {
			libPlayer.SmartPlayerStopRecorder(playerHandle);
		}

		libPlayer.SmartPlayerClose(playerHandle);
		playerHandle = 0;
	}
	super.onDestroy();
	finish();
	System.exit(0);
}

Android平台RTMP直播播放器延迟测试

接口设计

Android RTSP|RTMP播放端SDK接口详解

调用描述

接口

接口描述

最先调用,如成功返回播放********实例

SmartPlayerOpen

player初始化,设置上下文信息,返回player句柄

Event回调

SetSmartPlayerEventCallbackV2

设置event callback

硬解码设置****(H.264********)****

SetSmartPlayerVideoHWDecoder

设置是否用H.264硬解码播放,如硬解码不支持,自动适配到软解码

硬解码设置****(H.265********)****

SetSmartPlayerVideoHevcHWDecoder

设置是否用H.265硬解码播放,如硬解码不支持,自动适配到软解码

视频画面

填充模式

SmartPlayerSetRenderScaleMode

设置视频画面的填充模式,如填充整个view、等比例填充view,如不设置,默认填充整个view

设置SurfaceView模式下render类型

SmartPlayerSetSurfaceRenderFormat

设置SurfaceView模式下(NTRenderer.CreateRenderer第二个参数传false的情况),render类型

0: RGB565格式,如不设置,默认此模式; 1: ARGB8888格式

设置SurfaceView模式下抗锯齿效果

SmartPlayerSetSurfaceAntiAlias

设置SurfaceView模式下(NTRenderer.CreateRenderer第二个参数传false的情况),抗锯齿效果,注意:抗锯齿模式开启后,可能会影像性能,请慎用

设置播放的surface

SmartPlayerSetSurface

设置播放的surface,如果为null,则播放纯音频

设置********视频硬解码下Mediacodec自行绘制模式

SmartPlayerSetHWRenderMode

此种模式下,硬解码兼容性和效率更好,回调YUV/RGB****、快照和图像等比例缩放********功能将不可用****

更新硬解码surface

SmartPlayerUpdateHWRenderSurface

设置更新硬解码surface

音频回调

YUV/RGB

SmartPlayerSetExternalRender

提供解码后YUV/RGB数据接口,供用户自己render或进一步处理(如视频分析)

Audio

SmartPlayerSetExternalAudioOutput

回调audio数据到上层(供二次处理之用)

audio输出类型

SmartPlayerSetAudioOutputType

如果use_audiotrack设置为0,将会自动选择输出设备,如果设置为1,使用audiotrack模式,一对一回音消除模式下,请选用audiotrack模式

Video输出类型

NTRenderer.CreateRenderer(上层demo内)

第二个参数,如果是true,用openGLES绘制,false则用默认surfaceView

播放模式

缓冲时间设置

SmartPlayerSetBuffer

设置播放端缓存数据buffer,单位:毫秒,如不需buffer,设置为0

首屏秒开

SmartPlayerSetFastStartup

设置快速启动后,如果CDN缓存GOP,实现首屏秒开

低延迟模式

SmartPlayerSetLowLatencyMode

针对类似于直播娃娃机等期待超低延迟的使用场景,超低延迟播放模式下,延迟可达到200~400ms

快速切换URL

SmartPlayerSwitchPlaybackUrl

快速切换播放url,快速切换时,只换播放source部分,适用于不同数据流之间,快速切换(如娃娃机双摄像头切换或高低分辨率流切换)

RTSP TCP/UDP模式设置

SmartPlayerSetRTSPTcpMode

设置RTSP TCP/UDP模式,如不设置,默认UDP模式

RTSP超时时间设置

SmartPlayerSetRTSPTimeout

设置RTSP超时时间,timeout单位为秒,必须大于0

设置RTSP TCP/UDP自动切换

SmartPlayerSetRTSPAutoSwitchTcpUdp

对于RTSP来说,有些可能支持rtp over udp方式,有些可能支持使用rtp over tcp方式

为了方便使用,有些场景下可以开启自动尝试切换开关, 打开后如果udp无法播放,sdk会自动尝试tcp, 如果tcp方式播放不了,sdk会自动尝试udp.

设置RTSP用户名和密码

SetRTSPAuthenticationInfo

如果RTSP URL已包含用户名和密码, 此接口设置的用户名和密码将无效. 就是说要用这个接口设置的用户名和密码去做认证, RTSP URL不能包含用户名和密码.

实时静音

SmartPlayerSetMute

实时静音

设置播放音量

SmartPlayerSetAudioVolume

播放端音量实时调节,范围[0,100],0时为静音,100为原始流数据最大音量

设置是否禁用 Enhanced

RTMP

DisableEnhancedRTMP

disable enhanced RTMP, SDK默认是开启enhanced RTMP的

实时截图

CaptureImage

支持JPEG和PNG两种格式

视频镜像旋转

旋转

SmartPlayerSetRotation

设置顺时针旋转, 注意除了0度之外, 其他角度都会额外消耗性能,当前支持 0度,90度, 180度, 270度 旋转

水平反转

SmartPlayerSetFlipHorizontal

设置视频水平反转

垂直反转

SmartPlayerSetFlipVertical

设置视频垂直反转

设置URL

SmartPlayerSetUrl

设置需要播放或录像的RTMP/RTSP url

开始播放

SmartPlayerStartPlay

开始播放RTSP/RTMP流

停止播放

SmartPlayerStopPlay

停止播放RTSP/RTMP流

关闭播放实例

SmartPlayerClose

结束时必须调用close接口释放资源

功能支持

  • 音频:AAC/Speex(RTMP)/PCMA/PCMU;
  • 视频:H.264、H.265;
  • 播放协议:RTSP|RTMP;
  • 支持纯音频、纯视频、音视频播放;
  • 支持多实例播放;
  • 支持软解码,特定机型硬解码;
  • 支持RTSP TCP、UDP模式设置;
  • 支持RTSP TCP、UDP模式自动切换;
  • 支持RTSP超时时间设置,单位:秒;
  • 支持buffer时间设置,单位:毫秒;
  • 支持超低延迟模式;
  • 支持断网自动重连、视频追赶,支持buffer状态等回调;
  • 支持视频view实时旋转(0° 90° 180° 270°);
  • 支持视频view水平反转、垂直反转;
  • 支持Surfaceview/OpenGL ES/TextureView绘制;
  • 支持视频画面填充模式设置;
  • 音频支持AudioTrack、OpenSL ES模式;
  • 支持jpeg、png实时截图;
  • 支持实时音量调节;
  • 支持解码前音视频数据回调;
  • 支持解码后YUV/RGB数据回调;
  • 支持Enhanced RTMP;
  • 支持扩展录像功能;
  • 支持Android 5.1及以上版本。

iOS平台RTMP播放器时延测试

五、总结与展望

低空经济的崛起与具身智能的发展,本质上正在推动 物理世界与智能系统的深度耦合。在这一进化过程中,视频已经从“呈现内容”转变为感知输入与操控反馈的核心数据通道

视频不再是给人看的,而是给动作和决策用的。

基于大牛直播SDK构建的超低延迟音视频链路,在采集、编码、传输、解码、渲染的全路径上做了工程化优化,补齐了传统系统的“最后一公里”。它不仅是播放器,更是:

  • 远程指令的闭环起点

  • 智能操控系统的视觉神经末梢

  • 人与机器之间的实时共感界面

未来,随着空间计算、边缘AI、5G/卫星通信持续演进,毫秒级延迟将成为具身智能时代的基础设施门槛。能否稳定做到低延迟,决定的是:

  • 控制系统是否可商用

  • 智能体是否真正可执行任务

  • 人与机器人是否能实现无违和协同

因此,对于开发者而言,掌握高可靠、低延迟的视频链路技术,不仅是技术选型问题,更是下一代产业竞争力的底层武器

抢占实时视频链路,就是提前进入未来的入口。