ATTENTION READERS! Lucky's VB Gaming Site is no longer active. For updated game programming information and tutorials, please visit The Game Programming Wiki!
DirectShow
Introduction / Simple Playback
What
is DirectShow?
Active Movie was the original
name for DirectShow. Now that DirectShow has become a part of DirectX, since version 8, the term
ActiveMovie is no longer used.
However the type library we are going to use is called
"ActiveMovie control type library" (QUARTZ.DLL).
DirectShow is an interface for
high-quality and high-speed playback and capture of multimedia stream files. It
supports a large set of formats, including ASF, MPEG, AVI,
MP3,
and WAV files. DirectShow is integrated with other DirectX
technologies, and automatically detects and uses video and audio
acceleration hardware when available, but also supports systems
without acceleration hardware.
DirectShow
initialization
First go to the project -
reference menu and check the "ActiveMovie control type
library".
The next step is to declare the
needed objects. Place this code in your applications declaration:
Private m_objBasicAudio As IBasicAudio
Private m_objBasicVideo As IBasicVideo
Private m_objMediaEvent As IMediaEvent
Private m_objVideoWindow As IVideoWindow
Private m_objMediaControl As IMediaControl
Private m_objMediaPosition As IMediaPosition
OK... before we can create instances of these objects to play any media file,
we have to remove the old object instances! Here's a handy procedure to clean up
our objects:
Sub
RemoveDShow()
On Local Error GoTo RemoveDShowError
'If a MediaControl instance
exists, then stop it from playing
If ObjPtr(m_objMediaControl) > 0
Then
m_objMediaControl.Stop
End If
'If a VideoWindow instance
exists, then remove the link to the render target
If ObjPtr(m_objVideoWindow) > 0
Then
m_objVideoWindow.Owner = 0
End If
'Destroy all objects
If ObjPtr(m_objBasicAudio) > 0
Then Set m_objBasicAudio = Nothing
If ObjPtr(m_objBasicVideo) > 0
Then Set m_objBasicVideo = Nothing
If ObjPtr(m_objMediaControl) > 0
Then Set m_objMediaControl = Nothing
If ObjPtr(m_objVideoWindow) > 0
Then Set m_objVideoWindow = Nothing
If ObjPtr(m_objMediaPosition) > 0
Then Set m_objMediaPosition = Nothing
Exit Sub
RemoveDShowError:
Err.Clear
Exit Sub
End Sub
Now we are ready for opening a media file. It works like this:
Sub
OpenDShowFile(Filename As String)
On Local Error GoTo OpenFileError
Set m_objMediaControl =
New FilgraphManager
Call
m_objMediaControl.RenderFile(Filename)
Exit Sub
OpenFileError:
Err.Clear
Resume Next
End Sub
Before I begin to describe what's happening here, you might be wondering, why
we just execute the next command if any errors occur. Well, that's simple:
Imagine you want to open an Audio file. Unfortunately Audio files don't contain
Video data (at least my audio files don't do). So DirectShow returns an
error, when we try to initialize the VideoWindow object.
First we create an instance of the FilterGraph object for the
requested file format. A filter graph determines how to process media
files opened with DirectShow.
Then we create and initialize our BasicAudio object, and set the
initial volume and balance. These three lines may also cause an
error. For example if you open a video file that contains no audio data.
In our next step we create an instance of the VideoWindow object, that
is needed for visualization of motion picture files. As mentioned before it is
possible, that these lines cause error, due to the contents of the source file!
We set the WindowStyle property of the VideoWindow object to WS_VISIBLE.
All available WindowStyle constants can be found at the bottom of this
document, and in the API Text viewer files, that shipped with Visual
Basic. The Top, Left, Width, and Height
properties determine the size of the output window. Then we have to assign an owner.
That's our render target. In this case, I have used a simple PictureBox
control, and pass its WindowHandle.
Now we initialize the MediaEvent object, that we need to control our
media playback. We're going to use this object to get the playback status later.
The last object to initialize is the MediaPosition object. The MediaPosition
object enables us to get and set the currentposition, the playback speed
(rate)
and to get the duration of our media file. In the code above we set the speed to
1, which is normal playback speed. Higher values cause DirectShow to play the
file faster, lower will play it slower.
Now we're finished with initialization.
Playing the file
We'll start with playing our loaded file:
If CLng(m_objMediaPosition.CurrentPosition)
= CLng(m_objMediaPosition.Duration) Then
m_objMediaPosition.CurrentPosition = 0
End If
Call m_objMediaControl.Run
It's as easy as it looks like! :) First we check if the current position is
at the end. If so, then reset it to the start. Then we just call the run method
of the MediaControl object, and we're fine!
Pausing playback
To pause the playback simply call the pause method of the MediaControl
object:
Call
m_objMediaControl.Pause
Stopping playback
Sometimes silly users want to stop the playback, and want to restart from the
beginning. Well, then we'll let them do so. :)
Another simple feature a potential user might want to use. :) We will achieve
this by altering the CurrentPosition property of the MediaPosition object.
This WILL cause the filter graph to pause the media file,
set the new position,
and then resume playing the file. But this method has proven to be fast enough
for real-time use.
Public Sub
SeekPosition(Amount As Double)
If m_objMediaPosition.CurrentPosition
+ Amount < 0 Then
m_objMediaPosition.CurrentPosition = 0
ElseIf m_objMediaPosition.CurrentPosition
+ Amount > _
m_objMediaPosition.Duration Then
m_objMediaPosition.CurrentPosition = m_objMediaPosition.Duration
Else
m_objMediaPosition.CurrentPosition =
m_objMediaPosition.CurrentPosition + Amount
End If
End Sub
Simply pass a negative value for seeking backwards. Now that we give such a
powerful tool to the user, we have to watch his inputs closely! :) If he wants
to seek a position before the start, or behind the end, then we'll have to
correct his mistakes.
We'll only use the WaitForCompletion method of this object. This method
accepts two variables as arguments. The first determines when the method should
give back control to us, and the second argument will be set by the function
itself, and contains the event completioncode. If you pass 0 or a higher value
as msTimeout the method will return when the timelimit is reached
(0 = immediately) or the end of
file is reached, which ever comes first. If the timelimit was reached, then
EvCode will be 0 (zero) and the run-time error 287 will be raised ("Application-defined or
object-defined error"). You can handle this by using:
On Error Resume
Next
So for anything else then -1 passed as msTimeout, you have to resume on the
next line, and check the EvCode. 0 (zero) means DirectShow is still playing, 1
or anything higher means that the file end has been reached. If you pass -1 as msTimeout,
then DirectShow will give back control to you as soon as the file end is
reached. But in the meantime your application does not react on user input!
That's it!
That's all the basic stuff you need to know! With this code you are able to
play every file, that you can play with your standard player! If you want to play
a file, that doesn't use one of DirectShows native file formats, you need to install
the proper codec (COder/DECoder) for it.
I also created a sample app that uses the code shown above. Download it here.
I hope you enjoyed our time together. 'Til next time!
Have fun coding cool multimedia games and apps using DirectShow.
The WindowStyle constants... I guess you don't need more than the WS_VISIBLE,
but I listed them all:
Public
Const WS_BORDER = &H800000
Public Const WS_CAPTION = &HC00000
Public Const WS_CHILD = &H40000000
Public Const WS_CHILDWINDOW = (WS_CHILD)
Public Const WS_CLIPCHILDREN = &H2000000
Public Const WS_CLIPSIBLINGS = &H4000000
Public Const WS_DISABLED = &H8000000
Public Const WS_DLGFRAME = &H400000
Public Const WS_GROUP = &H20000
Public Const WS_HSCROLL = &H100000
Public Const WS_ICONIC = WS_MINIMIZE
Public Const WS_MAXIMIZE = &H1000000
Public Const WS_MAXIMIZEBOX = &H10000
Public Const WS_MINIMIZE = &H20000000
Public Const WS_MINIMIZEBOX = &H20000
Public Const WS_OVERLAPPED = &H0&
Public Const WS_OVERLAPPEDWINDOW = (WS_OVERLAPPED Or WS_CAPTION Or
_
WS_SYSMENU Or WS_THICKFRAME Or _
WS_MINIMIZEBOX Or WS_MAXIMIZEBOX)
Public Const WS_POPUP = &H80000000
Public Const WS_POPUPWINDOW = (WS_POPUP Or WS_BORDER Or WS_SYSMENU)
Public Const WS_SIZEBOX = WS_THICKFRAME
Public Const WS_SYSMENU = &H80000
Public Const WS_TABSTOP = &H10000
Public Const WS_THICKFRAME = &H40000
Public Const WS_TILED = WS_OVERLAPPED
Public Const WS_TILEDWINDOW = WS_OVERLAPPEDWINDOW
Public Const WS_VISIBLE = &H10000000
Public Const WS_VSCROLL = &H200000