Recently, I wanted to migrate the winform program that took photos of a USB camera to .net 5. First, I found it. There are examples of reading cameras on the Internet.Read Barcode from Webcam Viewer with 。
This program relies on, although it is from the .net framework version. I tried it and there was no obstacle to migration to .net 5. But I think these original APIs are still not very convenient to use, so I continued to search and found a simpler class
class UsbCamera:IDisposable { /// <summary>Usb camera image size.</summary> public Size Size { get; private set; } /// <summary>Start.</summary> public Action Start { get; private set; } /// <summary>Stop.</summary> public Action Stop { get; private set; } /// <summary>Release resource.</summary> public Action Release { get; private set; } /// <summary>Get image.</summary> /// <remarks>Immediately after starting, fails because image buffer is not prepared yet.</remarks> public Func<Bitmap> GetBitmap { get; private set; } /// <summary> /// Get available USB camera list. /// </summary> /// <returns>Array of camera name, or if no device found, zero length array.</returns> public static string[] FindDevices() { return (.CLSID_VideoInputDeviceCategory).ToArray(); } /// <summary> /// Get video formats. /// </summary> public static VideoFormat[] GetVideoFormat(int cameraIndex) { var filter = (.CLSID_VideoInputDeviceCategory, cameraIndex); var pin = (filter, 0, DirectShow.PIN_DIRECTION.PINDIR_OUTPUT); return GetVideoOutputFormat(pin); } /// <summary> /// Create USB Camera. If device do not support the size, default size will applied. /// </summary> /// <param name="cameraIndex">Camera index in FindDevices() result.</param> /// <param name="size"> /// Size you want to create. Normally use Size property of VideoFormat in GetVideoFormat() result. /// </param> public UsbCamera(int cameraIndex, Size size) : this(cameraIndex, new VideoFormat() { Size = size }) { } /// <summary> /// Create USB Camera. If device do not support the format, default format will applied. /// </summary> /// <param name="cameraIndex">Camera index in FindDevices() result.</param> /// <param name="format"> /// Normally use GetVideoFormat() result. /// You can change TimePerFrame value from to . /// TimePerFrame = 10,000,000 / frame duration. (ex: 333333 in case 30fps). /// You can change Size value in case > and OutputGranularityX/Y is not zero. /// Size = any value from to step with OutputGranularityX/Y. /// </param> public UsbCamera(int cameraIndex, VideoFormat format) { var camera_list = FindDevices(); if (cameraIndex >= camera_list.Length) throw new ArgumentException("USB camera is not available.", "cameraIndex"); Init(cameraIndex, format); } private void Init(int index, VideoFormat format) { //---------------------------------- // Create Filter Graph //---------------------------------- // +--------------------+ +----------------+ +---------------+ // |Video Capture Source|→| Sample Grabber |→| Null Renderer | // +--------------------+ +----------------+ +---------------+ // ↓GetBitmap() var graph = (); //---------------------------------- // VideoCaptureSource //---------------------------------- var vcap_source = CreateVideoCaptureSource(index, format); (vcap_source, "VideoCapture"); //------------------------------ // SampleGrabber //------------------------------ var grabber = CreateSampleGrabber(); (grabber, "SampleGrabber"); var i_grabber = ()grabber; i_grabber.SetBufferSamples(true); //--------------------------------------------------- // Null Renderer //--------------------------------------------------- var renderer = (.CLSID_NullRenderer) as ; (renderer, "NullRenderer"); //--------------------------------------------------- // Create Filter Graph //--------------------------------------------------- var builder = (.CLSID_CaptureGraphBuilder2) as DirectShow.ICaptureGraphBuilder2; (graph); var pinCategory = .PIN_CATEGORY_CAPTURE; var mediaType = .MEDIATYPE_Video; (ref pinCategory, ref mediaType, vcap_source, grabber, renderer); // SampleGrabber Format. { var mt = new DirectShow.AM_MEDIA_TYPE(); i_grabber.GetConnectedMediaType(mt); var header = ()(, typeof()); var width = ; var height = ; var stride = width * ( / 8); (ref mt); Size = new Size(width, height); // fix screen tearing problem(issure #2) // you can use previous method if you swap the comment line below. // GetBitmap = () => GetBitmapFromSampleGrabberBuffer(i_grabber, width, height, stride); GetBitmap = GetBitmapFromSampleGrabberCallback(i_grabber, width, height, stride); } // Assign Delegates. Start = () => (graph, DirectShow.FILTER_STATE.Running); Stop = () => (graph, DirectShow.FILTER_STATE.Stopped); Release = () => { Stop(); (ref i_grabber); (ref builder); (ref graph); }; // Properties. Properties = new PropertyItems(vcap_source); } public void Dispose() { Release?.Invoke(); } /// <summary>Properties user can adjust.</summary> public PropertyItems Properties { get; private set; } public class PropertyItems { public PropertyItems( vcap_source) { // Pan, Tilt, Roll, Zoom, Exposure, Iris, Focus = (typeof()).Cast<>() .Select(item => { prop = null; try { var cam_ctrl = vcap_source as ; if (cam_ctrl == null) throw new NotSupportedException("no IAMCameraControl Interface."); // will catched. int min = 0, max = 0, step = 0, def = 0, flags = 0; cam_ctrl.GetRange(item, ref min, ref max, ref step, ref def, ref flags); // COMException if not supports. prop = new Property(min, max, step, def, flags, (flag, value) => cam_ctrl.Set(item, value, (int)flag)); } catch (Exception) { prop = new Property(); } // available = false return new { Key = item, Value = prop }; }).ToDictionary(x => , x => ); // Brightness, Contrast, Hue, Saturation, Sharpness, Gamma, ColorEnable, WhiteBalance, BacklightCompensation, Gain = (typeof()).Cast<>() .Select(item => { prop = null; try { var vid_ctrl = vcap_source as ; if (vid_ctrl == null) throw new NotSupportedException("no IAMVideoProcAmp Interface."); // will catched. int min = 0, max = 0, step = 0, def = 0, flags = 0; vid_ctrl.GetRange(item, ref min, ref max, ref step, ref def, ref flags); // COMException if not supports. prop = new Property(min, max, step, def, flags, (flag, value) => vid_ctrl.Set(item, value, (int)flag)); } catch (Exception) { prop = new Property(); } // available = false return new { Key = item, Value = prop }; }).ToDictionary(x => , x => ); } /// <summary>Camera Control properties.</summary> private Dictionary<, Property> CameraControl; /// <summary>Video Processing Amplifier properties.</summary> private Dictionary<, Property> VideoProcAmp; /// <summary>Get CameraControl Property. Check Available before use.</summary> public Property this[ item] { get { return CameraControl[item]; } } /// <summary>Get VideoProcAmp Property. Check Available before use.</summary> public Property this[ item] { get { return VideoProcAmp[item]; } } public class Property { public int Min { get; private set; } public int Max { get; private set; } public int Step { get; private set; } public int Default { get; private set; } public Flags { get; private set; } public Action<, int> SetValue { get; private set; } public bool Available { get; private set; } public bool CanAuto { get; private set; } public Property() { = (flag, value) => { }; = false; } public Property(int min, int max, int step, int @default, int flags, Action<, int> set) { = min; = max; = step; = @default; = ()flags; = (Flags & ) == ; = set; = true; } public override string ToString() { return ("Available={0}, Min={1}, Max={2}, Step={3}, Default={4}, Flags={5}", Available, Min, Max, Step, Default, Flags); } } } private class SampleGrabberCallback : { private byte[] Buffer; private object BufferLock = new object(); public Bitmap GetBitmap(int width, int height, int stride) { var result = new Bitmap(width, height, .Format24bppRgb); if (Buffer == null) return result; var bmp_data = (new Rectangle(, ), , .Format24bppRgb); lock (BufferLock) { // copy from last row. for (int y = 0; y < height; y++) { var src_idx = - (stride * (y + 1)); var dst = (bmp_data.Scan0, stride * y); (Buffer, src_idx, dst, stride); } } (bmp_data); return result; } // called when each sample completed. // The data processing thread blocks until the callback method returns. If the callback does not return quickly, it can interfere with playback. public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen) { if (Buffer == null || != BufferLen) { Buffer = new byte[BufferLen]; } lock (BufferLock) { (pBuffer, Buffer, 0, BufferLen); } return 0; } // never called. public int SampleCB(double SampleTime, pSample) { throw new NotImplementedException(); } } private Func<Bitmap> GetBitmapFromSampleGrabberCallback( i_grabber, int width, int height, int stride) { var sampler = new SampleGrabberCallback(); i_grabber.SetCallback(sampler, 1); // WhichMethodToCallback = BufferCB return () => (width, height, stride); } /// <summary>Get Bitmap from Sample Grabber Current Buffer</summary> private Bitmap GetBitmapFromSampleGrabberBuffer( i_grabber, int width, int height, int stride) { try { return GetBitmapFromSampleGrabberBufferMain(i_grabber, width, height, stride); } catch (COMException ex) { const uint VFW_E_WRONG_STATE = 0x80040227; if ((uint) == VFW_E_WRONG_STATE) { // image data is not ready yet. return empty bitmap. return new Bitmap(width, height); } throw; } } /// <summary>Get Bitmap from Sample Grabber Current Buffer</summary> private Bitmap GetBitmapFromSampleGrabberBufferMain( i_grabber, int width, int height, int stride) { int sz = 0; i_grabber.GetCurrentBuffer(ref sz, ); // Get it if (sz == 0) return null; var ptr = (sz); i_grabber.GetCurrentBuffer(ref sz, ptr); var data = new byte[sz]; (ptr, data, 0, sz); var result = new Bitmap(width, height, .Format24bppRgb); var bmp_data = (new Rectangle(, ), , .Format24bppRgb); for (int y = 0; y < height; y++) { var src_idx = sz - (stride * (y + 1)); var dst = (bmp_data.Scan0, stride * y); (data, src_idx, dst, stride); } (bmp_data); (ptr); return result; } private CreateSampleGrabber() { var filter = (.CLSID_SampleGrabber); var ismp = filter as ; var mt = new DirectShow.AM_MEDIA_TYPE(); = .MEDIATYPE_Video; = .MEDIASUBTYPE_RGB24; (mt); return filter; } /// <summary> /// Video Capture Source made by フィルタをする /// </summary> private CreateVideoCaptureSource(int index, VideoFormat format) { var filter = (.CLSID_VideoInputDeviceCategory, index); var pin = (filter, 0, DirectShow.PIN_DIRECTION.PINDIR_OUTPUT); SetVideoOutputFormat(pin, format); return filter; } /// <summary> /// Select the power mode. /// </summary> private static void SetVideoOutputFormat( pin, VideoFormat format) { var formats = GetVideoOutputFormat(pin); for (int i = 0; i < ; i++) { var item = formats[i]; if ( != (.MEDIATYPE_Video)) continue; if (() == false && != ) continue; if ( != .FORMAT_VideoInfo) continue; if ( == && == ) { SetVideoOutputFormat(pin, i, , ); return; } } // Not found fixed size, search for variable size. for (int i = 0; i < ; i++) { var item = formats[i]; if ( != (.MEDIATYPE_Video)) continue; if (() == false && != ) continue; if ( != .FORMAT_VideoInfo) continue; if ( == 0) continue; if ( == 0) continue; for (int w = ; w < ; w += ) { for (int h = ; h < ; h += ) { if (w == && h == ) { SetVideoOutputFormat(pin, i, , ); return; } } } } // Not found, use default size. SetVideoOutputFormat(pin, 0, , 0); } private static VideoFormat[] GetVideoOutputFormat( pin) { var config = pin as ; if (config == null) { throw new InvalidOperationException("no IAMStreamConfig interface."); } int cap_count = 0, cap_size = 0; (ref cap_count, ref cap_size); if (cap_size != (typeof(DirectShow.VIDEO_STREAM_CONFIG_CAPS))) { throw new InvalidOperationException("no VIDEO_STREAM_CONFIG_CAPS."); } var result = new VideoFormat[cap_count]; var cap_data = (cap_size); for (int i = 0; i < cap_count; i++) { var entry = new VideoFormat(); DirectShow.AM_MEDIA_TYPE mt = null; (i, ref mt, cap_data); = PtrToStructure<DirectShow.VIDEO_STREAM_CONFIG_CAPS>(cap_data); = (); = (); if ( == .FORMAT_VideoInfo) { var vinfo = PtrToStructure<>(); = new Size(, ); = ; } else if ( == .FORMAT_VideoInfo2) { var vinfo = PtrToStructure<DirectShow.VIDEOINFOHEADER2>(); = new Size(, ); = ; } // Liberation (ref mt); result[i] = entry; } // Liberation (cap_data); return result; } private static void SetVideoOutputFormat( pin, int index, Size size, long timePerFrame) { var config = pin as ; if (config == null) { throw new InvalidOperationException("no IAMStreamConfig interface."); } int cap_count = 0, cap_size = 0; (ref cap_count, ref cap_size); if (cap_size != (typeof(DirectShow.VIDEO_STREAM_CONFIG_CAPS))) { throw new InvalidOperationException("no VIDEO_STREAM_CONFIG_CAPS."); } var cap_data = (cap_size); DirectShow.AM_MEDIA_TYPE mt = null; (index, ref mt, cap_data); var cap = PtrToStructure<DirectShow.VIDEO_STREAM_CONFIG_CAPS>(cap_data); if ( == .FORMAT_VideoInfo) { var vinfo = PtrToStructure<>(); if (!) { = ; = ; } if (timePerFrame > 0) { = timePerFrame; } (vinfo, , true); } else if ( == .FORMAT_VideoInfo2) { var vinfo = PtrToStructure<DirectShow.VIDEOINFOHEADER2>(); if (!) { = ; = ; } if (timePerFrame > 0) { = timePerFrame; } (vinfo, , true); } (mt); if (cap_data != ) (cap_data); if (mt != null) (ref mt); } private static T PtrToStructure<T>(IntPtr ptr) { return (T)(ptr, typeof(T)); } public class VideoFormat { public string MajorType { get; set; } public string SubType { get; set; } public Size Size { get; set; } public long TimePerFrame { get; set; } public DirectShow.VIDEO_STREAM_CONFIG_CAPS Caps { get; set; } public override string ToString() { return ("{0}, {1}, {2}, {3}, {4}", MajorType, SubType, Size, TimePerFrame, CapsString()); } private string CapsString() { var sb = new StringBuilder(); ("{0}, ", ()); foreach (var info in ().GetFields()) { ("{0}={1}, ", , (Caps)); } return (); } } public static class DirectShow { #region Function public static object CoCreateInstance(Guid clsid) { return ((clsid)); } public static void ReleaseInstance<T>(ref T com) where T : class { if (com != null) { (com); com = null; } } public static IGraphBuilder CreateGraph() { return CoCreateInstance(DsGuid.CLSID_FilterGraph) as IGraphBuilder; } public static void PlayGraph(IGraphBuilder graph, FILTER_STATE state) { var mediaControl = graph as IMediaControl; if (mediaControl == null) return; switch (state) { case FILTER_STATE.Paused: (); break; case FILTER_STATE.Stopped: (); break; default: (); break; } } public static List<string> GetFiltes(Guid category) { var result = new List<string>(); EnumMonikers(category, (moniker, prop) => { object value = null; ("FriendlyName", ref value, 0); var name = (string)value; (name); return false; //Online. }); return result; } public static IBaseFilter CreateFilter(Guid clsid) { return CoCreateInstance(clsid) as IBaseFilter; } public static IBaseFilter CreateFilter(Guid category, int index) { IBaseFilter result = null; int curr_index = 0; EnumMonikers(category, (moniker, prop) => { if (index != curr_index++) return false; { object value = null; Guid guid = .IID_IBaseFilter; (null, null, ref guid, out value); result = value as IBaseFilter; return true; } }); if (result == null) throw new ArgumentException("can't create filter."); return result; } private static void EnumMonikers(Guid category, Func<IMoniker, IPropertyBag, bool> func) { IEnumMoniker enumerator = null; ICreateDevEnum device = null; try { device = (ICreateDevEnum)((DsGuid.CLSID_SystemDeviceEnum)); (ref category, ref enumerator, 0); if (enumerator == null) return; var monikers = new IMoniker[1]; var fetched = ; while ((, monikers, fetched) == 0) { var moniker = monikers[0]; object value = null; Guid guid = DsGuid.IID_IPropertyBag; (null, null, ref guid, out value); var prop = (IPropertyBag)value; try { var rc = func(moniker, prop); if (rc == true) break; } finally { (prop); if (moniker != null) (moniker); } } } finally { if (enumerator != null) (enumerator); if (device != null) (device); } } public static IPin FindPin(IBaseFilter filter, string name) { var result = EnumPins(filter, (info) => { return ( == name); }); if (result == null) throw new ArgumentException("can't fild pin."); return result; } public static IPin FindPin(IBaseFilter filter, int index, PIN_DIRECTION direction) { int curr_index = 0; var result = EnumPins(filter, (info) => { if ( != direction) return false; return (index == curr_index++); }); if (result == null) throw new ArgumentException("can't fild pin."); return result; } private static IPin EnumPins(IBaseFilter filter, Func<PIN_INFO, bool> func) { IEnumPins pins = null; IPin ipin = null; try { (ref pins); int fetched = 0; while ((1, ref ipin, ref fetched) == 0) { if (fetched == 0) break; var info = new PIN_INFO(); try { (info); var rc = func(info); if (rc) return ipin; } finally { if ( != null) (); } } } catch { if (ipin != null) (ipin); throw; } finally { if (pins != null) (pins); } return null; } public static void ConnectFilter(IGraphBuilder graph, IBaseFilter out_flt, int out_no, IBaseFilter in_flt, int in_no) { var out_pin = FindPin(out_flt, out_no, PIN_DIRECTION.PINDIR_OUTPUT); var inp_pin = FindPin(in_flt, in_no, PIN_DIRECTION.PINDIR_INPUT); (out_pin, inp_pin); } public static void DeleteMediaType(ref AM_MEDIA_TYPE mt) { if ( != 0) (); if ( != ) (); mt = null; } #endregion #region Interface [ComVisible(true), ComImport(), Guid("56a8689f-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IFilterGraph { int AddFilter([In] IBaseFilter pFilter, [In, MarshalAs()] string pName); int RemoveFilter([In] IBaseFilter pFilter); int EnumFilters([In, Out] ref IEnumFilters ppEnum); int FindFilterByName([In, MarshalAs()] string pName, [In, Out] ref IBaseFilter ppFilter); int ConnectDirect([In] IPin ppinOut, [In] IPin ppinIn, [In, MarshalAs()] AM_MEDIA_TYPE pmt); int Reconnect([In] IPin ppin); int Disconnect([In] IPin ppin); int SetDefaultSyncSource(); } [ComVisible(true), ComImport(), Guid("56a868a9-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IGraphBuilder : IFilterGraph { int Connect([In] IPin ppinOut, [In] IPin ppinIn); int Render([In] IPin ppinOut); int RenderFile([In, MarshalAs()] string lpcwstrFile, [In, MarshalAs()] string lpcwstrPlayList); int AddSourceFilter([In, MarshalAs()] string lpcwstrFileName, [In, MarshalAs()] string lpcwstrFilterName, [In, Out] ref IBaseFilter ppFilter); int SetLogFile(IntPtr hFile); int Abort(); int ShouldOperationContinue(); } [ComVisible(true), ComImport(), Guid("56a868b1-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IMediaControl { int Run(); int Pause(); int Stop(); int GetState(int msTimeout, out int pfs); int RenderFile(string strFilename); int AddSourceFilter([In] string strFilename, [In, Out, MarshalAs()] ref object ppUnk); int get_FilterCollection([In, Out, MarshalAs()] ref object ppUnk); int get_RegFilterCollection([In, Out, MarshalAs()] ref object ppUnk); int StopWhenReady(); } [ComVisible(true), ComImport(), Guid("93E5A4E0-2D50-11d2-ABFA-00A0C9C6E38D"), InterfaceType()] public interface ICaptureGraphBuilder2 { int SetFiltergraph([In] IGraphBuilder pfg); int GetFiltergraph([In, Out] ref IGraphBuilder ppfg); int SetOutputFileName([In] ref Guid pType, [In, MarshalAs()] string lpstrFile, [In, Out] ref IBaseFilter ppbf, [In, Out] ref IFileSinkFilter ppSink); int FindInterface([In] ref Guid pCategory, [In] ref Guid pType, [In] IBaseFilter pbf, [In] IntPtr riid, [In, Out, MarshalAs()] ref object ppint); int RenderStream([In] ref Guid pCategory, [In] ref Guid pType, [In, MarshalAs()] object pSource, [In] IBaseFilter pfCompressor, [In] IBaseFilter pfRenderer); int ControlStream([In] ref Guid pCategory, [In] ref Guid pType, [In] IBaseFilter pFilter, [In] IntPtr pstart, [In] IntPtr pstop, [In] short wStartCookie, [In] short wStopCookie); int AllocCapFile([In, MarshalAs()] string lpstrFile, [In] long dwlSize); int CopyCaptureFile([In, MarshalAs()] string lpwstrOld, [In, MarshalAs()] string lpwstrNew, [In] int fAllowEscAbort, [In] IAMCopyCaptureFileProgress pFilter); int FindPin([In] object pSource, [In] int pindir, [In] ref Guid pCategory, [In] ref Guid pType, [In, MarshalAs()] bool fUnconnected, [In] int num, [Out] out IntPtr ppPin); } [ComVisible(true), ComImport(), Guid("a2104830-7c70-11cf-8bce-00aa00a3f1a6"), InterfaceType()] public interface IFileSinkFilter { int SetFileName([In, MarshalAs()] string pszFileName, [In, MarshalAs()] AM_MEDIA_TYPE pmt); int GetCurFile([In, Out, MarshalAs()] ref string pszFileName, [Out, MarshalAs()] out AM_MEDIA_TYPE pmt); } [ComVisible(true), ComImport(), Guid("670d1d20-a068-11d0-b3f0-00aa003761c5"), InterfaceType()] public interface IAMCopyCaptureFileProgress { int Progress(int iProgress); } [ComVisible(true), ComImport(), Guid("C6E13370-30AC-11d0-A18C-00A0C9118956"), InterfaceType()] public interface IAMCameraControl { int GetRange([In] CameraControlProperty Property, [In, Out] ref int pMin, [In, Out] ref int pMax, [In, Out] ref int pSteppingDelta, [In, Out] ref int pDefault, [In, Out] ref int pCapsFlag); int Set([In] CameraControlProperty Property, [In] int lValue, [In] int Flags); int Get([In] CameraControlProperty Property, [In, Out] ref int lValue, [In, Out] ref int Flags); } [ComVisible(true), ComImport(), Guid("C6E13360-30AC-11d0-A18C-00A0C9118956"), InterfaceType()] public interface IAMVideoProcAmp { int GetRange([In] VideoProcAmpProperty Property, [In, Out] ref int pMin, [In, Out] ref int pMax, [In, Out] ref int pSteppingDelta, [In, Out] ref int pDefault, [In, Out] ref int pCapsFlag); int Set([In] VideoProcAmpProperty Property, [In] int lValue, [In] int Flags); int Get([In] VideoProcAmpProperty Property, [In, Out] ref int lValue, [In, Out] ref int Flags); } [ComVisible(true), ComImport(), Guid("6A2E0670-28E4-11D0-A18C-00A0C9118956"), , InterfaceType()] public interface IAMVideoControl { int GetCaps([In] IPin pPin, [Out] out int pCapsFlags); int SetMode([In] IPin pPin, [In] int Mode); int GetMode([In] IPin pPin, [Out] out int Mode); int GetCurrentActualFrameRate([In] IPin pPin, [Out] out long ActualFrameRate); int GetMaxAvailableFrameRate([In] IPin pPin, [In] int iIndex, [In] Size Dimensions, [Out] out long MaxAvailableFrameRate); int GetFrameRateList([In] IPin pPin, [In] int iIndex, [In] Size Dimensions, [Out] out int ListSize, [Out] out IntPtr FrameRates); } [ComVisible(true), ComImport(), Guid("56a86895-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IBaseFilter { // Inherits IPersist int GetClassID([Out] out Guid pClassID); // Inherits IMediaControl int Stop(); int Pause(); int Run(long tStart); int GetState(int dwMilliSecsTimeout, [In, Out] ref int filtState); int SetSyncSource([In] IReferenceClock pClock); int GetSyncSource([In, Out] ref IReferenceClock pClock); // ----- int EnumPins([In, Out] ref IEnumPins ppEnum); int FindPin([In, MarshalAs()] string Id, [In, Out] ref IPin ppPin); int QueryFilterInfo([Out] FILTER_INFO pInfo); int JoinFilterGraph([In] IFilterGraph pGraph, [In, MarshalAs()] string pName); int QueryVendorInfo([In, Out, MarshalAs()] ref string pVendorInfo); } [ComVisible(true), ComImport(), Guid("56a86893-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IEnumFilters { int Next([In] int cFilters, [In, Out] ref IBaseFilter ppFilter, [In, Out] ref int pcFetched); int Skip([In] int cFilters); void Reset(); void Clone([In, Out] ref IEnumFilters ppEnum); } [ComVisible(true), ComImport(), Guid("C6E13340-30AC-11d0-A18C-00A0C9118956"), InterfaceType()] public interface IAMStreamConfig { int SetFormat([In, MarshalAs()] AM_MEDIA_TYPE pmt); int GetFormat([In, Out, MarshalAs()] ref AM_MEDIA_TYPE ppmt); int GetNumberOfCapabilities(ref int piCount, ref int piSize); int GetStreamCaps(int iIndex, [In, Out, MarshalAs()] ref AM_MEDIA_TYPE ppmt, IntPtr pSCC); } [ComVisible(true), ComImport(), Guid("56a8689a-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IMediaSample { int GetPointer(ref IntPtr ppBuffer); int GetSize(); int GetTime(ref long pTimeStart, ref long pTimeEnd); int SetTime([In, MarshalAs()] UInt64 pTimeStart, [In, MarshalAs()] UInt64 pTimeEnd); int IsSyncPoint(); int SetSyncPoint([In, MarshalAs()] bool bIsSyncPoint); int IsPreroll(); int SetPreroll([In, MarshalAs()] bool bIsPreroll); int GetActualDataLength(); int SetActualDataLength(int len); int GetMediaType([In, Out, MarshalAs()] ref AM_MEDIA_TYPE ppMediaType); int SetMediaType([In, MarshalAs()] AM_MEDIA_TYPE pMediaType); int IsDiscontinuity(); int SetDiscontinuity([In, MarshalAs()] bool bDiscontinuity); int GetMediaTime(ref long pTimeStart, ref long pTimeEnd); int SetMediaTime([In, MarshalAs()] UInt64 pTimeStart, [In, MarshalAs()] UInt64 pTimeEnd); } [ComVisible(true), ComImport(), Guid("89c31040-846b-11ce-97d3-00aa0055595a"), InterfaceType()] public interface IEnumMediaTypes { int Next([In] int cMediaTypes, [In, Out, MarshalAs()] ref AM_MEDIA_TYPE ppMediaTypes, [In, Out] ref int pcFetched); int Skip([In] int cMediaTypes); int Reset(); int Clone([In, Out] ref IEnumMediaTypes ppEnum); } [ComVisible(true), ComImport(), Guid("56a86891-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IPin { int Connect([In] IPin pReceivePin, [In, MarshalAs()] AM_MEDIA_TYPE pmt); int ReceiveConnection([In] IPin pReceivePin, [In, MarshalAs()] AM_MEDIA_TYPE pmt); int Disconnect(); int ConnectedTo([In, Out] ref IPin ppPin); int ConnectionMediaType([Out, MarshalAs()] AM_MEDIA_TYPE pmt); int QueryPinInfo([Out] PIN_INFO pInfo); int QueryDirection(ref PIN_DIRECTION pPinDir); int QueryId([In, Out, MarshalAs()] ref string Id); int QueryAccept([In, MarshalAs()] AM_MEDIA_TYPE pmt); int EnumMediaTypes([In, Out] ref IEnumMediaTypes ppEnum); int QueryInternalConnections(IntPtr apPin, [In, Out] ref int nPin); int EndOfStream(); int BeginFlush(); int EndFlush(); int NewSegment(long tStart, long tStop, double dRate); } [ComVisible(true), ComImport(), Guid("56a86892-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IEnumPins { int Next([In] int cPins, [In, Out] ref IPin ppPins, [In, Out] ref int pcFetched); int Skip([In] int cPins); void Reset(); void Clone([In, Out] ref IEnumPins ppEnum); } [ComVisible(true), ComImport(), Guid("56a86897-0ad4-11ce-b03a-0020af0ba770"), InterfaceType()] public interface IReferenceClock { int GetTime(ref long pTime); int AdviseTime(long baseTime, long streamTime, IntPtr hEvent, ref int pdwAdviseCookie); int AdvisePeriodic(long startTime, long periodTime, IntPtr hSemaphore, ref int pdwAdviseCookie); int Unadvise(int dwAdviseCookie); } [ComVisible(true), ComImport(), Guid("29840822-5B84-11D0-BD3B-00A0C911CE86"), InterfaceType()] public interface ICreateDevEnum { int CreateClassEnumerator([In] ref Guid pType, [In, Out] ref ppEnumMoniker, [In] int dwFlags); } [ComVisible(true), ComImport(), Guid("55272A00-42CB-11CE-8135-00AA004BB851"), InterfaceType()] public interface IPropertyBag { int Read([MarshalAs()] string PropName, ref object Var, int ErrorLog); int Write(string PropName, ref object Var); } [ComVisible(true), ComImport(), Guid("6B652FFF-11FE-4fce-92AD-0266B5D7C78F"), InterfaceType()] public interface ISampleGrabber { int SetOneShot([In, MarshalAs()] bool OneShot); int SetMediaType([In, MarshalAs()] AM_MEDIA_TYPE pmt); int GetConnectedMediaType([Out, MarshalAs()] AM_MEDIA_TYPE pmt); int SetBufferSamples([In, MarshalAs()] bool BufferThem); int GetCurrentBuffer(ref int pBufferSize, IntPtr pBuffer); int GetCurrentSample(IntPtr ppSample); int SetCallback(ISampleGrabberCB pCallback, int WhichMethodToCallback); } [ComVisible(true), ComImport(), Guid("0579154A-2B53-4994-B0D0-E773148EFF85"), InterfaceType()] public interface ISampleGrabberCB { [PreserveSig()] int SampleCB(double SampleTime, IMediaSample pSample); [PreserveSig()] int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen); } #endregion #region Structure [Serializable] [StructLayout(), ComVisible(false)] public class AM_MEDIA_TYPE { public Guid MajorType; public Guid SubType; [MarshalAs()] public bool bFixedSizeSamples; [MarshalAs()] public bool bTemporalCompression; public uint lSampleSize; public Guid FormatType; public IntPtr pUnk; public uint cbFormat; public IntPtr pbFormat; } [Serializable] [StructLayout(, CharSet = ), ComVisible(false)] public class FILTER_INFO { [MarshalAs(, SizeConst = 128)] public string achName; [MarshalAs()] public object pGraph; } [Serializable] [StructLayout(, CharSet = ), ComVisible(false)] public class PIN_INFO { public IBaseFilter pFilter; public PIN_DIRECTION dir; [MarshalAs(, SizeConst = 128)] public string achName; } [Serializable] [StructLayout(, Pack = 8), ComVisible(false)] public struct VIDEO_STREAM_CONFIG_CAPS { public Guid Guid; public uint VideoStandard; public SIZE InputSize; public SIZE MinCroppingSize; public SIZE MaxCroppingSize; public int CropGranularityX; public int CropGranularityY; public int CropAlignX; public int CropAlignY; public SIZE MinOutputSize; public SIZE MaxOutputSize; public int OutputGranularityX; public int OutputGranularityY; public int StretchTapsX; public int StretchTapsY; public int ShrinkTapsX; public int ShrinkTapsY; public long MinFrameInterval; public long MaxFrameInterval; public int MinBitsPerSecond; public int MaxBitsPerSecond; } [Serializable] [StructLayout(), ComVisible(false)] public struct VIDEOINFOHEADER { public RECT SrcRect; public RECT TrgRect; public int BitRate; public int BitErrorRate; public long AvgTimePerFrame; public BITMAPINFOHEADER bmiHeader; } [Serializable] [StructLayout(), ComVisible(false)] public struct VIDEOINFOHEADER2 { public RECT SrcRect; public RECT TrgRect; public int BitRate; public int BitErrorRate; public long AvgTimePerFrame; public int InterlaceFlags; public int CopyProtectFlags; public int PictAspectRatioX; public int PictAspectRatioY; public int ControlFlags; // or Reserved1 public int Reserved2; public BITMAPINFOHEADER bmiHeader; } [Serializable] [StructLayout(, Pack = 2), ComVisible(false)] public struct BITMAPINFOHEADER { public int biSize; public int biWidth; public int biHeight; public short biPlanes; public short biBitCount; public int biCompression; public int biSizeImage; public int biXPelsPerMeter; public int biYPelsPerMeter; public int biClrUsed; public int biClrImportant; } [Serializable] [StructLayout(), ComVisible(false)] public struct WAVEFORMATEX { public ushort wFormatTag; public ushort nChannels; public uint nSamplesPerSec; public uint nAvgBytesPerSec; public short nBlockAlign; public short wBitsPerSample; public short cbSize; } [Serializable] [StructLayout(, Pack = 8), ComVisible(false)] public struct SIZE { public int cx; public int cy; public override string ToString() { return ("{{{0}, {1}}}", cx, cy); } // for debugging. } [Serializable] [StructLayout(), ComVisible(false)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; public override string ToString() { return ("{{{0}, {1}, {2}, {3}}}", Left, Top, Right, Bottom); } // for debugging. } #endregion #region Enum [ComVisible(false)] public enum PIN_DIRECTION { PINDIR_INPUT = 0, PINDIR_OUTPUT = 1, } [ComVisible(false)] public enum FILTER_STATE : int { Stopped = 0, Paused = 1, Running = 2, } [ComVisible(false)] public enum CameraControlProperty { Pan = 0, Tilt = 1, Roll = 2, Zoom = 3, Exposure = 4, Iris = 5, Focus = 6, } [ComVisible(false), Flags()] public enum CameraControlFlags { Auto = 0x0001, Manual = 0x0002, } [ComVisible(false)] public enum VideoProcAmpProperty { Brightness = 0, Contrast = 1, Hue = 2, Saturation = 3, Sharpness = 4, Gamma = 5, ColorEnable = 6, WhiteBalance = 7, BacklightCompensation = 8, Gain = 9 } #endregion #region Guid public static class DsGuid { // MediaType public static readonly Guid MEDIATYPE_Video = new Guid("{73646976-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIATYPE_Audio = new Guid("{73647561-0000-0010-8000-00AA00389B71}"); // SubType public static readonly Guid MEDIASUBTYPE_None = new Guid("{E436EB8E-524F-11CE-9F53-0020AF0BA770}"); public static readonly Guid MEDIASUBTYPE_YUYV = new Guid("{56595559-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_IYUV = new Guid("{56555949-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_YVU9 = new Guid("{39555659-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_YUY2 = new Guid("{32595559-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_YVYU = new Guid("{55595659-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_UYVY = new Guid("{59565955-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_MJPG = new Guid("{47504A4D-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_RGB565 = new Guid("{E436EB7B-524F-11CE-9F53-0020AF0BA770}"); public static readonly Guid MEDIASUBTYPE_RGB555 = new Guid("{E436EB7C-524F-11CE-9F53-0020AF0BA770}"); public static readonly Guid MEDIASUBTYPE_RGB24 = new Guid("{E436EB7D-524F-11CE-9F53-0020AF0BA770}"); public static readonly Guid MEDIASUBTYPE_RGB32 = new Guid("{E436EB7E-524F-11CE-9F53-0020AF0BA770}"); public static readonly Guid MEDIASUBTYPE_ARGB32 = new Guid("{773C9AC0-3274-11D0-B724-00AA006C1A01}"); public static readonly Guid MEDIASUBTYPE_PCM = new Guid("{00000001-0000-0010-8000-00AA00389B71}"); public static readonly Guid MEDIASUBTYPE_WAVE = new Guid("{E436EB8B-524F-11CE-9F53-0020AF0BA770}"); // FormatType public static readonly Guid FORMAT_None = new Guid("{0F6417D6-C318-11D0-A43F-00A0C9223196}"); public static readonly Guid FORMAT_VideoInfo = new Guid("{05589F80-C356-11CE-BF01-00AA0055595A}"); public static readonly Guid FORMAT_VideoInfo2 = new Guid("{F72A76A0-EB0A-11d0-ACE4-0000C0CC16BA}"); public static readonly Guid FORMAT_WaveFormatEx = new Guid("{05589F81-C356-11CE-BF01-00AA0055595A}"); // CLSID public static readonly Guid CLSID_AudioInputDeviceCategory = new Guid("{33D9A762-90C8-11d0-BD43-00A0C911CE86}"); public static readonly Guid CLSID_AudioRendererCategory = new Guid("{E0F158E1-CB04-11d0-BD4E-00A0C911CE86}"); public static readonly Guid CLSID_VideoInputDeviceCategory = new Guid("{860BB310-5D01-11d0-BD3B-00A0C911CE86}"); public static readonly Guid CLSID_VideoCompressorCategory = new Guid("{33D9A760-90C8-11d0-BD43-00A0C911CE86}"); public static readonly Guid CLSID_NullRenderer = new Guid("{C1F400A4-3F08-11D3-9F0B-006008039E37}"); public static readonly Guid CLSID_SampleGrabber = new Guid("{C1F400A0-3F08-11D3-9F0B-006008039E37}"); public static readonly Guid CLSID_FilterGraph = new Guid("{E436EBB3-524F-11CE-9F53-0020AF0BA770}"); public static readonly Guid CLSID_SystemDeviceEnum = new Guid("{62BE5D10-60EB-11d0-BD3B-00A0C911CE86}"); public static readonly Guid CLSID_CaptureGraphBuilder2 = new Guid("{BF87B6E1-8C27-11d0-B3F0-00AA003761C5}"); public static readonly Guid IID_IPropertyBag = new Guid("{55272A00-42CB-11CE-8135-00AA004BB851}"); public static readonly Guid IID_IBaseFilter = new Guid("{56a86895-0ad4-11ce-b03a-0020af0ba770}"); public static readonly Guid IID_IAMStreamConfig = new Guid("{C6E13340-30AC-11d0-A18C-00A0C9118956}"); public static readonly Guid PIN_CATEGORY_CAPTURE = new Guid("{fb6c4281-0353-11d1-905f-0000c0cc16ba}"); public static readonly Guid PIN_CATEGORY_PREVIEW = new Guid("{fb6c4282-0353-11d1-905f-0000c0cc16ba}"); public static readonly Guid PIN_CATEGORY_STILL = new Guid("{fb6c428a-0353-11d1-905f-0000c0cc16ba}"); private static Dictionary<Guid, string> NicknameCache = null; public static string GetNickname(Guid guid) { if (NicknameCache == null) { NicknameCache = typeof(DsGuid).GetFields( | ) .Where(x => == typeof(Guid)) .ToDictionary(x => (Guid)(null), x => ); } if ((guid)) { var name = NicknameCache[guid]; var elem = ('_'); if ( >= 2) { var text = ("_", (1).ToArray()); return ("[{0}]", text); } else { return name; } } return (); } } #endregion } }
Very simple to use:
//Get all cameras string[] devices = (); //Get the resolution supported by the camera int cameraIndex = 0; [] formats = (cameraIndex); for (int i = 0; i < ; i++) ("{0}:{1}", i, formats[i]); // create usb camera and start. using var camera = new UsbCamera(cameraIndex, formats[0]); (); //If the first screenshot is not delayed, the screen will appear black. await (100); var bmp = (); (@$"r:\");
This code itself also encapsulates the direct show, but it only encapsulates the camera-related parts, with only 1k lines, and can be directly embedded into the project. In addition, this screenshot itself does not rely on the STA thread. It can be easily encapsulated into a remote USB photo function, and can also be used for web use. If the effect is not required, it is also OK to make a remote camera.
The above is the entire content of this article. I hope that the content of this article has certain reference value for your study or work. Thank you for your support. If you want to know more about it, please see the relevant links below