26、直播流处理:RTMP/RTSP/HLS协议、拉流与推流、直播转码
说到直播流处理,这可能是音视频工程师日常工作中最「接地气」的一块了。我入行那会儿,直播还没现在这么火,但协议那套东西已经打得不可开交。RTMP、RTSP、HLS,这三个名字你肯定不陌生。它们各有各的脾气,也各有各的用武之地。
今天这一章,我就带你把这些协议掰开揉碎,再聊聊拉流、推流和直播转码的那些坑。嗯,都是实战里摸爬滚打出来的经验。
直播协议三剑客:RTMP、RTSP、HLS
先说说这三个协议到底干嘛用的。说白了,它们就是音视频数据在网络上传输的「规矩」。不同的规矩,决定了延迟、兼容性、稳定性都不一样。
RTMP(Real-Time Messaging Protocol)
RTMP 是 Adobe 搞出来的,最初为了 Flash 播放器服务。现在 Flash 早没了,但 RTMP 在推流端依然坚挺。为什么?因为它延迟低,交互性好。
- 传输层:基于 TCP,长连接。数据包小,实时性高。
- 延迟:通常在 1-3 秒,适合互动直播。
- 缺点:默认端口 1935 容易被防火墙拦截。而且浏览器原生不支持,得靠插件或转码。
- 我的经验:我做过一个户外直播项目,推流端用 RTMP 到服务器,服务器再转 HLS 给观众。RTMP 推流非常稳,但一旦网络抖动,画面会卡住几秒,不像 HLS 那样能自适应。
rtmp://your-server.com/live/stream-key。stream-key 是流标识,别泄露,否则谁都能往你频道推流。
RTSP(Real-Time Streaming Protocol)
RTSP 是网络摄像头和安防领域的「老大哥」。它本身不传数据,只负责控制(播放、暂停、快进),真正的音视频数据走 RTP 协议。
- 传输层:控制用 TCP,数据用 UDP(默认)。所以延迟极低,可以做到 0.5 秒以内。
- 适用场景:安防监控、视频会议、低延迟直播。
- 缺点:UDP 传输容易丢包,网络差时画面会花屏。而且防火墙对 UDP 不友好。
- 避坑指南:我曾经在部署 RTSP 拉流时,发现画面每隔几分钟就卡一下。查了半天,原来是路由器对 UDP 包做了限速。后来改成 TCP 模式(
?tcp参数),问题解决。
HLS(HTTP Live Streaming)
HLS 是苹果推出的,现在几乎成了「通用语言」。它把直播流切成一个个小文件(.ts 或 .m4s),通过 HTTP 分发。说白了,就是把直播伪装成「文件下载」。
- 传输层:HTTP,能过任何防火墙。CDN 支持极好。
- 延迟:通常 6-30 秒。因为要等切片生成和下载,延迟天然高。
- 优点:兼容性无敌。浏览器、手机、电视盒子都能播。
- 我的看法:如果你做的是「一对多」的大规模直播,比如演唱会、教育直播,HLS 是首选。延迟高一点,但稳定性和覆盖范围没得比。
拉流与推流:数据怎么流动
搞清楚了协议,接下来就是「怎么把流弄进来」和「怎么把流送出去」。这两个动作,在 FFmpeg 里就是一行命令的事,但背后的逻辑你得懂。
推流(Publish/Stream Out)
推流,就是把本地的音视频数据,通过某种协议发送到服务器。最常见的推流协议就是 RTMP。
FFmpeg 推流命令示例:
ffmpeg -re -i input.mp4 -c:v libx264 -c:a aac -f flv rtmp://server/live/stream
-re:以原始帧率读取。不加这个,FFmpeg 会以最快速度推完,直播就变成「录播」了。-f flv:RTMP 推流通常封装成 FLV 格式。rtmp://...:推流地址。
-b:v 2M 或更低。
拉流(Pull/Stream In)
拉流,就是从服务器或摄像头获取直播流。FFmpeg 可以拉 RTMP、RTSP、HLS 等任何协议。
拉 RTSP 流并保存为文件:
ffmpeg -i rtsp://camera-ip:554/stream -c copy output.mp4
拉 HLS 流并实时转码:
ffmpeg -i https://example.com/live/playlist.m3u8 -c:v libx264 -b:v 1M output.ts
我个人的习惯是,拉流时先加个 -timeout 10000000(单位微秒),防止网络不好时 FFmpeg 一直卡着不动。
直播转码:从「源」到「端」的桥梁
直播转码,说白了就是把一路输入流,转成多种分辨率、多种码率、多种格式的输出。为什么要转?因为观众的网络和设备千差万别。
你想想看,有人用 5G 手机看 4K,有人用 2G 网络看 360p。如果只推一路流,那体验肯定不行。
转码的核心流程
- 解码:把输入的压缩数据(H.264/H.265)解成原始 YUV 帧。
- 滤镜处理:缩放、裁剪、加水印、调色等。
- 编码:重新压缩成目标分辨率/码率的流。
- 封装:输出为 FLV、TS、MP4 等格式。
FFmpeg 实现多路转码的经典命令:
ffmpeg -i rtmp://input/live/stream \
-c:v libx264 -b:v 2M -s 1280x720 -c:a aac -b:a 128k -f flv rtmp://output/live/720p \
-c:v libx264 -b:v 1M -s 854x480 -c:a aac -b:a 96k -f flv rtmp://output/live/480p \
-c:v libx264 -b:v 500k -s 640x360 -c:a aac -b:a 64k -f flv rtmp://output/live/360p
这条命令同时输出三路流:720p、480p、360p。每个输出都独立编码,CPU 压力很大。我建议用硬件编码(-c:v h264_nvenc 或 -c:v h264_vaapi)来减轻负担。
-filter_complex 先缩放,再编码,避免重复解码。比如:-filter_complex "[0:v]split=3[v1][v2][v3];[v1]scale=1280:720[v1out];[v2]scale=854:480[v2out];[v3]scale=640:360[v3out]"。
直播流处理的核心逻辑图
下面这张图,是我自己总结的直播流处理全链路。从推流端到播放端,每一步都离不开 FFmpeg。
实战中的几个坑
最后,分享几个我踩过的坑,希望能帮你省点时间。
- 推流断连:RTMP 推流时,如果网络闪断,FFmpeg 不会自动重连。我一般写个脚本循环检测,或者用
-reconnect 1参数(部分版本支持)。 - 音视频不同步:转码时如果用了
-vsync或-async参数不当,很容易导致音画不同步。我建议尽量用-c copy保持原始时间戳,除非必须转码。 - HLS 切片太大:默认 HLS 切片时长是 2 秒,但如果你不设置
-hls_time,有些版本会切出 10 秒的片,导致延迟飙升。我习惯设成-hls_time 2。 - RTSP 拉流超时:摄像头 RTSP 流如果断掉,FFmpeg 会一直等。加个
-stimeout 10000000(10秒超时),超时后自动退出,方便脚本重启。