3. 推流技术全景

做流媒体这行,视频编码是绕不开的坎。我记得刚入行那会儿,总觉得编码是算法工程师的事,我们做传输的懂个大概就行。结果第一次调试RTSP推流卡顿,抓包抓了半天,最后发现是编码器配置的GOP太大,客户端等了快两秒才等到I帧。从那以后,我老老实实把编码基础补了一遍。

说白了,视频编码的核心就两件事:去掉冗余和控制码率。冗余包括空间上的(同一帧里相邻像素长得像)和时间上的(相邻帧之间画面变化不大)。去掉这些冗余,视频就能压缩到原来的几十分之一甚至百分之一。

3.1 视频编码原理概述

先看一张整体流程图,帮你建立直觉:

视频编码核心流程 视频编码核心流程 原始帧 帧内/帧间预测 变换 + 量化 熵编码 码率控制 关键说明: • 预测阶段去掉空间/时间冗余,变换量化去掉人眼不敏感的高频细节 • 熵编码用更少的比特表示出现频率高的符号(类似哈夫曼编码思想) • 码率控制根据目标码率动态调整量化参数,反馈给变换量化阶段

编码器拿到原始帧后,先做预测。预测分两种:帧内预测用当前帧已编码的像素推测当前块,帧间预测用前面或后面的帧做参考。预测完得到残差(实际值减预测值),残差里大部分数值接近0。然后做变换(比如DCT)把残差转到频域,再用量化去掉人眼不敏感的高频分量。最后熵编码把量化后的系数压缩成二进制码流。

我的经验:很多新手以为量化就是"压缩",其实量化是有损的关键步骤。量化参数QP越大,高频细节丢得越多,码率越低,但画面会变模糊或出现块效应。RTSP推流时,如果网络带宽波动,我习惯动态调整QP而不是直接丢帧。

3.2 帧类型:I/P/B帧

视频编码不是一帧一帧独立压缩的。那样效率太低。编码器把帧分成三种类型,各司其职。

帧类型 全称 压缩方式 大小 关键特性
I帧 Intra-coded frame 仅帧内预测 最大 可独立解码,无需参考其他帧
P帧 Predictive-coded frame 参考前面的I/P帧 中等 只能向前参考,压缩率比I帧高
B帧 Bi-directional frame 参考前后I/P帧 最小 双向参考,压缩率最高,但需要缓存

I帧是"关键帧",相当于视频里的"锚点"。你拖动进度条时,播放器必须找到最近的I帧才能开始解码。所以I帧不能太少,否则seek响应慢;也不能太多,否则码率飙升。

P帧只参考前面的帧。比如第5帧是P帧,它可能只记录"第3帧的左上角那块往右移了3个像素"。B帧更聪明,它同时参考前面和后面的帧,能更精确地描述运动。但B帧需要缓存后面的帧才能解码,所以会增加延迟。

RTSP推流场景下的选择:

  • 低延迟场景(如视频通话):只用I帧+P帧,不用B帧。B帧的重排序会引入至少1帧的延迟。
  • 直播场景(如赛事转播):可以用少量B帧,但B帧数量控制在2以内,避免解码器缓冲区溢出。
  • 点播场景:B帧可以多用,压缩率优先,延迟不是问题。

我曾经在一个RTSP安防项目中踩过坑。摄像头编码器默认开了3个B帧,结果客户端解码时频繁花屏。查了半天,发现是部分低端NVR的B帧缓存不够。后来强制改成0个B帧,问题解决。嗯,兼容性有时候比压缩率更重要。

3.3 GOP结构与码率控制

GOP(Group of Pictures)就是一组连续的帧,从I帧开始到下一个I帧之前结束。GOP结构决定了视频的随机访问能力和压缩效率。

常见的GOP结构有两种:

  • 封闭式GOP:GOP内的帧只参考本GOP内的帧,不跨GOP参考。适合视频编辑场景,剪切时不会出现参考帧缺失。
  • 开放式GOP:B帧可以跨GOP参考后面的I帧。压缩率更高,但编辑时可能出问题。

GOP长度(两个I帧之间的帧数)是个关键参数。我一般这样配置:

场景 推荐GOP长度 理由
实时监控 30-60帧(1-2秒) 快速seek,丢包后快速恢复
直播推流 60-120帧(2-4秒) 平衡压缩率和延迟
短视频/点播 120-250帧(4-10秒) 追求高压缩率
避坑指南:我曾经把GOP设成300帧(10秒),结果推流到CDN后,播放器切换清晰度时等了整整10秒才出画面。CDN的转码节点需要等I帧才能重新编码,GOP太长会导致转码延迟暴增。现在我做直播,GOP长度绝不超过120帧。

码率控制是编码器的"油门"。它决定每一帧分配多少比特。常见模式有三种:

  • CBR(恒定码率):码率始终保持在目标值附近。适合带宽固定的场景,比如RTSP over TCP。缺点是画面复杂时质量会下降。
  • VBR(可变码率):码率随画面复杂度波动。简单场景用低码率,复杂场景用高码率。画质更稳定,但带宽需求会波动。
  • CRF(恒定质量):固定量化参数,码率完全由画面决定。画质最好,但码率不可控。适合本地录制,不适合网络推流。

RTSP推流我推荐用CBR或VBR带最大码率限制。为什么?因为RTSP的传输层通常是TCP,带宽波动时TCP会重传,导致延迟堆积。如果码率忽高忽低,TCP的拥塞控制会频繁触发,画面反而更卡。

我的配置习惯:做RTSP推流时,我会把码率控制模式设为CBR,然后留10%-15%的余量。比如目标2Mbps,我设成1.8Mbps。这样即使画面突然复杂,编码器也有缓冲空间,不会瞬间超出带宽。同时开启"场景切换检测",当画面剧烈变化时强制插入一个I帧,避免长时间花屏。

最后说一个容易被忽略的点:GOP和码率控制的联动。I帧的码率通常是P帧的5-10倍,B帧的15-20倍。如果码率控制没处理好,I帧瞬间的码率尖峰可能撑爆缓冲区。我见过有人把I帧的量化参数设得比P帧低很多,结果I帧码率爆炸,网络瞬间丢包。正确的做法是让码率控制器提前为I帧预留比特,或者适当提高I帧的QP,让它不要过于"突出"。

嗯,编码基础就聊到这儿。这些概念看起来简单,但实际调优时坑不少。后面我们会结合具体的编码器(x264、x265、NVIDIA NVENC)讲实战配置,到时候你会更清楚每个参数在RTSP推流中的真实表现。