使用DirectShow.NET获取摄像头视频流

我是研究僧i 提交于 2019-12-01 08:03:50

开源社区提供了DirectShow的.NET版本,为C#开发者提供了便利。这里分享下如何用DirectShow.NET API来启动摄像头,以及获取视频流数据。

参考原文:Read Barcode from Webcam Viewer with DirectShow.NET

作者:Xiao Ling

翻译:yushulx

学习资源

示例:获取视频流数据识别barcode

获取连接设备:

DsDevice[] devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

获取DirectShow接口:

int hr = 0;
 
this.graphBuilder = (IFilterGraph2)new FilterGraph();
this.captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
this.mediaControl = (IMediaControl)this.graphBuilder;
this.videoWindow = (IVideoWindow)this.graphBuilder;
DsError.ThrowExceptionForHR(hr);

把filter graph添加到capture graph中:

hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
DsError.ThrowExceptionForHR(hr);

绑定Moniker:

int hr = 0;
IEnumMoniker classEnum = null;
IMoniker[] moniker = new IMoniker[1];
object source = null;
 
// Create the system device enumerator
ICreateDevEnum devEnum = (ICreateDevEnum)new CreateDevEnum();
 
// Create an enumerator for the video capture devices
hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, 0);
DsError.ThrowExceptionForHR(hr);
 
// The device enumerator is no more needed
Marshal.ReleaseComObject(devEnum);
 
// If there are no enumerators for the requested type, then 
// CreateClassEnumerator will succeed, but classEnum will be NULL.
if (classEnum == null)
{
    throw new ApplicationException("No video capture device was detected.\r\n\r\n" +
                                   "This sample requires a video capture device, such as a USB WebCam,\r\n" +
                                   "to be installed and working properly.  The sample will now close.");
}
 
// Use the first video capture device on the device list.
// Note that if the Next() call succeeds but there are no monikers,
// it will return 1 (S_FALSE) (which is not a failure).  Therefore, we
// check that the return code is 0 (S_OK).
 
if (classEnum.Next(moniker.Length, moniker, IntPtr.Zero) == 0)
{
    // Bind Moniker to a filter object
    Guid iid = typeof(IBaseFilter).GUID;
    moniker[0].BindToObject(null, null, ref iid, out source);
}
else
{
    throw new ApplicationException("Unable to access video capture device!");
}
 
// Release COM objects
Marshal.ReleaseComObject(moniker[0]);
Marshal.ReleaseComObject(classEnum);
 
// An exception is thrown if cast fail
return (IBaseFilter)source;

把选择的设备添加到graph中:

hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
DsError.ThrowExceptionForHR(hr);

创建sampleGrabber来设置取视频流回调函数:

sampleGrabber = new SampleGrabber() as ISampleGrabber;
 
{
            AMMediaType media;
            int hr;
            // Set the media type to Video/RBG24
            media = new AMMediaType();
            media.majorType = MediaType.Video;
            media.subType = MediaSubType.RGB24;
            media.formatType = FormatType.VideoInfo;
            hr = sampleGrabber.SetMediaType(media);
            DsError.ThrowExceptionForHR(hr);
            DsUtils.FreeAMMediaType(media);
            media = null;
            hr = sampleGrabber.SetCallback(this, 1);
            DsError.ThrowExceptionForHR(hr);
}

把SampleGrabber添加到graph中:

hr = this.graphBuilder.AddFilter(sampleGrabber as IBaseFilter, "Frame Callback");
DsError.ThrowExceptionForHR(hr);

初始化视频属性:

private void SetConfigParams(ICaptureGraphBuilder2 capGraph, IBaseFilter capFilter, int iFrameRate, int iWidth, int iHeight)
        {
            int hr;
            object config;
            AMMediaType mediaType;
            // Find the stream config interface
            hr = capGraph.FindInterface(
                PinCategory.Capture, MediaType.Video, capFilter, typeof(IAMStreamConfig).GUID, out config);
 
            IAMStreamConfig videoStreamConfig = config as IAMStreamConfig;
            if (videoStreamConfig == null)
            {
                throw new Exception("Failed to get IAMStreamConfig");
            }
 
            // Get the existing format block
            hr = videoStreamConfig.GetFormat(out mediaType);
            DsError.ThrowExceptionForHR(hr);
 
            // copy out the videoinfoheader
            VideoInfoHeader videoInfoHeader = new VideoInfoHeader();
            Marshal.PtrToStructure(mediaType.formatPtr, videoInfoHeader);
 
            // if overriding the framerate, set the frame rate
            if (iFrameRate > 0)
            {
                videoInfoHeader.AvgTimePerFrame = 10000000 / iFrameRate;
            }
 
            // if overriding the width, set the width
            if (iWidth > 0)
            {
                videoInfoHeader.BmiHeader.Width = iWidth;
            }
 
            // if overriding the Height, set the Height
            if (iHeight > 0)
            {
                videoInfoHeader.BmiHeader.Height = iHeight;
            }
 
            // Copy the media structure back
            Marshal.StructureToPtr(videoInfoHeader, mediaType.formatPtr, false);
 
            // Set the new format
            hr = videoStreamConfig.SetFormat(mediaType);
            DsError.ThrowExceptionForHR(hr);
 
            DsUtils.FreeAMMediaType(mediaType);
            mediaType = null;
        }

绘制画面:

hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, (sampleGrabber as IBaseFilter), null);
DsError.ThrowExceptionForHR(hr);

设置视频输出窗口,调整视频位置:

 int hr = 0;
            // Set the video window to be a child of the PictureBox
            hr = this.videoWindow.put_Owner(pictureBox1.Handle);
            DsError.ThrowExceptionForHR(hr);
 
            hr = this.videoWindow.put_WindowStyle(WindowStyle.Child);
            DsError.ThrowExceptionForHR(hr);
 
            // Make the video window visible, now that it is properly positioned
            hr = this.videoWindow.put_Visible(OABool.True);
            DsError.ThrowExceptionForHR(hr);
 
            // Set the video position
            Rectangle rc = pictureBox1.ClientRectangle;
            hr = videoWindow.SetWindowPosition(0, 0, _previewWidth, _previewHeight);
            DsError.ThrowExceptionForHR(hr);

启动摄像头预览画面:

rot = new DsROTEntry(this.graphBuilder);
hr = this.mediaControl.Run();
DsError.ThrowExceptionForHR(hr);

获取视频流数据,异步读取barcode:

public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
        {
 
            Bitmap v = new Bitmap(_previewWidth, _previewHeight, _previewStride,
                PixelFormat.Format24bppRgb, pBuffer);
            v.RotateFlip(RotateFlipType.Rotate180FlipX);
 
            if (isFinished)
            {   
                this.BeginInvoke((MethodInvoker)delegate
                {
                    isFinished = false;
                    ReadBarcode(v);
                    isFinished = true;
                });
            }
            return 0;
        }

 

源码

https://github.com/yushulx/DirectShow.NET-Webcam-Barcode-Reader

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!