起因
最近挺流行云电脑、云游戏的。试一下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格式,因为直接输出到标准输出,就无法根据输出文件推断适合的格式了
这边可选的还有flv
和mpegts
,h264
因为是原始格式,延时会更低。flv
和mpegts
支持封装音频,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
允许多个客户端同时连接
延伸
- 鼠标在本地移动和点击后,发送相对于显示内容的位置和事件到远程,可以改善鼠标漂移的体验。
- 通过
-window_id
可以指定录制窗口,后台窗口也可以。如果配合xdotool应该可以操作单个窗口。 - 如果录制端是Windows系统和N卡,能做到最低多少延时。
最后修改于 2025-05-03