/// <summary> /// サンプルグラバを作成する /// </summary> private DirectShow.IBaseFilter CreateSampleGrabber() { var filter = DirectShow.CreateFilter(DirectShow.DsGuid.CLSID_SampleGrabber); var ismp = filter as DirectShow.ISampleGrabber; // サンプル グラバを最初に作成したときは、優先メディア タイプは設定されていない。 // これは、グラフ内のほぼすべてのフィルタに接続はできるが、受け取るデータ タイプを制御できないとうことである。 // したがって、残りのグラフを作成する前に、ISampleGrabber::SetMediaType メソッドを呼び出して、 // サンプル グラバに対してメディア タイプを設定すること。 // サンプル グラバは、接続した時に他のフィルタが提供するメディア タイプとこの設定されたメディア タイプとを比較する。 // 調べるフィールドは、メジャー タイプ、サブタイプ、フォーマット タイプだけである。 // これらのフィールドでは、値 GUID_NULL は "あらゆる値を受け付ける" という意味である。 // 通常は、メジャー タイプとサブタイプを設定する。 // https://msdn.microsoft.com/ja-jp/library/cc370616.aspx // https://msdn.microsoft.com/ja-jp/library/cc369546.aspx // サンプル グラバ フィルタはトップダウン方向 (負の biHeight) のビデオ タイプ、または // FORMAT_VideoInfo2 のフォーマット タイプのビデオ タイプはすべて拒否する。 var mt = new DirectShow.AM_MEDIA_TYPE(); mt.MajorType = DirectShow.DsGuid.MEDIATYPE_Video; mt.SubType = DirectShow.DsGuid.MEDIASUBTYPE_RGB24; ismp.SetMediaType(mt); return(filter); }
/// <summary> /// Get video formats. /// </summary> public static VideoFormat[] GetVideoFormat(int cameraIndex) { var filter = DirectShow.CreateFilter(DirectShow.DsGuid.CLSID_VideoInputDeviceCategory, cameraIndex); var pin = DirectShow.FindPin(filter, 0, DirectShow.PIN_DIRECTION.PINDIR_OUTPUT); return(GetVideoOutputFormat(pin)); }
/// <summary> /// Video Capture Sourceフィルタを作成する /// </summary> private DirectShow.IBaseFilter CreateVideoCaptureSource(int index, VideoFormat format) { var filter = DirectShow.CreateFilter(DirectShow.DsGuid.CLSID_VideoInputDeviceCategory, index); var pin = DirectShow.FindPin(filter, 0, DirectShow.PIN_DIRECTION.PINDIR_OUTPUT); SetVideoOutputFormat(pin, format); return(filter); }
/// <summary> /// ビデオキャプチャデバイスの出力形式を選択する。 /// 事前にGetVideoOutputFormatでメディアタイプ・サイズを得ておき、その中から希望のindexを指定する。 /// 同時に出力サイズとフレームレートを変更することができる。 /// </summary> /// <param name="index">希望のindexを指定する</param> /// <param name="size">Empty以外を指定すると出力サイズを変更する。事前にVIDEO_STREAM_CONFIG_CAPSで取得した可能範囲内を指定すること。</param> /// <param name="timePerFrame">0以上を指定するとフレームレートを変更する。事前にVIDEO_STREAM_CONFIG_CAPSで取得した可能範囲内を指定すること。</param> private static void SetVideoOutputFormat(DirectShow.IPin pin, int index, Size size, long timePerFrame) { // IAMStreamConfigインタフェース取得 var config = pin as DirectShow.IAMStreamConfig; if (config == null) { throw new InvalidOperationException("no IAMStreamConfig interface."); } // フォーマット個数取得 int cap_count = 0, cap_size = 0; config.GetNumberOfCapabilities(ref cap_count, ref cap_size); if (cap_size != Marshal.SizeOf(typeof(DirectShow.VIDEO_STREAM_CONFIG_CAPS))) { throw new InvalidOperationException("no VIDEO_STREAM_CONFIG_CAPS."); } // データ用領域確保 var cap_data = Marshal.AllocHGlobal(cap_size); // idx番目のフォーマット情報取得 DirectShow.AM_MEDIA_TYPE mt = null; config.GetStreamCaps(index, ref mt, cap_data); var cap = PtrToStructure <DirectShow.VIDEO_STREAM_CONFIG_CAPS>(cap_data); if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo) { var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER>(mt.pbFormat); if (!size.IsDefault) { vinfo.bmiHeader.biWidth = (int)size.Width; vinfo.bmiHeader.biHeight = (int)size.Height; } if (timePerFrame > 0) { vinfo.AvgTimePerFrame = timePerFrame; } Marshal.StructureToPtr(vinfo, mt.pbFormat, true); } else if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo2) { var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER2>(mt.pbFormat); if (!size.IsDefault) { vinfo.bmiHeader.biWidth = (int)size.Width; vinfo.bmiHeader.biHeight = (int)size.Height; } if (timePerFrame > 0) { vinfo.AvgTimePerFrame = timePerFrame; } Marshal.StructureToPtr(vinfo, mt.pbFormat, true); } // フォーマットを選択 config.SetFormat(mt); // 解放 if (cap_data != System.IntPtr.Zero) { Marshal.FreeHGlobal(cap_data); } if (mt != null) { DirectShow.DeleteMediaType(ref mt); } }
/// <summary> /// ビデオキャプチャデバイスがサポートするメディアタイプ・サイズを取得する。 /// </summary> private static VideoFormat[] GetVideoOutputFormat(DirectShow.IPin pin) { // IAMStreamConfigインタフェース取得 if (!(pin is DirectShow.IAMStreamConfig config)) { throw new InvalidOperationException("no IAMStreamConfig interface."); } // フォーマット個数取得 int cap_count = 0, cap_size = 0; config.GetNumberOfCapabilities(ref cap_count, ref cap_size); if (cap_size != Marshal.SizeOf(typeof(DirectShow.VIDEO_STREAM_CONFIG_CAPS))) { throw new InvalidOperationException("no VIDEO_STREAM_CONFIG_CAPS."); } // 返却値の確保 var result = new VideoFormat[cap_count]; // データ用領域確保 var cap_data = Marshal.AllocHGlobal(cap_size); // 列挙 for (var i = 0; i < cap_count; i++) { var entry = new VideoFormat(); // x番目のフォーマット情報取得 DirectShow.AM_MEDIA_TYPE mt = null; config.GetStreamCaps(i, ref mt, cap_data); entry.Caps = PtrToStructure <DirectShow.VIDEO_STREAM_CONFIG_CAPS>(cap_data); // フォーマット情報の読み取り entry.MajorType = DirectShow.DsGuid.GetNickname(mt.MajorType); entry.SubType = DirectShow.DsGuid.GetNickname(mt.SubType); if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo) { var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER>(mt.pbFormat); entry.Size = new Size(vinfo.bmiHeader.biWidth, vinfo.bmiHeader.biHeight); entry.TimePerFrame = vinfo.AvgTimePerFrame; } else if (mt.FormatType == DirectShow.DsGuid.FORMAT_VideoInfo2) { var vinfo = PtrToStructure <DirectShow.VIDEOINFOHEADER2>(mt.pbFormat); entry.Size = new Size(vinfo.bmiHeader.biWidth, vinfo.bmiHeader.biHeight); entry.TimePerFrame = vinfo.AvgTimePerFrame; } // 解放 DirectShow.DeleteMediaType(ref mt); result[i] = entry; } // 解放 Marshal.FreeHGlobal(cap_data); return(result); }
private void Init(int index, VideoFormat format) { //---------------------------------- // Create Filter Graph //---------------------------------- // +--------------------+ +----------------+ +---------------+ // |Video Capture Source|→| Sample Grabber |→| Null Renderer | // +--------------------+ +----------------+ +---------------+ // ↓GetBitmap() var graph = DirectShow.CreateGraph(); //---------------------------------- // VideoCaptureSource //---------------------------------- var vcap_source = CreateVideoCaptureSource(index, format); graph.AddFilter(vcap_source, "VideoCapture"); //------------------------------ // SampleGrabber //------------------------------ var grabber = CreateSampleGrabber(); graph.AddFilter(grabber, "SampleGrabber"); var i_grabber = (DirectShow.ISampleGrabber)grabber; i_grabber.SetBufferSamples(true); //サンプルグラバでのサンプリングを開始 //--------------------------------------------------- // Null Renderer //--------------------------------------------------- var renderer = DirectShow.CoCreateInstance(DirectShow.DsGuid.CLSID_NullRenderer) as DirectShow.IBaseFilter; graph.AddFilter(renderer, "NullRenderer"); //--------------------------------------------------- // Create Filter Graph //--------------------------------------------------- var builder = DirectShow.CoCreateInstance(DirectShow.DsGuid.CLSID_CaptureGraphBuilder2) as DirectShow.ICaptureGraphBuilder2; builder.SetFiltergraph(graph); var pinCategory = DirectShow.DsGuid.PIN_CATEGORY_CAPTURE; var mediaType = DirectShow.DsGuid.MEDIATYPE_Video; builder.RenderStream(ref pinCategory, ref mediaType, vcap_source, grabber, renderer); // SampleGrabber Format. { var mt = new DirectShow.AM_MEDIA_TYPE(); i_grabber.GetConnectedMediaType(mt); var header = (DirectShow.VIDEOINFOHEADER)Marshal.PtrToStructure(mt.pbFormat, typeof(DirectShow.VIDEOINFOHEADER)); var width = header.bmiHeader.biWidth; var height = header.bmiHeader.biHeight; var stride = width * (header.bmiHeader.biBitCount / 8); DirectShow.DeleteMediaType(ref mt); Size = new Size(width, height); // fix screen tearing problem(issue #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 = () => DirectShow.PlayGraph(graph, DirectShow.FILTER_STATE.Running); Stop = () => DirectShow.PlayGraph(graph, DirectShow.FILTER_STATE.Stopped); Release = () => { Stop(); DirectShow.ReleaseInstance(ref i_grabber); DirectShow.ReleaseInstance(ref builder); DirectShow.ReleaseInstance(ref graph); }; // Properties. Properties = new PropertyItems(vcap_source); }
/// <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(DirectShow.GetFilters(DirectShow.DsGuid.CLSID_VideoInputDeviceCategory).ToArray()); }