Infognition forum
October 22, 2017, 08:04:45 PM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: Last Video Enhancer version: 2.2
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: Trying to use CreateFilterByName issues  (Read 23995 times)
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« on: May 22, 2012, 06:21:50 AM »

Trying to use the code you posted for CreateFilterByName because my GetPin() calls are failing but DSDevice.GetDevicesofCat always returns an empty array.

In this case, I'm trying to use the category {17CCA71B-ECD7-11D0-B908-00A0C9223196} which, according to GEP and GraphStudio is the correct category GUID.
Since it always returns an empty array the code in the foreach() is never executed.

Here's the code I got from your post for CreateFilterByname.  Is this correct?

        public static IBaseFilter CreateFilterByName(string filterName, Guid category)
        {
            int hr = 0;
            DsDevice[] devices = DsDevice.GetDevicesOfCat(category);
            foreach (DsDevice dev in devices)
                if (dev.Name == filterName)
                {
                    IBaseFilter filter = null;
                    IBindCtx bindCtx = null;
                    try
                    {
                        hr = CreateBindCtx(0, out bindCtx);
                        DsError.ThrowExceptionForHR(hr);
                        Guid guid = typeof(IBaseFilter).GUID;
                        object obj;
                        dev.Mon.BindToObject(bindCtx, null, ref guid, out obj);
                        filter = (IBaseFilter)obj;
                    }
                    finally
                    {
                        if (bindCtx != null) Marshal.ReleaseComObject(bindCtx);
                    }
                    return filter;
                }
            return null;
        }

        [DllImport("ole32.dll")]
        public static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +13/-0
Posts: 743



View Profile WWW
« Reply #1 on: May 22, 2012, 02:47:30 PM »

The code looks fine. What is that category of filters? How do you build your program?
Remember, for C# by default you're building "Any CPU" code which on a 64-bit Windows runs in 64-bit mode, it will not see any 32-bit filters and devices. GraphEditPlus32 and GraphStudio are working in 32-bit mode and see 32-bit devices and filters. To build for 32-bit mode change your build target to x86.
Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #2 on: May 22, 2012, 11:31:01 PM »

As I mentioned, I'm trying to get Video Sources ({17CCA71B-ECD7-11D0-B908-00A0C9223196})

I am building for x86 as I did notice that I had to use GraphEditPlus32 to make my filters work.

Both the platform and platform target are set to x86.

Just for testing, I did a build for x64 and I get the same results.

Do I need to turn on Allow unsafe code?

FYI, I'm linking to the same DirectShowNet DLL that is supplied in your binaries (as opposed to one I built from source).
I tried that as well with the same results.
Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #3 on: May 22, 2012, 11:54:15 PM »

Just FYI, I also just did a re-build of the DirectShowNet code and also tried a different category with the same (empty list) results.
Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +13/-0
Posts: 743



View Profile WWW
« Reply #4 on: May 23, 2012, 11:31:22 AM »

Weird. Then you can try another approach, without DsDevice:
Code:
            ICreateDevEnum devenum = new CreateDevEnum() as ICreateDevEnum;
            IEnumMoniker emon;           
            int hr = devenum.CreateClassEnumerator(category, out emon, 0);
            //check hr here
            if (emon != null)
            {
                IMoniker[] mon = new IMoniker[1];
                while (0 == emon.Next(1, mon, IntPtr.Zero))
                {
                    object bagObj = null;
                    Guid propertyBagId = typeof(IPropertyBag).GUID;
                    mon[0].BindToStorage(null, null, ref propertyBagId, out bagObj);
                    IPropertyBag bag = (IPropertyBag)bagObj;
                    object nameObj;
                    bag.Read("FriendlyName", out nameObj, null);
                    string name = nameObj as string;

                    string dispname;
                    mon[0].GetDisplayName(null, null, out dispname);
                    bag.Read("CLSID", out nameObj, null);
                    string clsid = nameObj as string;
                   
                    //check if it's the right filter and use mon[0].BindToObject as above
                    //...

                    Marshal.ReleaseComObject(bagObj);
                    Marshal.ReleaseComObject(mon[0]);
                }
            }       
Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #5 on: May 24, 2012, 04:32:45 AM »

Unfortunately, same result.

hr comes back 1 and emon is null.
Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +13/-0
Posts: 743



View Profile WWW
« Reply #6 on: May 24, 2012, 11:27:11 AM »

This error code means "The category specified by clsidDeviceClass does not exist or is empty."
Check your Guid for correctness.
Also you may try to run your app with elevated rights ("run as administrator"), like GEP is run.
Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #7 on: May 24, 2012, 10:33:48 PM »

Thanks for the continued attempts, unfortunately still no joy.

I've tried 3 different category GUIDs and Run as Admin

I normally run Visual Studio as Admin so I believe my program-being-debugged is automatically admin but I ran it from the command line (elevated) just in case with the same result.

I'm going to re-build the graph and try again with unmodified code exported from GEP.
Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #8 on: May 24, 2012, 11:10:53 PM »

Additional information:

I pared the graph down to some absolute minimums and was able to finally make something work  Smiley

For example, if I connect my internal microphone to an MainConcept Rate Converter and then to the audio out I can get that to work (lots of nice feedback!) Cool

However, if I then try to connect my Logitech Webcam's microphone to the same simple graph, it fails.

So, some questions:

  • Is there some magic that GEP (the program) is doing that the exported code is not?
  • Is GEP written in C++ or C#?
  • Why do you think some filters will connect correctly inside GEP but not in your generated code?  For example, I attempt to connect the MainConcept Frame Rate Convert to the MainConcept ImageScaler and it works just fine in GEP.  In the generated code it can find the pins but fails to connect them with error 0x80040207.  Is it possible the connection order matters and GEP is doing it in a different way?

Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +13/-0
Posts: 743



View Profile WWW
« Reply #9 on: May 25, 2012, 12:38:36 PM »

Yes, there is a lot of magic in GEP. It was made by best magicians from Gryffindor, Hogwarts using latest developments in alchemy and wizardry. It contains traces of unicorn blood, dragon eggs and jobberknoll feathers. Voodoo is actively used too, so each time you generate C++ code in GEP Bjarne Stroustrup loses a hair.

It's written completely in C#.

Surely, connection order, state of filters and used method of connection (direct/intelligent, pins vs filters) matter a lot.
When you connect pins with left mouse button in GEP it uses graphBuilder.Connect(sourcePin, destPin), with right mouse button - graphBuilder.ConnectDirect(sourcePin, destPin, null), where graphBuilder is IGraphBuilder
« Last Edit: May 25, 2012, 12:51:57 PM by Dee Mon » Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #10 on: May 25, 2012, 09:53:23 PM »

Thanks for the behind-the-curtain view Smiley

Perhaps a different tactic is in order.

Is there a way for you to share (or hint at) how to simply load a .GRF file as GEP does?

Would that actually be easier for developers who don't need to customize the graph once it's working?

For what it's worth, all the pins in the graph I'm working with were connected with the left mouse button.
Not sure using ConnectDirect() would be of any help for me as the issue I'm encountering is that GetPin() isn't finding the pins in the first place.
Logged
Dee Mon
Administrator
Hero Member
*****

Karma: +13/-0
Posts: 743



View Profile WWW
« Reply #11 on: May 28, 2012, 04:49:26 PM »

Usually not found pins mean incorrectly created filters or filter being in wrong state. For example, some filters need to get a sample of input data before they show proper output pins. So the out pins in those filters appear after connecting input pins and going to paused state.

You can find the code for loading and saving graphs in samples coming with DirectShow lib. See FilterGraphTools.cs. Here's the graph loading function:
Code:
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)]
        public static void LoadGraphFile(IGraphBuilder graphBuilder, string fileName)
        {
            int hr = 0;
            IStorage storage = null;
#if USING_NET11
UCOMIStream stream = null;
#else
IStream stream = null;
#endif

            if (graphBuilder == null)
                throw new ArgumentNullException("graphBuilder");

            try
            {
                if (NativeMethods.StgIsStorageFile(fileName) != 0)
                    throw new ArgumentException();

                hr = NativeMethods.StgOpenStorage(
                    fileName,
                    null,
                    STGM.Transacted | STGM.Read | STGM.ShareDenyWrite,
                    IntPtr.Zero,
                    0,
                    out storage
                    );

                Marshal.ThrowExceptionForHR(hr);

                hr = storage.OpenStream(
                    @"ActiveMovieGraph",
                    IntPtr.Zero,
                    STGM.Read | STGM.ShareExclusive,
                    0,
                    out stream
                    );

                Marshal.ThrowExceptionForHR(hr);

                hr = (graphBuilder as IPersistStream).Load(stream);
                Marshal.ThrowExceptionForHR(hr);
            }
            finally
            {
                if (stream != null)
                    Marshal.ReleaseComObject(stream);
                if (storage != null)
                    Marshal.ReleaseComObject(storage);
            }
        }
GEP uses this code now, but future versions will use another approach (to show graphs even when some filters are missing and/or couldn't load).

However if your graph involves some capture devices, it most probably wouldn't load on another PC, only on the one where it was saved.
Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #12 on: May 28, 2012, 10:12:49 PM »

Thanks for the code (and the hints about pin visibility).

I'll give this a try.  Loading on "another machine" isn't an issue for me since my scenario is a museum system with only one live machine and it would never be a problem to reload in GEP and re-save again if something changes.
 
Logged
DreamTimerZ
Newbie
*

Karma: +0/-0
Posts: 9


View Profile
« Reply #13 on: May 31, 2012, 07:31:58 PM »

Thanks for the help.  That did the trick! Grin Grin

The code (as-is) couldn't be used directly but with a few tweaks (downloading the Visual Studio SDK, and searching for a blog post about loading a structured storage file) I got it to work!

Now, if only the encoder I'm using didn't insert black vertical lines in the middle of the encoded video sometimes!?!
Logged
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.13 | SMF © 2006-2011, Simple Machines LLC Valid XHTML 1.0! Valid CSS!