rtsp 直播推流
一、概述
rtsp 是合宙 LuatOS 的 RTSP 推流核心库,作用是把 H.264 编码的视频帧按 RTP 打包后推送到 RTSP 服务器(如合宙 RTMP/RTSP 测试服务器、自建流媒体服务),常用于摄像头模组的实时视频回传。
要点:
1、模块名为 rtsp,用法是先 rtsp.create(url) 得到上下文对象,再按 setCallback → connect → start 的顺序建立推流,之后循环调用 pushFrame 送帧;
2、只负责传输,不负责编码。SPS/PPS 需要自己从编码器取到,用 setSPS/setPPS 告知库,视频帧必须是 H.264 的 NALU 数据;
3、连接过程是异步的,connect() 返回 true 只代表请求已提交,真正的结果要看状态回调或 getState();
4、非 PLAYING 状态下调用 pushFrame 的帧会被直接丢弃并返回 0,所以送帧要等状态变成 rtsp.STATE_PLAYING 之后再开始。
⚠️ 该库需要固件在编译时打开 RTSP 组件(源码标记
LUAT_USE_RTSP)。如果脚本里rtsp为 nil,说明当前固件没有包含该库,需要向对接 FAE 确认固件版本。⚠️ 源码注释里出现的
rtsp:setFECParam并未在注册表中导出,调用会直接报 nil,请勿使用。
二、核心示例
-- 前提:已通过摄像头与 H.264 编码拿到 SPS/PPS 与视频帧
local rtsp = rtsp.create("rtsp://example.com:554/stream")
if not rtsp then
log.error("rtsp", "上下文创建失败")
return
end
-- 状态回调:只有 state 一个参数
rtsp:setCallback(function(state)
log.info("rtsp state", state)
end)
-- 传输模式:局域网用 udp,公网建议 tcp
rtsp:setTransportMode("tcp")
-- 告知库 SPS/PPS(从编码器取到的 NALU 数据)
rtsp:setSPS(sps_data)
rtsp:setPPS(pps_data)
-- 连接并启动事件轮询
rtsp:connect()
rtsp:start()
-- 等进入推流状态后再送帧
sys.waitUntil("RTSP_PLAYING", 10000)
while true do
local frame, is_key = get_h264_frame() -- 业务侧取帧
if frame then
local ret = rtsp:pushFrame(frame, mcu.ticks() % 0x100000000)
if ret < 0 then
log.warn("rtsp", "推帧失败", ret)
end
end
sys.wait(40)
end
-- 结束:先停轮询,再断开,最后销毁
rtsp:stop()
rtsp:disconnect()
rtsp:destroy()
三、常量详解
3.1 状态常量
| 常量 | 值 | 含义 |
|---|---|---|
rtsp.STATE_IDLE |
0 | 空闲 |
rtsp.STATE_CONNECTING |
1 | 正在连接 |
rtsp.STATE_OPTIONS |
2 | 已发 OPTIONS 请求 |
rtsp.STATE_DESCRIBE |
3 | 已发 DESCRIBE 请求 |
rtsp.STATE_SETUP |
4 | 已发 SETUP 请求 |
rtsp.STATE_PLAY |
5 | 已发 PLAY 请求,准备推流 |
rtsp.STATE_PLAYING |
6 | 正在推流(可以送帧) |
rtsp.STATE_DISCONNECTING |
7 | 正在断开 |
rtsp.STATE_ERROR |
8 | 出错 |
说明:注册表里没有“已连接”语义的状态常量(源码注释里出现过这个名字,但并未导出,属笔误),判断连上要用 rtsp.STATE_PLAYING 或 rtsp.STATE_PLAY,照抄注释里的写法会拿到 nil。
3.2 返回值常量
| 常量 | 含义 |
|---|---|
rtsp.OK |
成功 |
rtsp.ERR_FAILED |
一般性失败 |
rtsp.ERR_INVALID_PARAM |
参数非法(如帧长度为 0 或超过 1MB) |
rtsp.ERR_NO_MEMORY |
内存不足 |
rtsp.ERR_CONNECT_FAILED |
连接失败 |
rtsp.ERR_HANDSHAKE_FAILED |
握手(OPTIONS/DESCRIBE/SETUP)失败 |
rtsp.ERR_NETWORK |
网络错误 |
rtsp.ERR_TIMEOUT |
超时 |
rtsp.ERR_BUFFER_OVERFLOW |
缓冲区溢出 |
pushFrame 失败时返回的是这些负值,可以直接和常量比较。
3.3 传输模式常量
| 常量 | 值 | 适用场景 |
|---|---|---|
rtsp.TRANSPORT_UDP |
0 | 默认值,局域网、丢包少的链路,延迟最低 |
rtsp.TRANSPORT_TCP |
1 | 公网、NAT 后面、丢包多的链路,靠 TCP 重传保证完整 |
rtsp.TRANSPORT_UDP_FEC |
2 | UDP 加前向纠错,兼顾延迟与抗丢包 |
四、函数详解
rtsp.create(url)
功能
创建 RTSP 推流上下文。
参数
url
参数含义:RTSP 服务器地址;
数据类型:string;
取值范围:形如 rtsp://host:port/stream;
注意事项:必须带协议头 rtsp://,端口不写时由库按默认 554 处理;
参数示例:"rtsp://example.com:554/stream";
返回值
含义说明:RTSP 上下文对象;
数据类型:userdata;
取值范围:创建成功返回上下文,内部申请内存失败或 URL 解析失败返回 nil;
注意事项:返回 nil 时不要再调用后续接口;
返回示例:userdata: 0x...
示例
local rtsp = rtsp.create("rtsp://example.com:554/stream")
if not rtsp then
log.error("rtsp", "create failed")
end
rtsp:setCallback(func)
功能
设置状态回调函数,状态变化时被调用。
参数
func
参数含义:回调函数;
数据类型:function 或 nil;
取值范围:nil 表示清除已设置的回调;
注意事项:回调只带一个参数 state,即第三章的状态常量;源码注释中的附加错误码参数目前不会传;
参数示例:function(state) end;
返回值
含义说明:是否设置成功;
数据类型:boolean;
取值范围:true / false;
注意事项:传入非 function 且非 nil 时返回 false;
返回示例:true;
示例
rtsp:setCallback(function(state)
if state == rtsp.STATE_PLAYING then
log.info("rtsp", "开始推流")
elseif state == rtsp.STATE_ERROR then
log.error("rtsp", "推流出错")
end
end)
rtsp:connect()
功能
向 RTSP 服务器发起连接,依次完成 OPTIONS、DESCRIBE、SETUP、PLAY 握手。
参数
nil
返回值
含义说明:连接请求是否成功提交;
数据类型:boolean;
取值范围:true / false;
注意事项:true 只代表请求已入队,不代表已连上;是否连上以状态回调或 getState 为准;
返回示例:true;
示例
if rtsp:connect() then
log.info("rtsp", "连接请求已提交")
end
rtsp:disconnect()
功能
断开与 RTSP 服务器的连接。
参数
nil
返回值
含义说明:断开是否成功;
数据类型:boolean;
取值范围:true / false;
注意事项:断开后状态回到空闲,需要重新连接才能再推流;
返回示例:true;
示例
rtsp:disconnect()
rtsp:start()
功能
启动 RTSP 事件轮询。库内部每 20ms 轮询一次协议状态机,必须调用它,协议才会向前推进。
参数
nil
返回值
nil
注意事项
1、start() 只是启动轮询,不会自己建连接,connect() 要在它之前或之后单独调用;
2、重复调用会重复注册定时器,正常用法是连接前后各调用一次即可,不要放在循环里。
示例
rtsp:start()
rtsp:stop()
功能
停止 RTSP 事件轮询,暂停协议处理。
参数
nil
返回值
nil
注意事项
1、只停轮询,不断开连接,也不释放资源;
2、停止后可以再调 start() 恢复。
示例
rtsp:stop()
rtsp:getState()
功能
获取当前 RTSP 状态。
参数
nil
返回值
含义说明:当前状态值;
数据类型:number;
取值范围:见第三章状态常量;上下文已失效时返回 -1;
注意事项:-1 不等于 STATE_ERROR,它表示对象已不可用;
返回示例:6;
示例
local state = rtsp:getState()
if state == rtsp.STATE_PLAYING then
log.info("rtsp", "正在推流")
end
rtsp:setSPS(sps_data)
功能
设置 H.264 的 SPS(序列参数集),DESCRIBE 阶段要用它生成 SDP。
参数
sps_data
参数含义:H.264 SPS 原始 NALU 数据;
数据类型:string;
取值范围:长度大于 0;
注意事项:要传编码器输出的原始字节,不要用十六进制字符串或 base64;典型以 0x67 开头;
参数示例:string.char(0x67, 0x42, ...);
返回值
含义说明:是否设置成功;
数据类型:boolean;
取值范围:true / false;
注意事项:上下文失效时返回 false;
返回示例:true;
示例
rtsp:setSPS(sps_data)
rtsp:setPPS(pps_data)
功能
设置 H.264 的 PPS(图像参数集)。
参数
pps_data
参数含义:H.264 PPS 原始 NALU 数据;
数据类型:string;
取值范围:长度大于 0;
注意事项:典型以 0x68 开头;SPS 与 PPS 都要设置,只设一个会导致服务器解不出画面;
参数示例:string.char(0x68, 0xCB, ...);
返回值
含义说明:是否设置成功;
数据类型:boolean;
取值范围:true / false;
注意事项:上下文失效时返回 false;
返回示例:true;
示例
rtsp:setPPS(pps_data)
rtsp:pushFrame(frame_data, timestamp)
功能
推送一帧 H.264 视频数据,库内部完成 RTP 打包与发送。
参数
frame_data
参数含义:H.264 编码的一帧数据;
数据类型:string;
取值范围:1 字节 ~ 1MB;
注意事项:超过 1MB 或长度为 0 直接返回 ERR_INVALID_PARAM;必须传入完整的 NALU(含起始码),不要自己切分包;
参数示例:frame_buf;
timestamp
参数含义:时间戳,单位毫秒;
数据类型:number;
取值范围:32 位无符号整数范围;
注意事项:可选,传 nil 或 0 时库内部自己取时间;同一路流必须单调递增,回绕时按 32 位取模;
参数示例:mcu.ticks() % 0x100000000;
返回值
含义说明:已发送的字节数;
数据类型:number;
取值范围:成功为非负字节数;失败为第三章的负值常量;
注意事项:状态还没到 STATE_PLAYING 时帧会被直接丢弃并返回 0,不报错,容易误判成推流正常;
返回示例:1432;
示例
local ret = rtsp:pushFrame(frame, mcu.ticks() % 0x100000000)
if ret == 0 then
log.warn("rtsp", "未进入推流状态,帧被丢弃")
elseif ret < 0 then
log.error("rtsp", "推帧失败", ret)
end
rtsp:getStats()
功能
获取推流统计信息。
参数
nil
返回值
含义说明:统计信息表;
数据类型:table;
取值范围:
{
bytes_sent, -- 已发送字节数
video_frames_sent, -- 已发送视频帧数
rtp_packets_sent, -- 已发送 RTP 包数
connection_time, -- 连接持续时长,单位毫秒
last_video_timestamp -- 最后一帧的时间戳,单位毫秒
}
注意事项:注意 connection_time 的单位是毫秒,不是秒;上下文失效时返回 nil;
返回示例:{bytes_sent=14320, video_frames_sent=10, rtp_packets_sent=12, connection_time=400, last_video_timestamp=392}
示例
local stats = rtsp:getStats()
if stats then
log.info("rtsp", "帧数", stats.video_frames_sent, "时长(ms)", stats.connection_time)
end
rtsp:getNetworkStats()
功能
获取网络质量统计,用于判断链路是否撑得住当前码率。
参数
nil
返回值
含义说明:网络统计信息表;
数据类型:table;
取值范围:
{
packet_loss_rate, -- 丢包率,0.0 ~ 1.0
rtt_ms, -- 往返延迟,毫秒
jitter_ms, -- 抖动,毫秒
bandwidth_kbps, -- 估算带宽,Kbps
rtp_packets_sent, -- 已发送 RTP 包数
rtp_packets_lost, -- 丢失的 RTP 包数
rtp_bytes_sent, -- 已发送 RTP 字节数
rtp_packets_retransmitted, -- 重传的 RTP 包数
rtp_nack_received -- 收到的 NACK 请求数
}
注意事项:取不到统计时返回 nil,调用前先判空;
返回示例:{packet_loss_rate=0.012, rtt_ms=48, jitter_ms=7, bandwidth_kbps=1200, ...}
示例
local ns = rtsp:getNetworkStats()
if ns then
log.info("rtsp", "丢包率", ns.packet_loss_rate, "RTT", ns.rtt_ms)
end
rtsp:setNetworkStatsCallback(func)
功能
设置网络统计回调。当前版本尚未实现,接口保留但不会生效。
参数
func
参数含义:回调函数;
数据类型:function;
取值范围:任意 function;
注意事项:目前传入任何值都只打印一条“暂未实现”的告警;
返回值
含义说明:是否设置成功;
数据类型:boolean;
取值范围:当前恒为 false;
注意事项:需要网络质量数据请改用 getNetworkStats 轮询;
返回示例:false;
示例
-- 当前不生效,仅作占位;周期读取更可靠
if not rtsp:setNetworkStatsCallback(function(stats) end) then
sys.timerLoopStart(function()
local ns = rtsp:getNetworkStats()
if ns then log.info("rtsp", "loss", ns.packet_loss_rate) end
end, 5000)
end
rtsp:setTransportMode(mode)
功能
设置 RTP 的传输模式。
参数
mode
参数含义:传输模式;
数据类型:string;
取值范围:只接受 "udp"、"tcp"、"udp_fec" 三个字符串,大小写敏感;
注意事项:传其它字符串会打印错误并返回 false;需要在 connect 之前设置;
参数示例:"tcp";
返回值
含义说明:是否设置成功;
数据类型:boolean;
取值范围:true / false;
注意事项:上下文失效时无返回值(返回 nil);
返回示例:true;
示例
rtsp:setTransportMode("tcp") -- 公网推荐
rtsp:setTransportMode("udp") -- 局域网推荐
rtsp:setTransportMode("udp_fec") -- 抗丢包折中
rtsp:destroy()
功能
销毁 RTSP 上下文,释放套接字、回调引用与缓冲区。
参数
nil
返回值
nil
注意事项
1、销毁后对象不可再用,要重新推流必须重新 create;
2、正常用法是 stop → disconnect → destroy,直接 destroy 也可以,内部会一并释放;
3、如果忘了调用,GC 时也会通过 __gc 回收,但回收时机不可控,建议显式销毁。
示例
rtsp:stop()
rtsp:disconnect()
rtsp:destroy()
rtsp = nil
五、产品支持说明
目前除 8101 系列外,其他合宙主流模组暂不支持 rtsp 核心库;即使同为 8101 系列,也需要固件在编译时包含 RTSP 组件(LUAT_USE_RTSP)。脚本里 rtsp 为 nil 即表示当前固件未包含,需向对接 FAE 确认固件版本。