Setting the video capture format in DirectShow.NET

Here is one way to set the video capture format in the VideoRecorder sample (part of DVDBuilder.NET). Apart from the new code for setting the video capture format the only change in the original sample (in RecorderForm.cs) is that the video filters are connected later, i.e. AFTER the video capture format is set using the code below.

The following piece of code sets the format of the capture device to color space I420, frame size 640×480 and frame rate of 25 fps:

// BEGIN: set video capture parameters
/* NOTE: at this point the video filters are in the graph but they are not connected:
 [smart tee]  
After the video capture format is set the filters will be connected manually
*/
hr = ms.captureGraph.FindInterface(PinCategory.Capture, MediaType.Video,
                        ms.videoInput, streamConfigId, out videoConfigObj);
DsError.ThrowExceptionForHR(hr);
videoConfig = videoConfigObj as IAMStreamConfig;
if (null == videoConfig)
   throw new COMException(“Cannot obtain IAMStreamConfig”);

// enumerate the capabilities of the video capture device
// This code looks for a specific video format:
// colorspace I420, frame dimensions 640×480, frame rate of 25 fps
int capsCount, capSize;
hr = videoConfig.GetNumberOfCapabilities(out capsCount, out capSize);
DsError.ThrowExceptionForHR(hr);

VideoInfoHeader vih = new VideoInfoHeader();
VideoStreamConfigCaps vsc = new VideoStreamConfigCaps();
IntPtr pSC = Marshal.AllocHGlobal(capSize);
AMMediaType mt = null;
int videoFormatIndex = -1;
long frameInterval = 10000000 / 25; // 25 fps

for (int i = 0; i < capsCount; ++i)
{
   // the video format is described in AMMediaType and VideoStreamConfigCaps
   hr = videoConfig.GetStreamCaps(i, out mt, pSC);
   DsError.ThrowExceptionForHR(hr);

   // copy the unmanaged structures to managed in order to check the format
   Marshal.PtrToStructure(mt.formatPtr, vih);
   Marshal.PtrToStructure(pSC, vsc);

   // log the video format
   string capline = String.Format(“width:{0} height:{1} fps (min-max): {2}-{3}”,
                 vih.BmiHeader.Width, vih.BmiHeader.Height,
                 10000000 / vsc.MaxFrameInterval,
                 10000000 / vsc.MinFrameInterval);
    Debug.WriteLine(capline);

    // check colorspace
    if (mt.subType == DirectShowLib.MediaSubType.I420)
    {
       // the video format has a range of supported frame rates (min-max)
       // check the required frame rate and frame size
       if (vih.BmiHeader.Width == 640 &&
           vih.BmiHeader.Height == 480 &&
           vsc.MinFrameInterval = frameInterval)
       {
          // remember the index of the video format that we’ll use
          videoFormatIndex = i;
       }
    }
    DsUtils.FreeAMMediaType(mt);
 }

 // set the desired format to the video capture device
 if (videoFormatIndex != -1)
 {
    hr = videoConfig.GetStreamCaps(videoFormatIndex, out mt, pSC);
    DsError.ThrowExceptionForHR(hr);
    // explicitly set the framerate since the default may not what we want
    Marshal.PtrToStructure(mt.formatPtr, vih);
    vih.AvgTimePerFrame = frameInterval;
    Marshal.StructureToPtr(vih, mt.formatPtr, false);
    hr = videoConfig.SetFormat(mt);
    DsError.ThrowExceptionForHR(hr);
    DsUtils.FreeAMMediaType(mt);
 }

 Marshal.FreeHGlobal(pSC);
 // END: set video capture parameters

This is just a sample that shows how to set the capture format. However the device may not support the required format (I420, 640x480, 25 fps). In a real-world scenario the code should look for the closest (but not exact) match or probably provide a choice among several supported formats.


Blog Comments powered by Disqus.

Search