FirebirdGuy Posted August 21, 2003 Posted August 21, 2003 (edited) Keywords: VB.Net, AVI Compression, avifil32.dll Hello, I have been struggling for days now to write a VB.Net application which converts BMP Images to AVI. This program works just fine in VB but will not run in VB.Net. The problem lies with the conversion of VarPtr() in VB to some other means in VB.Net. The main problem begins when calling the avifil32.dll function AVISaveOptions Defined as follow: Public Declare Function AVISaveOptions Lib "avifil32.dll" (ByVal hWnd As Integer, ByVal uiFlags As Integer, ByVal nStreams As Integer, ByRef ppavi As Integer, ByRef ppOptions As Integer) As Integer 'TRUE if user pressed OK, False if cancel, or error if error This function wants to receive a pointer to a pointer to an AVI_COMPRESS_OPTIONS Structure. The problem is that with VB.Net we are working with managed memory and it seems this function wants a pointer to a pointer to unmanaged memory. It has been suggested to use the following algorithm in order to get the VarPtr within .Net: Public Function VarPtr(ByVal o As Object) As Integer Dim oGC As GCHandle = GCHandle.Alloc(o, GCHandleType.Pinned) Dim ret As Integer = oGC.AddrOfPinnedObject.ToInt32 oGC.Free() Return ret End Function I have attempted to use this method with no luck at all... I then came across another trick for allocating the memory of the AVI_COMPRESS_OPTIONS to unmanaged memory, and then passing a pointer to that memory location to the AVISaveOptions function. Once the function has completed I then read the memory location back in and I can get the updated valued from the AVISaveOptions call. Here is the code that accomplishes this for me: Dim opts As AVI_COMPRESS_OPTIONS '//Allocate enough memory on the global heap Dim lpB As IntPtr = Marshal.AllocHGlobal(Len(opts)) Dim source(11) As Integer ' 11 elements in AVI_COMPRESS_OPTIONS, all of type Integer Dim destination(11) As Integer source(0) = opts.fccType source(1) = opts.fccHandler source(2) = opts.dwKeyFrameEvery source(3) = opts.dwQuality source(4) = opts.dwBytesPerSecond source(5) = opts.dwFlags source(6) = opts.lpFormat source(7) = opts.cbFormat source(8) = opts.lpParms source(9) = opts.cbParms source(10) = opts.dwInterleaveEvery '//Copy the managed array to the un-managed pointer Marshal.Copy(source, 0, lpB, 11) 'Len(opts)) Dim pOpts As Integer pOpts = lpB.ToInt32() res = AVISaveOptions(Me.Handle.ToInt32, ICMF_CHOOSE_KEYFRAME Or ICMF_CHOOSE_DATARATE, 1, ps, pOpts) ' Get the data back out of unmanaged memory Marshal.Copy(lpB, destination, 0, 11) opts.fccType = destination(0) opts.fccHandler = destination(1) opts.dwKeyFrameEvery = destination(2) opts.dwQuality = destination(3) opts.dwBytesPerSecond = destination(4) opts.dwFlags = destination(5) opts.lpFormat = destination(6) opts.cbFormat = destination(7) opts.lpParms = destination(8) opts.cbParms = destination(9) opts.dwInterleaveEvery = destination(10) At this point my opts object has valid information after the user has chosen their AVI format to save as. Everything seems to be going ok at this point, the following code executes without error: res = AVIMakeCompressedStream(psCompressed, ps, opts, 0) I am still wondering if passing opts at this point is valid, have I updated the object properly to pass it into this function call? Then, once I try to call AVIStreamSetFormat the application fails with a return HRESULT which has a value of -2147205018 (AVIERR_BADPARAM ). Here is how I call that function: Dim B() As Byte = bmp.GetBitmapInfo() Dim iLength As Integer = B.Length '//Allocate enough memory on the global heap Dim lpB2 As IntPtr = Marshal.AllocHGlobal(iLength) '//Copy the managed array to the un-managed pointer Marshal.Copy(B, 0, lpB2, iLength) res = AVIStreamSetFormat(psCompressed, 0, lpB2.ToInt32(), iLength) This code fails totally when selecting the MPEG4 compression format, it seems to succeed with some other formats but the file is never written to with my calls to AVIStreamWrite. It would seem that the problem lies somehow with the opts.lpParms value which is created by the AVI dll since the code passes the AVIStreamSetFormat when this value is set to 0, and not otherwise. Just for completeness, here is how I call the AVIStreamWrite method: ' Now write out each video frame For i = 0 To listBoxImageList.Items.Count - 1 listBoxImageList.SelectedIndex = i bmp.CreateFromFile(listBoxImageList.Text) 'load the bitmap (ignore errors) ' bmp.PointerToBits uses the same technique as above with using the Marshal class to get a pointer the an unmanaged memory location holding the bitmap info. res = AVIStreamWrite(psCompressed, i, 1, bmp.PointerToBits, bmp.SizeImage, AVIIF_KEYFRAME, 0, 0) If (res <> AVIERR_OK) Then MsgBox("AVIStreamWrite failed.") Exit Function End If Next The Declared Functions are below: Public Declare Function AVIMakeCompressedStream Lib "avifil32.dll" (ByRef ppsCompressed As Integer, ByVal psSource As Integer, ByRef lpOptions As AVI_COMPRESS_OPTIONS, ByVal pclsidHandler As Integer) As Integer ' Public Declare Function AVIStreamSetFormat Lib "avifil32.dll" (ByVal pavi As Integer, ByVal lPos As Integer, ByRef lpFormat As Integer, ByVal cbFormat As Integer) As Integer Public Declare Function AVIStreamWrite Lib "avifil32.dll" (ByVal pavi As Integer, ByVal lStart As Integer, ByVal lSamples As Integer, ByVal lpBuffer As Integer, ByVal cbBuffer As Integer, ByVal dwFlags As Integer, ByRef plSampWritten As Integer, ByRef plBytesWritten As Integer) As Integer Can anyone help me out and tell me what I am doing wrong in my code. Unfortunately I am not a strong C++ programmer and am weak when it comes to pointers. Has anyone had success with writing bmp images to an AVI file after choosing a compression type in .NET? Any help would be greatly appreciated. Edited November 26, 2005 by PlausiblyDamp Quote
steved Posted August 21, 2003 Posted August 21, 2003 I was struggling with a similar problem in C# (the bmp-to-avi thing, not the rest of it). I have a friend who came up with a solution and is now making a go at wrapping up that entire API. I will post his C# code when I can get ahold of it - hopefully that will help. Quote zig?
FirebirdGuy Posted August 21, 2003 Author Posted August 21, 2003 (edited) steved, that would be great, I need to see some working source code whether it be C# or VB.Net, either is good :) Anyone else have any idea why the above code doesn't work or what I am doing wrong? Edited August 21, 2003 by FirebirdGuy Quote
steved Posted August 22, 2003 Posted August 22, 2003 Sorry it took so long. He wanted to add an example app before making it public. I haven't looked at this version yet, but he tells me it still uses all P/Invokes of the vfw API stuff, there is no comments, and to give him credit for blah, blah... :) Have fun with it. I think Gabe (the guy who wrote it) will be updating it as he makes improvements, so let me know if you have any trouble. Good luck! http://midget3d.com/gabe/AviLib.zip Quote zig?
FirebirdGuy Posted August 23, 2003 Author Posted August 23, 2003 Thanks steved, I'll take a look at it. Any code I borrow from there I have no problem whatsoever giving credit for :) Thank your friend as well for sharing some code on this difficult subject. Quote
FirebirdGuy Posted August 23, 2003 Author Posted August 23, 2003 steved/Gabe, thanks so much, I've been playing around with the DLL/code and it works well. I've been struggling for days to get cod that does what your DLL does. I see now how it is done but don't think I could have figured that out on my own. I should be ok from here out, thanks again. Quote
steved Posted August 25, 2003 Posted August 25, 2003 Hey, no prob! I'm glad it helped. I'll be sure to let Gabe know his first-ever GPL code already helped someone. :) Quote zig?
alx_dot_net Posted November 11, 2003 Posted November 11, 2003 Could someone post the classes in VB.NET format? Quote
*Experts* Volte Posted November 11, 2003 *Experts* Posted November 11, 2003 You can compile the library as a DLL and use it from VB.NET projects, regardless of what language it is orginally in. Quote
carlblanchard Posted September 26, 2004 Posted September 26, 2004 (edited) Nice work gabe I have used this in a vb application and it works very nice however compression dosnt seem to work ? My File size is Huge Let us know the score Regards Carl Blanchard PS VB for kid Dim aviObj As New AviLib.AviWriter("output.avi", AviLib.AviCompression.None, Convert.ToUInt32(24), 1280, 1024) Dim bitmaps As String() = Directory.GetFiles(System.Environment.CurrentDirectory & "\temp\", "*.jpg") Dim bitmap As String For Each bitmap In bitmaps Console.WriteLine(bitmap) aviObj.WriteFrame(New Bitmap(bitmap)) Next bitmap aviObj.Close() GC.Collect() Edited November 26, 2005 by PlausiblyDamp Quote
Giotto Posted May 31, 2005 Posted May 31, 2005 could you share the AviLib that I can't copile it? Hi Carl could you share the AviLib that I can't copile it? Thanks AB I have used this in a vb application and it works very nice however compression dosnt seem to work ? My File size is Huge Let us know the score Regards Carl Blanchard PS VB for kid Dim aviObj As New AviLib.AviWriter("output.avi", AviLib.AviCompression.None, Convert.ToUInt32(24), 1280, 1024) Dim bitmaps As String() = Directory.GetFiles(System.Environment.CurrentDirectory & "\temp\", "*.jpg") Dim bitmap As String For Each bitmap In bitmaps Console.WriteLine(bitmap) aviObj.WriteFrame(New Bitmap(bitmap)) Next bitmap aviObj.Close() GC.Collect() Quote
Giotto Posted May 31, 2005 Posted May 31, 2005 Can You help me? Hi steved Could you provide the dll since I would try to use it in VB.net and I'havent C#compiler? Thanks a lot AB Sorry it took so long. He wanted to add an example app before making it public. I haven't looked at this version yet, but he tells me it still uses all P/Invokes of the vfw API stuff, there is no comments, and to give him credit for blah, blah... :) Have fun with it. I think Gabe (the guy who wrote it) will be updating it as he makes improvements, so let me know if you have any trouble. Good luck! http://midget3d.com/gabe/AviLib.zip Quote
lhk_mgtf2008 Posted March 12, 2006 Posted March 12, 2006 Help on convert BMP to API i need this file http://midget3d.com/gabe/AviLib.zip izit possible i get the original source... Quote
Leaders dynamic_sysop Posted March 12, 2006 Leaders Posted March 12, 2006 if you look @ this example in C# ... link ... you will see this structure ... [structLayout(LayoutKind.Sequential, Pack=1)] public struct AVICOMPRESSOPTIONS { public UInt32 fccType; public UInt32 fccHandler; public UInt32 dwKeyFrameEvery; public UInt32 dwQuality; public UInt32 dwBytesPerSecond; public UInt32 dwFlags; public IntPtr lpFormat; public UInt32 cbFormat; public IntPtr lpParms; public UInt32 cbParms; public UInt32 dwInterleaveEvery; } you should be creating a new instance of one of those, filling it with all the stuff you need and sending that as the last parameter of the AviSaveOptions call. check out the link, it's on the codeproject & although it's in C# it is easy enough to understand from a vb point of view. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.