Mijn pagina voor prettig werken op de PC www.pcpret.nl |
Homepage | Stuur bericht | Gastenboek | Website Blog |
Software
The normal way to use DirectX and DirectShow functionality is to use the C++
oriented DirectX SDK with the corresponding header files and libraries.
The most interesting program to start with is Amcap.
There are some versions floating around.
When Using Delphi or C# (or just .Net) a special interface is needed to use
the DirectX functionality.
Knowledge about Windows programming and C++ will be an advantage.
I started with DSPack (see Prodigy) for Delphi.
A great package, only I did not have the DirectX knowledge yet.
The example I started with, did not provide TV tuner support and could not switch pins.
The next step was to get insight information on DirectX.
How? By looking around on the internet, getting the DirectX SDK, getting the Windows DDK.
The DDK is needed in some cases because some header files and libraries are missing that seems to
be needed for most of the SDK samples.
Than I came across The Code Project.
On this site a lot of general information, programming information and examples on DirectX
with C++, C# and Visual Basic can be found.
An interesting article for me was the
DirectX.Capture
project written by Brian Low (2003) that gives insight information on DirectShow.
Keep in mind that it is just an example.
The code seems to be okay, however problems may arise.
Sometimes it is just a programming error (mostly made by myself), sometimes it seems to be a mistery.
If you start digging around in de DirectX.Capture example, then it might be useful to look for
a slightly modified version of the
DirectX.Capture example.
The code has some additional functionality, also the code seems to be more stable.
The TV sound (captured via a PCI TV card) worked right away, with DShowNet, it did not work.
A nice extension is that the configuration can be saved.
It will save you a lot of clicking when testing and using the software.
And of course, I had already something written like that (not as nice and complete as that) ...
Directshow libraries
Originally the C# example DirectX.Capture came with DShowNet.
The use of DShowNet is free, no restrictions!
Thanks to .Net DShowNet can be used for any .Net language.
This library contains only the more general usable DirectShow interfaces.
These interfaces can be more or less be derived from the C header files in the DirectX SDK.
Additional information how to use it can quite often be found on MSDN or internet.
Sometimes a programming example gives more information.
However, quite often the information is very compact, incomplete or just missing.
Nowadays there is, for .Net (and C#), also DirectShowLib.
That library, Directshownet,
is subject to the LGPL license.
DirectShowLib seems to contain all DirectX 9 interfaces, most of them untested.
I used some of the untested interfaces, and partly, they worked okay.
I found out that the IAMWstDecoder interface needs a correction.
With respect to the IAMWstDecoder interface, the GetOutputFormat function does not work and I could not
figure out yet, what goes wrong.
The GetCurrentPage function works, only the declaration of the output parameter needs to be modified.
It needs a call to Marshalas.
I would expect that most of the interfaces that return data via an output parameter might fail,
those interfaces will probably need one or more modifications.
Practicing Directshow
Starting with a real DirectShow example is the easiest way to start.
The DirectX.Capture example mentioned before, is not an easy start that is a big challange.
Because I knew how to work with C++ and I am quite familiar with the C++ counterpart Amcap,
so there was a good chance to understand how to use DirectX, DirectShow and C# in the real world.
Furthermore I had many wishes, such as:
- Easy selection of broadcast stations on names
- Use the FM Radio on the Hauppauge PVR150-MCE TV-Card
- Mpeg video capturing with Hauppauge PVR150-MCE TV-Card
- Wav, MP3 audio capturing
- Use of the Microsoft remote control
- Teletext (WST)
- User VMR, VMR9
- Get acquinted with BDA
- Easy configuration and usable on various types of capture devices
When starting such project, it is important to have wishes so it becomes a game.
Get a wish completed and the game goes to a higher level ...
But the real work starts with the boring stuff: Compiling the DirectX.Capture project with Visual Studio.
Sometimes it just works (not for me).
Most of the time an library path must be set or Visual Studio setting must be changed.
Than you push the Debug-Start button to start the program.
There is a good chance the program works, than you have to figure how the program must be used.
After selecting the video device, the audio device and the preview I usually got a picture but
no audible sound ...
Also I noticed that the program was slow and the TV picture was moving slow too.
So the list of whisher becames a little longer: program must become more speedy and the video quality
should increase.
Soon I noticed that the program was very unstable, a lot of program errors occured and than
the program seems to become unusable.
Sometimes the program crashed, most of the time the error seems to be catched.
This is the way I discovered the nice and dangerous use of catching errors that are thrown
somewhere in the program.
Than the real work started, become acquinted with all kind of C# (.Net) features and object oriented
programming.
Maybe sometimes, there is a wish to go back to the old reliable C++ because reading this code is not
an easy job.
This program shows how object oriented programming can be used the right (and the wrong) way.
My impression the job can be done better so take your chance to improve it.
Keep in mind to take a look at the DirectX.Capture page on The
Code Project or the pages listed at the top of this webpage.
These pages shows questions from other developers and you can post also your own questions.
What I learned from DirectX.Capture and DirectX is that the description of most DirectX functions is bad or
incomplete.
Also most examples are in C++ so without knowledge of C++ it is difficult to translate to the C# way of
programming.
On the other hand, MSDN does explain a lot of subjects.
Sometimes difficult to find or to find back, so make notes!
Error handling is very important.
The DirectX.Capture shows how to handle that good and bad.
Than of course DirectX is also a little bit guilty.
When a RenderStream fails, it is unknown if possible allocated resources have been released properly.
Keep in mind that when an error occurs, than that will be the best moment to release possible allocated
resources that might have caused the error.
Or just release those allocated resources (and reallocate if needed) so the program comes back in a
usable state when a thrown is done.
The main disadvantage of this program is that that does not happen.
When a thrown occurs, the program does not know what to do.
Mostly a complete reset is needed (choose a new video or audio device) or the program just crashes.
If a thrown is done, than the release of previous allocated resources is not possible anymore because
the information needed is just gone.
At a certain moment I discovered that most errors occur when mediaControl.Run() was called in
the function StartPreviewIfNeeded().
From that moment on I used that function as reference as return point of a thrown for a graph build
that failed for whatever reason.
That was also the moment I noticed that the DirectX.Capture shows more stability.
Important is to put that function in a try - catch section and do the appropriate error handling if not done yet.
But keep in mind resources needs to be released as early as possible, so better before a thrown that after it.
Keep in mind to release possible added filters but still unconnected, eg a compression or a file writer filter.
These unused resources must be released too.
I got fatal errors when keeping the filters in the graph, especially when I went from avi->asf file saving when
changing the video render mode.
A question mark maybe on the compression filter, the DirectX.Capture authors status that a removal is not
needed, however, I got fatal errors when keeping it in (when changing the video render mode too).
The advantage of such filters in the graph as long as possible is that the settings are not lost.
A compression filter might be needed in the Avi leg of the graph.
If the property interface of all filters would be known, than a program could use that property interface
to change the settings itselfs.
Unfortunately most property interfaces, e.g. the Hauppauge Mpeg2 encoder, the Hauppauge file writer and the
DV Avi compressor can be accessed via GUI interface only.
Maybe there is a different way, but I did not find it (yet).
For the Asf file writer there seems to be a solution and my articles at
The Code Project shows a possible implementation.
For getting a better picture quality the use of a specific de-interlace filter might be a solution.
The major improvement I made to the DirectX.Capture program is the audio rendering part.
The original implementation supports wired TV-Card audio connections only.
This means that the audio capture device is usually the sound card in the computer.
It also means that audio is played "always".
Problems occur when a TV-card, such as the Hauppauge PVR150-MCE, that does support audio capturing via the PCI bus.
Than specific code needs to be added to render audio so audible sound is played.
More difficult it becomes when a TV-Card does not have its own audio capture device.
This is the case with the new december 2005 driver of the Hauppauge PVR150-MCE driver ...
Than more code changes are needed to get the audio device handled properly.
I added an option that enforce a check on the video device to find out if it supports audio.
If so than the result becomes the audio device filter.
Besides these programming challenges there is also things to repair.
Quite often the sound connection is lost, I discovered that this have quite often to do with the
video crossbar device.
An option is added to look an audio pin which is related to a video pin.
An effective solution is to release the audio and video sources and the property pages upon use.
Another interesting feature is the Video Standard.
Most software seems to be default to NTSC, but in my country the Pal video format is the common video format.
As result the video is displayed partly and distorted. Also the capture size of 720x576 can not be selected.
Thanks to a different project (
Change Video Signal Format with DirectX library),
there is an easy solution for changing the video format.
The video format affects the video frame size (for Pal usually 720x576, while for NTSC 720x480 is common).
But there is more, the country code should have also be set to the proper value.
The country code quite often affects the Video Standards that can be chosen and in some cases it also
affects the TV audio and the TV broadcast selection.
Graphedt, GraphStudio: Directshow graph tools
Very nice utility is Graphedt.exe (a Directshow graph tool in Microsoft's DirectX SDK).
With Graphedt it is possible to make a working design that could be tested in advance.
There is one disadvantage, it uses the filters that are on the computer, so specific configurations can
only be tested on dedicated computers.
>
Graphedt is ideal to find out which components or filters fits together and which pins can/must be used?
A very nice thing is that, when there are sufficient system resources, the design can also be tested!
The main disadvantage is probably that it does not provide real code.
The biggest advantage of using graphedt is to find out how filters needs to be handled.
So it is the first step to check whether RenderStream can do the job itselfs.
Or to find out if one or more filters needs to be added in advance, before RenderStream is called.
Or to find out that some filters needs to be added and/or connected separately.
So most of the time RenderStream tries to find suitable filters and will find them itselfs.
Sometimes RenderStream needs some help, than adding one filter is quite often enough, sometimes not.
In some cases the filter is already there and a findinterface is sufficient.
For using Graphedt the proppage.dll file (can be found together with grahpedt.exe in the DirectX SDK) needs to be registered. Registering goes via regsvr32.exe, a normal Windows tool: 'regsvr32 proppage.dll'. Unregistering proppage.dll can be done with regsvr32 also: 'regsvr32 proppage.dll /u'. The regsvr32 command can be excuted via a command line (cmd.exe). For Windows Vista and Windows 7 the cmd.exe needs to be started as administrator (e.g. by clicking on the filename with the right mouse button).
Another interesting Directshow graph tool is the opensource GPL tool GraphStudio. See Blog Monogram-GraphStudio for more information. This tool looks a little bit more user friendly then the graphedt tool.
Windows media format SDK
The use of the ASF (=Advanced Systems Format) file format means also that you have to become familiar with
the Windows media format SDK.
Mainly because it describes the interfaces that are needed to use the functionality in a more user friendly way.
Interfaces that will be used are: IWMProfile, IWMProfile2, IWMProfileManager, IWMProfileManager2,
IWMProfileManagerLanguage, IWMStreamConfig, IWMStreamList, IWMWriter, INSSBuffer,
IWMInputMediaProps, IWMMediaProps, IWMWriterAdvanced, IWMWriterAdvanced2,
IWMWriterSink, IServiceProvider.
The most important information to retrieve are the profiles that define the audio and/or the video format of an
ASF file.
The profiles can be selected via Guid, this method seems to be phased out.
Another way is to select on the name of the profile or loading a file containing the profile.
For the user it does not really matter how it is implemented.
What counts is the user friendlyness.
I would assume that selecting a format from a list will be very user friendly.
There are some things that might be interesting: instead of Asf (file extension) also the file
extensions wma (audio) and wmv (video and/or audio) can be used.
For audio it is important to select a format without any video.
For video it is important to select a format with video.
But there is more, if video is chosen and the format does not support audio, then also no audio might be
captured.
How to find out if an Asf or windows media format supports audio and/or video?
Well, that is possible by getting the IWMProfile information corresponding with the profile.
Then get the stream information (via IWMStreamConfig) which provides you the Guid of the stream type,
e.g. video, audio or something else.
The types video and audio should be taken into account, of course ...
IAMVfwCompressDialogs as coding example for making an interface
I came across the IAMVfwCompressDialogs interface when I was looking for a solution to get a possible
property page for a video compressor.
There are two methods to find a property page.
First, the ISpecifyPropertyPages interface can be used, e.g. 'DV Video Encoder'.
Second, the IAMVfwCompressDialogs interface can be used, e.g. 'Microsoft Video 1'.
The second interface seems to be used older filters.
Than I found a note somewhere in the code that the functionality in the IAMVfwCompressDialogs interface does
not seem to work properly, even in C++.
Well interesing, I like to dig and learn, so I tried to use it in C#.
To use an interface, the interface must be defined first.
Happily there are libraries who did the job for me.
// Calls ICGetState and gives you the result int GetState( [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] pState, ref int pcbState );
[PreserveSig] int GetState([In] IntPtr pState, [In, Out] ref int pcbState);
// vfwCompressDialogs points to the property page pointer. // IAMVfwCompressDialogs vfwCompressDialogs; byte[] data = null; int size = 0; // interface for GetState is: // int GetState([Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] byte[] pState, ref int pcbState); int hr = vfwCompressDialogs.GetState(null, ref size); if((hr == 0)&&(size > 0)) { data = new byte[size]; hr = vfwCompressDialogs.GetState(data, ref size); if(hr != 0) { data = null; } }When using the DirectShowLib version, coding becomes more complicated because unmanged data needs to be used and also data needs to be moved from unmanaged to managed data.
// vfwCompressDialogs points to the property page pointer. // IAMVfwCompressDialogs vfwCompressDialogs; // Get compress dialog data byte[] data = null; int size = 0; int hr = vfwCompressDialogs.GetState(IntPtr.Zero, ref size); if((hr == 0)&&(size > 0)) { data = new byte[size]; int sizeIntPtr = (size + 3)/ 4; // size in integer, rounded upwards using size in bytes IntPtr IntPtrData = Marshal.AllocCoTaskMem(sizeIntPtr); hr = vfwCompressDialogs.GetState(IntPtrData, ref size); if(hr >= 0) { Marshal.Copy(IntPtrData, data, 0, sizeIntPtr); } Marshal.FreeCoTaskMem(IntPtrData); if(hr != 0) { data = null; } }The DShowNET coding version is easy to understand and is also following the ASAP principle: As Simple As Possible. The DirectShowLib coding version is more complicated and there is more chance that unmanaged code is treated incorrectly. It is quite common to forget releasing of allocated memory. In this scenario it is clear and safe to release the allocated memory. The use of Marshal.ReleaseComObject() has usually more unexpected side-effects ...
Back to the beginning? Click here.