Linux使用FFmpeg制作简易云电脑

起因

最近挺流行云电脑、云游戏的。试一下Linux下使用FFmpeg制作简易云电脑的效果。

先上总结

最低延时为网络延时+60ms。显示效果不错。内网延时很小,外网鼠标略飘,键盘响应还行
因为鼠标在远端渲染,不像VNC鼠标是在本地渲染。

步骤

录制屏幕

FFmpeg使用x11grab可以录制X11的屏幕。intel核显的硬件QSV编码延时太高了,只能用软件libx264编码了。

ffmpeg -framerate 25 -f x11grab -i :0.0 -c:v libx264 output.mp4

此命令中
-framerate 25设置帧率为25
-f x11grab -i :0.0使用x11grab录制:0.0显示器的屏幕
输出到output.mp4文件中。

如果使用ssh远程执行并把结果转发到本地呢?

ssh user@remote ffmpeg -framerate 25 -f x11grab -i :0.0 -c:v libx264 -f h264 - | ffplay -fs -

此命令通过ssh连接在远程执行录制命令,把user@remote替换为ssh服务器用户和地址。其中
-c:v libx264指定使用libx264编码器进行视频编码
-f h264指定输出封装为raw的h264格式,因为直接输出到标准输出,就无法根据输出文件推断适合的格式了
这边可选的还有flvmpegtsh264因为是原始格式,延时会更低。flvmpegts支持封装音频,flv更简单更适合直播。
使用ffplay在本地播放标准输入。但是延时很高。

延时高的第一反应是播放器做了缓冲,尽量关闭播放器的缓冲

ffplay -framedrop -fflags nobuffer -flags low_delay -strict experimental -probesize 32 -analyzeduration 0 -an -vf setpts=0 -

此命令中
-framedrop允许丢帧
-fflags nobuffer关闭缓冲
-flags low_delay设置低延时模式
-strict experimental使用实验性功能,允许使用不稳定的编解码器。
-probesize 32设置探测大小为32字节
-analyzeduration 0设置分析持续时间为0
-an禁用音频
-vf setpts=0设置视频时间戳为0

效果非常明显,已经只能感觉到很小的延时了。
编码的时候也可以设置一些参数减少延时

ssh user@remote ffmpeg -framerate 25 -f x11grab -i :0.0 -preset ultrafast -tune zerolatency -c:v libx264 -f h264 - | ffplay -framedrop -fflags nobuffer -flags low_delay -strict experimental -probesize 32 -analyzeduration 0 -an -vf setpts=0 -

-preset ultrafast设置编码速度为最快
-tune zerolatency设置编码延时为0

声音

声音处理有2种方式:一种是封装进flv一起播放出来,另一种是单独再开一个通道播放。
方式依然采用ffmpeg+ffplay

先找到声卡设备,可以借助pulse。最简单也可能有效的直接选择default设备。

方式一:改用flv。把-an换成了-sync ext,做一下音视频同步。

ssh user@remote ffmpeg -framerate 25 -f x11grab -i :0.0 -f pulse -i default -preset ultrafast -tune zerolatency -c:v libx264 -f flv - | ffplay -framedrop -fflags nobuffer -flags low_delay -strict experimental -probesize 32 -analyzeduration 0 -sync ext -vf setpts=0 -

如果不行,可能要手动选择。先列出所有的声卡设备

pactl list short sources

会列出所有的声卡设备,找到对应的设备名称,比如alsa_input.pci-0000_00_1b.0.analog-stereo

pactl set-default-source alsa_input.pci-0000_00_1b.0.analog-stereo

设置为默认设备,再试就可以了,或者命令里直接-f pulse -i alsa_input.pci-0000_00_1b.0.analog-stereo

经测试,用flv封装音频比较正常,画面延时会比h264稍微高一点点,效果很不错了。
mpegts封装aac容易不识别,改为ac3可以,但是和hevc一起有会播放不了音频。

方式二:画面还是用h264,音频单独再开一个通道,用adts封装。

ssh user@remote ffmpeg -f pulse -i default -c:a aac -b:a 128k -f adts - | ffplay -fflags nobuffer -framedrop -flags low_delay -vn -nodisp -

其中
-c:a aac设置音频编码器为aac
-b:a 128k设置音频比特率为128kbps
-f adts设置音频封装格式为adts
-vn禁用视频流
-nodisp禁用显示窗口

这样画面延时会更低,音频延时会高一点点,会有不同步的情况。但有另一个好处是单独音频可以搭配VNC使用。

键鼠

键鼠方案其实挺多的,如usbip、x2x、x2vnc、evdev转发等,但是鼠标映射都会带来一些延时,最好是VNC哪种本地渲染鼠标发送到远程的方式,暂未尝试。

这边使用x2vnc,远端只要有VNC Server就行,相对简单。

/usr/bin/x2vnc remote:0 -west -passwdfile ~/.vnc/passwd -shared

其中
remote:0指定远程VNC服务器的显示器,remote替换为VNC服务器地址
-west指定鼠标从本地屏幕向西移动时切换到远程屏幕
-passwdfile ~/.vnc/passwd指定VNC密码文件
-shared允许多个客户端同时连接

延伸

  1. 鼠标在本地移动和点击后,发送相对于显示内容的位置和事件到远程,可以改善鼠标漂移的体验。
  2. 通过-window_id可以指定录制窗口,后台窗口也可以。如果配合xdotool应该可以操作单个窗口。
  3. 如果录制端是Windows系统和N卡,能做到最低多少延时。

最后修改于 2025-05-03