Recompress your videos
Video Capture Help ] AVIFile Tutorial ] Licensing and Distribution ] Resources ] Awards ] Latest News ] Source Code ] Free Controls ]

 

STEP 4 - Creating new AVI files from streams

HERE ARE THE PROJECT FILES FOR STEP 4 AVITutr4.zip

This sample code shows how to create new AVI files from existing streams.  It uses the CFileDlg class to allow the user to choose an existing file.  You have already seen how to use the CFileDlg class in step one so I won't repeat it here.  Again, I included this class simply to keep the code as simple and clear as possible while still allowing for full freedom in choosing a file.  After the filename is received from the user, the code gets an PAVIFILE handle and then finds the PAVISTREAM handle for the video stream.  All this was covered in step one so it should be easy to understand.  

Next, I use the CFileDlg again to get a save file name from the user because we are going to create a new file.  The code should be fairly straightforward.  Most of the necessary properties in the class are already initialized, we just need to add 3 lines:

ofd.DlgTitle = "Choose Location and Name to Save New AVI File"
ofd.DefaultExt = "avi"
szFileOut = "MyFile.avi"
'suggested name to prompt users with

And then call the VBGetSaveFileName method:

res = ofd.VBGetSaveFileName(szFileOut)

Once we have the input (existing) and output (non existing file or file to be overwritten) filenames we are ready to call some AVIFile functions.  The functions in this example were some of the most difficult to declare and call from Visual Basic.  The three AVISave functions all require a a pointer to a pointer to an array of AVI_COMPRESS_OPTIONS UDTs.  The only way I could figure out to call these was to declare the functions using ByRef AVI_COMPRESS_OPTIONS and then use the undocumented VarPtr() function to get a pointer to the UDT.  I then passed this pointer in to the API function and all went smoothly.  It would probably be cleaner to write and compile a TypeLibrary, but since my purpose in writing this tutorial was to keep it as simple as possible to understand, I stuck with straight API declares.

The other problem I ran into was even uglier.  AVISave is actually declared in Vfw.h as using CDECL calling convention.  As you may know, this is one of the worst situations a VB API programmer can run into.  VB only understands the STDCALL calling convention (also called Pascal or Fortran calling convention).  Because the parameters are pushed onto the stack in a different order and clean up is not handled the same way, VB cannot call exported functions which use this calling convention.  Fortunately, the Win32 system programmers at MS made a concession to languages other than C/C++ and included a second exported function with equivalent functionality called AVISaveV which is declared using STDCALL.  Because this is the only one we can use from Visual Basic, I aliased AVISaveV to be called AVISave, but if you use the MSDN documentation you should look up AVISaveV instead because the last parameter is different.

Now that I have explained some of the difficulties involved, let's get down to the code.  We are going to show the Compression Options dialog to the user to get the codec with which to save the new AVI file.  First, I get a pointer to the UDT:

pOpts = VarPtr(opts)

Then I pass this pointer to the function ByRef, which gives us a pointer to a pointer, which the API is expecting.  The 3 flags in the second parameter control how the compression options dialog will look:

res = AVISaveOptions(Me.hWnd, _
        ICMF_CHOOSE_KEYFRAME Or ICMF_CHOOSE_DATARATE Or ICMF_CHOOSE_PREVIEW, _
        1, _
        pAVIStream, _
        pOpts)
'returns TRUE if User presses OK, FALSE if Cancel, or an error code

If this function returns a 1 (which is TRUE in C), then you know that the AVI_COMP_OPTIONS UDT has been correctly initialized.  Now we have enough information to create a new compressed stream from the video stream we got from the existing AVI file at the beginning of the sample.  If the existing stream is already compressed it will be re-compressed using the new codec (and will probably lose some quality).  This sample would be useful for post-processing uncompressed video captures or creating video-only AVIs to use in the Win32 Animation control (*note- the Animation control can only playback uncompressed video or RLE compressed video, so choose one of those options if you want to use the video for an Animation control).  To create a compressed stream  we just need one line of code:

'recompress the stream with user options
res = AVIMakeCompressedStream(pAVIStreamOut, pAVIStream, opts, 0&)

Now that we have a new video stream interface, we are ready to save a new AVI file.  Because this can take a long time the AVISave function supports a callback which can show status information and allow the user to cancel if necessary.  I have filled in the Callback "template" function in the AviDecs.bas file with information specific to this sample app so you can see an example of how to use this.  I have also used a global "abort" flag to allow the user to abort by clicking a button.  Here is the call to AVISave:

pOpts = VarPtr(opts) 'make sure pointer is still valid
res = AVISave(szFileOut, 0&, AddressOf AVISaveCallback, 1, pAVIStreamOut, pOpts)

If you use a callback function which includes DoEvents to allow the user to cancel like I did, then you have to be careful about reentrancy problems.  Also you will want to handle the case where the user closes the application while it is saving a file.  In this simple app, I just prevented the user from closing the app during a save by putting a line of code in the form's Query_Unload event.  Another solution would be to cancel the file save and clean up when the user unloads the form this way.

Once the file is saved, you should deallocate the AVISaveOptions resources by calling AVISaveOptionsFree:

Call AVISaveOptionsFree(1, pOpts) 'frees resources

That's all there is to it.  Feel free to experiment with the codecs installed on your system.  

Go to the next step

Go back to the Table of Contents

This Shrinkwrap Visual Basic AVIFile Tutorial is Copyright (C) 2000 by Ray Mercer
Redistribution of the tutorial text and/or samples is prohibited.  Please contact the author Ray Mercer <raymer@shrinkwrapvb.com> if you have a question about this policy.