Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help regarding writing a Source Filter

239 views
Skip to first unread message

DevX

unread,
Feb 16, 2006, 5:32:26 AM2/16/06
to
Hi to all,

First I am a newbie on DirectShow programming, so sorry if I ask or tell
stupid things :)

Well, I must write a Source Filter that produce out a video stream of YUV
YV12 frames. I took the bouncing ball sample, modified It to read (for a
test) from a binary file (dump of yuv-buffer) and now in graph edit I have a
souce filters that works with VMR-7.

But all of this if for test and Hard-Coded. what I need now is:

1) To attach this DirectShow filter to a source of data (e.g. the YUV frames
already decoded...). This source of data is provided by some .NET components
that retrieve and decode mpeg4 data from the network or from disk. I need to
produce a link between my direct show filter (that implements the FillBuffer
methods) and the source of those yuv buffers.

2) When I create a app (I think it will be a C++ Win32 DLL called by the
main .NET app) that builds the graph, how I specifiy a destination window
for the VMR-7 (I need the video in an area of a .NET form).

3) how can I expose some custom methods/property of my Filter that the
client (e.g. the component who will build and start the filter graph) can
call to set the link I described in question (1)?

The structure I have in mind is this (please correct me or suggest a better
one - but I have the constraint of the .NET app producing the frames and
hosting the video window):

a) The main application (in .NET) has a ready source of YUV buffer that need
to be pushed to a renderer
b) Via a Win32 DLL that builds the graph the main app create a child windows
to use in the main form for playing the video (I know via Win32 API how to
"capture" an hwnd and put the window inside another window, but I don't know
if this trick is ok with directshow)
c) Via the Win32 DLL that builds the graph, the .NET main app obtain an
"access point" in which can push the frame (or furnish a callback so the
filter can pull the frames)

Someone can help me clarifying my ideas to build this solution. Many thanks
in advance!!

Dev

Iain

unread,
Feb 16, 2006, 6:16:56 AM2/16/06
to
On Thu, 16 Feb 2006 11:32:26 +0100, DevX wrote:

> Hi to all,
>
> First I am a newbie on DirectShow programming, so sorry if I ask or tell
> stupid things :)
>
> Well, I must write a Source Filter that produce out a video stream of YUV
> YV12 frames. I took the bouncing ball sample, modified It to read (for a
> test) from a binary file (dump of yuv-buffer) and now in graph edit I have a
> souce filters that works with VMR-7.
>
> But all of this if for test and Hard-Coded. what I need now is:
>
> 1) To attach this DirectShow filter to a source of data (e.g. the YUV frames
> already decoded...). This source of data is provided by some .NET components
> that retrieve and decode mpeg4 data from the network or from disk. I need to
> produce a link between my direct show filter (that implements the FillBuffer
> methods) and the source of those yuv buffers.

THere's lots of ways of doing it, but it is really a general programming
question rather than a DS specific question, but here are some things to
think about.

Your life will be a good deal easier (with your current architecture) if
you PULL the YUV frames from the dot net application. That is in
FillBuffer you call the dotnet decoding code to get the next frame. The
alternate which is that you push the data in to the source filter means
that you have to do buffering and thread management inside the filter. So
you can expose a com interface on the dot net part and call that, you can
raise an event when you need more data, or you can use (for example) a
named pipe between the dot net and hte source filter - pushing data in from
the dotnet bit and pulling it out (with a timeout) from the C++ side. I'd
probably try the latter.

You should consider using COutputQueue on your output pin to provide some
buffering.


>
> 2) When I create a app (I think it will be a C++ Win32 DLL called by the
> main .NET app) that builds the graph, how I specifiy a destination window
> for the VMR-7 (I need the video in an area of a .NET form).

pass in the window handle (IntPtr) to a custom method on the dll and set
IVideoWindows::put_Owner with it. You need to do a bit of casting here.

(See IVideoWindow for general control of the location of the output - there
is also a Windowless option which is supposed to be better, but I've not
used it a great deal - same principle).

>
> 3) how can I expose some custom methods/property of my Filter that the
> client (e.g. the component who will build and start the filter graph) can
> call to set the link I described in question (1)?

Well, obviously you can expose com interfaces on your dll fairly easily.
custom interfaces on the source filter are a tad more awkward as DS COM is
implemented in it's own way. But it's dead easy once you see an example -
Gargle provide an illustration of custom interfaces on filters.


>
> The structure I have in mind is this (please correct me or suggest a better
> one - but I have the constraint of the .NET app producing the frames and
> hosting the video window):
>
> a) The main application (in .NET) has a ready source of YUV buffer that need
> to be pushed to a renderer
> b) Via a Win32 DLL that builds the graph the main app create a child windows
> to use in the main form for playing the video (I know via Win32 API how to
> "capture" an hwnd and put the window inside another window, but I don't know
> if this trick is ok with directshow)

IVideoWindow


> c) Via the Win32 DLL that builds the graph, the .NET main app obtain an
> "access point" in which can push the frame (or furnish a callback so the
> filter can pull the frames)

Perfect. I'd use name pipes like as not though there are 1000 other ways
of doing it. YOu may need to share the name if there are going to be
several instances of your app running - otherwise hard code it.


>
> Someone can help me clarifying my ideas to build this solution. Many thanks
> in advance!!
>
> Dev

Iain
--
Iain Downs (DirectShow MVP)
Commercial Software Therapist
www.idcl.co.uk

DevX

unread,
Feb 16, 2006, 8:16:04 AM2/16/06
to
Thanks, Iain

I agree to your suggestion of a pull model from the Filter. But only some
more questions (sorry again, I'm very newbie on DirectShow and low-level COM
Programming):

You say that FillBuffer() must call the dotnet code that does the decoding,
Ok. But how I say to the CSourceStream-derived class where/what to call?
If I have a pointer to function in .NET, that I can easily create and pass
to the my wrapper [between dotNET and the source filter DLL], how can I
share this value to the current instance (e.g. the one that is part of the
filter graph) of my CSourceStream-derived class?
----> my real problem is a confusion about where/when/how the
CSourceStream-derived class is created when building the filter graph.
<-----

Later, in your reply, you suggest using named pipe. If I understand
correctly, in this manner you suggest a completely separated mode of
operation between the dotNET code (that write on the pipe unaware of the
client) and the filter (that can read from the pipe, unaware of the
writer)...this approach can be Ok for me and much more easier to implement,
but a more coupled approach (like the one I tried to describe with the
questions above) is possible?

Thanks a lot and again sorry for newbie questions!

Dev

"Iain" <Ia...@idclTAKEAWAY.co.uk> wrote in message
news:hff51i6oxex2$.1ckugwxjsc2gr$.dlg@40tude.net...

Iain

unread,
Feb 16, 2006, 9:02:09 AM2/16/06
to
On Thu, 16 Feb 2006 14:16:04 +0100, DevX wrote:

> Thanks, Iain
>
> I agree to your suggestion of a pull model from the Filter. But only some
> more questions (sorry again, I'm very newbie on DirectShow and low-level COM
> Programming):

Prepare for some sleepless nights!


>
> You say that FillBuffer() must call the dotnet code that does the decoding,
> Ok. But how I say to the CSourceStream-derived class where/what to call?
> If I have a pointer to function in .NET, that I can easily create and pass
> to the my wrapper [between dotNET and the source filter DLL], how can I
> share this value to the current instance (e.g. the one that is part of the
> filter graph) of my CSourceStream-derived class?
> ----> my real problem is a confusion about where/when/how the
> CSourceStream-derived class is created when building the filter graph.
> <-----

the easiest way is to create a custom interface on the source filter. An
example of how to do this is in the Gargle sample. Then, having created
and added the filter you simply call QueryInterface with your interface ID
and you have it and can call your custom method on it [passing in the
addres sof the dot net wrapper for your decoder] (in passing DO use Smart
pointers like CComPtr and CComQIPtr in your code - it will make life so
much easier).

eg

// Custom interface

typedef (HRESULT DecodeNext)(long size, BYTE *Buffer)

SetDecodeFunction(DecodeNext *ptr)

// implement

DecodeNext pDecoder;
HRESULT SetDecodeFunction(DecodeNext *Ptr)
{
pDecoder = Ptr;
}
and in FillBuffer

return pDecoder(SampleSize, SampleBuffer);

//
The function deferencing stuff is likely wrong in detail as I haven't done
any for ages. But the idea is you pas a pointer to a funtion into the
method that represents the dotnet decoder and the simply call it with
thesample buffer info in FillBuffer. Should work OK barring the details.


>
> Later, in your reply, you suggest using named pipe. If I understand
> correctly, in this manner you suggest a completely separated mode of
> operation between the dotNET code (that write on the pipe unaware of the
> client) and the filter (that can read from the pipe, unaware of the
> writer)...this approach can be Ok for me and much more easier to implement,
> but a more coupled approach (like the one I tried to describe with the
> questions above) is possible?

Yes the more closely coupled method is possible. I've not written any C++
code that calls back into dotnet so it may be less simple than I think.

I'd be tempted to write a a named pipes implementation (which will take 20
mins) and worry about optimisations later - but I'm lazy!


>
> Thanks a lot and again sorry for newbie questions!
>

Your welcome - they are well thought out informed questions. A pleasure!

Alessandro Angeli [MVP::DS/MF]

unread,
Feb 16, 2006, 2:34:15 PM2/16/06
to
DevX wrote:

> I agree to your suggestion of a pull model from the
> Filter. But only some more questions (sorry again, I'm
> very newbie on DirectShow and low-level COM Programming):

Instead I disagree. A push model would be easier to
implement. See below.

> my real problem is a confusion about where/when/how the
> CSourceStream-derived class is created when building the
> filter graph.

Your source filter can be created in 2 ways and it's up to
you to decide:

1. you create it anyway you like and add it to the graph
yourself; this way you have a reference to the object and
you can do whatever you need with it

2. the filter graph adds it when it tries to render a custom
URL; this way you need to package the filter in its own COM
inproc server DLL, globally register it, register your
custom protocol and last you will need to enumerate the
filters in the graph to get a reference to it

If your filter is only used internally in your application,
#1 is a lot easier.

> Later, in your reply, you suggest using named pipe. If I
> understand correctly, in this manner you suggest a
> completely separated mode of operation between the dotNET
> code (that write on the pipe unaware of the client) and
> the filter (that can read from the pipe, unaware of the
> writer)...this approach can be Ok for me and much more
> easier to implement,

An alternative would be using UDP sockets: they are
message-based instead of stream-based, so that they would
preserve the sample boundaries without you implementing your
own framing, and as efficient (since they would be routed
over the virtual loopback device), but you would need to
implement your own inter-process security, if local security
is a concern (local meaning on the same machine, since total
security from the outside world would be provided the socket
itself).

> but a more coupled approach (like
> the one I tried to describe with the questions above) is
> possible?

Yes. You can do it in any number of ways depending on your
needs and how complex you want it to be, but this is the
easiest:

1. derive your filter class from CBaseFilter and your output
pin class from CBaseOutputPin

2. in your filter class, override GetPin() and GetPinCount()

3. in your output pin class override GetMediaType(),
CheckMediaType() and DecideBufferSize()

4. add a custom interface to your filter class that has a
single method you call to synchronously feed a data block to
the graph; this method calls GetDeliveryBuffer() on the
output pin, copies the data block to the sample and calls
Deliver() on the output pin

5. you may want to add a couple more methods to the custom
interface to set the number of output pins and their media
types

From the application point of view, pushing data through the
graph will be as simple as calling a normal synchronous
function in VideoForWindows style and the code required to
create filter and pins is less the 3 screenfuls in C++.

This works well unless you need asynchronous processing or
you need to connect to a parser/splitter, which will expect
an async reader upstream instead of a push source (but this
would be easy enough to accomplish as well).


--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// a dot angeli at psynet dot net


Iain

unread,
Feb 16, 2006, 5:22:27 PM2/16/06
to
On Thu, 16 Feb 2006 20:34:15 +0100, Alessandro Angeli [MVP::DS/MF] wrote:

Alessandro, I think you missed some details here.

Firstly the poster has a source filter working fine.

Secondly the ultimate source of his data (YUV frames of known size) is a
dot net application.

He is seeking the simplest wat to join the two (not being a big DS and COM
expert).

So IMHO the easiest way for him to proceed is to 'pull' decoded frames from
the source application from within the FillBuffer of the (currently working
source filter).

The question is how to do that.

My two proposals are

1. The simples way is to use a named pipe. Grabbing known amounts of
source data (a frame buffer at a time) with a wait until there is enough
there. Pushing decoded frames in from the dot net application. no
complicated IPC, no C++/.net transition. dead easy. I agree that UDP and
various other IPC are feasible and would have benefits.

2. Providing some callback function that allows the FillBuffer to call back
into the .net app. A bit shaky on the mechanics of this, but I know its
doable. Potentially more performant, but harder.

Alessandro Angeli [MVP::DS/MF]

unread,
Feb 16, 2006, 7:04:19 PM2/16/06
to
Iain wrote:

> Alessandro, I think you missed some details here.
>
> Firstly the poster has a source filter working fine.

You are right. But, in my defense, he opened with "I must
write a Source Filter" so I missed that he already had in
fact modified a sample :-)

> Secondly the ultimate source of his data (YUV frames of
> known size) is a dot net application.

This I didn't miss :-) What I described works with .NET as
long as the source filter is written in C++, which is also
the case with his current one.

> He is seeking the simplest wat to join the two (not being
> a big DS and COM expert).
>
> So IMHO the easiest way for him to proceed is to 'pull'
> decoded frames from the source application from within
> the FillBuffer of the (currently working source filter).

If he wants to keep his current source filter, yes. But from
what he said it's just a modified Ball sample. So, throwing
it away and rewriting a source filter the way I described I
think is going to be a lot easier than adapting Ball with an
IPC based pull system between managed and unmanaged code. It
will also be more efficient, without IPC and synchronization
resources or the push thread in the source filter. If he
plays his cards well, he might even avoid the marshalled
buffer copy (I'm not 100% sure of this).

> The question is how to do that.
>
> My two proposals are
>
> 1. The simples way is to use a named pipe. Grabbing
> known amounts of source data (a frame buffer at a time)
> with a wait until there is enough there. Pushing decoded
> frames in from the dot net application. no complicated
> IPC, no C++/.net transition. dead easy. I agree that
> UDP and various other IPC are feasible and would have
> benefits.

Once decided to go this way, one IPC or the other is the
same to me :-)

Named pipes are easier to set up and security is handled by
the system, but they require a bit more work with chunked
data and I am not sure you can use them from .NET without
P/Invoke (if you can, don't make me discover it by myself
:-)).

UDP sockets are easier to use in .NET and almost as easy to
use in C++ and they keep the frame boundaries.

The best IPC would of course be shared memory, but nodody
wants to go that way, especially in .NET, would he? :-)

> 2. Providing some callback function that allows the
> FillBuffer to call back into the .net app. A bit shaky
> on the mechanics of this, but I know its doable.
> Potentially more performant, but harder.

It's actually very easy using a managed callback:

http://msdn.microsoft.com/library/en-us/cpguide/html/cpconusingcallbackfunctions.asp

It's also easy, but not as easy as callbacks, to do it using
COM event sinks:

http://msdn.microsoft.com/library/en-us/cpguide/html/cpconhandlingeventsraisedbycomsource.asp

lgs.lgs

unread,
Feb 16, 2006, 7:46:43 PM2/16/06
to
I already have a rough sample that may do what you need.

Take a look at http://www.LimeGreenSocks.com/DShow/DvdTest2.zip.

Also, have you taken a look at http://DirectShowNet.SourceForge.net? It may
not be necessary to have a separate c++ dll to build your graph for you.


DevX

unread,
Feb 17, 2006, 3:42:31 AM2/17/06
to
Thanks Iain and Alessandro for yours precious help.

Sorry Alessandro if I do not specify correctly that I have already a
prototype Source Filter, English is not my first language (first is Italian
...and from your name something made me think is also your)

This prototype source filter is the stripped down Ball sample, that open
some files (a raw dump of a YUV buffer) and "spit" out the stream, that is
then rendered...I used this because, as a completely newbie in DShow, I
thinked that it was the best approach, but I'm open to more interesting
solution. The production version, off course, will obtain in another manner
those YUV buffer.

Supposing I want to preserve the modified Ball, that is built as a separate
inproc DLL Server, I must say that this filter will be prevalently used
internally in my main dotNet app, so in your first post you say to me:

>1. you create it anyway you like and add it to the graph
>yourself; this way you have a reference to the object and
>you can do whatever you need with it

what means? I anticipated to have the filter in the DLL, then a normal Win32
DLL (because I need C++ code) will manually builds the graph , adding only
the source and the renderer. In this manner I will get a pointer to the
interface of the source filter. As Iain said, I checked the Gargle sample
and saw how to implement custom interface to manipulate members on my
CSourceStream-derived class.
So, what you wrote on #1 above, is what I have intention to do or I missed
something? (I have only the intention and the idea...how to implement really
this will need some study and some other questions I will post)

Regarding the means on how communicate between filter/.net:
I must say I have already experience in .NET/native interop and I have
already implemented Win32 DLL that callbacks code in the .NET side, but all
my experience is on "concrete" and basic code and classes...entering in the
realm of DShow and low-level COM something confuse me with all of those
automatism and complicate (for me) plumbing...but once (with your help) I
can give my filter a pointer to a delegate on .NET, I think I will be fine
(...hoping to not encounter some exotic marshaling problems :( ).

Thanks guys, I stay tuned to read your replies, and probably I will post
more questions as I delve on this DShow world. You are very helpful and kind
to me.

Dev

"Alessandro Angeli [MVP::DS/MF]" <nob...@nowhere.in.the.net> wrote in
message news:#NHT3X1M...@TK2MSFTNGP15.phx.gbl...

DevX

unread,
Feb 17, 2006, 3:47:17 AM2/17/06
to
Hi lgs,

I have problems contacting the site...I will try later this morning or
afternoon.
I know that is possible to use DShow in .NET but I've read somewhere (don't
remin where, but an official source) that is not advised to do so.
Obviously I can always make some test about it.

Thanks


"lgs.lgs" <limegre...@yahoo.com> wrote in message
news:OrPihu1M...@TK2MSFTNGP15.phx.gbl...

Iain

unread,
Feb 17, 2006, 4:31:41 AM2/17/06
to
On Fri, 17 Feb 2006 09:42:31 +0100, DevX wrote:

> Thanks Iain and Alessandro for yours precious help.
>
> Sorry Alessandro if I do not specify correctly that I have already a
> prototype Source Filter, English is not my first language (first is Italian
> ...and from your name something made me think is also your)

Ah - yes, but your ENglish (both of you!) is so much better than my
italian!


>
> This prototype source filter is the stripped down Ball sample, that open
> some files (a raw dump of a YUV buffer) and "spit" out the stream, that is
> then rendered...I used this because, as a completely newbie in DShow, I
> thinked that it was the best approach, but I'm open to more interesting
> solution. The production version, off course, will obtain in another manner
> those YUV buffer.

Both solutions will work fine. Alessandro's will let you push data in from
the .net application through a custom com interface or similar. It's
probably a better solution in many respects. I tend to try and provide
solutions that minimise learning curve rather than which work best.


>
> Supposing I want to preserve the modified Ball, that is built as a separate
> inproc DLL Server, I must say that this filter will be prevalently used
> internally in my main dotNet app, so in your first post you say to me:

> what means? I anticipated to have the filter in the DLL, then a normal Win32


> DLL (because I need C++ code) will manually builds the graph , adding only
> the source and the renderer. In this manner I will get a pointer to the
> interface of the source filter. As Iain said, I checked the Gargle sample
> and saw how to implement custom interface to manipulate members on my
> CSourceStream-derived class.
> So, what you wrote on #1 above, is what I have intention to do or I missed
> something? (I have only the intention and the idea...how to implement really
> this will need some study and some other questions I will post)

There is no need to go through the registration and CoCreateInstance and
COM stuff if a filter will only be used in your application.

you can simply call new on the filter and use it as if it were CoCreated,
e.g.

CComPtr<IBaseFilter> mSwitcherFilter;

mSwitcherFilter = new SwitcherFilter(NAME("Switcher"), NULL, &hr);
if (FAILED(hr))
return hr;
if (FAILED(hr = m_pReadingGraph->AddFilter(mSwitcherFilter, L"Switcher")))
return hr;

YOu can also cast the CComPtr to the bas class of your filter (In this
particular piece of code I was using a differnt smart pointer
implementation so I'm not 100% sure that this modified cast will work - but
you get the idea)

SwitcherFilter *pFilt = (SwitcherFilter*)
mSwitcherFilter;

(and you can get rid of the gubbins which registers it if you wish)


>
> Regarding the means on how communicate between filter/.net:
> I must say I have already experience in .NET/native interop and I have
> already implemented Win32 DLL that callbacks code in the .NET side, but all
> my experience is on "concrete" and basic code and classes...entering in the
> realm of DShow and low-level COM something confuse me with all of those
> automatism and complicate (for me) plumbing...but once (with your help) I
> can give my filter a pointer to a delegate on .NET, I think I will be fine
> (...hoping to not encounter some exotic marshaling problems :( ).

SOunds like you know more than me on this (and Alessandro certainly does!)

Don't forget, of course, that you can create a standard com interface on
your dll (which is simple) and then delegate it to a public method on the
source class.


>
> Thanks guys, I stay tuned to read your replies, and probably I will post
> more questions as I delve on this DShow world. You are very helpful and kind
> to me.
>
> Dev
>

Iain

unread,
Feb 17, 2006, 4:34:33 AM2/17/06
to
On Fri, 17 Feb 2006 09:47:17 +0100, DevX wrote:

> Hi lgs,
>
> I have problems contacting the site...I will try later this morning or
> afternoon.
> I know that is possible to use DShow in .NET but I've read somewhere (don't
> remin where, but an official source) that is not advised to do so.
> Obviously I can always make some test about it.
>

LGS's wrapper seems to be popular and effective. I've not tried to use it,
myself - but people seem to produce working code with it. If you look at
it it would be helpful if you would post your experiences back here.

Alessandro Angeli [MVP::DS/MF]

unread,
Feb 17, 2006, 4:35:31 AM2/17/06
to
DevX wrote:

> Sorry Alessandro if I do not specify correctly that I
> have already a prototype Source Filter, English is not my
> first language

It's not your fault: I should've read your post more
carefully.

> (first is Italian ...and from your name
> something made me think is also your)

You guessed right :-)

> Supposing I want to preserve the modified Ball, that is
> built as a separate inproc DLL Server, I must say that
> this filter will be prevalently used internally in my
> main dotNet app, so in your first post you say to me:
>
>> 1. you create it anyway you like and add it to the graph
>> yourself; this way you have a reference to the object and
>> you can do whatever you need with it
>
> what means? I anticipated to have the filter in the DLL,
> then a normal Win32 DLL (because I need C++ code) will
> manually builds the graph , adding only the source and
> the renderer. In this manner I will get a pointer to the
> interface of the source filter. As Iain said, I checked
> the Gargle sample and saw how to implement custom
> interface to manipulate members on my
> CSourceStream-derived class.
> So, what you wrote on #1 above, is what I have intention
> to do or I missed something? (I have only the intention
> and the idea...how to implement really this will need
> some study and some other questions I will post)

You can do it if you want, but it's a bit problematic in the
managed world.

In the unmanaged world, you usually link in the filter's
code and then use the new operator or an internal factory
function to create instances of the filter.

But you can not link unmanaged object code into a managed PE
module (DLL or EXE). Or rather, you could, but the only .NET
compiler capable of doing it is the mC++ or C++/CLI
compiler. In this case, you must put your unmanaged code in
a separate module unless you want to use the C++ compiler.

It's up to you to decide whether to make this DLL a standard
COM inproc server or export a custom factory function from
it. In the former case, it's also up to you whether to
register the DLL as a COM server and a DirectShow filter
implementation.

Once you decide in what way you want to package your
filter's code and what creation mechanism you want to
provide, just use it in your managed code via the
appropriate InterOp.

Most DirectShow samples are packaged into standard COM
inproc servers that can be globally registered with COM and
DirectShow, so maybe that's what you want to do just to
write less unmanaged code.

To give you more options, P/Invoke can be used to easily
create instances of C++ classes exported from a DLL without
exported factory functions, even if it's not a well know
technique and is somewhat tricky.

> Regarding the means on how communicate between
> filter/.net:
> I must say I have already experience in .NET/native
> interop and I have already implemented Win32 DLL that
> callbacks code in the .NET side, but all my experience is
> on "concrete" and basic code and classes...entering in
> the realm of DShow and low-level COM something confuse me
> with all of those automatism and complicate (for me)
> plumbing...but once (with your help) I can give my filter
> a pointer to a delegate on .NET, I think I will be fine

Implement a custom interface in your filter's class and
create a managed wrapper for it. This interface must have a
method that takes a function pointer as parameter, then call
it from managed code passing in the corresponding delegate
and you're set.

Alessandro Angeli [MVP::DS/MF]

unread,
Feb 17, 2006, 4:46:30 AM2/17/06
to
Iain wrote:

> Both solutions will work fine. Alessandro's will let you
> push data in from the .net application through a custom
> com interface or similar. It's probably a better
> solution in many respects. I tend to try and provide
> solutions that minimise learning curve rather than which
> work best.

Which, given DirectShow complexities and how little COM is
known, is maybe a wiser approach :-)

Alessandro Angeli [MVP::DS/MF]

unread,
Feb 17, 2006, 4:56:56 AM2/17/06
to
Alessandro Angeli [MVP::DS/MF] wrote:

>> Supposing I want to preserve the modified Ball, that is
>> built as a separate inproc DLL Server, I must say that
>> this filter will be prevalently used internally in my
>> main dotNet app, so in your first post you say to me:
>>
>>> 1. you create it anyway you like and add it to the graph
>>> yourself; this way you have a reference to the object
>>> and you can do whatever you need with it
>>
>> what means? I anticipated to have the filter in the DLL,
>> then a normal Win32 DLL (because I need C++ code) will
>> manually builds the graph , adding only the source and
>> the renderer. In this manner I will get a pointer to the
>> interface of the source filter. As Iain said, I checked
>> the Gargle sample and saw how to implement custom
>> interface to manipulate members on my
>> CSourceStream-derived class.
>> So, what you wrote on #1 above, is what I have intention
>> to do or I missed something? (I have only the intention
>> and the idea...how to implement really this will need
>> some study and some other questions I will post)

After reading Iain's post, I realized I misinterpreted your
question again (what is wrong with me?!) :-(

You are building the graph in unmanaged C++ and not managed
code. So no problems: as Iain said, get rid of all the
registration stuff and only keep the filter and pin's
classes and then just call the CreateInstance() static
method. new() and AddRef() the way Iain suggested is the
same, but since you have a factory method, I'd go with it
(btw, CreateInstance() doesn't AddRef() the new instance, so
maybe you shouldn't).

DevX

unread,
Feb 17, 2006, 6:36:11 AM2/17/06
to
Dear Alessandro and Iain,

I also think that a single non-COM DLL in which I have the filter classes
(derived from CSource and CSourceStream), the code that builds the filter
graph and some exported function usable from .NET is the best solution.

The problem is that I don't think I'm [now] able to transform my modified
Ball Sample from COM to non COM...:-( (...if you have any already made
sample which I can point to...)

So I try first to add an interface to my source filter, in the Gargle
example I see that is show a IID_IGargle interface that can manipulate
fields in the main CGargle class...I think I can try to implement a similar
interface in my CSource-derived class and call methods on it in the graph
builder code, that will lie in a separate non COM DLL.

Thanks alot, I am sure that in the near future I will be back begging for
more help :-(

Dev


"Alessandro Angeli [MVP::DS/MF]" <nob...@nowhere.in.the.net> wrote in

message news:enV4bi6M...@tk2msftngp13.phx.gbl...

Iain

unread,
Feb 17, 2006, 7:12:50 AM2/17/06
to
On Fri, 17 Feb 2006 12:36:11 +0100, DevX wrote:

> Dear Alessandro and Iain,
>
> I also think that a single non-COM DLL in which I have the filter classes
> (derived from CSource and CSourceStream), the code that builds the filter
> graph and some exported function usable from .NET is the best solution.

I wasn't proposing that you have a non com dll.

I was proposing you have a com dll which wraps your graph and stuff and
gets called from your dotnet stuff (yes, you can access non com dll
functions, but Com interop is automatic and easy).

I was proposing that in your graph building code, you use new to create
your source filter. Mind you there's no particular need to do this if you
have a separate dll (except tidiness and keeping your source filter private
and secure), so maybe I misunderstood this part.


>
> The problem is that I don't think I'm [now] able to transform my modified
> Ball Sample from COM to non COM...:-( (...if you have any already made
> sample which I can point to...)

Don't bother!


>
> So I try first to add an interface to my source filter, in the Gargle
> example I see that is show a IID_IGargle interface that can manipulate
> fields in the main CGargle class...I think I can try to implement a similar
> interface in my CSource-derived class and call methods on it in the graph
> builder code, that will lie in a separate non COM DLL.

I tend to write DS / .net code like this.

1. Create an ATL dll
2. Create com objects with interfaces in the dll (with names like
BuildGraph, Run, SetSourceNamedPipe [or PushYUVBuffer if you use
Alessandros approach]).
3. Create filters derived from CSource or whatever - junk the registration
bits.
4. In the com object have mthods that create teh graph and source filters
and so on.
5. Control the graph via the com interface from the .net app.

this way you have a nice clean separation between the dot net bits and the
graph bits. You can use (automatic) Com Interop in the dotnet app which is
nice and easy. You don't expose your custom filters to the outside world.
You CAN access C++ methods on your custom filters with a simple cast, whcih
can make things far less of a pain.

In the example above, the body of SetSourceNamedPipe (or PushYUVBuffer)
would find the source filter in the graph (you would have stored it of
course), gets a C++ method on it and calls that with the data. Dad easy.

>
> Thanks alot, I am sure that in the near future I will be back begging for
> more help :-(

Welcome

lgs.lgs

unread,
Feb 17, 2006, 10:51:31 PM2/17/06
to
> I have problems contacting the site

Whoops! Sorry about that. Sometimes I have to go kick that box.
Eventually I'll probably move this sample over to SourceForge with the rest
of the lib, but it isn't quite ready yet.

> I know that is possible to use DShow in .NET but I've read somewhere
> (don't remin where, but an official source) that is not advised to do so.

<sigh> Hard to debate a post I can't see. If you find it again, let me
know. I've got my response all ready:

"Those who claim it can't be done are mildly annoying to those of us
actually doing it."

Or perhaps you mean this (from the DS FAQ):

"Will DirectShow ever be accessible through managed code? There are no
current plans to implement a "Managed DirectShow" platform. You can use COM
interop to create DirectShow client applications in managed code, but
creating filters that depend on the Common Language Runtime (CLR) is not
recommended for performance reasons. "

It's unclear how MS can make assertions about the performance when
they have no methods for managed access. Are they guessing? Those of us
who have actually done this find the performance to be quite acceptable.

Thore Karlsen [DShow MVP]

unread,
Feb 17, 2006, 11:07:52 PM2/17/06
to
On Fri, 17 Feb 2006 19:51:31 -0800, "lgs.lgs" <limegre...@yahoo.com>
wrote:

>> I know that is possible to use DShow in .NET but I've read somewhere
>> (don't remin where, but an official source) that is not advised to do so.

><sigh> Hard to debate a post I can't see. If you find it again, let me
>know. I've got my response all ready:
>
>"Those who claim it can't be done are mildly annoying to those of us
>actually doing it."
>
>Or perhaps you mean this (from the DS FAQ):
>
>"Will DirectShow ever be accessible through managed code? There are no
>current plans to implement a "Managed DirectShow" platform. You can use COM
>interop to create DirectShow client applications in managed code, but
>creating filters that depend on the Common Language Runtime (CLR) is not
>recommended for performance reasons. "
>
>It's unclear how MS can make assertions about the performance when
>they have no methods for managed access. Are they guessing? Those of us
>who have actually done this find the performance to be quite acceptable.

The performance issues are for filters, not for simple graph building
through COM interop. Building a graph and running/controlling it isn't
CPU intensive in any way, so that will work just fine from just about
any language.

Your library looks great. My biggest concern about DirectShow from a
managed language is that you need custom filters for so many things.
Sometimes it feels to me like I need a new filter for the slightest
non-trivial thing, so that's the reason I'm hesitant to recommend
managed languages for any serious DirectShow programming. Those who only
need to build some graphs and interact with them have nothing to worry
about, though.

--
New to newsgroups? Read: http://dev.6581.com/newsgroups.html

lgs.lgs

unread,
Feb 19, 2006, 4:20:39 AM2/19/06
to
> The performance issues are for filters,

Oh, oh. Now you've done it!<g>

I'll ask you the same question then: How do you *know* that there are
performance issues? Have you personally tried it?

As it happens, I have:

My first attempt at "creating filters that depend on the Common Language
Runtime (CLR)" was when I modified a c# program that was using the
SampleGrabber callback to alter the sample buffer. This clearly fits the
definition of having a filter depend on CLR code. Because of this
performance warning (and the docs at the time which said you mustn't alter
the SampleGrabber buffer), I wasn't sure it would work. And if it did work,
I expected the performance to suck.

Guess what? Worked fine. Performance was a non-issue.

My second attempt (much later) was to try writing a DMO and using the DMO
Wrapper filter. I figured if ever there was a place where I would see this
dreaded performance issue, this was going to be it. And sure enough, I did
see a major performance hit. But then I did a little debugging, tracing,
and study. I discovered that there were a few statements in my innermost
loop that were real pigs. I re-wrote that routine and, tada, no performance
issues.

Moral of this story: Poorly written code performs poorly, regardless of the
language.

My third attempt involved trying to create an actual filter. As I'm sure
you can imagine, attempting to do this completely from scratch (ie no base
classes) is so huge a project as to be impractical. So, the obvious
approach was to try to convert the base classes to managed code. Not c#,
mind you, just managed c++. Well, let's just say these classes weren't
designed with managed code in mind.

Now, does this mean there is *no* performance penalty for coding in c#? Of
course not. At the very least, there are marshaling issues and c# has more
runtime checks than c++, so there must be some level of performance hit.

That said, however, the question becomes: How much of a performance hit
does c# add? And how much is too much?

My experience shows that adding a c# DMO filter which flips a video (meaning
a read/write of every byte in the sample buffer) running against a live
capture (30fps) shows no perceptible increase in cpu utilization (using the
admittedly rough measurement tool of watching cpu utilization in taskmgr)
and no dropped frames. In fact, there was no visible difference between
adding the dmo and not adding the dmo to the graph (after I took out those
piggy statements which were causing an almost 30% increase in cpu usage!).

In summary, while there may be unacceptable performance hits that come from
using c#, I have yet to see them. As near as I can tell, the only reason
you can't write filters in c# is that MS has chosen not to make a managed
version of the base classes.

My code (including source) is publicly available on
http://DirectShowNet.SourceForge.net for those who want to do their own
testing. DxLogo does the SampleGrabber buffer manipulation, and DMOFlip is
the dmo that flips the buffer (note that I left the piggy statements in this
sample code to show that you don't *have* to use unsafe code to write a dmo.
The more performant verson of the code is in the readme).

If MS would like to post their DS sample that shows the motivation for this
warning, I'd love to see it. Absent that, I guess I'll just have to stick
to believing my own eyes over the unsupported statements of some unknown
person who (by their own admission) has no way of testing their allegations.
I guess that's just the way I am.

> you need custom filters for so many things.

I haven't had much need to create custom filters for the graphs I have been
doing, but I can see how you could be quite right on this point. On the
other hand, you *can* create DMOs in c# and use the DMO Wrapper to call
them. MS itself describes DMOs as "easier to create, easier to test, and
easier to use" than traditional filters. While DMOs can't satisfy every
need, they can get a good chunk of them.

See what happens if you encourage me?


Alessandro Angeli [MVP::DS/MF]

unread,
Feb 19, 2006, 4:55:31 AM2/19/06
to
lgs.lgs wrote:

> Now, does this mean there is *no* performance penalty for
> coding in c#? Of course not. At the very least, there
> are marshaling issues and c# has more runtime checks than
> c++, so there must be some level of performance hit.

[...]


> In summary, while there may be unacceptable performance
> hits that come from using c#, I have yet to see them. As
> near as I can tell, the only reason you can't write
> filters in c# is that MS has chosen not to make a managed
> version of the base classes.

As in many other scenarios, whether the performance is
unacceptable depends on what you do and the scale of it.

Simple processing or I/O and stuff like that on a small
scale is not that CPU-hungry and managed code is often
perfectly fine, because you can afford the marshalling
overhead, the runtime checks, the GC hits and the lack of
ASM optimizations.

But CPU-intensive tasks or large scale ones, like video
encoders/decoders and effects, HD stuff or multiple streams
processors, sometimes can barely run on fast machines even
when written in highly optimized native code, so you can not
afford the luxury of managed code.

Most people here attempt tasks in the second category and
that, coupled with the difficulties of writing a filter
without the BaseClasses and that the level of InterOp
required is beyond most people's knowledge, makes using
managed code impractical, either because it's too much work
or because the result will not live up to the requirements
performance-wise.

Keep in mind that you are talking to someone who writes
network services in Java or C# before biting me :-))

Iain

unread,
Feb 19, 2006, 5:06:24 AM2/19/06
to
On Sun, 19 Feb 2006 01:20:39 -0800, lgs.lgs wrote:

> Oh, oh. Now you've done it!<g>

Thanks for this exposition lgs. NOt saying you've turned me off C++, but
it is very useful to have some facts in the debate rather than myth.

Iain

Thore Karlsen [DShow MVP]

unread,
Feb 19, 2006, 12:47:17 PM2/19/06
to
On Sun, 19 Feb 2006 01:20:39 -0800, "lgs.lgs" <limegre...@yahoo.com>
wrote:

>> The performance issues are for filters,

>Oh, oh. Now you've done it!<g>
>
>I'll ask you the same question then: How do you *know* that there are
>performance issues? Have you personally tried it?

I wasn't making a statement about my personal opinions, merely pointing
out that that's what Microsoft meant. I haven't tried it so I don't
know, and I suspect managed code would be fine for a lot of filter
stuff.

(I wonder if garbage collection would be an issue in filters where
timing would be very important? Like e.g. audio filters working on very
small buffers, where latency needs to be very low.)

>> you need custom filters for so many things.

>I haven't had much need to create custom filters for the graphs I have been
>doing, but I can see how you could be quite right on this point. On the
>other hand, you *can* create DMOs in c# and use the DMO Wrapper to call
>them. MS itself describes DMOs as "easier to create, easier to test, and
>easier to use" than traditional filters. While DMOs can't satisfy every
>need, they can get a good chunk of them.

That's what they claim. Personally I've never written a DMO. Once I
figured out how to write a filter I never saw the point in bothering
with DMOs. :)

>See what happens if you encourage me?

That'll teach me. :)

lgs.lgs

unread,
Feb 19, 2006, 6:28:40 PM2/19/06
to
Well said, and good points all. In fact, the only thing I'm not sure I
accept is:

> Most people here attempt tasks in the second category

It's true I mostly skim the postings in this forum looking for things that
interest me, so perhaps my perceptions are skewed. However, I find it
difficult to believe that most of the people here are writing next gen video
encoders. A few, sure. Some, maybe. But most?

> Keep in mind that you are talking to someone who writes network services
> in Java or C# before biting me :-))

It wasn't my intention to bite anyone (except maybe that anonymous guy who
wrote the DS faq).

Filters come in all shapes and sizes. I think we are agreed that c++ can be
more performant than c#, and that assembler can be more performant still.
On that basis, everyone should be writing in assembler. Of course, other
factors come into play: abilities of the available programmers, maintenance,
debugging, tools, etc.

In general, one should pick the right tool for the job, based on the
available resources and the project requirements. Sometimes that is
assembler, and sometimes that is c/c++. For some tasks, even (I assert) for
some filters, c# is an appropriate solution.

Of course for a guy who writes network services in Java, I probably don't
have to tell you any of this. You've probably had to make these same
arguments.


lgs.lgs

unread,
Feb 19, 2006, 6:32:40 PM2/19/06
to
> NOt saying you've turned me off C++

It was never my intent to do so. People who are comfortable in C++ should
use it. Heck, some of my best friends are C++ programmers<g>.

Seriously, if you have a team of all c++ programmers, of course you should
write your filters in c++. Even if your team are all multi-lingual c#/c++,
you should still choose c++ for your filters (IMO).

All I'm trying to say is that if, for whatever reason, c++ isn't an
attractive option, c# may prove to be a viable solution.

Note: My opinion on this may change if MS ever produces a managed version of
the base classes...


lgs.lgs

unread,
Feb 19, 2006, 6:34:56 PM2/19/06
to
> (I wonder if garbage collection would be an issue in filters where
> timing would be very important? Like e.g. audio filters working on very
> small buffers, where latency needs to be very low.)

Off hand I wouldn't expect it to be a problem. The sample buffers aren't
allocated by c# after all. If you are using DMO (the only option today),
they are created by the wrapper. c# just reads/populates them.

GC, however, might be an issue. It's hard (impossible?) to avoid its
effects completely. On the plus side, it runs on its own thread.

> I never saw the point in bothering with DMOs

I've written (very) simple filters and (very) simple DMOs. Frankly, they
don't strike me as all that different. Maybe if I did bigger projects I
would see why DMO is so much "easier", but I doubt it.


Iain

unread,
Feb 20, 2006, 3:54:42 AM2/20/06
to

Yeah, and that's why I've never tried your stuff. I can't imagine that I'm
going to gain by stepping a layer away from the system. I should also add
I probably write 10 times more c# code than C++ these days and in general I
would recommend C# over C~~ (or VB6) for almost any application.

lgs.lgs

unread,
Feb 20, 2006, 7:11:57 PM2/20/06
to
> Yeah, and that's why I've never tried your stuff. I can't imagine that
> I'm
> going to gain by stepping a layer away from the system.

Well, from a maintenance and supportability standpoint, there could be value
in having the code all in one language. It also cuts down on the number of
tools you need to own/update/study. Further it minimizes the skillsets
required and the learning curve for new hires. Additionally there may be
debugging/stability benefits that come from those extra run-time checks.

Of course on the minus side there is the fact that accessing DS from c# is
relatively new. It hasn't had the years of shakeout that the c++
samples/libraries have had. No doubt you also have existing code that you
re-use regularly that would have to be ported & tested in the new language.
Plus, there will be a learning curve (a small one, but still).

There are probably a number additional items that could placed on both sides
of the scales depending on the requirements of the project, the skills of
the developers, the resources of the company where the work is being done,
etc.

Even with all this, I'm STILL not trying to convice you to dump c++. All
I'm trying to do is provide info, provoke a little thought, and challenge
unfounded/unproven assertions. If in the end people choose c++, great!
More power to ya. If people choose c#, great! Help push us over the 10,000
download mark (8,851 and counting!).


Iain

unread,
Feb 21, 2006, 3:19:49 AM2/21/06
to
On Mon, 20 Feb 2006 16:11:57 -0800, lgs.lgs wrote:

> Even with all this, I'm STILL not trying to convice you to dump c++. All
> I'm trying to do is provide info, provoke a little thought, and challenge
> unfounded/unproven assertions. If in the end people choose c++, great!
> More power to ya. If people choose c#, great! Help push us over the 10,000
> download mark (8,851 and counting!).

All of these points are good. You (and other readers) shouldn't take my
preference for c++ for DS code as any indictment of your library and the
use of c#.

Try it. If it works, great. If it doesn't learn C++ (or contract the hard
bits out to me <g>).

I wish you the best with the library. Maybe one day ....

0 new messages