摘要: 随着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虽然延迟低但部署复杂且很难兼容传统的安防/广电架构。RTMP 和RTSP依然是目前工业界、安防界最成熟、兼容性最好的选择。
然而,开源播放器(如FFmpeg命令行、VLC、IJKPlayer默认配置)在处理这两个协议时,通常会有几秒的缓存。
大牛直播SDK(SmartPlayer)的核心价值在于:在保持RTMP/RTSP标准协议兼容性的前提下,通过自研的各种策略,将延迟压榨到了极致(100-200ms)。
核心技术点解析
-
极速Jitter Buffer策略 传统播放器为了抗抖动,会预设较大的Buffer。大牛直播SDK采用了动态Buffer策略,在网络良好的情况下,可以配置为0缓冲模式,数据收到即解码,解码即渲染,实现真正的实时播放。
-
多路H.265硬件解码 低空经济和机器人往往依赖4K甚至8K的高清图像来识别细节。SDK支持Android/iOS/Windows全平台的H.265硬解。不仅降低了CPU占用和设备发热(对电池供电的无人机至关重要),还能在同等画质下比H.264节省的带宽。
-
追帧与丢帧算法 在弱网环境下,累积延迟是最大的敌人。SDK内置了智能的追帧逻辑:当检测到网络拥塞导致缓存堆积时,播放器会策略性地丢弃非关键帧(P帧),加速解码播放,确保当前看到的画面是最新的,而不是几秒前的"历史"。
-
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():
java
/*
* 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(),完成常规参数初始化,然后调用仅播放相关的其他接口。
java
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()实现:
java
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状态回调外、还有录像状态、快照状态等回调:
java
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流需要录像:
java
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("停止录像");
}
}
});
其中,录像参数配置选项设置如下,除了下面演示接口外,还可以设置仅录视频或音频:
java
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);
}
}
}
}
如需播放过程中实时截图:
java
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做水平、垂直翻转或旋转:
java
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() 的时候,停掉播放、录像、释放播放端实例句柄:
java
@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/卫星通信持续演进,毫秒级延迟将成为具身智能时代的基础设施门槛。能否稳定做到低延迟,决定的是:
-
控制系统是否可商用
-
智能体是否真正可执行任务
-
人与机器人是否能实现无违和协同
因此,对于开发者而言,掌握高可靠、低延迟的视频链路技术,不仅是技术选型问题,更是下一代产业竞争力的底层武器。
抢占实时视频链路,就是提前进入未来的入口。
📎 CSDN官方博客:音视频牛哥-CSDN博客