Linux:通过网络捕获桌面视频和 VNC 帧率

Posted

技术标签:

【中文标题】Linux:通过网络捕获桌面视频和 VNC 帧率【英文标题】:Linux: Screen desktop video capture over network, and VNC framerate 【发布时间】:2011-05-16 14:32:16 【问题描述】:

对不起文字墙 - TL;DR:

VNC 连接的帧速率是多少(以帧/秒为单位)- 或者更确切地说,由谁决定:客户端还是服务器? 有关桌面屏幕捕获的任何其他建议 - 但“时间编码正确”/具有无抖动帧速率(具有稳定周期);并有可能将其作为未压缩(或无损)图像序列获得?

简而言之 - 我遇到了一个典型的问题:我有时会开发硬件,并想录制一个视频,显示在 PC 上输入的两个命令(“桌面捕获”),和硬件的响应(“实时视频”)。在我谈到具体细节之前,接下来是一段介绍。

简介/背景

目前,我的策略是使用摄像机记录硬件测试过程(作为“实时”视频) - 同时进行桌面捕获。摄像机产生 29.97 (30) FPS MPEG-2 .AVI 视频;我想以与视频相同的帧速率将桌面捕获作为 PNG 的图像序列。那么,这个想法是:如果两个视频的帧速率相同;那么我可以简单地

将桌面捕获的开始时间与“实时”视频中的匹配点对齐 设置picture-in-picture,将桌面捕获的缩小版本(作为覆盖)放置在“实时”视频之上 (“实况”视频上的一部分屏幕用作与“桌面捕获”叠加层的视觉同步源) 导出“最终”组合视频,并针对 Internet 进行适当压缩

原则上,我想可以使用像ffmpeg 这样的命令行工具来处理这个过程;但是我更喜欢使用 GUI 来查找两个视频的对齐起点。

最终,我还想要实现的是在导出“最终”视频时保持最高质量:“实时”视频在离开相机时已经被压缩,这意味着当它通过 Theora 时会进一步降级。 ogv 编解码器 - 这就是为什么我想保留原始视频,并在需要不同的压缩/分辨率时使用命令行之类的东西重新生成“最终”视频。这也是我喜欢将“桌面捕获”视频作为 PNG 序列的原因(尽管我猜任何未压缩的格式都可以):我采取措施“调整”桌面,因此没有太多渐变和无损编码(即PNG)将是合适的。

桌面捕获选项

嗯,在我目前使用的 Ubuntu Lucid 下这个过程有很多麻烦(你可以在 10.04: Video overlay/composite editing with Theora ogv - Ubuntu Forums 阅读我的一些考验)。然而,关键问题之一是假设两个传入视频的帧速率相等 - 实际上,通常桌面捕获的帧速率较低;更糟糕的是,帧经常不同步

因此,这需要坐在视频编辑器前,在帧级别手动剪切和编辑不到一秒的剪辑的麻烦 - 需要 小时 的工作才能完成最后是一个 5 分钟的视频。另一方面,如果两个视频('live' 和 'capture')确实具有相同的帧速率和同步:原则上,您只需几分钟即可找到在视频编辑器中开始同步点 - 其余的“合并”视频处理可以由单个命令行处理。这就是为什么在这篇文章中,我想重点介绍桌面捕获部分。

据我所知,在 Linux / Ubuntu 中只有少数可行(与 5 Ways to Screencast Your Linux Desktop 不同)用于桌面捕获的替代方案(注意,我通常使用笔记本电脑作为桌面目标捕获):

    让您的目标 PC(笔记本电脑)在其 VGA 输出上克隆桌面;使用 VGA-to-composite 或 VGA-to-S-video 硬件从 VGA 获取视频信号;使用其他 PC 上的视频采集卡抓取视频 在目标电脑上使用recordMyDesktop 在要捕获的目标PC上设置VNC server(在Ubuntu上为vino;或vncserver);在不同的 PC 上使用 VNC 捕获软件(例如 vncrec)来抓取/记录 VNC 流(随后可以转换为视频)。 将ffmpegx11grab 选项一起使用 *(在目标 PC 上使用一些工具,直接将桌面图像帧 DMA 从显卡帧缓冲内存传输到网络适配器内存)

请注意,上述方法的实用性受到我的使用环境的限制:我要捕获的目标 PC 通常运行围绕大量数据移动的软件(使用经过测试的硬件);关于描述这样一个系统,你可以说的最好的说法是“几乎不稳定”:) 我猜这类似于游戏玩家在想要获得要求苛刻的游戏的视频捕获时所面临的问题。一旦我开始使用recordMyDesktop 之类的东西,它也使用了相当多的资源并想在本地硬盘上捕获 - 我立即遇到严重的内核崩溃(通常没有生成 vmcore)。

因此,在我的上下文中,我通常会假设有 第二台 计算机参与 - 运行“目标”PC 桌面的捕获和记录。除此之外,到目前为止我可以看到上述选项的利弊如下。

(桌面准备)

对于下面讨论的所有方法,我倾向于事先“准备”桌面:

删除桌面背景和图标 通过 System/Preferences/Monitors (gnome-desktop-properties) 将分辨率设置为 800x600 Change color depth 低至 16 bpp(使用 xdpyinfo | grep "of root" 进行检查)

...为了最大程度地减少桌面捕获软件的负载。请注意,在 Ubuntu 上更改颜色深度需要更改 xorg.conf;但是,“No xorg.conf (is) found in /etc/X11 (Ubuntu 10.04)” - 所以您可能需要先运行 sudo Xorg -configure

为了保持较低的图形资源使用率,我通常也禁用compiz - 或者更确切地说,我会将“系统/首选项/外观/视觉效果”设置为“无”。但是,在我尝试通过将“视觉效果”设置为“正常”(其中doesn't get saved)启用compiz 之后,我可以注意到液晶屏幕上的窗口重绘速度要快得多;所以我保持这样,也用于桌面捕获。我觉得这有点奇怪:more 效果怎么会导致 faster 屏幕刷新?它看起来不像是由于专有驱动程序(该卡是“Intel Corporation N10 Family Integrated Graphics Controller”,Ubuntu 在切换到 compiz 时没有提供专有驱动程序选项) -不过,可能所有的模糊和效果都会欺骗我的眼睛:))。

克隆 VGA

嗯,这是最昂贵的选择(因为它需要额外购买的不仅仅是一个,而是两个硬件:VGA 转换器和视频采集卡);并且主要适用于笔记本电脑(同时具有屏幕 + 额外的 VGA 输出 - 对于台式机,可能还需要购买额外的显卡或 VGA 克隆硬件)。

然而,它也是唯一一个不需要目标 PC 额外软件的选项(因此使用目标 CPU 的 0% 处理能力) - 也是唯一一个可以提供带有 的视频的选项true,30 fps 的无抖动帧速率(因为它由单独的硬件执行 - 尽管假设时钟域未对齐,存在于各个硬件部件之间,可以忽略不计)。

实际上,由于我已经拥有像采集卡这样的东西,我已经投资了一个 VGA 转换器 - 期望它最终能让我制作最终的“合并”视频,只需 5 分钟寻找对齐点,并且单个命令行;但我还没有看到这个过程是否会按预期工作。我也在徘徊将桌面捕获为未压缩视频@ 800x600、30 fps 的可能性有多大。

recordMyDesktop

好吧,如果你在没有任何参数的情况下运行recordMyDesktop - 它首先会在/tmp/rMD-session-7247 之类的文件夹中捕获(看起来像)原始图像数据;在您按下 Ctrl-C 中断它后,它会将这些原始图像数据编码为 .ogv。显然,在与我的测试软件相同的硬盘上抓取大图像数据(它也移动大量数据)通常是导致 instacrash 的原因:)

因此,我尝试做的是setup Samba在网络上共享一个驱动器;然后在目标 PC 上,我将连接到此驱动器 - 并指示 recordMyDesktop 使用此网络驱动器(通过 gvfs)作为其临时文件位置:

recordmydesktop --workdir /home/user/.gvfs/test\ on\ 192.168.1.100/capture/ --no-sound --quick-subsampling --fps 30 --overwrite -o capture.ogv 

请注意,虽然此命令将使用网络位置存储临时文件(从而使recordMyDesktop 可以与我的软件并行运行) - 一旦您按下 Ctrl-C,它将开始编码并将capture.ogv 直接保存在目标的本地硬盘上(不过,那时我并不在意:))

我对@9​​87654370@ 的第一个抱怨是你不能指示它保留临时文件并避免对它们进行编码:你可以使用 Ctrl+Alt+p 暂停 - 或者你可以快速按下 Ctrl-C在第一个之后,导致它崩溃;然后它会留下临时文件(如果您第二次没有足够快地按 Ctrl-C,程序将“清理缓存...”)。然后你可以运行,说:

recordmydesktop --rescue /home/user/.gvfs/test\ on\ 192.168.1.100/capture/rMD-session-7247/

...为了转换原始临时数据。然而,recordMyDesktop 通常会在执行此“救援”的过程中出现段错误。虽然,我想保留临时文件的原因是为了获得画中画蒙太奇的未压缩源。请注意,“--on-the-fly-encoding”将完全避免使用临时文件 - 以使用更多 CPU 处理能力为代价(对我来说,这又是导致崩溃的原因。)

然后是帧率 - 显然,您可以使用 '--fps N' 选项设置 requested 帧率;但是,这并不能保证您将实际获得该帧速率;例如,我会得到:

recordmydesktop --fps 25
...
Saved 2983 frames in a total of 6023 requests
...

... 在我的测试软件运行时进行捕获;这意味着实际达到的速率更像是 25*2983/6032 = 12.3632 fps!

显然,帧被丢弃了 - 大部分显示为video playback is too fast。但是,如果我将请求的 fps 降低到 12 - 然后根据保存/总报告,我会达到 11 fps;在这种情况下,视频播放看起来并没有“加速”。而且我还没有尝试将这样的捕获与实时视频对齐 - 所以我不知道实际保存的那些帧是否也有准确的时间戳

VNC 捕获

对我而言,VNC 捕获包括在“目标”PC 上运行 VNC 服务器,并在“记录器”PC 上运行 vncrec(twibright 版)。作为 VNC 服务器,我使用vino,即“系统/首选项/远程桌面(首选项)”。显然,即使vino configuration 可能不是最容易管理的东西,vino 作为服务器似乎对“目标”PC 来说并不太费力;因为当它与我的测试软件并行运行时,我没有经历过崩溃。

另一方面,当vncrec 在“记录器”PC 上进行捕获时,它还会弹出一个窗口,向您显示“目标”桌面,就像它在“实时”中看到的一样;当“目标”上有大量更新(即整个窗口移动)时 - 可以很明显地看到“记录器”上的更新/刷新率问题。但是,对于小的更新(即只是一个在静态背景上移动的光标),事情似乎还不错。

这让我想知道我对这篇文章的主要问题之一 - 它是什么,在 VNC 连接中设置帧速率?

我还没有找到明确的答案,但从零碎的信息(请参阅下面的参考文献),我收集到:

VNC 服务器在收到更改(屏幕更改 + 点击等)后,会尽可能快地发送更改;受限于服务器可用的最大网络带宽 VNC 客户端接收到那些因网络连接延迟和抖动的更改事件,并尝试再次以尽可能快的速度重建桌面“视频”流

...这意味着,人们无法用稳定的周期性帧速率(如视频)来说明任何事情。

vncrec 的客户而言,我得到的最终视频通常被声明为 10 fps,尽管帧可能相当位移/抖动(这需要在视频编辑器中进行剪辑)。请注意vncrec-twibright/README 声明:“影片的采样率默认为 10,或被 VNCREC_MOVIE_FRAMERATE 环境变量覆盖,如果未指定,则为 10。”;但是,手册页还指出“VNCREC_MOVIE_FRAMERATE - 指定输出电影的帧速率。仅在 -movie 模式下有效。默认为 10。当您的转码器从 10 吐出时尝试 24。”。如果查看“vncrec/sockets.c”源,可以看到:

void print_movie_frames_up_to_time(struct timeval tv)

  static double framerate;
  ....
  memcpy(out, bufoutptr, buffered);
  if (appData.record)
    
      writeLogHeader (); /* Writes the timestamp */
      fwrite (bufoutptr, 1, buffered, vncLog);
    

... 这表明写入了一些时间戳 - 但这些时间戳是来自“原始”“目标”PC,还是来自“记录器”,我无法确定。 编辑:感谢@kanaka 的回答,我再次检查了vncrec/sockets.c,可以看到是writeLogHeader 函数本身调用了gettimeofday;所以它写入的时间戳是本地的——也就是说,它们来自“记录器”PC(因此,这些时间戳不能准确地描述帧何时起源于“目标”PC)。

无论如何,在我看来,服务器发送 - 和 vncrec 作为客户端接收 - 无论何时;并且只有在之后从原始捕获中编码视频文件的过程中,才会设置/内插某种形式的帧速率。

我还想在我的“目标”笔记本电脑wired network connection is broken 上说明这一点;所以无线是我访问路由器和本地网络的唯一选择 - 速度远低于路由器可以通过有线连接处理的 100MB/s。但是,如果捕获帧中的抖动是由“目标”PC 上的负载导致的错误时间戳引起的,我认为良好的网络带宽不会有太大帮助。

最后,就 VNC 而言,可能还有其他替代方案可供尝试 - 例如 VNCast 服务器(很有希望,但需要一些时间从源代码构建,并且处于“早期实验版本”中 em>);或MultiVNC(虽然它看起来像一个客户端/查看器,没有录制选项)。

ffmpeg 与 x11grab

没有玩过这么多,但是,我已经尝试过与netcat相关的;这个:

# 'target'
ffmpeg -f x11grab -b 8000k -r 30 -s 800x600 -i :0.0 -f rawvideo - | nc 192.168.1.100 5678
# 'recorder'
nc -l 0.0.0.0 5678 > raw.video  #

... 确实捕获了一个文件,但ffplay 无法正确读取捕获的文件;而:

# 'target'
ffmpeg -f x11grab -b 500k -r 30 -s 800x600 -i :0.0 -f yuv4mpegpipe -pix_fmt yuv444p - | nc 192.168.1.100 5678
# 'recorder'
nc -l 0.0.0.0 5678 | ffmpeg -i - /path/to/samplimg%03d.png

确实会生成 .png 图像 - 但带有压缩伪像(我猜是 yuv4mpegpipe 所涉及的压缩结果)。

因此,我目前不太喜欢ffmpeg+x11grab - 但也许我根本不知道如何根据自己的需要进行设置。

*(显卡 -> DMA -> 网络)

诚然,我不确定这样的事情是否存在 - 事实上,我敢打赌它不存在 :) 而且我不是这里的专家,但我推测:

如果 DMA 内存传输可以从作为 source 的显卡(或其保存当前桌面位图的缓冲区)启动,而网络适配器作为 destination - 那么原则上,应该可以获得具有正确(和体面)帧速率的未压缩桌面捕获。当然,使用 DMA 传输的目的是将处理器从将桌面图像复制到网络接口的任务中解放出来(因此,减少捕获软件对运行在 ' 上的进程的影响目标电脑——尤其是那些处理 RAM 或硬盘的电脑)。

这样的建议当然是假设:有大量的网络带宽(对于 800x600,30 fps 至少 800*600*3*30 = 43200000 bps = 42 MiB/s,这应该对于本地 100 MB/s 网络来说没问题);另一台 PC 上的大量硬盘进行“记录” - 最后是可以读取原始数据并基于它生成图像序列或视频的软件 :)

我可以接受的带宽和硬盘需求——只要保证稳定的帧速率和未压缩的数据;这就是为什么我很想知道这样的事情是否已经存在。

-- -- -- --

好吧,我想就是这样 - 尽可能简短 :) 任何有关工具或流程的建议,都可以通过桌面捕获产生

未压缩格式(最终可转换为未压缩/无损 PNG 图像序列),并且 具有“正确的时间编码”、稳定的帧率

...,最终将有助于“简单”的单一命令行处理以生成“画中画”叠加视频 - 将不胜感激!

提前感谢任何cmets, 干杯!


参考文献

    Experiences Producing a Screencast on Linux for CryptoTE - idlebox.net The VideoLAN Forums • View topic - VNC Client input support (like screen://) VNCServer throttles user inpt for slow client - Kyprianou, Mark - com.realvnc.vnc-list - MarkMail Linux FAQ - X Windows: How do I Display and Control a Remote Desktop using VNC How much bandwidth does VNC require? RealVNC - Frequently asked questions x11vnc: a VNC server for real X displays HowtoRecordVNC (an X11 session) - Debian Wiki Alternative To gtk-RecordMyDesktop in Ubuntu (Ffmpeg-user) How do I use pipes in ffmpeg (ffmpeg-devel) (PATCH) Fix segfault in x11grab when drawing Cursor on Xservers that don't support the XFixes extension

【问题讨论】:

+1 表示史诗长度但连贯的问题。引用也+1:P 干杯@Matt Ball - 谢谢:) 如果您仍然在使用 Compiz,请试一试 vidcap plugin。 谢谢,@ephemient - 这确实看起来 非常 有趣!.. 我看不到很多文档,但我可以看到一些 OpenGL 调用 - 看起来很有希望!我相信我很快就会开始尝试它(虽然看起来我需要一段时间才能确切地理解它的作用 - 尽管我必须承认,我对优雅的简单性感到有些困惑 i>) :) 再次感谢,干杯! 经过所有这些研究,您想出了什么解决方案? 【参考方案1】:

您应该为这么长的问题获得徽章。 ;-)

在回答您的主要问题时,VNC 使用 RFB 协议,它是一种远程帧缓冲协议(因此是首字母缩略词)而不是流式视频协议。 VNC 客户端向服务器发送 FrameBufferUpdateRequest 消息,该消息包含客户端感兴趣的视口区域和增量标志。如果未设置增量标志,则服务器将使用包含请求区域内容的 FrameBufferUpdate 消息进行响应。如果设置了增量标志,则服务器可能会以 FrameBufferUpdate 消息进行响应,该消息包含自上次向客户端发送该区域以来所请求区域的任何更改部分。

请求和更新如何交互的定义没有明确定义。如果没有任何变化,服务器不一定会通过更新响应每个请求。如果服务器有多个来自客户端的请求排队,它也被允许发送一个更新作为响应。此外,客户端确实需要能够响应来自服务器的异步更新消息(而不是响应请求),否则客户端将不同步(因为 RFB 不是框架协议)。

客户端通常被简单地实现为定期发送整个帧缓冲区视口的增量更新请求,并在它们到达时处理任何服务器更新消息(即不尝试将请求和更新绑定在一起)。

Here 是 FrameBufferUpdateRequest 消息的描述。

【讨论】:

先生,您当然应该收到一个接受和 +1 :) 非常感谢您的简洁解释 - 它终于让我通过vncrec/sockets.c,并意识到它记录的时间戳,对客户端来说是本地的(在 OP 中添加编辑)。干杯! 看起来原来的链接现在已经失效了。 Here's 已更新。

以上是关于Linux:通过网络捕获桌面视频和 VNC 帧率的主要内容,如果未能解决你的问题,请参考以下文章

vnc viewer 远程桌面,11步实现vnc viewer 远程桌面连接Linux

vnc viewer 远程桌面,11步完成Linux连接vnc viewer 远程桌面

视频识别:SlowFast Networks

vnc 连接linux,为啥不显示桌面?

学术论文丨视频识别SlowFast Networks

从 Raspicam 捕获慢帧率视频