開源社區提供了DirectShow的.NET版本,爲C#開發者提供了便利。這裏分享下如何用DirectShow.NET API來啓動攝像頭,以及獲取視頻流數據。html
參考原文:Read Barcode from Webcam Viewer with DirectShow.NETgit
做者:Xiao Linggithub
翻譯:yushulxweb
獲取鏈接設備:異步
DsDevice[] devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
獲取DirectShow接口:ide
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中:ui
hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture"); DsError.ThrowExceptionForHR(hr);
建立sampleGrabber來設置取視頻流回調函數:this
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