## Controlling Filter Graphs Using Visual Basic

This article describes how to use the methods, events, and properties exposed by the Microsoft® DirectShow™ dynamic-link library, Quartz.dll, to render a stream of time-stamped video data in applications based in Microsoft Visual Basic®. This article is written for the Visual Basic developer who is already familiar with Windows®-based application programming, Windows-based multimedia programming, and Automation features of the Visual Basic programming system version 5.0.

Contents of this article:

- DirectShow Filters and Filter Graphs
- DirectShow Interfaces, Visual Basic Objects, and Registering Quartz.dll
- The VBDemo Sample Application
  - Installing the Files
  - Registering Quartz.dll with Visual Basic
  - Preparing to Use the DirectShow Objects
  - Instantiating the Filter Graph
  - Rendering Video
  - Controlling Audio
  - Scaling and Translating the Video Output
  - Tracking Status
  - Getting and Setting the Start Position
  - Getting and Setting the Rate
  - Cleaning Up

DirectShow Filters and Filter Graphs

When multimedia is displayed in an application by using Quartz.dll, the application is using a collection of objects called filters; this collection is sometimes called a filter graph. The following diagram depicts a filter graph that is capable of rendering an audio-video interleaved (.avi) file.

In this illustration, the AVI source filter reads the file from disk. The AVI decompressor filter (codec) decompresses the video data as it is passed from the source filter. The codec filter then passes this data to the video renderer. The video renderer, in turn, passes the data to the device in a format that the device understands. The AVI source filter passes the audio data directly to the audio renderer, which, in turn, passes the data to the audio device.

In addition to filters, DirectShow supports an Automation object called the filter graph manager. This object knows about the available filters and understands which filter types are required to render which file formats. The filter graph manager exposes the methods, events, and properties supported by the filters in a given graph. The filter graph manager also exposes its own set of methods, events, and properties. These are exposed by using interfaces, which are simply collections of related methods, events, and properties.

The following table identifies the DirectShow interfaces available in Quartz.dll for use with Visual Basic-based applications, and describes the purpose of each interface.

Interface | Description
IAMCollection | Accesses pin and filter collections.
IBasicAudio | Controls and retrieves current volume setting.
IBasicVideo | Controls a generic video renderer.
IFilterInfo | Retrieves information about a filter and about pin objects in the filter.
IMediaControl | Instantiates the filter graph and controls media flow (running, paused, stopped).
IMediaEvent | Allows customized event handling for events such as repainting, user termination, completion, and so on.
IMediaPosition | Controls and retrieves start time, stop time, rate, and current position.
IMediaTypeInfo | Retrieves the media type and subtype.
IPinInfo | Accesses pin information, such as pin direction and media type, and controls pin connection, disconnection, and rendering.
IRegFilterInfo | Contains information about registered (transform and render) filters.
IVideoWindow | Controls window aspects of a video renderer.

DirectShow Interfaces, Visual Basic Objects, and Registering Quartz.dll

To use the DirectShow interfaces in your Microsoft Visual Basic-based application, you must register the ActiveMovie Control type library in your Visual Basic project.

When you register the ActiveMovie Control type library by using the Visual Basic References dialog box, you are identifying the type library that contains the Automation information that Visual Basic requires. The following illustration shows the References dialog box.

Once the type library is registered, you can use the Object Browser dialog box to view the list of methods, events, and properties associated with a given interface.

Note The type information in the filter graph manager is organized by interface, rather than object.

The VBDemo Sample Application

This section is based on the VBDemo sample application, which enables the user to do the following:

- Choose an DirectShow file (.avi, .mpg, or .mov).
- Display a simple toolbar that lets the user play, pause, or stop the rendering.
- Display the length of the video and the elapsed time.
- Display start position and run rate.
- Display a volume control and a balance control.
- Position the destination window (a shape control) below all other controls in the main form.

The application, when running a file, appears as follows:

Installing the Files

Before using the DirectShow objects in your Visual Basic-based application, you must install Quartz.dll in the Windows\System directory and ensure that the appropriate entries are made in your system's registry database. Currently, the DirectShow Software Development Kit (SDK) setup program automates this process. To install, start Setup.exe and choose the Runtime option. The dynamic-link library (DLL) will be copied to the correct location, and the registry will be automatically updated.

Registering Quartz.dll with Visual Basic

Open the Visual Basic application and choose the References command from the Tools menu to verify that the files were installed succesfully. (At startup, Visual Basic examines the registry database for registered automation controls and adds their names to the list that appears in this dialog box.) To use the filter graph manager, click the box that appears next to the ActiveMovie Control type library name.

Once Visual Basic registers the type information, you can use the filter graph manager and its associated interfaces in your application.

Preparing to Use the DirectShow Objects

Visual Basic initializes all objects in the VBDemo sample program using the FilgraphManager object, which implements the following interfaces.

- IBasicAudio
- IBasicVideo
- IMediaControl
- IMediaEvent
- IMediaPosition
- IVideoWindow

Each of the interfaces is accessed by a Visual Basic programmable object defined to be of that interface type. The objects in the sample application are defined as global variables in the general declarations section, as shown in the following example.

    Dim g_objVideoWindow As IVideoWindow  		'VideoWindow Object
    Dim g_objMediaControl As IMediaControl          'MediaControl Object
    Dim g_objMediaPosition As IMediaPosition        'MediaPosition Object
    Dim g_objBasicAudio  As IBasicAudio             'Basic Audio Object
    Dim g_objBasicVideo As IBasicVideo              'Basic Video Object

All the programmable objects are initialized using FilgraphManager, as shown in the following example:

         Set g_objMediaControl = New FilgraphManager
        g_objMediaControl.RenderFile (g_strFileName)    ' name of input file
        ...
        Set g_objBasicAudio = g_objMediaControl
        Set g_objVideoWindow = g_objMediaControl
        Set g_objMediaEvent = g_objMediaControl
        Set g_objMediaPosition = g_objMediaControl

The other interfaces available for use with Visual Basic-based applications are obtained by calling methods that explicitly return the desired interface. The following table summarizes how to obtain these interfaces.

Interface | Methods that return the interface pointer
IAMCollection | IPinInfo.MediaTypes, IFilterInfo.Pins, IMediaControl.FilterCollection, IMediaControl.RegFilterCollection
IFilterInfo | First IMediaControl.FilterCollection, then IAMCollection.Item or IPinInfo.FilterInfo
IMediaTypeInfo | IPinInfo.ConnectionMediaType
IPinInfo | IFilterInfo.FindPin, IAMCollection.Item
IRegFilterInfo | First IMediaControl.RegFilterCollection, then IAMCollection.Item

For a sample that shows how to manipulate these filter and pin interfaces, see Constructing Filter Graphs Using Visual Basic.

Instantiating the Filter Graph

You can use the filter graph manager to render existing files of the following types.

- .avi (audio-video interleaved)
- .mov (Apple® QuickTime®)
- .mpg (Motion Picture Experts Group)

In addition, you can use the filter graph manager to render an existing filter graph by specifying the file that contains that graph as a parameter to the RenderFile method.

Because the filters in a filter graph are dependent on the type of file being rendered, the sample application does not instantiate a filter graph until the user selects a file. The code that handles this selection is embedded in the procedure that opens the file, mnu_FileOpen. This code displays the Show Open common dialog box and stores the selected file name in a g_strFileName variable. After this, the code verifies that the correct file type was chosen. Quartz.dll issues an error message if it is passed a file extension other than .mpg, .avi, or .mov.

Once the g_strFileName variable is set, the application instantiates the filter graph manager and creates the filter graph object. The filter graph manager is instantiated when the Visual Basic keyword New is used to create the AUTOMATION object. The filter graph object is created when the IMediaControl::RenderFile method is called, as shown in the following example.

        'Instantiate a filter graph for the requested
        'file format.

        Set g_objMediaControl = New FileGraphManager
        g_objMediaControl.RenderFile (g_strFileName)

Rendering Video

The IMediaControl interface supports three methods (Run, Pause, and Stop) that an application can call to render, pause, or stop a video stream. After the filter graph object is instantiated, your application can call these methods.

The sample application displays a toolbar from which the user controls video rendering. When the user clicks Run, the Run method is activated and a global Boolean variable (fVideoRun) is set to True. This variable is used in a timer procedure that retrieves the current media position (or elapsed rendering time). If the Pause or Stop button is clicked, this variable is set to False, and the current media position is not retrieved during timer events.

The code that activates the Run, Pause, and Stop methods is found in the Toolbar1_ButtonClick procedure. The toolbar contains buttons that are numbered 1, 3, and 5; the buttons numbered 2 and 4 are separators that provide additional space between the buttons, as shown in the following example.

    Private Sub Toolbar1_ButtonClick(ByVal Button As Button)
    ' handle buttons on the toolbar
    ' buttons 1, 3 and 5 are defined; 2 and 4 are separators
    ' all DirectShow objects are defined only if the user
    ' has already selected a filename and initialized the objects

        ' if the objects aren't defined, avoid errors
        If g_objMediaControl Is Nothing Then
            Exit Sub
        End If

        If Button.Index = 1 Then 'PLAY
            'Invoke the MediaControl Run() method
            'and play the video through the predefined
            'filter graph.

            g_objMediaControl.Run
            g_fVideoRun = True

        ElseIf Button.Index = 3 Then  'PAUSE
            'Invoke the MediaControl Pause() method
            'and pause the video that is being
            'displayed through the predefined
            'filter graph.

            g_objMediaControl.Pause
            g_fVideoRun = False

        ElseIf Button.Index = 5 Then  'STOP

            'Invoke the MediaControl Stop() method
            'and stop the video that is being
            'displayed through the predefined
            'filter graph.

            g_objMediaControl.Stop
            g_fVideoRun = False
            ' reset to the beginning of the video
            g_objMediaPosition.CurrentPosition = 0
            txtElapsed.Text = "0.0"

Controlling Audio

The IBasicAudio interface supports two properties: the Volume property and the Balance property. The Volume property retrieves or sets the volume. In the sample application, this property is bound to the slider control slVolume. The Balance property retrieves or sets the stereo balance. In the sample application, this property is bound to the slider control slBalance.

Note The volume is a linear volume scale, so only the far right side of the slider is useful.

The following example shows the code that adjusts the volume (by setting the g_objBasicAudio.Volume property) is found in the slVolume_Change procedure.

    Private Sub slVolume_Change()

        'Set the volume on the slider

        If Not g_objMediaControl Is Nothing Then
        'if g_objMediaControl has been assigned

           g_objBasicAudio.Volume = slVolume.Value

        End If

    End Sub

Scaling and Translating the Video Output

The IVideoWindow interface supports the methods and properties you can use to alter the size, state, owner, palette, visibility, and so on, for the destination window. If you are not concerned with the location or appearance of the destination window, you can render output in the default window (which appears in the upper-left corner of the desktop) without calling any of these methods or properties.

The sample application moves the destination window to a position below the other controls on its main form. In addition to moving the window, the sample application alters the window style by removing the caption, border, and dialog box frame. To do this, set the g_objVideoWindow.WindowStyle property to 0x06000000. This corresponds to the logical OR operation of the values WS_DLGFRAME (0x04000000) and WS_VSCROLL (0x02000000). For a complete list of window styles and corresponding values, see the Winuser.h file in the Microsoft® Platform SDK.

To move the destination window onto the form, specify a new position by setting the Top and Left properties of g_objVideoWindow. The Top and Left properties are set to correspond to the upper-left corner of a blank control with a rectangular shape, a placeholder of sorts, that appears on the form. The ScaleMode property for the form was set to 3, which specifies units of pixels. This allows the form properties and DirectShow object properties to be used without conversion. The DirectShow object properties are also expressed in pixels. The default units for a Visual Basic form are twips.

The sample application uses the left top of the placeholder rectangle, then resizes the shape based on the size of the specified video. The application determines the required size of the rectangle by retrieving the source video width and height. These values correspond to the VideoWidth and VideoHeight properties of the g_objBasicVideo object.

In addition to setting the Top and Left properties, it is necessary to identify the form of the application as the new parent window by passing the window handle of the form, hWnd, to the g_objVideoWindow.Owner property. If the handle is not passed, the destination window will appear relative to the desktop and not the form.

The following example shows the tasks that are accomplished in the mnu_FileOpen procedure.

        Set g_objVideoWindow = g_objMediaControl
        g_objVideoWindow.WindowStyle = CLng(&H6000000)   ' WS_DLGFRAME | WS_VSCROLL
        g_objVideoWindow.Left = CLng(Shape1.Left)   ' shape is a placeholder on the form
        g_objVideoWindow.Top = CLng(Shape1.Top)
        Shape1.Width = g_objVideoWindow.Width    ' resize the shape given the input video
        Shape1.Height = g_objVideoWindow.Height
        g_objVideoWindow.Owner = frmMain.hWnd    ' set the form as the parent

The following example shows how the ScaleMode property is initialized in the Form_Load procedure.

    ' code fragment from the Form_Load procedure
    ' ...
        frmMain.ScaleMode = 3    ' pixels
    ' ...

Avoid attempting to scale the destination window by setting the Width and Height properties for the g_objVideoWindow object, because performance suffers considerably.

Tracking Status

The g_objMediaPosition object exposes a number of properties that you can use to retrieve or set the current position, stop point, duration, and rate. When the user selects a file, the sample application retrieves and displays the duration, starting position, and rate. The corresponding code appears in the mnu_FileOpen procedure, as shown in the following example.

        Set g_objMediaPosition = g_objMediaControl
        g_dblRunLength = g_objMediaPosition.Duration
        txtDuration.Text = CStr(g_dblRunLength)   ' display the duration
        g_dblStartPosition = 0.0
        txtStart.Text = CDbl(g_dblStartPosition)   ' display the start time
        g_dblRate = g_objMediaPosition.Rate
        txtRate.Text = CStr(g_dblRate)

The current position is also displayed, using a timer that is started when the user clicks Run. When the user clicks Run, a global Boolean variable, g_fVideoRun, is set to True, indicating that the program should retrieve and display the current media position, which is expressed as the elapsed rendering time from the absolute beginning of the multimedia stream.

If Pause or Stop is clicked, the variable is set to False, and the current media position is not retrieved. The corresponding code (which displays the current position) appears in the Timer1_Timer procedure, as shown in the following example.

    Private Sub Timer1_Timer()
        'Retrieve the Elapsed Time and
        'display it in the corresponding
        'textbox.
    Dim Dbl As Double

        If g_fVideoRun = True Then
            Dbl = g_objMediaPosition.CurrentPosition
            If Dbl < g_dblRunLength Then
                txtElapsed.Text = CStr(Dbl)
            Else
                txtElapsed.Text = CStr(g_dblRunLength)
            End If
        End If
    End Sub

Getting and Setting the Start Position

The sample application uses the IMediaPosition.CurrentPosition property to let the user adjust the point at which the video begins rendering. If the user enters a new CurrentPosition and then clicks Play, the video begins rendering at the frame whose timestamp is closest to the requested time.

In addition to adjusting the starting time, the user can jump to new frames while the video is rendering by specifying a new value in the corresponding text box and then pressing ENTER.

The code that handles the CurrentPosition property is found in the following example of the txtStart_KeyDown procedure.

     Private Sub txtStart_KeyDown(KeyCode As Integer, Shift As Integer)
    ' handle user input to change the start position
    If KeyCode = vbKeyReturn Then
        If g_objMediaPosition Is Nothing Then
            Exit Sub
        ElseIf CDbl(txtStart.Text) > g_dblRunLength Then
            MsgBox "Specified position invalid: re-enter new position."
        ElseIf CDbl(txtStart.Text) < 0 Then
            MsgBox "Specified position invalid: re-enter new position."
        ElseIf CDbl(txtStart.Text) <> "" Then
            g_dblStartPosition = CDbl(txtStart.Text)
            g_objMediaPosition.CurrentPosition = g_dblStartPosition
        End If
    End If
    End Sub

Getting and Setting the Rate

The sample application uses the IMediaPosition.Rate property to let the user adjust the rate at which the video is rendered. This rate is a ratio with respect to typical playback speed. For example, a rate of 0.5 causes the video to be rendered at one-half its typical speed, and a rate of 2.0 causes the video to be rendered at twice its typical speed.

Unlike the CurrentPosition property, which can be set while the video is being rendered, the Rate property must be set prior to rendering.

Note The sound track can be disabled for some videos when the rate is less than 1.0.

The code that handles the Rate property is found in the following txtRate_KeyDown procedure.

    Private Sub txtRate_KeyDown(KeyCode As Integer, Shift As Integer)
    ' DirectShow VB sample
    ' handle user updates to the Rate value
    If KeyCode = vbKeyReturn Then
        If g_objMediaPosition Is Nothing Then
            Exit Sub
        ElseIf CDbl(txtRate.Text) < 0# Then
            MsgBox "Negative values invalid: re-enter value between 0 and 2.0"
        ElseIf CStr(txtRate.Text) <> "" Then
            g_dblRate = CDbl(txtRate.Text)
            g_objMediaPosition.Rate = g_dblRate
        End If
    End If
    End Sub

Cleaning Up

Each time your application uses the Visual Basic Set statement to instantiate a new DirectShow object, it must include a corresponding Set statement to remove that object (and its corresponding resources) from memory prior to shutdown. For example, in the mnu_FileOpen procedure, a new g_objBasicAudio object is instantiated with the following syntax.

    Set g_objBasicAudio = g_objMediaControl

When the user selects Exit from the File menu, a corresponding Set statement removes this object:

    Set g_objBasicAudio = Nothing

© 1997 Microsoft Corporation. All rights reserved. Terms of Use.