Hatena::ブログ(Diary)

ラシウラ このページをアンテナに追加 RSSフィード Twitter

2007-07-19

DirectShowフィルタとPinの名前を列挙するコード

完成版↓

はてなグループが重いので一時退避

using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using DirectShowLib;

namespace listfilters {
  class Program {
    //[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
    static void Main(string[] args) {
      Guid clsidSystemDeviceEnum = new Guid("62BE5D10-60EB-11d0-BD3B-00A0C911CE86");
      ICreateDevEnum devEnum = GetFromClsid(clsidSystemDeviceEnum) as ICreateDevEnum;
      Guid[] categories = new Guid[] {
        FilterCategory.LegacyAmFilterCategory,
        FilterCategory.AudioCompressorCategory,
        FilterCategory.VideoCompressorCategory,
        //FilterCategory.BDASourceFiltersCategory,
      };
      foreach (Guid category in categories) {
        //Console.WriteLine();
        //Console.WriteLine("new category: " + category);
        
        IEnumMoniker monikers;
        devEnum.CreateClassEnumerator(category, out monikers, CDef.None);
        monikers.Reset();
        IntPtr count = new IntPtr();
        IMoniker[] moniker = new IMoniker[1];
        while (monikers.Next(1, moniker, count) == 0) {
          Console.WriteLine("Filter: \"" + GetFilterName(moniker[0]) + "\"");
          try {
            IBaseFilter filter = GetFilter(moniker[0]);
            IEnumPins pins;
            filter.EnumPins(out pins);
            int pinCount;
            IPin[] pin = new IPin[1];
            while (pins.Next(1, pin, out pinCount) == 0) {
              PinInfo info;
              pin[0].QueryPinInfo(out info);
              Console.WriteLine("  Pin " + info.dir + ": \"" + info.name + "\"");
            }
          } catch (Exception ex) {
            //Console.WriteLine(ex);
          } finally {
            Marshal.ReleaseComObject(moniker[0]);
          }
        }
        Marshal.ReleaseComObject(monikers);
      }
      Marshal.ReleaseComObject(devEnum);
    }
    
    static IBaseFilter GetFilter(IMoniker filterMoniker) {
      object filterObj;
      Guid baseFilterId = typeof(IBaseFilter).GUID;
      filterMoniker.BindToObject(null, null, ref baseFilterId, out filterObj);
      IBaseFilter filter = filterObj as IBaseFilter;
      return filter;
    }
    
    static string GetFilterName(IMoniker filterMoniker) {
      object bagObj;
      Guid propertyBagId = typeof(IPropertyBag).GUID;
      filterMoniker.BindToStorage(null, null, ref propertyBagId, out bagObj);
      IPropertyBag bag = bagObj as IPropertyBag;
      object nameObj;
      bag.Read("FriendlyName", out nameObj, null);
      string name = nameObj as string;
      Marshal.ReleaseComObject(bagObj);
      return name;
    }
    
    static object GetFromClsid(Guid clsid) {
      Type comType = Type.GetTypeFromCLSID(clsid);
      return Activator.CreateInstance(comType);
    }
  }
}

DirectShowLibがうまく動いた

勘違いを直したらうまく動かせた。参考は


以下はDirectShowフィルタを列挙するコード

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using DirectShowLib;

namespace listfilters {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine("Start");
            
            Guid clsidSystemDeviceEnum = new Guid("62BE5D10-60EB-11d0-BD3B-00A0C911CE86");
            ICreateDevEnum devEnum = GetFromClsid(clsidSystemDeviceEnum) as ICreateDevEnum;
            Guid[] categories = new Guid[] {
                FilterCategory.LegacyAmFilterCategory,
                FilterCategory.AudioCompressorCategory,
                FilterCategory.VideoCompressorCategory,
            };
            foreach (Guid category in categories) {
                Console.WriteLine();
                Console.WriteLine("new category: " + category);

                IEnumMoniker monikers;
                devEnum.CreateClassEnumerator(category, out monikers, CDef.None);
                monikers.Reset();
                IntPtr count = new IntPtr();
                IMoniker[] moniker = new IMoniker[1];
                while (monikers.Next(1, moniker, count) == 0) {
                    object bagObj;
                    Guid propertyBagId = typeof(IPropertyBag).GUID;
                    moniker[0].BindToStorage(null, null, ref propertyBagId, out bagObj);
                    IPropertyBag bag = bagObj as IPropertyBag;
                    object nameObj;
                    bag.Read("FriendlyName", out nameObj, null);
                    string name = nameObj as string;
                    Console.WriteLine(name);

                    //object filterObj;
                    //Guid baseFilterId = typeof(IBaseFilter).GUID;
                    //moniker[0].BindToObject(null, null, ref baseFilterId, out filterObj);
                    //IBaseFilter filter = filterObj as IBaseFilter;
                }
            }
            Console.WriteLine("Start");
        }

        static object GetFromClsid(Guid clsid) {
            Type comType = Type.GetTypeFromCLSID(clsid);
            return Activator.CreateInstance(comType);
        }
    }
}

ビルド

csc /r:DirectShowLib-2005.dll /platform:x86 /out:listfilters.exe Program.cs

ポイントは/platformオプションです。これがないと64ビット版では、64ビットフィルタを、32ビット版では32ビットフィルタを使うようになります。DirectShowフィルタはまだ32ビット版のほうが多いので、強制的に32ビットで動かすために/platformオプションをつけます。このオプション、Visual C# 2005 Express Editionだとどうやって指定するのかな。

DirectShowLibがうまく動かない

の処理を自動化するためにコードを書こうとしたけど、これで使ったDirectShowLibがうまく動かなかった。

単に使えるフィルタリストアップしたいだけだが、そのフィルタがまったく出てこない。

using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using DirectShowLib;

namespace listfilters {
    class Program {
        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
        static void Main(string[] args) {
            Console.WriteLine("Start");
            IGraphBuilder graph = new FilterGraph() as IGraphBuilder;

            IEnumFilters filters = null;
            graph.EnumFilters(out filters);
            int fetched;
            IBaseFilter[] filter = new IBaseFilter[1];
            while (filters.Next(1, filter, out fetched) == 0) {
                Console.WriteLine(filter[0]);
                FilterInfo info;
                filter[0].QueryFilterInfo(out info);
                Console.WriteLine(info.achName);
                Marshal.ReleaseComObject(filter[0]);
            }
            Marshal.ReleaseComObject(filters);
            Marshal.ReleaseComObject(graph);
            Console.WriteLine("End");
        }
    }
}

whileループに入らない。どうすればいいんだろうか。

どうやらEnumFiltersする前に、適当ファイルでgraph.RenderFile("test.avi", null)すれば、出てくるようになった。

ということはEnumFiltersは、graph中のフィルタを列挙してるだけに過ぎなくなる。GraphEditはどうやってフィルタリストを作ってるんだろうか。

Connection: close