ESC
科技 2 分钟阅读

Apple「随航」的无感体验里,藏着多少流畅的秘密?

文章回顾iPad变Mac副屏方案的演进:从早期iDisplay、Air Display的WiFi传输,到Duet Display有线方案,再到Astropad、Luna Display硬件适配产品。2019年WWDC上Apple推出随航功能,引发Astropad「被Sherlock」争议。随航流畅的秘密在于虚拟屏幕渲染、WindowServer画面合成与编码传输的系统级精密协同,体验超越第三方方案

来源:少数派

iDisplay 会在 Mac 中安装一套扩展驱动,创建一块系统能够识别的虚拟显示器,再通过 Wi-Fi 将画面发送到 iPad。用户可以像使用普通副屏一样排列两块屏幕,把 Mac 窗口拖到 iPad 上;甚至在遥远的 2010 年,iDisplay 就能「十分先进」地将 iPad 的触摸及键入操作反向传回 Mac。

只是这款诞生于 iPad 发售之初的软件远远谈不上「流畅」,甚至有着堪称灾难的使用体验:无论是繁琐的前期设置、极不稳定的连接,还是动辄数秒的延迟,都表明它更像是一次对新技术的探索,而非成熟的解决方案。

所以同年,Avatron Software 推出了 Air Display。它采用了与 iDisplay 相似的思路,进行了一部分的优化,不过仍称不上「好用」,动态画面仍有不小的延迟。此后几年,围绕「iPad 作为扩展副屏」的解决方案不断涌现,但总体而言,彼时「将 iPad 作为扩展副屏」这个点子在大多数人看来还是一种新奇的功能玩法,或是应急需求,没有人真正将它视作生产力的一部分。

读到这相信你也在想:既然「无线」带来了那么多问题,那加上一根线不就行了?巧了,正有一群和你抱有同样想法的前 Apple 工程师。于是 Duet Display 来了。

与上述使用过 Wi-Fi 传输的产品不同,Duet Display 须使用 Lightning 或 30 Pin 数据线连接 Mac 与 iPad。得益于有线这一较为稳定的传输方式,Duet Display 打出了「Retina、60 fps、No Lag」的宣传旗号。

但需要注意的是,这里的「有线连接」有别于普通的显示器连接,它并不能直接将 iPad 扩展为一块普通的显示器 —— 因为iPad 不能通过它直接接收 Mac 输出的视频信号,本质上,它只是将数据传输方式从无线改为有线;画面的生成与显示过程仍与先前的软件类似,需要先在 Mac 中创建一块虚拟显示器,再将画面处理后传送至 iPad。

因此 Duet 也并没有像宣传的那么美好:其 Retina 与 60 fps 模式会占用大量 CPU,部分旧款 Mac 仍会出现光标延迟、画面伪影与系统卡顿。所以再后来,市面上又出现了针对将 iPad 扩展为数位板的 Astropad、以及借助 DisplayPort 硬件适配器、让 Mac 将 iPad 识别为「真实外接显示器」的 Luna Display 等产品……

时至今日,市场上依然活跃着不少第三方随航类软件,其中一些在满足特定需求方面仍有优势,在此暂且按下不表,有兴趣的读者可以根据自己的需求进一步探索。

2019 年 6 月 3 日,Craig Federighi 在 Apple 的 WWDC 2019 上首次公布了一项名为 Sidecar 的新功能,正式将「让 iPad 变成 Mac 副屏」纳入系统功能中。

这里有一段颇有意思的小插曲。随航亮相后,Astropad 作为前文介绍的 Astropad Studio 与 Luna Display 背后的团队,很快在官网发文「抗争」,声称 Apple「高度复制」了自己的产品线,并把这次遭遇称为被 Apple Sherlock1。这番指控究竟有多少事实依据,我们便不得而知了。

虽然 Sidecar 在整场发布会中只出现了不足 60 秒,但其中一些有趣的细节仍值得我们探索。毕竟很长一段时间里,Apple 的软件功能似乎都给人一种印象:它们或许未必最早出现,但被 Apple 整合进系统后,往往能呈现出相较第三方要更加完整的体验。

简单来说,一帧画面要显示在作为 Mac 副屏的 iPad 上,主要需要经过以下几个环节:

前文中提到的 iDisplay、Air Display 等第三方软件,其实已经用上了「虚拟屏幕渲染」的思路。简单来说,它们会先在系统中创建一块虚拟的显示器,并像对待实体显示器一样,为其正常分配桌面空间和分辨率等。此时应用仍然按照正常方式绘制窗口,再由 macOS 中负责管理和合成屏幕画面的 WindowServer 组合成虚拟显示器上的完整画面。

不过这些画面最终不会被送往真正的物理显示接口,而是由系统或第三方软件读取,再进入后续的编码与传输流程。

相比之下,接下来的几个环节的精密协同,才是随航真正与第三方方案拉开差距的地方,也是其能够做到如此流畅的关键。

传统外接显示器的逻辑其实很简单,GPU 完成一帧画面的渲染与合成后,只需要按照显示器规格生成显示信号,再通过 HDMI、DisplayPort 或 Thunderbolt 等接口送往显示器即可。

但一块高分辨率屏幕每秒产生的数据量远比想象中庞大。做一个并不严谨的计算:以 2388 × 1668 分辨率的画面为例(2018—2022 款 11 英寸 iPad Pro,也是笔者所用的型号),假设每个像素使用 4 字节(RGBA)表示,那么每帧图像所占用的空间大约为 2388 × 1668 × 4 ÷ 1000² ≈ 15.9 MB。如果设备的刷新率为默认的 60Hz,一秒钟产生的原始画面数据便已经接近 1 GB。

对于上述针对外接显示器的有线传输来说,这样的数据量并不是什么大问题。HDMI 2.0 的最高传输带宽可以达到 18 Gbps,而 DisplayPort 1.2 则可以达到 21.6 Gbps,足以承载 4K 60Hz 级别的显示信号。但对于无线传输的随航来说,想要稳定传输如此庞大的原始画面数据显然并不现实。因此在画面离开 Mac 之前,还需要先经过一道关键步骤——编码。

本质上,随航所传输的其实是一条实时视频流,因此它对屏幕画面的压缩也沿用了现代视频 HEVC 编码的基本思路。

HEVC 是 High Efficiency Video Coding (高效率视频编码)的缩写,你或许对它的另一个名字更熟悉——H.265。它由 ITU-T 与 MPEG 共同制定,可以看作 H.264/AVC 的继任者。HEVC 的核心精髓便是「猜」,用尽可能少的原始画面,推算出接下来的视频内容,从而节省海量的空间。

那上述的「海量」究竟如何量化?简单做个演示,我们可以借助 FFmpeg 对系统 UI 进行无损录屏。在系统「终端」中输入以下指令,查看 FFmpeg 可以调用的视频设备:

ffmpeg -hide_banner -f avfoundation -list_devices true -i "" 在输出结果中找到 Capture screen 0,并记下它前面的设备编号:

再输入以下指令开启无损录屏(若 Capture screen 0 指令得到的编号不为 3,则在第三行「3:none」中替换为实际的数字):

ffmpeg -f avfoundation -framerate 30 -pixel_format bgr0 -capture_cursor 1 \ -i "3:none" \ -c:v ffv1 -level 3 -coder 1 -context 1 -slicecrc 1 -pix_fmt bgr0 \ "$HOME/Downloads/screen-lossless.mkv" 按 Q 即可停止录制。接下来我们在终端中输入以下命令,将刚刚录制的无损视频压缩为 HEVC:

ffmpeg -i "$HOME/Downloads/screen-lossless.mkv" \ -c:v libx265 -preset medium -crf 23 \ -pix_fmt yuv420p \ "$HOME/Downloads/screen-hevc.mp4" 这种视觉上近乎无损的压缩,几乎节省了 99% 的文件体积:

为了模拟使用随航时画面变化更加频繁的场景(如播放视频),笔者在影视飓风官网的「飓风素材库」中下载了* Bo-Kaap-02 *这条素材进行演示。

下图为使用 HEVC 压缩前后的首帧对比截图。相信你和我一样,哪怕是将下图铺满全屏,也很难分辨究竟哪边才是原片。

为了理解这 98% 的数据究竟去了哪里,我们需要先简单了解 HEVC 的编码原理,也就是笔者前文所说的「猜」的过程。

在预测开始前,HEVC 会先将画面划分为一个个编码树单元,也就是 CTU(Coding Tree Unit)。在 HEVC 中,一个 CTU 最多覆盖 64 × 64 个亮度像素,并可以继续通过四叉树结构划分为尺寸更小的编码单元 CU(Coding Unit)。

这种划分并不是固定的。天空、墙面等颜色和纹理较为平缓的区域,可以保留尺寸较大的 CU;车辆、树木和建筑边缘等细节密集的区域,则往往需要继续向下划分。编码器由此能够根据不同区域的复杂程度,选择更合适的处理粒度。在 StreamEye 中2,这一结构可以被直接观察到。

比如选中画面右侧较为平坦的白墙时,一个 CTU 内只有少量尺寸较大的 CU;切换到细节复杂的塔楼后,分块会明显变得更加密集。

确定 CU 的大小后,编码器还会为其选择预测方式,并根据需要将其划分为一个或多个预测单元,也就是 PU(Prediction Unit)。接下来,编码器会针对这些区域寻找尽可能接近原始画面的预测结果。而用于预测的信息主要有两个来源:一种来自当前画面中已经得到的相邻区域,另一种则来自视频中的其他参考画面。根据参考信源的不同,HEVC 中的预测也就可以分为两大类——「帧内预测」与「帧间预测」。

「帧内预测」(Intra Prediction),顾名思义,即不依赖视频中其它帧,而是利用当前帧中已经得到的相邻画面信息,来预测当前单元中的内容。

这里的「相邻区域」通常位于编码块的上方与左侧。由于画面会按照一定顺序逐块处理,当编码器来到当前块时,这些区域已经完成了编码与重建,因此编码器和解码器都能够获得同一组参考像素。

HEVC 共提供了 35 种亮度帧内预测模式,其中包括 33 种角度模式,以及 Planar(平面)模式与 DC 模式。Planar 模式更适合颜色缓慢变化的区域,它会综合块上方与左侧的参考像素,在块内生成较为平滑的渐变。DC 模式则会根据周围参考像素计算一个平均值,再用这个近似的颜色填充整个块。

回到 StreamEye,这个过程也可以被直观地观察到。这里笔者选择了一帧完全依靠帧内预测完成编码的 I 帧(至于什么是 I 帧,我们将在后文继续说明)。下图左、右两侧分别展示了两种帧内预测模式。左图选中的是天空中颜色过渡较为平缓的区域,编码器采用了 Planar 模式,通过相邻参考像素生成连续、平滑的渐变;右图选中的街景区域则具有更加明显的边缘与纹理走向,因此采用了 25 Angular 模式,沿特定方向将相邻像素的信息延伸至当前块内。