• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:DIBからAVIファイル作成)

DIBからAVIファイル作成で再生時間が速い問題の解決方法を教えてください

このQ&Aのポイント
  • DIBからAVIファイル作成するプログラムで、再生時間が実際の録画時間の5~7分の1になってしまう問題が発生しています。
  • また、CCDカメラで写したデジタル時計の再生では、秒をうつ間隔が一定ではない不具合も発生しています。
  • 画像処理プログラムはインターネットで見つけたコードを使用しており、詳しい理屈がわかっていないため、問題の原因を特定することができません。ご存知の方、解決方法を教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.2

質問の中で「時計が秒をうつ間隔が一定ではない」というところを読み落としていました。リアルタイムで取得した画像をAVIファイルに出力しているのですね。 その場合、その「リアルタイムでの画像取得」の取得間隔自体が一定していないことが考えられます。 画像取得の間隔が一定しない場合、その対策は3通りあります。 1つは、画像取得のたびに取得時刻を算出し、あらかじめ定めた間隔よりも短い場合は破棄、長い場合はダミーフレームをAVIに挿入し、平均のフレーム間隔が「あらかじめ定めた間隔」に一致するようにする方法。 2つ目は、こういった処理を自動的に行ってくれるDirectShowのフィルタを使って、面倒な処理を全部任せてしまうこと。 3つ目は、自分専用の独自のAVIフォーマットを作成し、そのフォーマットで可変フレーム間隔をサポートしてしまうことです。 既にDirectShowを使っているのであれば2つ目、そうでなければ1つ目が簡単です。

real_neo
質問者

補足

回答ありがとうございます。 本当はDirectShowに全部任せたいのですが、使っているビデオキャプチャカードが、 ビデオキャプチャのデバイスの列挙をしても見つからない(※)ので、 カードとのインタフェースにはカードに付属しているSDKを使っています。 フレームのスナップとDIBの取得はそのSDKを使っています。 ダミーを挿入するのは難しくないですかね? ダミーってどんなフレームでもいいんでしょうか? 「あらかじめ定めた間隔」とはどのくらいの間隔が適当でしょうか? ※CreateClassEnumerator (CLSID_VideoInputDeviceCategory, &pClassEnum, 0); を実行して、pClassEnumがNULLになる。

すると、全ての回答が全文表示されます。

その他の回答 (7)

  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.8

BITMAPINFOHEADER構造体とAVISTREAMINFO構造体の二者択一でしたら、AVISTREAMINFO構造体です。(BITMAPINFOHEADER構造体には「時間」に関するメンバ変数はありませんので。) ただし、AVIファイルのヘッダにはこのほかAVIMAINHEADER構造体というものがあり、ここにもフレーム間隔の情報があります。 同じAVIファイルの中でAVIMAINHEADER構造体とAVISTREAMINFO構造体に別のフレーム間隔を設定したことがないので、AVIファイル再生時に実際にはどちらが優先して使用されるのかは分かりません。 DIBに関しては、1つのDIBは要するに1コマのビットマップですので、1つの画像データのみが入ります。

real_neo
質問者

お礼

ありがとうございました!

すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.7

別の場所でこの手の質問をするとすれば、どこでしょうね・・・どうも2chくらいしか思いつきません。 なお、どうか気を悪くしないでいただきたいのですが、私としては当初の質問である「早送りになってしまう/ロジックのどこが問題なのか」に対する回答(「出力ファイル中のフレーム間隔とフレーム数の関係のせいで早送りとなる/フレーム数調整ロジックに問題があると思われる」)として、回答No.2か、せめてNo.3まででご納得いただけることを期待しておりました。 今回の質問のようにある程度専門的な話題の場合、いったん回答者が回答を始めると他の回答者が割って入るのが難しいので、最初に回答した者の責任として回答を続けておりましたが、正直なところ場所を変えてまで続きを行うのは遠慮させていただきたいです。 (注:この回答は質問への回答となっておらず、質問者の叱責のようになっておりますため、運営スタッフにより削除される可能性があります。また、不快に思われました場合は、お手数ですが右上の「運営スタッフに連絡」を使用して削除をご依頼ください。)

real_neo
質問者

お礼

今まで付き合っていただき、ありがとうございました。 最後にもう少しだけ教えていただきたいのですが、 「AVIのヘッダに設定するフレーム間隔」とは、BITMAPINFOHEADER構造体のメンバ変数のことでしょうか?それともAVISTREAMINFO構造体のメンバ変数のことでしょうか? (AVIのヘッダはAVISetStreamFormatで設定しますよね?) それと、一つのDIBに複数のフレームデータが入っていることはありえるのでしょうか?

すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.6

ダミーフレーム挿入の判断について: AVIのヘッダに設定するフレーム間隔を仮に100msとします。またフレームレート調整ポリシーは「予定時刻よりも早く来たフレームはすべて捨てる、予定時刻よりも1フレーム分以上遅れたフレームはダミーフレームを埋める」とします。 この場合、フレーム取得時刻とAVIファイルに出力するフレームの関係は次のようになります。 最初に1枚フレームを取得します。このときの時刻が0.00秒だったとします。1枚目はそのままAVIファイルに出力します。 次のフレームを取得。時刻は0.05秒だったとします。2枚目を出力すべき時刻(0.10秒)より早いので、このフレームは捨てます。 次を取得。時刻は0.12秒だったとします。2枚目を出力すべき時刻(0.10秒)以降なので、このフレームをAVIファイルに出力します。3枚目を出力すべき時刻(0.20秒)よりは前なのでダミーフレームは出力しません。 次を取得。時刻は0.35秒だったとします。3枚目を出力すべき時刻(0.20秒)以降なので、このフレームをAVIファイルに出力します。4枚目を出力すべき時刻(0.30秒)も過ぎているので、もう1枚ダミーフレームを出力します。5枚目を出力すべき時刻(0.40秒)よりは前なので、それ以上ダミーフレームは出力しません。 次を取得。時刻は0.39秒だったとします。5枚目を出力すべき時刻(0.40秒)より早いので、このフレームは捨てます。 次を取得。時刻は0.45秒だったとします。5枚目を出力すべき時刻(0.40秒)以降なので、このフレームをAVIファイルに出力します。6枚目を出力すべき時刻(0.50秒)よりは前なのでダミーフレームは出力しません。 この例ではちょっとでも早く取得したフレームをすべて捨てていますが、実際にはある程度幅を持たせて弾性的に調整したほうがよいでしょう。その具体的な方法は説明するには長すぎるので省略します。

real_neo
質問者

お礼

ありがとうございます。 いろいろと聞きたいことが多すぎるので、ここではなく別の方法で聞きたいのですが、何か良い方法はありますか? MSNメッセンジャーくらいしか思いつかないんですけど。

すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.5

フィルタがGraph Editで表示されないのでは、DirectShow以外の方法でキャプチャするしかありませんね・・・(自前でフィルタを作る手もないではないですが) 録画時間と再生時間に直接の関係はありません。再生時間は単純に、ヘッダに書いてあるフレーム間隔×ファイルの中にあるフレーム数で決まるからです。 それで、フレーム数が明らかに足りないということですが、それは「間隔が開いた場合にはダミーフレームを挿入する」という方法を取ってもなお足りないということでしょうか。例えば、AVIファイルのヘッダにフレーム間隔1/30秒と設定し、10秒間に相当するはずのAVIファイルを作成しても、ファイル内のフレーム数が300フレームよりだいぶ少ないということでしょうか。 そうだとすれば、フレーム間隔の認識あるいはダミーフレーム挿入のロジックが誤っていると思われます。 フレーム取得時の時刻はちゃんと毎回取得しているでしょうか。ダミーフレームを挿入するかどうかの判断はフレーム間の時間間隔ではなく「これまで出力したフレーム数と現在時刻」で判断しているでしょうか。 「フレーム数が足りない」の意味が「カメラから取得できるフレームの数が少ない」という意味合いでしたら、AVIファイル作成処理を云々する前に、まずカメラから取得できるフレームレートを測っておいたほうがよいでしょう。 プログラム上全速力で例えば100フレームを取得し、その時間を測ります。ファイル出力は必要ありません。ただフレームを取得し、それに要した時間をフレーム数で割って出力するだけです。(あるいは一定時間内に取得できたフレーム数から計算してもいいでしょう。) 仮にこの数字が毎秒10フレームとなったとすれば、そのカメラとAPIの組み合わせでは、どんなにがんばっても毎秒10フレームを超えるフレーム数のAVIファイルは(ダミーフレームを挿入しない限り)作成できないということになります。

real_neo
質問者

補足

>それは「間隔が開いた場合にはダミーフレームを挿入する」という方法を取ってもなお足りないということでしょうか。 そうです。 約30秒間録画したときのフレーム数(AVIStreamWriteを呼び出した回数)は、100~160でした。 >フレーム取得時の時刻はちゃんと毎回取得しているでしょうか。ダミーフレームを挿入するかどうかの判断はフレーム間の時間間隔ではなく「これまで出力したフレーム数と現在時刻」で判断しているでしょうか。 補足でも触れましたが、AVIStreamWriteを呼び出した後にGetTickCountを実行(A)、その次にAVIStreamWriteを呼び出す前にGetTickCountを実行(B)、B-Aで時間間隔を算出しています。 どうやら、間違っているようですね。 ビデオキャプチャカードの仕様によれば、フレームレートは29.9くらいだそうです。 基本的なことを聞くようで申し訳ないのですが、そもそもキャプチャカードのフレームレートというのは何を意味するのでしょうか? 1秒間に何枚のフレームがキャプチャできるかを意味すると思って良いでしょうか? それにしても、いくら多くキャプチャできても、AVIに出力しなければ、何の意味もないと思うんですが。 AVIStreamWriteでDIBから1フレームしか書き込むようにしか作っていないので、「カメラから取得できるフレームの数が少ない?」という件については、よく意味がわかりません。 取得したDIBで数枚のフレームをAVIに出力可能なんでしょうか?

すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.4

Video for Windowsのキャプチャデバイスも、確かカテゴリCLSID_VideoInputDeviceCategoryで列挙されたかと思います。Graph Editでは列挙されませんでしたか?(Graph Editで列挙されないのであれば望み無しです。) ダミーフレーム挿入に関しては、そのような感じです。 そういえば、もしかしたらAVIには「フレームデータ省略」というフラグのようなものがあったような気もしてきました。そういうものが本当にあったかどうかはっきりとは覚えていないのですが。もしそういうものがあれば、ダミーフレームを書くよりは省略フラグを立てておくほうが良さそうですね。

real_neo
質問者

補足

いろいろとやってみました。 実際の録画時間と再生時間は必ずしも同じにはならないようですね。 しかし、再生時間が録画時間の5~3分の1というのは明らかにおかしいですよね。 Video for WindowsのAVIStreamWriteを使って出力しています。 AVIStreamWriteを呼び出している自前の関数で、出力間隔を調節するようにしましたが、フレーム数が明らかに足りないんです。 基準とする間隔は、1000/30(1秒/30)にしています。 調節した間隔は画像取得を行う間隔ではないのがまずかったでしょうか? AVIStreamWriteを呼び出す自前の関数を無限ループで呼び出すように作ってありますが、呼び出す間隔は50ms(GetTickCountで計算)くらいです。 あと、デバイス列挙については、GraphEditorでも列挙されませんでした。

すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.3

デバイスの列挙で見つからないという点については、DirectShowに付属のユーティリティGraphEdit (GraphEdt.exe)を使って、フィルタ一覧の中にそのデバイスに対応するキャプチャフィルタが表示されるかどうか確認してみてください。 もし一覧の中に表示されていれば、そのデバイスは列挙可能です。一覧の中に表示されていないのであれば、残念ながらそのデバイスはDirectShowでは使えません。 もっとも、Video for WindowsのデバイスもDirectShowは列挙するので、DirectShowで列挙されないということはDirectShowでもVideo for Windowsでも使用できないデバイスということになります。そんなビデオキャプチャデバイス本当に存在するんかいな?とちょっと疑問に思います。 フレームのダミー挿入については、何も絵的に前フレームと後フレームの中間になるようなものを計算して作成したりする必要はなく、単に同じフレームを複数回出力すればよろしいかと思います。同じフレームを出力するのは簡単ですので。 どのくらいの間隔が適当かについては、いろいろ考え方があると思います。キャプチャしたフレームを1枚も無駄にしないことが目標であれば、最大フレームレートと同じ(かそれより短い)間隔にすることになりますし、生成するAVIファイルの内容が「毎秒5コマあれば十分だ」と判断されるのであれば200msで良いことになります。

real_neo
質問者

補足

ありがとうございます。 >もっとも、Video for WindowsのデバイスもDirectShowは列挙するので、DirectShowで列挙されないということはDirectShowでもVideo for Windowsでも使用できないデバイスということになります。そんなビデオキャプチャデバイス本当に存在するんかいな?とちょっと疑問に思います。 カテゴリCLSID_VideoInputDeviceCategoryによるCreateClassEnumeratorではデバイスが列挙されないが、CLSID_VideoInputDeviceCategory以外のカテゴリでなら列挙できるということですよね? 調節する場合、例えば、前回フレーム出力時からの間隔が定義済みフレーム間隔の2倍だったときは、ダミーを1枚挿入、3倍だったときは2枚挿入して、実フレームを書き込めば良いということですよね?

すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.1

AVIファイルのヘッダにあるAVIMAINHEADER構造体にdwMicroSecPerFrameというメンバがあり、「フレーム間の間隔をマイクロ秒単位で指定する」とされています。 この値がゼロあるいは実際のフレーム間隔より小さい値ですと、早送りのようになってしまいます。

すると、全ての回答が全文表示されます。