OpenGL 编程/视频录制
它具有保存/回放功能,可以捕获您对显卡的所有指令,并在以后重现,甚至可以将结果保存为一系列图片。
我们将使用它来创建一个适合上传到维基共享资源的视频!
获取源代码
cd /usr/src/
git clone https://github.com/apitrace/apitrace.git
cd apitrace/
安装 cmake 和依赖项
apt-get install cmake libx11-dev
编译!
cmake -H. -Bbuild
cd build
make
注意:对于 64 位主机上的 32 位构建
CFLAGS="-m32" CXXFLAGS="-m32" cmake -H. -Bbuild
让我们使用简单的波浪后处理效果进行测试
cd wikibooks-opengl-modern-tutorials/obj-viewer/
LD_PRELOAD=/usr/src/apitrace/build/wrappers/glxtrace.so ./obj-viewer
运行程序几秒钟,旋转物体,缩放等,然后退出程序。
这将创建一个 obj-viewer.trace
二进制文件。如果文件已经存在,它将创建 obj-viewer.1.trace
,等等。
您可以使用 glretrace
命令,将跟踪文件作为参数传递给它
/usr/src/apitrace/build/glretrace suzanne.trace
当然,这不再是交互式的,这只是一个回放。
让我们安装 ffmpeg
apt-get install ffmpeg
注意:我们尝试使用 ffmpeg 的缩放过滤器来减小屏幕尺寸 (-vf scale=200:150
),但遗憾的是,无论我们如何尝试[1],它都会导致段错误。因此,我们只是重新编译了应用程序,并直接指定了更小的屏幕尺寸。
ffmpeg 的选项按以下方式组织
ffmpeg <input options> -i source <output options> destination
- 我们将使用
.ogg
输出,因为这是维基共享资源唯一接受的格式(如果您知道谁可以获得对免费且更好的 .webm 格式的支持,请与他/她联系!)。 - 教程中使用的屏幕的刷新率为 75Hz,但视频通常为 25 帧/秒,因此我们将降低速率(双倍输入和输出
-r
参数) - 我们将使用一个固定、高质量的 (
-qscale
) - 我们将覆盖目标文件 (
-y
)
我们得到
/usr/src/apitrace/build/glretrace -s - suzanne.trace \
| ffmpeg -r 75 -f image2pipe -vcodec ppm -i pipe: -r 25 -qscale 31 -y output.ogg
我们已经得到了我们的视频 - 并且不需要额外的代码。
这是结果!
在运行 WebGL 应用程序时,捕获浏览器对我们来说效果不佳:性能很差,它捕获了整个 Firefox 窗口 - 而不是仅仅是动画。
因此,我们实现了一个内部捕获系统
手动捕获的一项优点是,您可以根据需要控制时间流,从而避免在捕获过程中出现任何性能问题。我们通过在时间函数(在我们的例子中是 threejs)周围添加一个小包装器来做到这一点
var capture_rate = 30;
var capture_frame = 0;
...
function getElapsedTime() {
if (capture) {
return capture_frame/capture_rate;
} else {
return clock.getElapsedTime();
}
}
...
function render() {
...
var angle = getElapsedTime() * 10; // 10° per second
...
if (capture) {
capture_frame++;
}
}
我们决定使用 30FPS 帧率,这在视频中很常见(截至 2013 年)。
使用您的 WebGL 画布的 toDataURL
方法
var base64_encoded_image = renderer.domElement.toDataURL();
这将返回一个以 base64 编码的图像,格式为 data:image/png;base64,iVBORw0KGgoAAAA...
。
JavaScript 无法直接保存本地文件,因此我们将使用 Ajax 将这些图像导出到 web 服务器
if (capture) {
capture_frame++;
r = XMLHttpRequest();
r.open('POST', 'https://127.0.0.1:1337/' + capture_frame);
r.send(renderer.domElement.toDataURL().substr("data:image/png;base64,".length));
}
我们可以编写一个最小 web 服务器,它将使用 NodeJS 存储我们导出的图像
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
var idx = req.url.split('/')[1];
var filename = "capture/" + ("0000" + idx).slice(-5)+".png";
var img = '';
req.on('data', function(chunk) { img += chunk });
req.on('end', function() {
f = fs.writeFileSync(filename, Buffer(img));
res.end();
});
console.log('Wrote ' + filename);
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');
您可以使用以下命令运行它
mkdir capture/
nodejs save_capture.js
此步骤类似于上面使用 glretrace 的步骤。我们将只使用特殊语法来获取所有 PNG 文件
avconv -r 30 -i capture/%05d.png -y capture/output.webm
(顺便说一下,avconv 是 ffmpeg 的一个分支/替代品,具有几乎相同的命令行选项。)
我们完成了:我们获得了 WebGL 动画的完美同步捕获!
欢迎贡献如何捕获同步应用程序音频流 :)
- ↑ 此错误可能与 https://ffmpeg.org/trac/ffmpeg/ticket/397 相关