Some DirectShow interfaces were enabled for access from OLE Automation clients such as Visual Basic. Unfortunately, some of them require C/C++ code to access them. By special request I have created a C++ wrapper DLL that allows access to a number of problem interfaces. You can download this DLL here. You can also download capstill.dll -- a frame-grabber dll -- together with a sample VB project, here.
The File Writer filter needs you to pass in the pathname to use as an output filename, using the IFileSinkFilter interface. Unfortunately, you can't do this from VB without a small C++ wrapper. FSFWrap.zip (11Kb) contains a small DLL that provides this wrapper.
Download FSFWrap and register the dll with regsvr32 fsfwrap.dll, and then add a reference to the FSFWrap type library. You can then create a SinkInfo object, assign an IFilterInfo object to its filter property and then set the output filename.
As an example, open the vb\builder example from the DirectShow SDK, and change AddRegFilter to the following:
Private Sub cmdAddRegFilter_Click()
Dim filter As IRegFilterInfo
For Each filter In g_objRegFilters
If filter.Name = listRegFilters.Text Then
Dim f As IFilterInfo
If f.IsFileSource Then
' handle user cancel
f.FileName = CommonDialog1.FileName
Dim sink As SinkInfo
Set sink = New SinkInfo
sink.filter = f
If sink.IsFileSink Then
sink.FileName = CommonDialog1.FileName
' Set frmRegFilters = g_objMC.RegFilterCollection
HHow can I select the video capture format with the "Stream Format" dialog?
The Stream Format property page allows you to select the pixel format and image size (using the IAMStreamConfig interface). It is exposed by the preview and capture pins of WDM video capture filters. You need to show the property pages of the pin, and not the filter. I have extended fsfwrap.dll to support this, using the following code to show the property page of a pin. This is also used in the CapStill sample below.
How can I specify a capture format and capture parameters from a VB program?
Some VB programs need to specify a capture format such as RGB24 320x240, rather than simply showing the Stream Format dialog for the user to select a type. The media type is a complex structure which is hard to deal with directly in VB. I have provided a simple but effective method for using them: a tool that saves the current media type to a file and restores from a file.
The capstill sample demonstrates this in use. The application shows the Stream Format dialog (see here) and then saves to a file the format that the user selects. Next time the app is run, before showing the Stream Format dialog, the app restores and selects the saved media type.
The fsfwrap dll contains a StreamConfig object. The program creates one of these and assigns an IPinInfo to its Pin property, and then uses the SaveCurrentFormat and Restore methods. This only works with pins that support the IAMStreamConfig interface (typically on video capture filters).
The latest version of FSFWrap.dll also allows you to control the crossbar settings (to select between eg Composite and S-Video input), and the video standard (PAL, NTSC). This is demonstrated in the capstill sample.
How can I grab still frames from a movie using Visual Basic?
DirectX 8 includes a SampleGrabber filter. This is a pass-through filter that allows an application to view frames as they pass through the graph. However, it is hard to use from Visual Basic. I've written a small dll that, when called from VB, saves the next frame to a .BMP file. To use it, you need to add the SampleGrabber filter to the graph, then construct a VBGrabber object and set the sample grabber to the VBGrabber.FilterInfo property.
I've also written a small test app in VB that demonstrates how to use capstill.dll. To use the demo app, you need to select a source filter (Bouncing Ball works) and then press Preview to build and run a preview graph. Press Snap to save the next frame to a bitmap file. The sample also uses the Stream Format property page on the pin, if present, to allow you to select the image size (the format of the file will always be RGB24). Clearly for a real app you will need a more sophisticated way of selecting the source filter and output pin.
New! you can now also capture still frames to memory. It returns an IBitmapAccess COM object containing the bitmap, from which you can get an HBITMAP (a DIB Section) and also a pointer directly to the bits, and there is an updated sample that demonstrates this, including a dreadful hack which creates a byte array from the bits
Download capstill.dll and the vbcap demo app here.
Why does the DirectX Builder sample not work properly?
The DirectShow VB sample Builder does not work with live graphs because it tries to set the file position, and if this fails, it silently does not start the graph. Change the code in the builder’s mnu_FilterGraphRun_Click method to the following
Also the "Connect One Pin" implementation in the v8.1 sdk is broken. This code (in frmSelectPins, method listFilters_Click) is intended to show all the unconnected pins that you could connect to. To do this, it uses the pin.ConnectedTo method and then shows the pin if there is an error. Unfortunately a statement "On Local Error Goto Errline" was added which means that when a useful pin is found, the error handler jumps out of the loop. You need to add On Error Resume Next instead:
How can I list all the video capture filters (or any another category of filters)?
FSFWrap now contains a FilterCatEnumerator object that allows VB programs to enumerate filters by category. Examples of categories include Video Capture sources, Audio input and output devices and audio or video compressors. A modified version of the DirectShow 8.1 SDK sample builder is included in the zip, which shows how to use this feature. The category is specified by a GUID in text form. The most common categories are given in the builder example.
How can I remove filters from a graph in VB
The VBGraphHelper (in FSFWrap) has a method RemoveChain(pFilter). This removes from the graph the specified filter, and all filters downstream of it, and returns the output pin that was connected to pFilter.
Then you can render pOut using a different set of transforms or whatever. At this point, you might want to add your own transform by class id:
Then use pOut.Connect to connect the output pin to the new transform.