cscの作法 その285

# 概要
cscの作法、調べてみた。
directshow.dll使ってみた。
カメラを表示してみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/009c525d-ca00-b209-1a7e-465b278bfc6e.png)


# サンプルコード

```

using System.ComponentModel;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;
using System.Windows.Forms;
using DirectShowLib;

namespace SnapShot
{
	internal class Capture : ISampleGrabberCB, IDisposable {
		private IFilterGraph2 m_FilterGraph = null;
		private IAMVideoControl m_VidControl = null;
		private IPin m_pinStill = null;
		private ManualResetEvent m_PictureReady = null;
		private bool m_WantOne = false;
		private int m_videoWidth;
		private int m_videoHeight;
		private int m_stride;
		private IntPtr m_ipBuffer = IntPtr.Zero;
		DsROTEntry m_rot = null;
		[DllImport("Kernel32.dll", EntryPoint="RtlMoveMemory")]
		private static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] int Length);
		public Capture(int iDeviceNum, int iWidth, int iHeight, short iBPP, Control hControl) {
			DsDevice [] capDevices;
			capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
			if (iDeviceNum + 1 > capDevices.Length)
			{
				throw new Exception("No video capture devices found at that index!");
			}
			try
			{
				SetupGraph(capDevices[iDeviceNum], iWidth, iHeight, iBPP, hControl);
				m_PictureReady = new ManualResetEvent(false);
			}
			catch
			{
				Dispose();
				throw;
			}
		}
		public void Dispose() {
			if (m_rot != null)
			{
				m_rot.Dispose();
			}
			CloseInterfaces();
			if (m_PictureReady != null)
			{
				m_PictureReady.Close();
			}
		}
		~Capture() {
			Dispose();
		}
		public IntPtr Click() {
			int hr;
			m_PictureReady.Reset();
			m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);
			try
			{
				m_WantOne = true;
				if (m_VidControl != null)
				{
					hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);
					DsError.ThrowExceptionForHR(hr);
				}
				if (! m_PictureReady.WaitOne(9000, false))
				{
					throw new Exception("Timeout waiting to get picture");
				}
			}
			catch
			{
				Marshal.FreeCoTaskMem(m_ipBuffer);
				m_ipBuffer = IntPtr.Zero;
				throw;
			}
			return m_ipBuffer;
		}
		public int Width {
			get {
				return m_videoWidth;
			}
		}
		public int Height {
			get {
				return m_videoHeight;
			}
		}
		public int Stride {
			get {
				return m_stride;
			}
		}
		private void SetupGraph(DsDevice dev, int iWidth, int iHeight, short iBPP, Control hControl) {
			int hr;
			ISampleGrabber sampGrabber = null;
			IBaseFilter capFilter = null;
			IPin pCaptureOut = null;
			IPin pSampleIn = null;
			IPin pRenderIn = null;
			m_FilterGraph = new FilterGraph() as IFilterGraph2;
			try
			{
				m_rot = new DsROTEntry(m_FilterGraph);
				hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);
				DsError.ThrowExceptionForHR(hr);
				m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0);
				if (m_pinStill == null)
				{
					m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Preview, 0);
				}
				if (m_pinStill == null)
				{
					IPin pRaw = null;
					IPin pSmart = null;
					m_VidControl = null;
					IBaseFilter iSmartTee = (IBaseFilter) new SmartTee();
					try
					{
						hr = m_FilterGraph.AddFilter(iSmartTee, "SmartTee");
						DsError.ThrowExceptionForHR(hr);
						pRaw = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);
						pSmart = DsFindPin.ByDirection(iSmartTee, PinDirection.Input, 0);
						hr = m_FilterGraph.Connect(pRaw, pSmart);
						DsError.ThrowExceptionForHR(hr);
						m_pinStill = DsFindPin.ByName(iSmartTee, "Preview");
						pCaptureOut = DsFindPin.ByName(iSmartTee, "Capture");
						if (iHeight + iWidth + iBPP > 0)
						{
							SetConfigParms(pRaw, iWidth, iHeight, iBPP);
						}
					}
					finally
					{
						if (pRaw != null)
						{
							Marshal.ReleaseComObject(pRaw);
						}
						if (pRaw != pSmart)
						{
							Marshal.ReleaseComObject(pSmart);
						}
						if (pRaw != iSmartTee)
						{
							Marshal.ReleaseComObject(iSmartTee);
						}
					}
				}
				else
				{
					m_VidControl = capFilter as IAMVideoControl;
					pCaptureOut = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);
					if (iHeight + iWidth + iBPP > 0)
					{
						SetConfigParms(m_pinStill, iWidth, iHeight, iBPP);
					}
				}
				sampGrabber = new SampleGrabber() as ISampleGrabber;
				IBaseFilter baseGrabFlt = sampGrabber as IBaseFilter;
				ConfigureSampleGrabber(sampGrabber);
				pSampleIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);
				IBaseFilter pRenderer = new VideoRendererDefault() as IBaseFilter;
				hr = m_FilterGraph.AddFilter(pRenderer, "Renderer");
				DsError.ThrowExceptionForHR(hr);
				pRenderIn = DsFindPin.ByDirection(pRenderer, PinDirection.Input, 0);
				hr = m_FilterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
				DsError.ThrowExceptionForHR(hr);
				if (m_VidControl == null)
				{
					hr = m_FilterGraph.Connect(m_pinStill, pSampleIn);
					DsError.ThrowExceptionForHR(hr);
					hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn);
					DsError.ThrowExceptionForHR(hr);
				}
				else
				{
					hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn);
					DsError.ThrowExceptionForHR(hr);
					hr = m_FilterGraph.Connect(m_pinStill, pSampleIn);
					DsError.ThrowExceptionForHR(hr);
				}
				SaveSizeInfo(sampGrabber);
				ConfigVideoWindow(hControl);
				IMediaControl mediaCtrl = m_FilterGraph as IMediaControl;
				hr = mediaCtrl.Run();
				DsError.ThrowExceptionForHR(hr);
			}
			finally
			{
				if (sampGrabber != null)
				{
					Marshal.ReleaseComObject(sampGrabber);
					sampGrabber = null;
				}
				if (pCaptureOut != null)
				{
					Marshal.ReleaseComObject(pCaptureOut);
					pCaptureOut = null;
				}
				if (pRenderIn != null)
				{
					Marshal.ReleaseComObject(pRenderIn);
					pRenderIn = null;
				}
				if (pSampleIn != null)
				{
					Marshal.ReleaseComObject(pSampleIn);
					pSampleIn = null;
				}
			}
		}
		private void SaveSizeInfo(ISampleGrabber sampGrabber) {
			int hr;
			AMMediaType media = new AMMediaType();
			hr = sampGrabber.GetConnectedMediaType(media);
			DsError.ThrowExceptionForHR(hr);
			if((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
			{
				throw new NotSupportedException("Unknown Grabber Media Format");
			}
			VideoInfoHeader videoInfoHeader = (VideoInfoHeader) Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
			m_videoWidth = videoInfoHeader.BmiHeader.Width;
			m_videoHeight = videoInfoHeader.BmiHeader.Height;
			m_stride = m_videoWidth * (videoInfoHeader.BmiHeader.BitCount / 8);
			DsUtils.FreeAMMediaType(media);
			media = null;
		}
		private void ConfigVideoWindow(Control hControl) {
			int hr;
			IVideoWindow ivw = m_FilterGraph as IVideoWindow;
			hr = ivw.put_Owner(hControl.Handle);
			DsError.ThrowExceptionForHR(hr);
			hr = ivw.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);
			DsError.ThrowExceptionForHR(hr);
			hr = ivw.put_Visible(OABool.True);
			DsError.ThrowExceptionForHR(hr);
			Rectangle rc = hControl.ClientRectangle;
			hr = ivw.SetWindowPosition(0, 0, rc.Right, rc.Bottom);
			DsError.ThrowExceptionForHR(hr);
		}
		private void ConfigureSampleGrabber(ISampleGrabber sampGrabber) {
			int hr;
			AMMediaType media = new AMMediaType();
			media.majorType = MediaType.Video;
			media.subType = MediaSubType.RGB24;
			media.formatType = FormatType.VideoInfo;
			hr = sampGrabber.SetMediaType(media);
			DsError.ThrowExceptionForHR(hr);
			DsUtils.FreeAMMediaType(media);
			media = null;
			hr = sampGrabber.SetCallback(this, 1);
			DsError.ThrowExceptionForHR(hr);
		}
		private void SetConfigParms(IPin pStill, int iWidth, int iHeight, short iBPP) {
			int hr;
			AMMediaType media;
			VideoInfoHeader v;
			IAMStreamConfig videoStreamConfig = pStill as IAMStreamConfig;
			hr = videoStreamConfig.GetFormat(out media);
			DsError.ThrowExceptionForHR(hr);
			try
			{
				v = new VideoInfoHeader();
				Marshal.PtrToStructure(media.formatPtr, v);
				if (iWidth > 0)
				{
					v.BmiHeader.Width = iWidth;
				}
				if (iHeight > 0)
				{
					v.BmiHeader.Height = iHeight;
				}
				if (iBPP > 0)
				{
					v.BmiHeader.BitCount = iBPP;
				}
				Marshal.StructureToPtr(v, media.formatPtr, false);
				hr = videoStreamConfig.SetFormat(media);
				DsError.ThrowExceptionForHR(hr);
			}
			finally
			{
				DsUtils.FreeAMMediaType(media);
				media = null;
			}
		}
		private void CloseInterfaces() {
			int hr;
			try
			{
				if (m_FilterGraph != null)
				{
					IMediaControl mediaCtrl = m_FilterGraph as IMediaControl;
					hr = mediaCtrl.Stop();
				}
			}
			catch (Exception ex)
			{
				Debug.WriteLine(ex);
			}
			if (m_FilterGraph != null)
			{
				Marshal.ReleaseComObject(m_FilterGraph);
				m_FilterGraph = null;
			}
			if (m_VidControl != null)
			{
				Marshal.ReleaseComObject(m_VidControl);
				m_VidControl = null;
			}
			if (m_pinStill != null)
			{
				Marshal.ReleaseComObject(m_pinStill);
				m_pinStill = null;
			}
		}
		int ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample) {
			Marshal.ReleaseComObject(pSample);
			return 0;
		}
		int ISampleGrabberCB.BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen) {
			Debug.Assert(BufferLen == Math.Abs(m_stride) * m_videoHeight, "Incorrect buffer length");
			if (m_WantOne)
			{
				m_WantOne = false;
				Debug.Assert(m_ipBuffer != IntPtr.Zero, "Unitialized buffer");
				CopyMemory(m_ipBuffer, pBuffer, BufferLen);
				m_PictureReady.Set();
			}
			return 0;
		}
	}
	public class Form1 : System.Windows.Forms.Form {
		private System.Windows.Forms.Button button1;
		private System.Windows.Forms.PictureBox pictureBox1;
		private System.ComponentModel.Container components = null;
		private System.Windows.Forms.PictureBox pictureBox2;
		private Capture cam;
		public Form1() {
			InitializeComponent();
			const int VIDEODEVICE = 0;
			const int VIDEOWIDTH = 640;
			const int VIDEOHEIGHT = 480;
			const int VIDEOBITSPERPIXEL = 24;
			cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, pictureBox2);
		}
		protected override void Dispose(bool disposing) {
			if (disposing)
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose(disposing);
			if (m_ip != IntPtr.Zero)
			{
				Marshal.FreeCoTaskMem(m_ip);
				m_ip = IntPtr.Zero;
			}
		}
		private void InitializeComponent() {
			this.button1 = new System.Windows.Forms.Button();
			this.pictureBox1 = new System.Windows.Forms.PictureBox();
			this.pictureBox2 = new System.Windows.Forms.PictureBox();
			((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
			((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
			this.SuspendLayout();
			this.button1.Location = new System.Drawing.Point(368, 80);
			this.button1.Name = "button1";
			this.button1.Size = new System.Drawing.Size(75, 40);
			this.button1.TabIndex = 0;
			this.button1.Text = "Click";
			this.button1.Click += new System.EventHandler(this.button1_Click);
			this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
			this.pictureBox1.Location = new System.Drawing.Point(16, 256);
			this.pictureBox1.Name = "pictureBox1";
			this.pictureBox1.Size = new System.Drawing.Size(640, 480);
			this.pictureBox1.TabIndex = 1;
			this.pictureBox1.TabStop = false;
			this.pictureBox2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
			this.pictureBox2.Location = new System.Drawing.Point(16, 8);
			this.pictureBox2.Name = "pictureBox2";
			this.pictureBox2.Size = new System.Drawing.Size(320, 240);
			this.pictureBox2.TabIndex = 2;
			this.pictureBox2.TabStop = false;
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(776, 794);
			this.Controls.Add(this.pictureBox2);
			this.Controls.Add(this.pictureBox1);
			this.Controls.Add(this.button1);
			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
			this.Name = "Form1";
			this.Text = "DxSnap";
			this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Form1_FormClosed);
			((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
			((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
			this.ResumeLayout(false);
		}
		IntPtr m_ip = IntPtr.Zero;
		private void button1_Click(object sender, System.EventArgs e) {
			Cursor.Current = Cursors.WaitCursor;
			if (m_ip != IntPtr.Zero)
			{
				Marshal.FreeCoTaskMem(m_ip);
				m_ip = IntPtr.Zero;
			}
			m_ip = cam.Click();
			Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);
			b.RotateFlip(RotateFlipType.RotateNoneFlipY);
			pictureBox1.Image = b;
			Cursor.Current = Cursors.Default;
		}
		private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
			cam.Dispose();
			if (m_ip != IntPtr.Zero)
			{
				Marshal.FreeCoTaskMem(m_ip);
				m_ip = IntPtr.Zero;
			}
		}
		[STAThread]
		static void Main() {
			Application.Run(new Form1());
		}
	}
}





```

以上。