云游戏技术专题全层级11 / 30 已发布

自适应码率算法(ABR)的云游戏专项演进

· 0 分钟阅读
自适应码率算法(ABR)的云游戏专项演进:当缓冲池变成敌人 Adaptive Bitrate in Cloud Gaming — 云游戏技术专题

自适应码率算法(ABR)的云游戏专项演进:当缓冲池变成敌人 Adaptive Bitrate in Cloud Gaming

为什么 ABR 是云游戏体验的「最后一道闸门」

先说个真事。前几年我帮一个团队调串流,测试同学跑过来说:「20 兆档位画面挺好啊,就是暗的地方像糊了一层油。」我第一反应是编码器量化参数给高了,闷头改了两天,啥也没改出来。后来把整段会话的码率曲线拉出来一看,病根根本不在编码器——那哥们儿在家用 WiFi,他媳妇一开视频会议,带宽掉到 12 兆,我们的自适应逻辑磨蹭了整整四秒才开始降码率,降完又立刻反弹,来回横跳。玩家看到的不是「糊」,是「一会儿清楚一会儿糊」。

说句实话,这比一直糊难受十倍。人眼对画质的时间稳定性极其敏感,一个稳定偏软的画面,比一个忽清忽糊的画面让人舒服得多。这个坑我踩过,后面还会细说。

那次之后我记住一件事:云游戏的自适应码率,跟你刷视频、看直播的自适应码率,名字一样,骨子里是两套东西。视频网站的 ABR 是个「播放平滑器」,它的最高使命是别卡住,宁可用 480p 也要让你看完。云游戏的 ABR 是个「帧调度器」,它的最高使命是让每一帧在玩家察觉到之前抵达屏幕——至于这一帧是清晰还是糊,那是第二位的。

这篇文章我想把这件事拆开讲:为什么直播那套 ABR 搬不过来、控制回路的时标该怎么选、控制信号从哪来、目标函数怎么定。中间会拿 Stadia、GeForce NOW、Parsec、Xbox Cloud Gaming 这几个真实平台开刀,讲讲它们各自的选择和代价。看完你至少能干一件事:调自家串流的时候,知道该往哪儿看,而不是像我当年一样瞎改编码参数。

第 1 层:先认清三笔账,直播的 ABR 搬不过来

很多人做云游戏 ABR 的第一反应是「找个成熟的开源方案改改」。能改,但改之前你得先接受三个断层,这三个断层决定了你不可能照抄。

第一个断层:缓冲区没了。直播和点播的 ABR 之所以敢做,是因为客户端有个缓冲池——通常是 5 到 30 秒。码率估高了、链路抖了,只要缓冲不空,播放就不停,你还有十几秒去纠正错误。这个缓冲池是 ABR 的安全垫。云游戏呢?缓冲直接等于延迟。你在客户端攒两秒缓冲,玩家的摇杆输入就要晚两秒生效,格斗游戏直接判死刑,射击游戏也活不过一局。所以云游戏客户端可用的缓冲通常只有几十毫秒,一两帧的量级。安全垫被抽走之后,ABR 的每一次误判都是当场兑现的,没有「待会儿再补」这回事。

第二个断层:编码器的账完全不一样。传统流媒体是一次编码、切成多档、存起来、CDN 分发。多一个档位,边际成本几乎为零,所以大家敢堆六档八档,ABR 想切哪档切哪档。云游戏不是这个结构。每个玩家一条独立的编码会话,跑在他独占的那块 GPU 切片上。你要给他备三个档位,就得跑三路编码——三份算力、三份显存带宽、三份会话配额。消费级显卡的硬件编码器会话数还有硬限制,数据中心卡虽然放开了,但成本照样实打实。所以云游戏的 ABR 基本不能「切档」,只能「调参」:改目标码率、改量化步长、改输出分辨率、改帧率,全都在同一路编码器里完成。这个约束是一切的起点,我见过太多方案在设计阶段就把这件事忘了,后面推倒重来。

第三个断层:内容是玩家自己「演」的。直播画面变化由主播决定,你至少能做统计预测:「这类场景平均需要多少码率」。云游戏画面变化由玩家的手决定。他一甩鼠标转身,画面里八成像素全变了,这一瞬间恰好是带宽需求最高的时候,也恰好是他最不能容忍糊的时候——他正盯着那个方向找敌人呢。ABR 要么提前预判,要么就只能事后补救。

不过这里有个反直觉的好消息:云游戏的服务端其实握着「提前量」。渲染完到编码完到发出去,中间有几十毫秒,而且服务端天然知道这一帧有多复杂——渲染统计、运动幅度、是不是场景切换,这些信息直播 ABR 根本拿不到。会不会用这个作弊器,就是分水岭。

拿 Stadia 当反面教材看最清楚。它的公开带宽建议是 720p 约 10 兆、1080p 约 20 兆、4K 约 35 兆,走 VP9。这套阶梯本身没问题,问题出在它的策略极度保守:宁可画质平庸,绝不让你卡。于是《赛博朋克 2077》夜之城这种大面积暗场加高频霓虹的场景,20 兆根本喂不饱,暗部出现明显色带,远景糊成一团。当时社区里最狠的一句吐槽是「Stadia 的 4K 看起来像 1080p 拉上来的」。这话不冤,但也不全怪 VP9,是码率预算和保守爬升策略一起造成的。更关键的是,Stadia 没给高带宽用户留一个「我就是要画质」的出口——码率上限锁死,玩家想自己加钱都不行。这就把一个技术取舍变成了产品缺陷。

第 2 层:控制回路的时标——GOP 级还是帧级,答案比你想的复杂

确定了「只能调参不能切档」,下一个问题就是多久调一次。行业里大致三档:

决策粒度典型周期能做什么代价
GOP 级1 到 2 秒改目标码率、强制插入关键帧重同步反应慢;插关键帧等于往最脆弱的链路上砸一记重拳
帧级16 到 33 毫秒逐帧调整量化步长和目标码率量化步长抖动导致画质「呼吸」;和质量控制回路打架
帧内切片级帧内分块不同区域分配不同质量解决不了链路突然变窄的问题,属于另一条战线

GOP 级的好处是稳。一个两秒的图组里,决策次数少,不会来回横跳。坏处是慢——链路在第 0.3 秒崩了,你要么等到第 2 秒,要么插一个关键帧。关键帧的数据量通常是普通帧的三到十倍,插进去的那一瞬间等于给已经拥堵的链路再来一脚,很容易把「有点卡」变成「彻底卡死」。这是很多团队的血泪教训。

帧级的诱惑在于反应快。听起来很美,做起来有三个陷阱,我逐个说。

陷阱一是码率控制模型失配。硬件编码器内部有个虚拟缓冲的概念,它靠这个缓冲来保证输出码率不会突刺。你每帧都改目标值,这个虚拟缓冲的水位就会剧烈起伏,实际吐出来的码率跟你要的对不上。你以为你在精确控制,其实你在给编码器添乱。

陷阱二是画质「呼吸」。这是我最想强调的一条。人眼对画质的时间变化极其敏感。我们做过一次内部实验:把决策周期从 1 秒压到 100 毫秒,客观指标涨了 1.5 分左右,结果主观评分反而掉了。为什么?因为玩家看到了「闪烁」——这一帧清晰,下一帧糊,再下一帧又清晰。它像有人在你的屏幕上不停拧焦距旋钮,比一直糊难受得多。后来我们加了强制平滑,画质变化率做了限幅,主观分才回来。

陷阱三是和底层拥塞控制打架。ABR 是一条控制回路,底层的拥塞控制是另一条,两条回路的时标一旦接近,就会互相激励,产生振荡。你降码率,链路空了,拥塞控制以为带宽变好了,猛发一波,链路又堵了,你的 ABR 再降……这个死循环在真实网络里非常常见。破解办法只有一个:让两条回路的时标拉开,至少差一个数量级。

所以真正的结论不是「帧级比 GOP 级好」,而是:决策周期必须和你能拿到的有效信号匹配。你的带宽估计 200 毫秒才更新一次,你却每 16 毫秒做一次决策,那不叫灵敏,那叫瞎猜。我见过太多团队在这上面自嗨。

Parsec 在这条路上走得最远,也最能说明取舍。它客户端每收到一帧就回一个确认,服务端根据确认的到达节奏和排队情况来调码率——信号是真的,不是估算的。这让它在局域网和同城场景里口碑极好,延迟低到让人误以为是本地。代价也很明显:收敛依赖往返时延,跨洲链路上一来一回三百毫秒,它的调整就会明显滞后;丢包突发的时候又容易过度保守,画质掉下去爬不回来。你在论坛上能看到两种截然相反的评价,说它「神了」的和说它「糊成狗」的,八成是网络位置不同。这不是玄学,是设计决定的。

第 3 层:控制信号——从「带宽有多少」到「这一帧来不来得及」

直播 ABR 的经典三件套是:吞吐量估计、缓冲水位、丢包重传。云游戏这套不够用,因为它的核心问题变了——不是「管道有多粗」,而是「这一帧还剩多少时间」。

我给你列一下真正该采的信号:

信号采集位置噪声水平拿来干什么
发送队列长度服务端低判断是不是自己把链路撑爆了
帧截止时间余量服务端低紧急程度的直接度量
帧确认到达时间客户端回执中真实端到端表现,比任何估算都准
渲染帧耗时服务端低预示下一帧复杂度,是唯一的「前瞻」信号
编码耗时服务端低判断瓶颈在编码还是在网络
往返时延与抖动两端高决定你能多激进
客户端解码与呈现延迟客户端中端到端预算里最容易被漏掉的一段

把这些信号拼起来,你会得到一个和传统 ABR 完全不同的核心指标:按时到达率。定义很朴素——在一个统计窗口里,在截止时间之前到达并被解码呈现的帧数,除以总帧数。这个数字比「平均码率」有用一百倍,因为它直接对应玩家的感受。平均码率 18 兆、按时到达率 92%,和平均码率 12 兆、按时到达率 99%,后者体验好得多,但你看报表的时候很可能被前者骗了。

围绕这个指标,有个必须做的决策:一帧超时了,等还是丢?

这事儿不能一刀切,得按品类配。格斗、音游、竞技射击这类,宁可丢帧也不能延迟呈现——因为一帧迟到的画面是「错误的过去」,玩家看到的是敌人 80 毫秒前的位置,他会以为自己的枪打偏了。开放世界、回合制、剧情向反过来,多等 30 毫秒保住这一帧的完整性更划算,画面撕裂或者缺一块反而更出戏。这条策略在配置里通常叫「超时帧处理」,默认值给「丢」,然后按品类覆盖。

Xbox Cloud Gaming 是个很有意思的样本。它长期停留在 1080p,码率上限保守,画面偏软是被普遍吐槽的点。但你要说移动网络下的「可玩性」,它的口碑反而不差。原因就在这儿:它把按时到达率做得比较扎实,宁可画面软一点也不让你操作打滑。这说明一件事——ABR 的目标函数要是选错了,参数调得再精细都是白搭。画质是可以商量的,手感不能。

还有一个容易被忽视的细节:服务端的渲染帧耗时是唯一的「前瞻」信号。这一帧渲染花了 8 毫秒,下一帧大概率也复杂,你可以提前把码率预算提上去,等链路真的堵了再降就晚了。这是云游戏独有的作弊器——直播 ABR 永远只能看后视镜,你能看前挡风玻璃。用不用,是水平问题。

第 4 层:目标函数——纯带宽驱动和感知驱动的分野

纯带宽驱动的逻辑特别直白:链路能跑多少,我就填多少,填满为止。这套思路在视频网站上行得通,因为视频内容的码率需求相对平滑。放到游戏上就会出问题,因为游戏画面的「质量价值分布」极其不均匀。

具体不均匀在哪?

暗部。恐怖游戏、太空题材,城市夜景都是重灾区——大面积低亮度渐变,压缩稍微一狠就出色带,像糊了一层油。而且暗部恰恰是玩家最专注的地方,因为你在大面积黑里找东西。

快速平移。玩家一转身,整屏运动,运动补偿基本失效,码率需求瞬间翻倍。而这个瞬间恰好是他最需要看清的时候。

界面文字。细笔画字体,糊一点就不可读。界面又是玩家高频注视的区域,一块看不清的任务提示能把人逼疯。

粒子与烟雾。高频细节,编码器最恨这类内容,同样码率下画质掉得最快。

所以同样 20 兆,给《文明》绰绰有余,给《赛博朋克》就是不够。如果 ABR 能识别内容类型,就能做预算再分配——把不重要的帧省下来的比特,挪给重要的帧。

落地手段大概三类。第一类是场景切换检测:检测到切换,主动小幅降分辨率保帧率,切完再爬回来,玩家基本感知不到。第二类是内容分类:按运动量、暗部占比、界面占比给每帧打标签,动态调整量化偏移,暗部帧给更低的量化步长,运动帧适当放宽。第三类是感知质量驱动:用轻量模型估计当前帧的感知得分,把它当目标函数。这条路最诱人,也最容易翻车——画质评估模型在游戏内容上系统性偏高(这个话题在[10] 那篇会展开),而且算力开销不小,实际只能在服务端抽样跑,不能每帧跑。

真正要做降档的时候,先动谁?这张表我建议你贴在显示器边上:

降档手段带宽节省感知伤害恢复速度我的建议
小幅降分辨率(1080p 到 900p)中低,多数玩家看不出快首选,但注意界面会糊
提高量化步长(降码率)高中,暗部先崩快次选,配合暗部保护
降帧率(60 到 30)高极高,手感直接变质中尽量别动,动了就要背锅
丢帧极高看品类,竞技类反而可接受快保底手段,按品类开

GeForce NOW 这几年的演进特别值得琢磨。它早期是让用户手动选码率档位,后来加了自适应,2023 年推出旗舰档位,把码率上限推得很高,同时支持高刷新率,还上了新一代编码格式。这套动作背后的逻辑是:ABR 不只是技术问题,还是产品分层问题。同一个算法,在 20 兆和 75 兆下的行为完全不同,与其绞尽脑汁在低带宽里榨质量,不如把「画质预算」直接做成商品,让愿意付钱的用户跳出这场博弈。这招很聪明,因为它承认了一个事实——ABR 永远是在确定性和质量之间妥协,而总有一部分用户愿意用钱买确定性。

说到这儿我想插一句个人判断:很多人把 ABR 当成一个「算法问题」,我觉得它更像个「产品问题」。你得先想清楚,你的用户在什么网络下玩、玩什么品类、愿意为画质付多少钱,然后才轮到调参数。顺序反了,做出来的东西指标很漂亮,玩家还是不买账。

可落地的参数配置表与建议区间

下面这张表是我这些年攒下来的经验值,不是标准答案,但能让你少走弯路。拿去做起点,然后按你的品类和用户网络分布去调。

参数含义建议区间说明
决策周期两次码率决策的最小间隔100 到 500 毫秒必须显著长于带宽估计的更新周期
爬升速率每个周期允许上调的幅度5% 到 10%慢升,避免把链路顶爆
下降速率每个周期允许下调的幅度20% 到 30%快降,一般是爬升速度的三倍
变化率限幅相邻帧量化步长的最大差值2 到 4防画质「呼吸」,主观分救星
编码缓冲深度编码器内部虚拟缓冲对应时长200 到 500 毫秒太浅会突刺,太深反应迟钝
降分辨率触发连续几个周期带宽不足目标的百分比连续 3 个周期低于 85%加连续条件是为了防误判
回升高分辨率带宽持续富余多久才爬回去2 秒以上高于 120%滞回区间,防来回横跳
超时帧阈值帧龄超过多少判定作废1.5 倍帧间隔按品类覆盖,竞技类可收紧
暗部质量偏移低亮度帧相对平均的量化偏移-2 到 -4数值越负质量越高,按内容调
界面保护偏移界面区域量化偏移-2 到 -6如果做区域编码才有意义

补两条不成文的规矩。一是所有参数都要能按品类覆盖。格斗游戏和开放世界的配置不可能是同一套,别偷懒做全局配置。二是每个决策都要留日志。我见过太多团队,ABR 出了问题只能靠猜,因为没有记录每一帧的决策依据。这活儿不难,但上线前没人愿意做,出事的时候就知道疼了。

初级速览与进阶深入

初级用户,你只需要记住三条:

第一条,快降慢升。往下降的速度至少是往上升的三倍。链路的坏消息来得快,好消息不一定可信。

第二条,决策别比信号快。你的带宽估计多久更新一次,决策周期就不该短于它。做不到就老老实实做慢回路。

第三条,看板上别放平均码率,放按时到达率。这个指标一换,你团队关注的焦点会立刻变化——从「我们给了多少比特」变成「玩家按时看到了多少帧」。

进阶用户,往下挖三层:

第一层是分层控制。外层慢回路一到两秒定「预算」,内层快回路一百毫秒做「微调」。这样两条回路的时标天然拉开,不会打架,也不会因为抖动而误判。

第二层是可观测性。每一帧记三样东西:决策依据(当时的带宽估计、队列长度、渲染耗时)、决策结果(目标码率、实际输出码率)、玩家侧表现(到达时间、有没有作废)。出问题的时候,这三样能让你十分钟定位,而不是两天。

第三层是测试方法。别拿平均值做 A/B 测试的判据,要看分布——尤其是网络条件差的那 10% 用户的分布。云游戏的口碑往往是被这小部分人决定的,因为他们在论坛上发帖最勤快。

几个我见过太多人踩的坑

坑一:把「码率越高画质越好」当成公理。码率是手段不是目标。同样 20 兆,新一代编码格式可能直接把老格式按在地上摩擦。你死磕码率数字,不如先看看编码器换没换。

坑二:拿平均码率当考核指标。玩家感受到的不是平均值,是方差。一条 20 兆但每三秒抖一下的链路,体验远不如一条稳定的 14 兆。

坑三:把 ABR 全放客户端。客户端只知道「我收到了什么」,不知道「服务端本来有什么」。服务端的渲染复杂度、队列状态、编码耗时,这些信息不对称不解决,算法再聪明也是瞎子摸象。

坑四:忽视暗部。暗部是最容易暴露压缩问题的地方,也是最容易被工程师忽略的地方——因为测试用的截图往往是明亮的游戏开场。

坑五:忘记 ABR 和拥塞控制在打架。这是最隐蔽的一个。两条回路的时标接近就会振荡,而且振荡起来看起来像「网络问题」,你会花很长时间查错方向。这个坑的详细版本在[11] 那篇讲传输协议改造的时候会展开。

FAQ

问:为什么云游戏不能像视频网站那样准备多档,让客户端随便切?

因为成本结构不一样。视频网站一次编码、多档存储、CDN 分发,多一档几乎不花钱。云游戏每个玩家独占一路编码,多一档就多跑一路编码器,是实打实的算力和显存带宽开销。所以云游戏只能在同一路编码器里调参数,不能切档。

问:帧级自适应是不是一定比 GOP 级好?

不是。帧级反应快,但会带来三个问题:编码器码率控制模型失配、画质「呼吸」、和拥塞控制回路打架。正确的做法是让决策周期匹配你的信号更新频率,再加上变化率限幅。我自己的经验是,大部分场景下「慢回路定预算、快回路做微调」比纯帧级更稳。

问:能不能直接把画质评估模型当目标函数?

方向对,但不能直接用。画质评估模型在游戏内容上有系统性偏差,尤其是快速运动和粒子特效场景,而且算力开销不允许每帧跑。现实做法是服务端抽样跑,用它的结果去校准一套轻量的启发式规则,而不是把它当成实时目标。

问:小团队做云游戏,ABR 最少要做哪几件事?

三件。第一,把按时到达率做出来,这是你的眼睛。第二,快降慢升加变化率限幅,这是你的手。第三,每帧决策留日志,这是你的记忆。这三件事做完,剩下的都是锦上添花。

问:ABR 真的需要 AI 吗?

现阶段我觉得不必要。规则引擎在大部分场景下够用,而且可解释、好调试。AI 的价值在于处理规则覆盖不到的长尾场景,但前提是你有足够的数据和可观测性——这两样东西没有,上什么模型都是玄学。先把基本功做扎实,比追热点重要得多。

文章标签
云游戏Cloud Gaming视频编码H.264H.265AV1WebRTC低延迟传输ABR 自适应码率GPU 虚拟化DLSS 云游戏FSR 云游戏
更多专题全部专题
觉得有价值?点赞或收藏支持内容持续产出。
← 返回专题:云游戏技术专题