Filters and the TBaseFilterIn the last part, we skipped over a few lines so we should try to understand them a bit more fully before we progress any further. The first line we "'took for granted" is:
All Filters have a TBaseFilter interface which can expose the underlying device connected to it. When we created our System Device Enumerator in the Form's FormCreate Event, we created a structure containing, amongst other things, pointers to the device drivers themselves, called Monikers. These pointers can subsequently be accessed by simply referring to their index in the structure - the first index being 0. (Another member of the structure is CountFilters which we used in the for i:= 0 to SysDev.CountFilters - 1 do loop to populate the ListBox).
As the ItemIndex of each item in the ListBox 'reflects' the same structure, we can retrieve any of these Moniker pointers by using the GetMoniker(index: Integer) method of the System Device Enumerator and set the Filter's BaseFilter.Moniker property to the same pointer.
Although it would be a rather "inflexible" thing to do, we could actually set the Filter's BaseFilter 'manually' at design time and the line of code shown above could be omitted altogether. We would then, of course, be 'stuck' with the input device we'd hard-coded in and I'm really just using it as a demonstration of what the Filter's BaseFilter.Moniker property actually is and how it relates to the ListBox1's ItemIndex. Click on the ellipsis (the three dots...) alongside the TBaseFilter property to open the Base Filter Editor.
ICaptureGraphBuilder2.RenderStreamLet's take a look at the other lines of code we skipped over:
with FilterGraph1 as ICaptureGraphBuilder2 do begin RenderStream(@PIN_CATEGORY_PREVIEW, nil, Filter1 as IBaseFilter, nil, VideoWindow1 as IBaseFilter); end;
You may recall, from our earlier project, we used FilterGraph1.RenderFile(FileName: WideString) so why do we now cast FilterGraph1 as ICaptureGraphBuilder2 ?
By default, the FilterGraph only exposes the interfaces (methods) of the IGraphBuilder Object which, unfortunately, is unable to build a graph for live streaming video. The ICaptureGraphBuilder2 is a more powerful interface, with additional methods, so,by casting FilterGraph1 as ICaptureGraphBuilder2, we are able to take advantage of the extra methods - in particular its ability to use Intelligent Connect and RenderStream with a live video stream.
(As noted on the previous page, Delphi 5 is not able to use the as operator in this way, so a pointer to the FilterGraph1 ICapturGraphBuilder2 interface has to be obtained by using the FilterGraph1.QueryInterface method. If you skipped the basic introduction to COM, you may want to look at it now.)
OK, let's have a look at RenderStream. You can find the C++ documentation at the msdn website and, below, the Delphi equivalent. I've typed an 'extra' RenderStream in the picture below in order to invoke Delphi's code insight so we can look at the parameters:
RenderStream takes 5 arguments:
There is a lot more information at the msdn website so I'd recommend taking a look and doing the mental translations to Delphi where required.
Briefly, we could describe it as:
RenderStream(which-output-pin, media-type, source-filter, intermediate-filter, renderer-filter)
Here, in our project, we are specifying the Source Filter and the Renderer Filter and letting RenderStream's Intelligent Connect fill in any intermediate filters. If we take another look at the Filter Graph using GraphEdit, we see that RenderStream has, indeed, inserted an additional filter - in fact, it's inserted two: The Smart Tee and the Color Space Converter.
You'll notice that the output from the Smart Tee Filter is taken from its 'Preview' pin. That's because we specified PIN_CATEGORY_PREVIEW as the first argument in RenderStream. If we had specified PIN_CATEGORY_CAPTURE, the ouput from the Smart Tee would have been taken from its 'CAPTURE' pin instead.
In most applications, we would probably want to use both output pins from the Smart Tee so, what's the difference? Basically, there is very little. The video stream is split into two and presented at both outputs. The only real difference is that the PREVIEW pin will drop frames of video if the computer starts to run out of CPU resources whereas the CAPTURE pin will do its utmost not to do so.
The PREVIEW pin is normally used as we've used it here - to provide a display for the monitor. Output from the CAPTURE pin is used in more critical situations where, for example, the source is being captured to a file. Missed frames on the monitor would hardly be noticed but should ideally be avoided in the "hard copy".
Now that I've mentioned writing the video to a file, we'll have a look at that in the next part.