流媒体协议基础:RTMP、HLS、RTSP协议原理与数据推拉流实战

说到流媒体协议,很多刚入行的朋友容易一头雾水。RTMP、HLS、RTSP……这些缩写看着都眼熟,但真要你说清楚它们各自干什么、怎么选,可能就卡壳了。

我当年刚接触音视频开发时,也踩过不少坑。有一次做直播项目,选了RTMP推流,结果在弱网环境下卡得不行,用户全跑了。后来换成HLS配合自适应码率,才把问题解决。说白了,选协议不是技术炫技,而是看场景。

这一章,我就带你把这三种主流协议彻底搞明白。咱们不光讲原理,还会动手写代码,实现真正的推拉流。

1. 三种协议的核心定位

先给个总览。这三种协议,各有各的“脾气”。

协议 传输层 延迟 典型场景 我的评价
RTMP TCP 1-3秒 直播推流、互动直播 老牌劲旅,推流首选
HLS HTTP 5-30秒 点播、OTT、大屏 兼容性无敌,延迟是硬伤
RTSP TCP/UDP 0.1-1秒 安防监控、IP摄像头 低延迟王者,但穿透差

你想想看,如果做的是游戏直播,延迟超过3秒观众就受不了,那RTMP或RTSP更合适。如果是视频网站点播,HLS几乎是最佳选择——因为它基于HTTP,CDN随便配,防火墙基本不拦。

2. RTMP协议原理与实战

RTMP是Adobe搞出来的,虽然Flash已经凉了,但RTMP在直播推流领域依然坚挺。为什么?因为它稳定、成熟,而且几乎所有编码器都支持。

2.1 握手与连接

RTMP基于TCP,建立连接后先做握手。握手分三个阶段:

  • C0/S0:版本号协商
  • C1/S1:随机数据交换
  • C2/S2:确认握手完成

握手完成后,客户端发送connect命令,服务端返回成功,然后就可以创建流了。我个人习惯把握手过程封装成一个工具函数,避免每次重复写。

2.2 推流实战(C++实现)

下面是一个简化版的RTMP推流代码,使用librtmp库。注意,这只是核心逻辑,实际项目需要加错误处理和重连机制。

#include <librtmp/rtmp.h>
#include <stdio.h>

int rtmp_push(const char* url, const char* flv_file) {
    RTMP* rtmp = RTMP_Alloc();
    RTMP_Init(rtmp);
    
    // 设置推流地址
    if (!RTMP_SetupURL(rtmp, (char*)url)) {
        printf("URL设置失败\n");
        return -1;
    }
    
    // 设置为推流模式
    RTMP_EnableWrite(rtmp);
    
    // 连接服务器
    if (!RTMP_Connect(rtmp, NULL)) {
        printf("连接失败\n");
        return -1;
    }
    
    // 连接流
    if (!RTMP_ConnectStream(rtmp, 0)) {
        printf("连接流失败\n");
        return -1;
    }
    
    // 读取FLV文件并发送
    FILE* fp = fopen(flv_file, "rb");
    if (!fp) return -1;
    
    char buf[4096];
    int bytes;
    while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) {
        RTMP_Write(rtmp, buf, bytes);
    }
    
    fclose(fp);
    RTMP_Close(rtmp);
    RTMP_Free(rtmp);
    return 0;
}
注意:librtmp库已经很久不更新了。我在项目中遇到过内存泄漏问题,建议用srs-librtmp或者自己封装一层RAII管理资源。

3. HLS协议原理与实战

HLS是苹果推出的,核心思想是把视频切成一个个小片段(通常是10秒一段),然后通过m3u8索引文件来管理。播放器先下载索引文件,再按顺序下载片段播放。

3.1 m3u8文件结构

一个典型的m3u8文件长这样:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
segment_000.ts
#EXTINF:10.0,
segment_001.ts
#EXTINF:10.0,
segment_002.ts
#EXT-X-ENDLIST

如果做直播,m3u8文件会不断更新,旧的片段会被移除,新的片段加进来。这就是HLS延迟高的原因——你至少要等一个片段下载完才能播放。

3.2 拉流实战(C++实现)

用FFmpeg拉HLS流非常简单,本质上就是打开一个URL:

#include <libavformat/avformat.h>

int hls_pull(const char* url, const char* output) {
    AVFormatContext* fmt_ctx = NULL;
    
    // 打开HLS流
    if (avformat_open_input(&fmt_ctx, url, NULL, NULL) != 0) {
        printf("无法打开HLS流\n");
        return -1;
    }
    
    // 查找流信息
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        printf("无法获取流信息\n");
        return -1;
    }
    
    // 这里可以继续做解码、保存等操作
    // 实际项目中需要处理AVPacket
    
    avformat_close_input(&fmt_ctx);
    return 0;
}
小技巧:HLS的延迟可以通过缩短片段时长来降低,比如从10秒改成2秒。但片段太短会增加服务器压力和CDN请求次数。我一般取4-6秒作为平衡点。

4. RTSP协议原理与实战

RTSP是实时流传输协议,它本身不传输数据,而是充当“遥控器”。真正的音视频数据通过RTP传输,RTCP负责质量控制。

4.1 信令流程

RTSP的交互过程很像VCR操作:

  1. OPTIONS:客户端询问服务器支持哪些方法
  2. DESCRIBE:获取媒体描述信息(SDP)
  3. SETUP:建立传输通道(指定端口、传输方式)
  4. PLAY:开始播放
  5. TEARDOWN:结束会话

我曾经调试过一个RTSP摄像头,发现SETUP阶段总是失败。后来抓包一看,是服务器要求用UDP传输,但我的代码默认用了TCP。嗯,这里要注意,很多安防设备只支持UDP。

4.2 拉流实战(C++实现)

用live555库拉RTSP流是业界标准做法。下面是一个简化示例:

#include <live555/liveMedia.hh>
#include <live555/BasicUsageEnvironment.hh>

int rtsp_pull(const char* url) {
    // 创建环境
    TaskScheduler* scheduler = BasicTaskScheduler::createNew();
    UsageEnvironment* env = BasicUsageEnvironment::createNew(*scheduler);
    
    // 创建RTSP客户端
    RTSPClient* rtspClient = RTSPClient::createNew(*env, 0, NULL, 0);
    if (!rtspClient) {
        *env << "创建RTSP客户端失败\n";
        return -1;
    }
    
    // 发送DESCRIBE命令
    rtspClient->sendDescribeCommand(continueAfterDESCRIBE);
    
    // 进入事件循环
    env->taskScheduler().doEventLoop();
    
    return 0;
}
避坑指南:live555的API设计比较老,内存管理需要格外小心。我曾经因为忘记释放UsageEnvironment导致内存泄漏,跑了三天服务器挂了。建议用智能指针封装一下。

5. 协议对比与选型建议

说了这么多,到底怎么选?我总结了一个决策树:

  • 推流场景:RTMP是首选,几乎所有编码器都支持。如果要做低延迟互动,考虑WebRTC。
  • 点播场景:HLS最稳妥,CDN支持最好。如果用户量大,配合DASH更灵活。
  • 监控场景:RTSP是事实标准,但要注意NAT穿透问题。可以用RTSP over HTTP来绕过防火墙。
  • 移动端:HLS是iOS原生支持,Android也兼容。RTMP在移动端需要第三方库。
核心观点:没有最好的协议,只有最适合场景的协议。我见过太多人为了追求“技术先进”选了冷门协议,结果在兼容性上吃尽苦头。稳,比新更重要。

6. 知识体系总览

下面这张图,把三种协议的核心流程和关系梳理清楚了。建议你保存下来,面试前看一眼。

流媒体协议知识体系 RTMP HLS RTSP 推流(Flash/编码器) 延迟1-3秒,TCP可靠 m3u8索引 + TS片段 延迟5-30秒,HTTP穿透 信令+RTP传输 延迟<1秒,UDP低延迟 选型原则:推流用RTMP,点播用HLS,监控用RTSP librtmp / FFmpeg FFmpeg / m3u8-segmenter live555 / FFmpeg

这张图把三种协议的核心链路和实战工具都标出来了。你写代码时,对着这张图选库就行。

好了,这一章的内容就到这里。三种协议的原理和实战代码都给了,剩下的就是动手练。记住,看十遍不如写一遍,赶紧打开IDE试试吧。

公众号:蓝海资料掘金营,微信 deep3321