视频通话里对方一动就马赛克,云游戏里按一下W键角色零点几秒后才跑出去,这些卡顿和延迟的背后,都绕不开一个东西——视频编码。AV1是现在很火的编码格式,压缩率比老将H.264高不少,但想让它跑得快、延迟低,却没那么容易。今天我们就从日常体验出发,把AV1低延迟的“窍门”掰开揉碎讲一讲,并且给出一套能落到实处的实时方案。

一、为什么实时场景这么看重延迟

先想一个生活里的场景。你和朋友视频聊天,你说了一句话,对方要等半秒才听到,然后他回话,又要等半秒。这种一来一回,说话节奏全乱了,最后只能变成“你先说”“你说”。在视频会议、直播连麦、云游戏、远程手术这些场景里,延迟就是生命线。人眼对画面卡顿非常敏感,一般来说,端到端延迟超过150毫秒,就能明显感觉到“不跟手”。视频编码是整条链路里最关键的一环,如果编码器磨磨蹭蹭,后面的网络传输再快也白搭。

所以研究AV1的低延迟,不是单纯追求压缩率,而是让它在“尽量短的时间内,把画面变成可以传输的数据”。

二、AV1编码为什么天生“慢半拍”

AV1想要高压缩率,就得用更聪明的运算。比如在各种小方块里找最像的块,范围越大效果越好,但计算量也越大。又比如它允许很多种预测方向,每个块都要试一遍。这就像让一个大厨做佛跳墙,食材丰富、工序复杂,好吃是好吃,但出菜慢。

2.1 编码器的工作流程

编码器拿到一帧画面后,通常会把画面切成很多小块,然后逐个分析。它先猜这个小块跟周围像素有什么关系,这叫帧内预测;再看看跟前面某帧的某个位置是不是更像,这叫帧间预测。猜完之后,把误差和那些“快照”里的位置信息一块存下来。AV1把这些步骤做得特别精细,所以每个块都要花更多时间去“猜”。

2.2 帧类型带来的延迟

视频帧分为三种:I帧是完整的画面快照,P帧是参考前面某一帧的“补丁”,B帧则是参考前面和后面的帧。B帧压缩率最高,因为它能结合“过去”和“未来”的信息。但编码B帧的时候,必须先把未来的那一帧编码完,才能动手。这就像做菜需要等下一道菜的食材到了才能做上一道,出菜顺序全乱了。所以低延迟编码的第一招,就是干脆不用B帧,全部用P帧。虽然压缩率差一点,但延迟立刻降下来了。

三、把它“调校”成低延迟模式

AV1的设计很灵活,你可以把“慢而准”的版本调成“快而稳”的版本。下面几个方法是最常用的。

3.1 提高编码速度

编码器一般提供速度档位,越快的档位会跳过一些复杂的搜索,换取消耗时间。在FFmpeg里,libaom的速度档位数值越大编码越快,SVT-AV1的预设档位也是数字越大越快。对于实时场景,不要太贪心,一般把速度档位拉到8以上,才能保证720P或1080P在普通电脑上实时转完。

3.2 关掉B帧,只留P帧

前面说过B帧会引入未来依赖,所以低延迟配置里都要把B帧数量设为0。这样编码器只需要参考前面的帧,一帧接一帧,流水线就通了。虽然B帧压缩率最高,但为了延迟,我们得放弃它。如果你去查很多实时编码器的配置,都会看到“关闭B帧”这一条。

3.3 精简参考帧数量

有时候为了压缩率,编码器会保留很多历史帧作为参考。参考帧多,查找时间就长,缓存压力也大。低延迟场景下,可以限制参考帧只保留最近1到2帧。这样编码器不用到处翻“旧账”,延迟自然变小。

3.4 让码率控制更“听话”

码率控制就像开车时踩油门。恒定码率模式会尽量让每一秒的数据量保持平稳,这样网络不容易堵。但编码器为了平稳,有时会排队等待后面的帧过来再平均分配,这就增加了延迟。所以低延迟一般用固定量化参数或单次编码的可变码率,不搞“秋后算账”。

四、具体示例:用FFmpeg实现低延迟AV1

这一节我们全程使用FFmpeg命令行来演示。FFmpeg是开源多媒体工具,把各种编码器都封装成了简单的命令,非常适合快速落地。

4.1 先看看你手头有哪些AV1编码器

打开终端,输入下面的命令,就能看到支持的AV1编码器。

# 列出FFmpeg中所有编码器,过滤出名字里带av1的行
ffmpeg -encoders 2>/dev/null | grep av1:

# 常见输出有:
#  V....D libaom-av1       (AOMedia Project AV1)
#  V....D librav1e         (Rav1e AV1 encoder)
#  V....D libsvtav1        (SVT-AV1)
# 其中libaom是官方参考实现,libsvtav1是面向多核CPU的快速实现

4.2 用libaom做一次低延迟本地编码

下面这段命令把原始的YUV视频文件压缩成AV1的MP4文件,关键点都写在注释里。

# 输入分辨率1920x1080,30帧/秒,像素格式nv12
# 使用libaom-av1编码器,输出为mp4容器

ffmpeg -f rawvideo -pix_fmt nv12 -s 1920x1080 -r 30 -i input.yuv \
  -c:v libaom-av1 \
  -deadline realtime \
  -cpu-used 8 \
  -lag-in-frames 0 \
  -bf 0 \
  -g 30 \
  -keyint_min 30 \
  -row-mt 1 \
  -tile-columns 2 \
  -tile-rows 2 \
  -crf 32 \
  -an \
  output.mp4
# -deadline realtime: 告诉编码器按实时模式工作,别“精雕细琢”
# -cpu-used 8: 速度档位拉高,牺牲一点压缩率换速度
# -lag-in-frames 0: 不看未来帧,把“向后看”的缓冲关掉
# -bf 0: 关闭B帧,禁止依赖未来帧
# -g 30: 每30帧放一个关键帧(I帧),方便随机接入
# -keyint_min 30: 关键帧最小间隔也是30,避免编码器自做主张插I帧
# -row-mt 1: 按行并行编码,多核CPU利用率更高
# -tile-columns 2 -tile-rows 2: 把画面切成若干块,并行处理,显著提速
# -crf 32: 固定质量,数值越大画质越低,但体积越小
# -an: 不处理音频,这里只看视频部分

这段命令里,实时模式和不看未来帧是低延迟的灵魂。关闭B帧则保证了每一帧都只依赖前面已经编码完成的帧。

4.3 快速换用SVT-AV1

如果你手里的CPU核心很多,用SVT-AV1速度会更快。SVTAV1是专门为现代多核CPU优化的编码器,压缩率略低一点,但速度优势明显。同样的低延迟配置可以这样写。

# 用SVT-AV1做低延迟编码,输入同样是YUV,输出MP4
# 所有专用参数都通过 svtav1-params 传递,避免和FFmpeg全局参数混淆

ffmpeg -f rawvideo -pix_fmt nv12 -s 1920x1080 -r 30 -i input.yuv \
  -c:v libsvtav1 \
  -preset 8 \
  -svtav1-params "rc=0:qp=30:tf=0:pred-struct=1:scd=0" \
  -g 30 \
  -f mp4 output.mp4
# -preset 8: SVT-AV1的速度档位,数字越大越快
# rc=0: 使用固定QP,不依赖未来帧做码率分配
# qp=30: 固定量化参数,数字越大画质越低
# tf=0: 关闭时域滤波,进一步降低延迟
# pred-struct=1: 使用低延迟预测结构,相当于只做P帧
# scd=0: 关闭场景切换检测,避免编码器突然插入关键帧导致延迟抖动
# -g 30: 每30帧一个关键帧

这个配置在视频会议类场景里很常用。如果画面变化不大,甚至可以放到preset 10,速度更快。

4.4 实时采集摄像头并推流

如果是做视频会议或者直播,我们经常需要直接读取摄像头,边采集边编码边推送。下面命令演示了从Linux下读取摄像头,用AV1实时编码后通过SRT协议推流。SRT是一种支持低延迟的互联网传输协议,比RTMP更稳。

# 从/dev/video0读取摄像头,YUV420p格式,每秒25帧
# 输出到SRT地址,适合局域网或公网直播

ffmpeg -f v4l2 -framerate 25 -video_size 1280x720 -input_format nv12 -i /dev/video0 \
  -c:v libaom-av1 \
  -deadline realtime \
  -cpu-used 8 \
  -lag-in-frames 0 \
  -bf 0 \
  -g 50 \
  -keyint_min 50 \
  -row-mt 1 \
  -tile-columns 2 \
  -tile-rows 2 \
  -b:v 2M \
  -maxrate 2M \
  -bufsize 4M \
  -f mpegts srt://192.168.1.100:9000?mode=caller
# 这里用恒定码率2Mbps,让网络带宽占用稳定
# SRT地址中的mode=caller表示主动连接对端

注意,如果网络带宽波动较大,可以把视频码率和最大码率设成一样,再配合缓冲区大小,编码器会让码率尽量平滑,避免网络拥塞。

五、不同实时场景怎么选方案

刚才的命令是通用模板,实际场景里还要根据业务侧重点做微调。

5.1 视频会议

视频会议里,画面内容大多是人的上半身,背景变化小。这时候可以适当降低关键帧间隔,让编码器重点优化人脸区域。还可以开启分辨率自适应,网络差时降到720P甚至480P。如果CPU资源紧张,甚至可以换用SVT-AV1的更高预设档位,换回流畅度。

5.2 云游戏

云游戏画面复杂、运动剧烈,对压缩率的要求很高,不然带宽扛不住。但延迟又不能高。这时候可以尝试混合使用P帧和少量B帧,但B帧数量不要超过1,并且设置成“低延迟B帧”模式。同时配合服务端并行编码,把编码耗时降到10毫秒以内。显卡支持AV1硬编码的话,比如NVIDIA的NVENC或Intel的QuickSync,一定要优先用硬件,延迟和CPU占用都会好看很多。

5.3 远程操控机器人或无人车

这类场景需要把画面和指令同时送回操作台,延迟稍高就可能撞车。AV1在这种场景下最大的问题是编码器不够快,所以建议使用实时档位,并且把分辨率降到540P或720P,码率根据无线环境动态调整。另外要做好容错,丢包时立刻重传关键帧,否则画面会一直花屏。

六、技术有哪些优点、缺点和该躲的坑

6.1 优点

AV1的压缩率比H.264高30%以上,同样清晰度下更省带宽。低延迟模式下,虽然比硬件H.264后期稍高,但很多新设备已经支持AV1硬解,播放端不费电。对于视频厂商来说,长期节省CDN成本非常可观。

6.2 缺点

AV1的软件编码非常吃CPU,即使调到最高速档位,在低端手机上依然很难实时。硬件编码器的画质又不如软件精细。另外,当前很多WebRTC服务端默认还不支持AV1,需要自己集成。生态处于“能跑但不够顺”的阶段。

6.3 注意事项

第一,别盲目追求最低延迟。延迟太低会导致编码器来不及利用后面的帧做优化,画质下降。第二,务必做端到端延迟测试,因为编码只占其中一部分,网络抖动、抖动缓冲、解码器都影响体验。第三,尽量使用最新版本的编码器库,AV1标准本身也在演进,新的编码器在速度和压缩率上表现更好。第四,如果目标平台支持AV1硬件编码,不要犹豫,直接选硬编,这是目前最省心的低延迟方案。

6.4 工具选型:软件编码器和硬件编码器怎么选

libaom是官方参考实现,更新频繁,但速度一般。SVT-AV1是面向多核CPU优化的库,速度比libaom快不少,压缩率略低一点。如果你的服务器核心数很多,SVT-AV1是首选。如果要跑到嵌入式设备上,硬件编码器如NVIDIA NVENC AV1、Intel Arc的AV1编码器,则是“低延迟+低功耗”的答案。实际项目中,硬件编码器常常能提供更低的端到端延迟,因为它的运算单元是专门为视频编解码设计的,不占用CPU通用计算资源。如果你的云服务商提供了支持AV1硬编码的实例,那就直接用,省心又稳定。

七、总结

AV1能不能用于实时场景?答案是能,但需要“调校”。放弃B帧、关闭前瞻、提高速度档、限制参考帧,这四招能让AV1从“慢炖”变成“爆炒”。视频会议、云游戏、远程操控,每个场景都有自己的侧重点,但整体思路一致:用工具(比如FFmpeg)把编码器的“性子”按下来,让它在规定时间内出结果。未来随着硬件支持越来越广,AV1的低延迟应用一定会越来越普遍。现在开始动手测试,正是时候。