34

对不起文字墙 - TL; DR:

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

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

介绍/上下文

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

  • 将桌面捕获的开始时间与“实时”视频中的匹配点对齐
  • 设置画中画,将桌面捕获的缩小版本(作为叠加)放置在“实时”视频的顶部
    • (其中“实时”视频上的一部分屏幕用作带有“桌面捕获”叠加层的视觉同步源)
  • 导出“最终”组合视频,为 Internet 适当压缩

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

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

桌面捕获选项

好吧,在我目前使用的 Ubuntu Lucid 下这个过程有很多麻烦(你可以在 10.04 中阅读我的一些考验:使用 Theora ogv 进行视频叠加/合成编辑 - Ubuntu 论坛)。然而,关键问题之一是假设两个传入视频的帧速率相等 - 实际上,通常桌面捕获的帧速率较低;更糟糕的是,帧经常不同步

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

据我所知,Linux / Ubuntu 中的桌面捕获只有几个可行的(与5 种方式截屏您的 Linux 桌面相反)替代方案(注意,我通常使用笔记本电脑作为桌面捕获的目标):

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

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

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

(桌面准备)

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

  • 删除桌面背景和图标
  • gnome-desktop-properties通过 System/Preferences/Monitors ( )将分辨率设置为 800x600
  • 将颜色深度更改为 16 bpp(xdpyinfo | grep "of root"用于检查)

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

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

克隆 VGA

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

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

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

记录我的桌面

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

因此,我尝试做的是设置 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直接保存在本地硬盘上目标的驱动力(虽然,在那一点上,我真的不在乎:))

我的第一个问题recordMyDesktop是,您不能指示它保留临时文件并避免对其进行编码:您可以使用 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但是,这并不能保证您将实际获得该帧速率;例如,我会得到:

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

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

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

VNC 捕获

对我来说,VNC 捕获包括在“目标”PC 上运行 VNC 服务器,以及vncrec在“记录器”PC 上运行(twibright 版)。作为 VNC 服务器,我使用vino的是“系统/首选项/远程桌面(首选项)”。显然,即使vino 配置可能不是最容易管理的事情,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,服务器都会发送 - 并且作为客户端接收 - ;并且只有在之后从原始捕获中编码视频文件的过程中,才会设置/内插某种形式的帧速率。

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

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

带有 x11grab 的 ffmpeg

没有玩过这么多,但是,我已经尝试过与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 内存传输可以从图形卡(或其保留当前桌面位图的缓冲区)作为启动,网络适配器作为目标启动- 那么原则上,应该可以获得具有正确 (和体面的)帧率。当然,使用 DMA 传输的目的是将处理器从将桌面图像复制到网络接口的任务中解放出来(从而减少捕获软件对“目标”PC 上运行的进程的影响- 特别是那些处理 RAM 或硬盘的)。

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

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

-- -- -- -- -- 

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

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

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

提前感谢您的任何评论,
干杯!


参考

  1. 在 Linux 上为 CryptoTE 制作截屏视频的经验 - idlebox.net
  2. VideoLAN 论坛 • 查看主题 - VNC 客户端输入支持(如 screen://)
  3. VNCServer 为慢速客户端限制用户输入 - Kyprianou,Mark - com.realvnc.vnc-list - MarkMail
  4. Linux 常见问题解答 - X Windows:如何使用 VNC 显示和控制远程桌面
  5. VNC 需要多少带宽?RealVNC - 常见问题
  6. x11vnc:用于真实 X 显示器的 VNC 服务器
  7. HowtoRecordVNC(X11 会话) - Debian Wiki
  8. 在 Ubuntu 中替代 gtk-RecordMyDesktop
  9. (ffmpeg-user) 如何在 ffmpeg 中使用管道
  10. (ffmpeg-devel) (PATCH) 在不支持 XFixes 扩展的 Xserver 上绘制光标时修复 x11grab 中的段错误
4

1 回答 1

16

你应该为这么长的一个很好的问题获得一个徽章。;-)

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

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

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

是 FrameBufferUpdateRequest 消息的描述。

于 2010-11-30T19:00:49.037 回答