サブタイトル:「mer2のマイノリティ・レポート(笑)」 --- 最近忍者ブログの仕様が変わったようで、一部の画像が見えなくなってますが、画像のURLコピペで見られます。(どうしよう困ったな) --- ご用件など、ございましたらtwitterまでどうぞ。
デスクトップキャプチャーでARToolkitの動画を作るのにどうも抵抗が有ったんです。面倒だし、なんかオシャレじゃないじゃないですか。どうせやるんだったら一つのプログラムで済ませたほうがオシャレです。更にステレオ撮影の場合はカメラ2台使うのでCPUの負荷が上ります。余計なソフトはできるだけ動かしたくないんです。
んで、ARToolkitのプログラムからダイレクトに動画を作れないもんかなと調べてみましたが、どうも今の私には難しそうです。まあそんな事ほえっとできてたら、ステレオ動画撮影のプログラムなんかとっくにできてますよね。今後の課題として勉強しようと思います。誰かダイレクトに動画作れてる人はいませんか。いたらソースください。
だったら各フレームの画像をキャプチャーしておいて、後からffmpeg技なりで動画にすればいいんじゃないかな、と考えました。ARToolkitのソースを眺めてみると、最終的な画面出力はglut関係でやっているようです。そっち関係を調べてみたら、glutを使った画面キャプチャの方法がソース付きでそのまんま有りました。
[OpenGL] Bitmapファイルへの書き出し
ここの「010-GLUTsaveBMP.zip」ってやつです。
これをそのまんまビルドすると、
exit' : 再定義 ; __declspec(noreturn) が異なります。
というエラー。V+Cのstdlib.hとglut.hでexitの定義がダブっているようです。
GLUTsaveBMPのフォルダ内にstdlib.hをコピーして、
//_CRTIMP __declspec(noreturn) void __cdecl exit(_In_ int _Code);
//_CRTIMP __declspec(noreturn) void __cdecl _exit(_In_ int _Code);
とコメントアウトして、main.cppを
#include "stdlib.h"
としたら通りました。ちゃんと動いてます。glutのスクリーンキャプチャができてしまいました。きゃっほー!
早速応用しましょう。simpleLiteのソースフォルダに
Bitmap.cpp
Bitmap.h
をコピーして、
「simpleLite.c」の
頭のほうに
#include "Bitmap.h"
キー入力のところに
case 'B':
case 'b':
WriteBitmap("output.bmp",640,480);
break;
を追加して、
simpleLiteのプロジェクトに
「Bitmap.cpp」
を追加。それから「simpleLite.c」を「simpleLite.cpp」にリネーム。そうしないと「Bitmap.cpp」を一緒にビルドしてくれません。何故か上のexit関連のエラーは出ませんでした。
これでARToolkitの画面キャプチャができてしまいました!"B"キーを押すとファイル名「output.bmp」で一画面キャプチャーします。mer2さん大笑い海水浴場。
したらば連続フレームをキャプチャーできるようにしてしまいましょう。
変数追加
int flg=0;
int count=0;
char filename[20];
Bキーでフラグ
case 'B':
case 'b':
if (flg) flg=0; else flg=1;
// WriteBitmap("output.bmp",640,480);
break;
このへんでいいんじゃないかな。Display()内。
if (flg) {
sprintf( filename, "file_%05d.bmp",count);
WriteBitmap( filename,640,480);
count++;
}
glutSwapBuffers();
"B"キーを押してからもう一度押すまでの間の各フレームが「file_00000.bmp」からの連番でキャプチャーされます。キャプチャー中は凄く重くなるけど、そんなのは想定内よ。後でなんとかするから。
連番ファイルを動画にするのはffmpegを使います。
> ffmpeg -r 10 -i file_%05d.bmp -sameq test.avi
この時、大笑海水浴場がピークに逹っしました。
ディスクアクセスを軽くしようとRAM DISKを導入してみました。まあこれは結果的に無駄足だったので不要な手順なのですが、RAM DISK使用レポということで。RAM DISK使ってみたかったんです。
ERAM for Windows:正式版置き場
とりあえずベクターで星がいっぱいついてたから、これにしました。
参考:
EZ-NET レポート: RAM DISK を使ってみる
メモリ量がここのレポートと同じ3GBなのでちょうどよかった。
「simpleLite.cpp」内のbmpファイル名のみ書き換え。
sprintf( filename, "R:\\file_%05d.bmp",count);
RAM DISKはRドライブで固定。X68000の時からの伝統。X68000のRAM DISKドライバはリセットしても内容が残ってたんだけどなー。スペースハリアーやA-JAXやサンダーブレードをRAM DISKに転送すると、もう極楽だったっけ。
うむ、ちょっと軽くなった。でもまだ重いな。
Bitmap.cppをいじって、欲しい範囲[0,120-639,359]だけを取り込むようにしてみる。
頭のほうに追加。
width = 640;height = 240;
読み出し範囲を修正
glReadPixels(
// 0,0,
0,120,
width,height,
GL_RGB,
GL_UNSIGNED_BYTE,
pixel_data);
うん、かなり軽くなった。bmp作成の時のループがオーバーヘッドになっているようだ。
ならばbmp作成のループを無くしてしまおう。bmp化前の元画像データだけ保存しておいて、bmp化は後でやればいいのだ。
Bitmap.cppをさらに変更。
bmp作成の部分をまるごとコメントして、
fwrite( pixel_data, sizeof(GLubyte), (glByteWidth)*(height), fp);
を追加。
simpleLite.cpp内の保存ファイル名を
sprintf( filename, "R:\\file_%05d.dat",count);
とかにすると、RAM DISKに「file_?????.dat」の連番ベタ書きデータファイルができあがります。
うほっ、体感的にはキャプチャー中のフレームレートの変化が無くなりました。
Bitmap.cppをいじってベタ書きデータファイルをbmpファイルにするプログラムを作ります。下のzipにまとめときました。
「gltobmp_test.cpp」が一画面ベタ書きデータファイルを変換するプログラムです。めんどうなのでファイル名も画面サイズも固定です。Visual studioのプロジェクトを作るのも面倒だったので、コマンドラインからコンパイル仕様です。スタートメニューの「Visual Studio 2008 コマンド プロンプト」から
> cl tobitmap_test.cpp
でいけます。
でもglut関係の関数はコマンドラインなプログラムだと(?)エラーになってしまうみたいです。だからglut関数がらみで計算される数値は定数にしてしまっています。という訳で全然汎用性はありません。ごめんなさい。
実行するとベタ書きデータファイルから"bmp"フォルダにbmpファイルを作成します。サンプルにベタ書きデータファイル「file_00001.dat」を一個入れときます。
今回の場合は、一画面あたり、
640*240*3(Byte) = 460800Byte
になってます。
まだ無駄な部分が有るので一気にまとめます。「simpleLite_Capture.c」です。
メインループ内の無駄な処理を外に出して、ベタ書きデータも一つのファイルにまとめて書き出してます。simpleLiteのソースフォルダに置けばビルドできると思います。
simpleLiteは"C"キーを押すと瞬間的fpsを見られますが、うちの環境では記録前も記録中も15fpsぐらいで安定してます。記録中はちょっと低めの数字が見られる程度です。
試しに最終バージョンでハードディスクに記録してみたら、RAM DISKとそんなに変わりないや。なんだ、RAM DISK要らなかったかな。
ファイルは追記モードで開いてますので、消すなりリネームするなりしないとどんどん追記されます。ご注意下さい。
ひとまとめなベタ書きデータを一気にbmpファイルに変換するのが「gltobmp.cpp」です。ほとんど「Bitmap.cpp」のWriteBitmap()をmain()にしただけです。例によって汎用性は有りません。ごめんなさい。
250MBのベタ書きデータを変換するのに一分ぐらいかかります。こりゃ重くなるわ。見ていて不安になるのでカウンターを付けました。
変換した大量のbmpファイルをffmpegで動画にまとめます。
> ffmpeg -r 10 -i file_%05d.bmp -sameq test.avi
とか、
> ffmpeg -r 29.7 -i file_%05d.bmp -b 1024k test.avi
とか。
カメラをゆっくり動かせば、30fpsなARToolkit動画も作れます。
なんだったら60fpsなんてのも作れます。
> ffmpeg -r 60 -i file_%05d.bmp -sameq test.avi
[ 動画 ]
100fpsなんてのも作れますが、リフレッシュレート100HzのCRTで見ても80fps再生になってしまいます。なんで?
> ffmpeg -r 100 -i file_%05d.bmp -sameq test.avi
[ 動画 ]
リフレッシュレート60Hzの液晶モニターではコマ落ち風再生になってしまいます。
120fpsは動画が上手く作れませんでした。
キャプチャー動画のコマ落ちが嫌な人、マシンがロースペックな人にはお勧めです。音とシンクロさせるような場合は駄目ですが。(いや、どうにかなる。(と思う。)) (多重括弧)
んで、ARToolkitのプログラムからダイレクトに動画を作れないもんかなと調べてみましたが、どうも今の私には難しそうです。まあそんな事ほえっとできてたら、ステレオ動画撮影のプログラムなんかとっくにできてますよね。今後の課題として勉強しようと思います。誰かダイレクトに動画作れてる人はいませんか。いたらソースください。
だったら各フレームの画像をキャプチャーしておいて、後からffmpeg技なりで動画にすればいいんじゃないかな、と考えました。ARToolkitのソースを眺めてみると、最終的な画面出力はglut関係でやっているようです。そっち関係を調べてみたら、glutを使った画面キャプチャの方法がソース付きでそのまんま有りました。
[OpenGL] Bitmapファイルへの書き出し
ここの「010-GLUTsaveBMP.zip」ってやつです。
これをそのまんまビルドすると、
exit' : 再定義 ; __declspec(noreturn) が異なります。
というエラー。V+Cのstdlib.hとglut.hでexitの定義がダブっているようです。
GLUTsaveBMPのフォルダ内にstdlib.hをコピーして、
//_CRTIMP __declspec(noreturn) void __cdecl exit(_In_ int _Code);
//_CRTIMP __declspec(noreturn) void __cdecl _exit(_In_ int _Code);
とコメントアウトして、main.cppを
#include "stdlib.h"
としたら通りました。ちゃんと動いてます。glutのスクリーンキャプチャができてしまいました。きゃっほー!
早速応用しましょう。simpleLiteのソースフォルダに
Bitmap.cpp
Bitmap.h
をコピーして、
「simpleLite.c」の
頭のほうに
#include "Bitmap.h"
キー入力のところに
case 'B':
case 'b':
WriteBitmap("output.bmp",640,480);
break;
を追加して、
simpleLiteのプロジェクトに
「Bitmap.cpp」
を追加。それから「simpleLite.c」を「simpleLite.cpp」にリネーム。そうしないと「Bitmap.cpp」を一緒にビルドしてくれません。何故か上のexit関連のエラーは出ませんでした。
これでARToolkitの画面キャプチャができてしまいました!"B"キーを押すとファイル名「output.bmp」で一画面キャプチャーします。mer2さん大笑い海水浴場。
したらば連続フレームをキャプチャーできるようにしてしまいましょう。
変数追加
int flg=0;
int count=0;
char filename[20];
Bキーでフラグ
case 'B':
case 'b':
if (flg) flg=0; else flg=1;
// WriteBitmap("output.bmp",640,480);
break;
このへんでいいんじゃないかな。Display()内。
if (flg) {
sprintf( filename, "file_%05d.bmp",count);
WriteBitmap( filename,640,480);
count++;
}
glutSwapBuffers();
"B"キーを押してからもう一度押すまでの間の各フレームが「file_00000.bmp」からの連番でキャプチャーされます。キャプチャー中は凄く重くなるけど、そんなのは想定内よ。後でなんとかするから。
連番ファイルを動画にするのはffmpegを使います。
> ffmpeg -r 10 -i file_%05d.bmp -sameq test.avi
この時、大笑海水浴場がピークに逹っしました。
ディスクアクセスを軽くしようとRAM DISKを導入してみました。まあこれは結果的に無駄足だったので不要な手順なのですが、RAM DISK使用レポということで。RAM DISK使ってみたかったんです。
ERAM for Windows:正式版置き場
とりあえずベクターで星がいっぱいついてたから、これにしました。
参考:
EZ-NET レポート: RAM DISK を使ってみる
メモリ量がここのレポートと同じ3GBなのでちょうどよかった。
「simpleLite.cpp」内のbmpファイル名のみ書き換え。
sprintf( filename, "R:\\file_%05d.bmp",count);
RAM DISKはRドライブで固定。X68000の時からの伝統。X68000のRAM DISKドライバはリセットしても内容が残ってたんだけどなー。スペースハリアーやA-JAXやサンダーブレードをRAM DISKに転送すると、もう極楽だったっけ。
うむ、ちょっと軽くなった。でもまだ重いな。
Bitmap.cppをいじって、欲しい範囲[0,120-639,359]だけを取り込むようにしてみる。
頭のほうに追加。
width = 640;height = 240;
読み出し範囲を修正
glReadPixels(
// 0,0,
0,120,
width,height,
GL_RGB,
GL_UNSIGNED_BYTE,
pixel_data);
うん、かなり軽くなった。bmp作成の時のループがオーバーヘッドになっているようだ。
ならばbmp作成のループを無くしてしまおう。bmp化前の元画像データだけ保存しておいて、bmp化は後でやればいいのだ。
Bitmap.cppをさらに変更。
bmp作成の部分をまるごとコメントして、
fwrite( pixel_data, sizeof(GLubyte), (glByteWidth)*(height), fp);
を追加。
simpleLite.cpp内の保存ファイル名を
sprintf( filename, "R:\\file_%05d.dat",count);
とかにすると、RAM DISKに「file_?????.dat」の連番ベタ書きデータファイルができあがります。
うほっ、体感的にはキャプチャー中のフレームレートの変化が無くなりました。
Bitmap.cppをいじってベタ書きデータファイルをbmpファイルにするプログラムを作ります。下のzipにまとめときました。
「gltobmp_test.cpp」が一画面ベタ書きデータファイルを変換するプログラムです。めんどうなのでファイル名も画面サイズも固定です。Visual studioのプロジェクトを作るのも面倒だったので、コマンドラインからコンパイル仕様です。スタートメニューの「Visual Studio 2008 コマンド プロンプト」から
> cl tobitmap_test.cpp
でいけます。
でもglut関係の関数はコマンドラインなプログラムだと(?)エラーになってしまうみたいです。だからglut関数がらみで計算される数値は定数にしてしまっています。という訳で全然汎用性はありません。ごめんなさい。
実行するとベタ書きデータファイルから"bmp"フォルダにbmpファイルを作成します。サンプルにベタ書きデータファイル「file_00001.dat」を一個入れときます。
今回の場合は、一画面あたり、
640*240*3(Byte) = 460800Byte
になってます。
まだ無駄な部分が有るので一気にまとめます。「simpleLite_Capture.c」です。
メインループ内の無駄な処理を外に出して、ベタ書きデータも一つのファイルにまとめて書き出してます。simpleLiteのソースフォルダに置けばビルドできると思います。
simpleLiteは"C"キーを押すと瞬間的fpsを見られますが、うちの環境では記録前も記録中も15fpsぐらいで安定してます。記録中はちょっと低めの数字が見られる程度です。
試しに最終バージョンでハードディスクに記録してみたら、RAM DISKとそんなに変わりないや。なんだ、RAM DISK要らなかったかな。
ファイルは追記モードで開いてますので、消すなりリネームするなりしないとどんどん追記されます。ご注意下さい。
ひとまとめなベタ書きデータを一気にbmpファイルに変換するのが「gltobmp.cpp」です。ほとんど「Bitmap.cpp」のWriteBitmap()をmain()にしただけです。例によって汎用性は有りません。ごめんなさい。
250MBのベタ書きデータを変換するのに一分ぐらいかかります。こりゃ重くなるわ。見ていて不安になるのでカウンターを付けました。
変換した大量のbmpファイルをffmpegで動画にまとめます。
> ffmpeg -r 10 -i file_%05d.bmp -sameq test.avi
とか、
> ffmpeg -r 29.7 -i file_%05d.bmp -b 1024k test.avi
とか。
カメラをゆっくり動かせば、30fpsなARToolkit動画も作れます。
なんだったら60fpsなんてのも作れます。
> ffmpeg -r 60 -i file_%05d.bmp -sameq test.avi
[ 動画 ]
100fpsなんてのも作れますが、リフレッシュレート100HzのCRTで見ても80fps再生になってしまいます。なんで?
> ffmpeg -r 100 -i file_%05d.bmp -sameq test.avi
[ 動画 ]
リフレッシュレート60Hzの液晶モニターではコマ落ち風再生になってしまいます。
120fpsは動画が上手く作れませんでした。
キャプチャー動画のコマ落ちが嫌な人、マシンがロースペックな人にはお勧めです。音とシンクロさせるような場合は駄目ですが。(いや、どうにかなる。(と思う。)) (多重括弧)
ソースコード(いーかげんです)
PR
この記事にコメントする
参考にさせてもらってます
初めまして、動画処理したいなと思ってたら
ここに行き着いたものです。
この記事見てて気づいたことなのですが
すでに気づいておられたらごめんなさい
[OpenGL] Bitmapファイルへの書き出し
「010-GLUTsaveBMP.zip」
これをそのまんまビルドすると、
exit' : 再定義 ; __declspec(noreturn) が異なります。
というエラー。V+Cのstdlib.hとglut.hでexitの定義がダブっているようです。
GLUTsaveBMPのフォルダ内にstdlib.hをコピーして、
//_CRTIMP __declspec(noreturn) void __cdecl exit(_In_ int _Code);
//_CRTIMP __declspec(noreturn) void __cdecl _exit(_In_ int _Code);
とコメントアウトして、main.cppを
#include "stdlib.h"
としたら通りました。
↑の部分で
どうもincludeファイルの読み込む順番に問題があるようです。main.cppのほうで
#include <stdlib.h>
#include <GL/glut.h>
の順番に読み込めばexit再定義エラーは発生しないで通りました。
たぶん<GL/glut.h>のほうで再定義しないように割り振りしてるんだと思います。
ここに行き着いたものです。
この記事見てて気づいたことなのですが
すでに気づいておられたらごめんなさい
[OpenGL] Bitmapファイルへの書き出し
「010-GLUTsaveBMP.zip」
これをそのまんまビルドすると、
exit' : 再定義 ; __declspec(noreturn) が異なります。
というエラー。V+Cのstdlib.hとglut.hでexitの定義がダブっているようです。
GLUTsaveBMPのフォルダ内にstdlib.hをコピーして、
//_CRTIMP __declspec(noreturn) void __cdecl exit(_In_ int _Code);
//_CRTIMP __declspec(noreturn) void __cdecl _exit(_In_ int _Code);
とコメントアウトして、main.cppを
#include "stdlib.h"
としたら通りました。
↑の部分で
どうもincludeファイルの読み込む順番に問題があるようです。main.cppのほうで
#include <stdlib.h>
#include <GL/glut.h>
の順番に読み込めばexit再定義エラーは発生しないで通りました。
たぶん<GL/glut.h>のほうで再定義しないように割り振りしてるんだと思います。
Re:参考にさせてもらってます
あら、こんなに簡単に解決できたのね。もちろん気付いてませんでした。
「exit' : 再定義 ;」で検索してくる人も時々いますので、お兄ちゃんのコメントはきっとそんな人々の役に立つことでしょう。お兄ちゃん、ありがとう。
ところで、動画処理のいい参考は見つかりましたか?いいところあったら教えてください。サルでもわかるようなところ。
「exit' : 再定義 ;」で検索してくる人も時々いますので、お兄ちゃんのコメントはきっとそんな人々の役に立つことでしょう。お兄ちゃん、ありがとう。
ところで、動画処理のいい参考は見つかりましたか?いいところあったら教えてください。サルでもわかるようなところ。
最新記事
(04/20)
(11/21)
(01/01)
(06/12)
(06/12)
(05/29)
(05/22)
(05/21)
(12/25)
(12/20)
最新コメント
[08/27 BernardSr]
[08/27 BernardSr]
[08/27 BernardSr]
[12/29 GroverIcow]
[12/26 gayenKinesl]
[12/25 gayenKincfv]
[12/25 geRoesonokp]
[12/24 geRoesonmxu]
[06/30 LindsayDom]
[06/24 Ayukupim]
[06/22 francinerj2]
[06/21 Karsewis]
[06/17 Porsulik]
[06/16 Porsulik]
[06/16 Porsulik]
[06/16 Amimior]
[06/15 WilfordMof]
[06/11 lakeishatb1]
[06/04 Mathewlomi]
[05/31 tiopomWarriorvrp]
[05/31 Lasdumor]
[05/29 Aredorer]
[05/27 IMPUCKICT]
[05/26 Asosans]
[05/24 RaymondZice]
カテゴリー
リンク
アーカイブ
アクセス解析
カウンター
カレンダー
10 | 2024/11 | 12 |
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
プロフィール
HN:
mer2
性別:
男性
趣味:
野良猫の餌付け