Introduction
Since this is my first article on The Code Project, I would like to apologize
for my bad English. It is based only on some "school english" and a few words
which I snapped during my leisure job as a Ski Instructor and a Rafting Guide
during my education.
I hope everyone can understand this article. Still if questions should exist,
I will gladly answer these. And if someone should find some errors, please send
me the correct version of the wrong text - thanks for the help when improving my
English knowledge spoke ;-).
So, let's start...
This small sample program shows, how simple it is to play a video or an audio
track with DirectShow and C#.
The program uses the following controls: MainMenu, ToolBar,
StatusBar, Panel, ImageList, and a Timer.
Many of the properties are set using the designer, so I would suggest that
you download the project, unless of course you are not a beginner.
On the other side, the sample program includes the DirectShow Interface to
play videos or audio tracks.
The program demonstrates the following
- How to select a media file on the disk, using the OpenFileDialog instance
class.
- How to enable or disable the buttons of the ToolBar Control.
- How to change the text in the StatusBar Control.
- How to use a basic Timer.
- How to use the Events of the Timer Control.
- How to use the Events of the MainMenu Control.
- How to use the Events of the ToolBar Control.
- How to use the Events of the Windows Form.
- How to play a media file with DirectShow.
- How to determine, if the media file were finished played.
- ...
The user interface
Beside the 3 buttons to play and stop a video or an audio track, there are
also a menu option to select the desired media file. So, before you can play the
desired media file you have to open this file with the "File -> Open..."
Command in the MainMenu Control. If the file was duly loaded, it can be played
now with the "Play" Button in the ToolBar Control. During playing the video or
the audio track, the application shows the current position and the duration of
the media file in the StatusBar Control. If the media file were finished played,
you can restart playing the media file with the "Play" Button. To select another
media file, you can use the "File -> Open..." Command of the MainMenu
Control.
With the "Info" Command of the MainMenu Control the Info-Dialog of the
application will be displayed.
The DirectShow Interface:
To play videos or audio files we use the DirectShow Component of the DirectX
Package. With the DirectShow Interface it is very simple to play a video or an
audio file, most of the work is doing the Interface for you. You only have to
setting up the Interface and calling the Interface methods with the correct
parameters.
Unfortunately .NET and C# is not an officially supported platform for DirectX
development and will not be until DirectX 9 is released at the end of the year.
However we can use DirectX with C# in the meantime by using the Visual Basic
type library's that come with version 7 and 8 of the API. This article
demonstrate how to use the DirectX VB Type Lib in C#.
Before we can begin a .NET DirectShow application we need to create a
reference to the DirectShow COM DLL. So, copy the
"Interop.QuartzTypeLib.dll" DLL into your project folder and add a
reference to this DLL. In Visual Studio.NET this is done by choosing Add
Reference from the project menu. As next choose the "Browse..." Button of the
Add reference Dialog and select the DirectShow COM DLL.
So, after the reference to the DirectShow COM DLL is created add the
following code line to your project, to make the DirectShow Interface Classes
visible.
using QuartzTypeLib;
The Code
How to select the media file and create the DirectShow Interface?
After the user pressed the "File -> Open..." Command of the MainMenu
Control, a "Open File" Dialog is shown and the user can select the desired media
file. In C# this is done by creating a instance of the
OpenFileDialog
class and call the ShowDialog()
function.
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Media Files|*.mpg;*.avi;*.wma;*.mov;" +
"*.wav;*.mp2;*.mp3|All Files|*.*";
if (DialogResult.OK == openFileDialog.ShowDialog())
{
.
.
.
After the user terminated the dialog with OK, we begin to create the
DirectShow Interface and to render the selected media file.
This is done in three steps:
- Create the filter graph manager (FGM)
- Create the filter graph (through FGM)
- Run the graph and respond to event
In the following code you see how to create the filter graph manager and the
filter graph:
CleanUp();
m_objFilterGraph = new FilgraphManager();
m_objFilterGraph.RenderFile(openFileDialog.FileName);
m_objBasicAudio = m_objFilterGraph as IBasicAudio;
try
{
m_objVideoWindow = m_objFilterGraph as IVideoWindow;
m_objVideoWindow.Owner = (int) panel1.Handle;
m_objVideoWindow.WindowStyle = WS_CHILD | WS_CLIPCHILDREN;
m_objVideoWindow.SetWindowPosition(panel1.ClientRectangle.Left,
panel1.ClientRectangle.Top,
panel1.ClientRectangle.Width,
panel1.ClientRectangle.Height);
}
catch (Exception ex)
{
m_objVideoWindow = null;
}
m_objMediaEvent = m_objFilterGraph as IMediaEvent;
m_objMediaEventEx = m_objFilterGraph as IMediaEventEx;
m_objMediaEventEx.SetNotifyWindow((int) this.Handle, WM_GRAPHNOTIFY, 0);
m_objMediaPosition = m_objFilterGraph as IMediaPosition;
m_objMediaControl = m_objFilterGraph as IMediaControl;
With the CleanUp()
method we try to delete the old interfaces,
if someone exists. Before we can start to render the file we have to create an
new instance of the FilterGraphManager with the new
method. The
RenderFile()
method builds a filter graph that renders the
specified file. The IBasicAudio
Interface is to set the volume and
the balance of the sound. With the IVideoWindow
Interface you can
set the window style, the owner window and the position of video window. This
functions are enclosed by a try
because, if you render a audio file
and you try to set the owner window the method throws an exception. So, to play
a audio track we don't need the IVideoWindow
Interface and we set
the m_objVideoWindow
member to null
. The
IMediaEvent
and the IMediaEventEx
Interface serves for
interception of message, which sends DirectShow to the parent window. With the
IMediaPosition
Interface the current position of the file can be
determined. To start and stop the video or the audio track we use the
IMediaControl
Interface.
For more information about the Interface read the DirectShow
documentation on MSDN.
How to play a media file?
To start a video or an audio track use the Run()
method of the
IMediaControl
Interface.
m_objMediaControl.Run();
How to break the media file?
If you want to break the playing video or audio track just use the
Pause()
method of the IMediaControl
Interface.
m_objMediaControl.Pause();
How to stop the media file?
To stop the video or the audio track use the Stop()
method of
the IMediaControl
Interface.
m_objMediaControl.Stop();
How to get the position and the duration of the media file?
While the media file is played, we indicate the current position and the
length of the file in the StatusBar Control. In addition we read all 100ms the
CurrentPosition
member of the IMediaPosition
Interface
over a timer and represent its value in the statusbar. To get the length of the
file we read the Duration
member of the IMediaPosition
Interface.
private void timer1_Tick(object sender, System.EventArgs e)
{
if (m_CurrentStatus == MediaStatus.Running)
{
UpdateStatusBar();
}
}
The timer function calls every 100ms the UpdateStatusBar()
method, who is displaying the current position and and the duration of the media
files in the panels of the statusbar.
private void UpdateStatusBar()
{
switch (m_CurrentStatus)
{
case MediaStatus.None : statusBarPanel1.Text = "Stopped"; break;
case MediaStatus.Paused : statusBarPanel1.Text = "Paused "; break;
case MediaStatus.Running: statusBarPanel1.Text = "Running"; break;
case MediaStatus.Stopped: statusBarPanel1.Text = "Stopped"; break;
}
if (m_objMediaPosition != null)
{
int s = (int) m_objMediaPosition.Duration;
int h = s / 3600;
int m = (s - (h * 3600)) / 60;
s = s - (h * 3600 + m * 60);
statusBarPanel2.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s);
s = (int) m_objMediaPosition.CurrentPosition;
h = s / 3600;
m = (s - (h * 3600)) / 60;
s = s - (h * 3600 + m * 60);
statusBarPanel3.Text = String.Format("{0:D2}:{1:D2}:{2:D2}", h, m, s);
}
else
{
statusBarPanel2.Text = "00:00:00";
statusBarPanel3.Text = "00:00:00";
}
}
When is the end of the file reached?
In order to determine, when the file was finished played, we overwrite the
WndProc
method, to intercept the EC_COMPLETE
message,
which sends DirectShow to the parent window, when the end of the file is
reached.
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_GRAPHNOTIFY)
{
int lEventCode;
int lParam1, lParam2;
while (true)
{
try
{
m_objMediaEventEx.GetEvent(out lEventCode,
out lParam1,
out lParam2,
0);
m_objMediaEventEx.FreeEventParams(lEventCode, lParam1, lParam2);
if (lEventCode == EC_COMPLETE)
{
m_objMediaControl.Stop();
m_objMediaPosition.CurrentPosition = 0;
m_CurrentStatus = MediaStatus.Stopped;
UpdateStatusBar();
UpdateToolBar();
}
}
catch (Exception)
{
break;
}
}
}
base.WndProc(ref m);
}
History
- 19.07.2002 - posted (first version)
- 26.07.2002 - some changes in design and code
Links
Bugs and comments
If you have any comments or find some bugs, I would love to hear about it and
make it better.