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

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
イグトランス
記事: 899
登録日時: 2005年5月31日(火) 17:59
お住まい: 東京都
連絡する:

#1 投稿記事 by イグトランス »

落ちる問題の解決になるかどうかはわかりませんが,
ビットマップハンドルがなくても,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そのものと考えて平気だと思います。
西野孝雄

#2 投稿記事 by 西野孝雄 »

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

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を入れてるサンプルを見たので
試したところ急に落ちてしまいます。(落ちない時もあった)

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

今更なのですが

#3 投稿記事 by 西野孝雄 »

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

コードの切れ端は既になくなっているので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
返信する