- 締切済み
AVIStreamWriteの使用方法
BMPファイルからAVIファイルを作成する際のAVIStreamWriteの使用方法を教えてください。 AVIStreamWriteを使用して1枚ずつBMPファイルをAVIファイルに書き込むことはできたのですが複数のBMPファイルを一度にAVIファイルに書き込むことはできるのでしょうか。 AVIStreamWriteのパラメータに「書き込むサンプル数」の指定など複数ファイルの登録ができそうな感じがあるのですがうまくいきません。 おそらくパラメータの指定方法が誤っているのだと思うのですが、具体的な例などがありましたら教えてください。
- みんなの回答 (3)
- 専門家の回答
みんなの回答
- machongola
- ベストアンサー率60% (434/720)
こんばんは。 動画が出来上がらないと言う事でしょうか? AVIStreamWrite()の2番目のパラメータにAVIストリームの書き込む位置を渡していないなど。 //AVIストリームの長さを取る(次に書き込む位置にもなる) LONG lLen = ::AVIStreamLength(pAVIStream); HRESULT hResult = ::AVIStreamWrite(pAVIStream, lLen, 1, dib.dsBm.bmBits, dib.dsBmih.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); 昔参考にしたサイトを紹介しておきます。 http://eternalwindows.jp/winmm/avi/avi07.html 以下は、1秒間30コマ(フレーム)で黒→赤にジュワ~っと変色するAVIファイル作成プログラムをしてみました。 アラもあるかと思いますが、参考程度に。 #include<windows.h> #include<vfw.h> #pragma comment(lib, "vfw32.lib") //BITMAPINFOHEADERを元にAVIストリームのフォーマットを確定する PAVISTREAM CreateDIBStream(PAVIFILE pAVIFile, LPBITMAPINFOHEADER pbih) { PAVISTREAM pAVIStream = NULL; AVISTREAMINFO asf = {0}; asf.fccType = streamtypeVIDEO; asf.fccHandler = mmioFOURCC('D', 'I', 'B', ' '); asf.dwQuality = static_cast<DWORD>(-1); asf.dwScale = 1; asf.dwRate = 30; asf.dwLength = 30; //描写エリアの設定 ::SetRect(&asf.rcFrame, 0, 0, pbih->biWidth, pbih->biHeight); //AVIストリームの作成 HRESULT hResult = ::AVIFileCreateStream(pAVIFile, &pAVIStream, &asf); //AVIストリームにBITMAPINFOHEADERを渡してフォーマットを確定する hResult = ::AVIStreamSetFormat(pAVIStream, 0, pbih, sizeof(*pbih)); return pAVIStream; } //DIBイメージを作成する HBITMAP CreateTestDIB(int width, int height) { BITMAPINFOHEADER bmih = {sizeof(bmih)}; bmih.biBitCount = 24; bmih.biPlanes = 1; bmih.biWidth = width; bmih.biHeight = height; BITMAPINFO bmi = {0}; bmi.bmiHeader = bmih; LPVOID pvBits = NULL; return ::CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0); } //お試し int main() { PAVIFILE pAVIFile = NULL; //AVIライブラリの初期化 ::AVIFileInit(); //AVIファイルを開く ::AVIFileOpen(&pAVIFile, "test.avi", OF_CREATE | OF_READWRITE | OF_SHARE_EXCLUSIVE, NULL); //DIBの作成 HBITMAP hBitmap = ::CreateTestDIB(120, 80); //作成したDIBから情報を取る DIBSECTION dib; ::GetObject(hBitmap, sizeof(dib), &dib); //BITMAPINFOHEADERを元にAVIストリームを作成する PAVISTREAM pAVIStream = ::CreateDIBStream(pAVIFile, &dib.dsBmih); //AVIストリーム情報を取る AVISTREAMINFO asi = {0}; ::AVIStreamInfo(pAVIStream, &asi, sizeof(asi)); //DIBの背景色等を初期化しておく HDC hDC = ::CreateCompatibleDC(NULL); ::SetTextColor(hDC, RGB(255, 255, 0)); ::SetBkMode(hDC, TRANSPARENT); ::SelectObject(hDC, hBitmap); for(int frame = 0; frame < asi.dwRate; ++frame) { RECT rc = {0, 0, dib.dsBm.bmWidth, dib.dsBm.bmHeight}; //取り敢えず[赤色]を変色させながら背景を塗り潰して見る HBRUSH hBrush = ::CreateSolidBrush(RGB((256 / asi.dwRate) * frame, 0, 0)); ::FillRect(hDC, &rc, hBrush); ::DeleteObject(hBrush); //フレーム数をテキストで書き込んでみる TCHAR text[80]; ::wsprintf(text, "%d", frame); ::DrawText(hDC, text, ::strlen(text), &rc, DT_CENTER); //AVIストリームの長さを取る LONG lLen = ::AVIStreamLength(pAVIStream); //AVIストリームにDIBイメージを書き込む HRESULT hResult = ::AVIStreamWrite(pAVIStream, lLen, 1, dib.dsBm.bmBits, dib.dsBmih.biSizeImage, AVIIF_KEYFRAME, NULL, NULL); } //フレーム用に使ったリソースを捨てる ::DeleteDC(hDC); ::DeleteObject(hBitmap); //AVIストリームを閉じる ::AVIStreamRelease(pAVIStream); //AVIファイルを閉じる ::AVIFileRelease(pAVIFile); //AVIライブラリの開放 ::AVIFileExit(); return 0; }
- chie65536(@chie65535)
- ベストアンサー率44% (8741/19839)
追記。 良いサンプルがありました。下記ページのTEST03.Cを見て下さい。 http://www.ecoop.net/coop/vfw/avi.html AVISTREAMINFO構造体の総コマ数を「LENG」に初期化してから「for (i=0;i<LENG;i++) 」のループで、LENG回、1コマづつAVIStreamWrite()で書き込んでいます。
お礼
回答ありがとうございます 教えていただいたサイトは私も参考にしていました。 1コマづつAVIStreamWrite()でBMPを書き込んでいくのはできています。 複数コマを一度にAVIStreamWrite()で書き込もうとすると戻り値が0x80044065(AVIERR_UNSUPPORTED?)となりエラーとなってしまいます。 ここでわからないのがlpBufferとcbBufferの指定なのですがlpBufferは1つの領域に複数のBMPデータをlSamplesの分だけ設定してcbBufferにはその領域のサイズを指定すればよいのでしょうか? 例:640×320 24bitのBMPの場合(BMPを一度に2つ書く場合) BYTE byBuffer[640 * 320 * 3 * 2]; byBufferにBMPデータを設定(2枚分のBMPデータを続けて設定) AVIStreamWrite(pAviStream,nStart,2,byBuffer,sizeof(byBuffer),AVIIF_KEYFRAME, NULL, NULL); 現在、上記のように設定しようとするとエラーになってしまいます。 間違っている点を教えていただけないでしょうか?
補足
回答に書き忘れたのですが総コマ数は決まっていない(リアルタイムで作成されるBMPをその場でAVIに登録しています)のでAVISTREAMINFO構造体のdwLengthメンバは初期値として0を設定してあります。(1コマづつ登録する場合はこの設定で問題なく動作しています) これは問題ないでしょうか?
- chie65536(@chie65535)
- ベストアンサー率44% (8741/19839)
AVIFileCreateStream()を呼び出す際の、AVISTREAMINFO構造体のdwLengthメンバに「書き込むサンプル数の総数」をセットしなければいけません。 その上で、AVIStreamWrite()のlSamples引数に「1回で書き込むサンプル数」を指定します。 AVIStreamWrite()のlSamples引数が1でないのなら、データは「指定したサンプル数の分だけ、連続して並んでいる」のが想定されます。 AVIStreamWrite()のlSamples引数が1なら、データは「1サンプル分だけしかない」のが想定されます。 1分間の動画を作る場合、もし仮にフレームレート(1秒間のコマ数)が30コマなら、1分間の動画には1800コマ必要ですから、以下のようにします。 1.AVIFileCreateStream()を呼び出す際に、AVISTREAMINFO構造体のdwLengthメンバに1800をセットして呼ぶ 2.1コマ分のデータを用意する 3.AVIStreamWrite()のlSamples引数に1を指定して、1コマ書き込む 4.上記の2と3を1800回繰り返す と言う処理が必要です。 「総サンプル数が1800」であれば良いので「10コマ書き込むのを180回繰り返し」でも構いませんし「100コマ書き込むのを18回繰り返し」でも構いません。
お礼
回答ありがとうございます。 教えていただいたサイトは私も参考にしていました。 前の回答者様のところにも書かしていただきましたが1コマづつBMPを登録することはできています。 複数コマを一度に登録しようとするとエラーになってしまします。 複数コマのBMPを一度に登録する例などがありましたら教えていただけないでしょうか?