AVIをBMPに分解後、ビットマップハンドルを得たい

返信する


答えを正確に入力してください。答えられるかどうかでスパムボットか否かを判定します。

BBCode: ON
[img]: ON
[url]: ON
スマイリー: OFF

トピックのレビュー
   

展開ビュー トピックのレビュー: AVIをBMPに分解後、ビットマップハンドルを得たい

今更なのですが

by 西野孝雄 » 2007年9月15日(土) 04:03

古い記事に今更書くのもどうかと思いましたが、検索して参照する方もおられると思うし、質問もしたいので書かせて頂きます。

コードの切れ端は既になくなっているのでInternet Archiveのアドレスを。
表示→エンコード→日本語シフトJISにしないと表示されないみたい(私の環境下のみかもしれませんが)。
http://web.archive.org/web/200605021735 ... iew&no=262

AVIStreamGetFrameは「パックDIB」なるものが返るようで、これはBITMAPINFOとビットマップデータがくっ付いた物のようです。
で、イグトランスさんも仰られているようにBITMAPINFOは実質BITMAPINFOHEADERと考えて良いようです。
コードの切れ端内のコードでは*BITMAPINFOHEADERで受けてますが、その後にちゃんとデータがくっ付いてます。こんな事出来るんですね。

表示に関してはビットマップデータがあるのでそのままSetDIBitsToDeviceか、StretchDIBitsか、DrawDibDrawで直接描画できました。
どんな物でもそうかもしれませんが分かってみれば簡単なものですね。コードもたった数行ですむとは思いもしませんでした。

コード: 全て選択

hWndDC = GetDC(hMainWnd)
SetStretchBltMode(hWndDC,COLORONCOLOR)	'これやらないと縮小した時に画像が滲みます。

pGetFrameObj=AVIStreamGetFrameOpen(pAVIStream, AVIGETFRAMEF_BESTDISPLAYFMT)
ptr=AVIStreamGetFrame(pGetFrameObj,a)

StretchDIBits((hWndDC, 0, 0, 幅, 高さ, 0, 0, ptr->biWidth, ptr->biHeight, ptr +ptr->biSize, ByVal ptr, DIB_RGB_COLORS, SRCCOPY)	'幅, 高さで縮小拡大できます

ReleaseDC(hMainWnd,hWndDC)
因みにコードの切れ端内のコードではAVIStreamReleaseでpAVIStreamを開放してないのでバグが出る様です。

で、この方法の難点は非常に遅いという事です。ということで質問はもっと速い方法はないのかなという事です。
AVIStreamReadで読み込んでDrawDibDrawで描画する方法を試して、圧縮画像を解凍しないからだと思いますが、速いけど画像が汚い。
ICDecompressで解凍してみましたが画像は変らず。何か良い方法を知っている方はいないでしょうか。

参考にしたサイト
http://www7a.biglobe.ne.jp/~lshen/Etern ... AVI15.html

by 西野孝雄 » 2006年6月22日(木) 14:21

イグトランスさん、返信ありがとうございます。

CreateDIBSectionを書いてた所に教えてもらったのを書きました。
それ以外は①のAVI2BMPの内容と同じです。
実質BITMAPINFOHEADERそのものということで以下のようにしました。
Hozon()の内容は②のMainWnd_IDM_SAVE_MenuClick()とほぼ同じですが、一応載せます。

コード: 全て選択

GdipCreateBitmapFromGdiDib(ByVal ptr,VarPtr(bfh),g_gpBitmap)
Hozon()

コード: 全て選択

Sub Hozon()

	Dim Buffer As String
	Dim pwFileName As WordPtr
	Dim dwFNSize As DWord
	Dim sClsId As String
	Dim pwClsId As WordPtr
	Dim dwCISize As DWord
	Dim tClsId As CLSID


	'毎回選択するのは面倒なので決め打ち
	Buffer ="C:\Program Files\ActiveBasic\MyProjects\ImageViewerAB\Avi2J.jpg"
	sClsId = CLSID_JPEG


	'ファイルパスワイド文字格納領域サイズを取得し、動的に確保する  ワイド文字に変換する
	dwFNSize = MultiByteToWideChar(0, 0, StrPtr(Buffer), -1, 0, 0) * 2
	pwFileName = malloc(dwFNSize)
	MultiByteToWideChar(0, 0, StrPtr(Buffer), -1, pwFileName, dwFNSize)


	'クラスIDワイド文字格納領域サイズを取得し、動的に確保する  クラスIDをワイド文字に変換する
	dwCISize = MultiByteToWideChar(0, 0, StrPtr(sClsId), -1, 0, 0) * 2
	pwClsId = malloc(dwCISize)
	MultiByteToWideChar(0, 0, StrPtr(sClsId), -1, pwClsId, dwCISize)

	

	'クラスID文字列から128BitクラスID値を取得する
	If CLSIDFromString(pwClsId As Long, tClsId) <> 0 Then
		MessageBox(hMainWnd, "ファイル形式のID値取得に失敗しました", "エラー", MB_OK)
		free(pwFileName)
		free(pwClsId)
		Exit Sub
	End If

	
	'指定形式でファイルを保存する  確保したワイド文字格納領域を解放する
	If GdipSaveImageToFile(g_gpBitmap, pwFileName As Long, tClsId, 0) <> 0 Then
		MessageBox(hMainWnd, "ファイルの保存に失敗しました", "エラー", MB_OK)
	Else
		MessageBox(hMainWnd, "ファイルを保存しました", "成功", MB_OK)
	End If

	free(pwFileName)
	free(pwClsId)

End Sub
しかし、②のGdipSaveImageToFileのところでファイルの書き込みに失敗します。(0Kbyteのjpgファイルは作成されます)

何度も試していると、落ちたり、落ちなかったり、その場所も毎回違うのですが
②のMainWnd_Paintを消すと落ちる事がなくなりました。
GDI+のBitmapオブジェクトが正確に得られてないのでしょうか?

ptrをBITMAPINFOにコピーし、GdipCreateBitmapFromGdiDibに入れたりしましたが結果は変わりません。

デバッグ実行すると、アクセス違反がでるAVIStreamGetFrameOpenの
第二引数に、NULLやBITMAPINFOHEADERを入れてるサンプルを見たので
試したところ急に落ちてしまいます。(落ちない時もあった)

結局、色々いじっても成功しませんでした。
なので、どこが間違っているのか教えて頂けないでしょうか。
宜しくお願いします。

by イグトランス » 2006年6月21日(水) 20:53

落ちる問題の解決になるかどうかはわかりませんが,
ビットマップハンドルがなくても,GdipCreateBitmapFromGdiDib関数を使えばDIBからGDI+のBitmapオブジェクトを作ることができます。
そこのページに合わせた形で宣言を行うとこんな感じになると思います。

コード: 全て選択

Declare FunctionGdipCreateBitmapFromGdiDib Lib "gdiplus.dll"(
    ByRef gdiBitmapInfo As BITMAPINFO,
    ByVal gdiBitmapData As VoidPtr,
    ByRef bitmap As Long) As Long
BITMAPINFOはヘルプを見ればわかりますが,BITMAPINFOHEADERとRGBQUADの配列が並んでいます。
このRGBQUADの配列は,16ビット以上のビットマップでは原則無視するので,
その場合は実質BITMAPINFOHEADERそのものと考えて平気だと思います。

ページトップ