Handy code: Determine capture device frame sizes

Nov 13, 2013 at 5:14 PM
I needed this function for myself and it looks like lots of you could benefit from it so here you go. This function, given a capture DsDevice, will return the video formats it supports, all without creating a graph.
  public struct VideoFormatDescription
  {
    public Size size;
    public double minFps;
    public double maxFps;
  };
  private VideoFormatDescription[] GetVideoFrameSizes(DsDevice vidCapDevice)
  {
    IMoniker mon = vidCapDevice.Mon;
    IBaseFilter filter = null;
    object filterObj = null;
    Guid guid = typeof(IBaseFilter).GUID;
    mon.BindToObject(null, null, ref guid, out filterObj);
    filter = filterObj as IBaseFilter;
    VideoFormatDescription[] result = null;
    if (filter != null)
    {
      IPin pin = null;
      pin = DsFindPin.ByCategory(filter, PinCategory.Capture, 0);
      if (pin != null)
      {
        IAMStreamConfig videoStreamConfig = pin as IAMStreamConfig;
        int count = 0, size = 0;
        int hr = videoStreamConfig.GetNumberOfCapabilities(out count, out size);
        DsError.ThrowExceptionForHR(hr);

        HashSet<VideoFormatDescription> sizes = new HashSet<VideoFormatDescription>(new VFDHelper());
        IntPtr pss = Marshal.AllocCoTaskMem(size);
        if (size == Marshal.SizeOf(typeof(VideoStreamConfigCaps)))
        {
          for (int i = 0; i < count; i++)
          {
            AMMediaType media;
            hr = videoStreamConfig.GetStreamCaps(i, out media, pss);
            VideoStreamConfigCaps vscc =
              (VideoStreamConfigCaps)Marshal.PtrToStructure(pss, typeof(VideoStreamConfigCaps));
            VideoFormatDescription vfd = new VideoFormatDescription();
            vfd.size = vscc.InputSize;
            vfd.minFps = DSHOW_ONE_SECOND_UNIT / vscc.MaxFrameInterval;
            vfd.maxFps = DSHOW_ONE_SECOND_UNIT / vscc.MinFrameInterval;
            sizes.Add(vfd);
            DsUtils.FreeAMMediaType(media);
          }
        }
        result = new VideoFormatDescription[sizes.Count];
        sizes.CopyTo(result);
        Marshal.ReleaseComObject(pin);
      }
      Marshal.ReleaseComObject(filter);
    }
    return result;
  }
Jan 17, 2014 at 3:02 PM
I am very interested in this code as I am having problems tracking down a way of getting a devices capabilities. I have a few questions tho

What is the constant DSHOW_ONE_SECOND_UNIT referring 2 and also what is the class VFDHelper
Jan 17, 2014 at 3:31 PM
figured out the constant and it seems to work fine if i just remove the call to VFDHelper

DSHOW_ONE_SECOND_UNIT = 10000000
Jan 17, 2014 at 6:47 PM
Edited Jan 17, 2014 at 9:11 PM
Yes you did get that constant right. I missed a few external dependencies in that code.
protected const long DSHOW_ONE_SECOND_UNIT = 10000000;  // One second in 100ns units
VFDHelper is a class that makes HashSet<VideoFormatDescription> not include duplicates. Here's the code:
  public class VFDHelper : IEqualityComparer<VideoFormatDescription>
  {
    public bool Equals(VideoFormatDescription a, VideoFormatDescription b)
    {
      return (a.size == b.size && a.minFps == b.minFps && a.maxFps == b.maxFps);
    }
    public int GetHashCode(VideoFormatDescription a)
    {
      return ((double)(a.size.Width * a.size.Height + a.minFps + a.maxFps)).GetHashCode();
    }
  }
Good luck and do post if you run into any more trouble.