Building a DirectShow Code Sample in Visual Studio .NET
Recently, I had to write some Windows multimedia code--the idea was to build an extension to a media player with a bit of custom image processing. Not knowing a thing about multimedia under Windows, I had to spend a few hours reading about media APIs (DirectX, VideoLan, etc).
In the end, I decided that the path of least resistance was to employ DirectShow, which is a part of DirectX (at least, it used to be). DirectShow is a framework and API for handling media files, like audio and video; it has a nifty Pipes And Filters architecture. My plan-of-attack: I would find an existing application of the CTransformFilter baseclass, gut it, so to speak, and add my own image processing. How hard could it be?
A bit harder than it ought to be, as it turns out. Merely figuring out what software to download from the Microsoft site was a bit of a challenge, and once I had the relevant software development kit (or, actually, kits), it was still a slog to get the code in a useful state.
This article discusses the steps I took to download DirectShow, build a code sample (ezrgb24), then convert ezrgb24 to a Visual Studio .NET project.
Contents
Install SDKs
First, you'll need to download and install two Microsoft SDKs:
- the Windows Platform SDK (Windows® Server 2003 R2 Platform SDK ISO Download)
- this is a general, Windows platform development kit. I think you can ignore the "Windows Server" nomenclature--this package applies to XP, and probably all post-NT flavors)
- the DirectX SDK
- a development kit for multimedia applications
Recently, Microsoft decided to move their DirectShow code from the DirectX SDK into the Windows Platform SDK. This alone was confusing, but then it took a bit of sleuthing to determine that you actually need both the Windows Platform SDK and the DirectX to build the DirectShow library. sigh.
These are both hefty downloads, by the way. Don't dawdle.
Build DirectShow
Before using the DirectShow library, you must first build it. Currently, the source code is located in c:\platformsdk\Samples\Multimedia\DirectShow\BaseClasses (assuming you installed the Platform SDK under c:\platformsdk). We're going to build strmbasd.dll, the debug version of DirectShow.
define an environment variable, DXSDK_DIR, which points to the top level of the DirectX SDK installation. The DirectShow makefile needs this environment variable to resolve DirectX references.
I installed the DirectX SDK directly under c:\, so I set DXSDK_DIR=c:\dxsdk
using emacs, which is your favorite editor, open c:\platformsdk\Samples\Multimedia\DirectShow\BaseClasses\makefile.
At the top of the file, define the symbol APPVER. The value of APPVER determines a number of other definitions in win32.mak. If you installed the SDKs, there are multiple versions of win32.mak hanging around on your PC (with conflicting definitions for APPVER). The critical file is the Visual Studio .NET win32.mak: C:\Program Files\Microsoft Visual Studio .NET 2003\Vc7\PlatformSDK\Include.
for Windows XP, set APPVER to 5.2 by adding this line: APPVER = 5.2
- Start the Visual Studio .NET Command prompt.
Build the DirectShow debug library:
> cd c:\platformsdk\Samples\Multimedia\DirectShow\BaseClasses\ > nmake clean > nmake
The library, strmbasd.lib, is built in subdirectory .\xp32_debug (for APPVER=5.2).
Build the ezrgb32 Sample
Next, we'll build the DirectShow example ezrgb32. For mysterious reasons, Microsoft chose not to distribute Visual Studio solutions for building the examples, only nmake makefiles (it sounds like the examples once came with Visual Studio projects, but no longer). The makefiles are fine for building the examples, but there are obvious advantages to using the Visual Studio IDE--namely, the debugger works properly.
Build from Makefile
The first step is to build ezrgb32 from the makefile. The source code is located in c:/platformsdk/Samples/Multimedia/DirectShow/Filters/EZRGB24.
open c:/platformsdk/Samples/Multimedia/DirectShow/Filters/EZRGB24/Makefile
At the top of the makefile, define MSSDK to point to the Platform SDK directory. In my case, I add the line MSSDK=c:\platformsdk.
At the top of the makefile, define APPVER to indicate your OS, as in the previous step. For Windows XP, use APPVER=5.2
- From the Visual Studio .NET Command Prompt, run nmake:
> nmake clean > nmake
If it works, the ezrgb32 filter will be built in .\XP32_DEBUG as ezrgb24.ax.
You can register the ezrgb24.ax filter (using regsvr32) and try out the filter with GraphEdit.
Migrate to a Visual Studio Project
Finally, let's create a Visual Studio project which accomplishes the same thing as the makefile.
Copy the ezrgb24 directory to a new directory, e.g. c:\ezrgb24_vs
- This step avoids some file naming problems later; for example, Visual Studio will generate .cpp, .h, and .def files, and the new files will clobber any existing files
Define some handy environment variables for the compiler & linker:
Define STRMBASE_INCL to point to the directory containing DirectShow header files
Define STRMBASE to point to the location of the DirectShow library you just built
STRMBASE_INCL=c:\platformsdk\samples\multimedia\directshow\baseclasses STRMBASE=STRMBASE_INCL=c:\platformsdk\samples\multimedia\directshow\baseclasses\xp32_debug
- Start Visual Studio.
Select File->New->Project
Under Visual C++ Projects/MFC, select the MFC DLL template.
Specify the name & location of your new solution: c:\ezrgb24_vs
- In the Solution Explorer pane, delete all of the default stuff which comes with the solution:
- ezrgb24_vs.cpp, ezrgb24_vs.def, stdafx.cpp, ezrgb24_vs.h, stdafx.h, resource.h, ezrgb24_vs.rc, ezrgb24_vs.rc2
- Add the existing files
- ezprop.*
- ezrgb24.*
- iez.h
- ezprop.rc
- ezrgb.def (not strictly necessary, but nice to have around)
Under Project->Properties, set the compiler options (under C/C++)
Additional Include Directories: $(STRMBASE_INCL); $(DXSDK_DIR)\include; Preprocessor Definitions: WIN32;_WINDOWS;_DEBUG;_USRDLL Runtime Library: Multi-threaded Debug DLL (/MDd) Treat wchar_t as Built-in Type: No Create/Use Precompiled Header: Not Using Precompiled Headers Calling Convention: __stdcall (/Gz)
- Set Linker options:
OutputFile: $(OutDir)/ezrgb24_vs.ax Additional Library Directories: $(STRMBASE);
- Additional Dependencies:
strmbasd.lib msvcrtd.lib atlsd.lib quartz.lib vfw32.lib winmm.lib kernel32.lib ws2_32.lib mswsock.lib advapi32.lib version.lib user32.lib gdi32.lib comctl32.lib ole32.lib olepro32.lib oleaut32.lib uuid.lib
Ignore All Default Libraries: Yes (/NODEFAULTLIB) Module Definition File: .\ezrgb24.def Import Library: $(OutDir)/ezrgb24.lib
- Set Resource build options:
Additional Include Directories: $(IntDir); $(STRMBASE_INCL)
At this point, you should be able to build the filter directly from Visual Studio (Build->Rebuild Solution). The output file will be debug\ezrgb24_vs.ax.
At this point, you can throw that Makefile away.
Bonus Tip: Register as Part of the Build
You can make Visual Studio register the filter with regsvr32 as part of the build process:
Project->Properties->Custom Build Step
Command Line:c:\windows\system32\regsvr32.exe $(OutDir)\ezrgb24_vs.ax Description:register filter w/ regsvr32 Outputs:faketarget.dat Additional Dependencies:$(OutDir)\ezrgb24_vs.ax
Bonus Tip: Debugging
Debugging: Since we've gone to all this effort to set up a Visual Studio project, we may as well set up the debugger. The ezrgb24 filter runs as part of a DirectShow application, so we'll use GraphEdit to run the filter.
Using GraphEdit, create and save a render graph using ezrgb24_vs.ax. Call it render.grf. If you don't know how to use GraphEdit, go spend some time with google and come back when you're ready.
- In Visual Studio, set the debugger properties:
Project -> Properties
- In the left pane, click Debugging
Command: graphedt.exe (replace with appropriate path to your graphedt.exe) Command Arguments: render.grf
At this point, you should be able to set a breakpoint in your filter code then select Debug->Start. GraphEdit should execute with your predefined graph. Start rendering. When the code hits your breakpoint, you'll magically drop into the debugger.
