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://: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 相關