cscの作法 その284

# 概要
cscの作法、調べてみた。
directshow.dll使ってみた。
動画を再生してみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/9a3df826-7a75-2e03-726f-5c5640178828.png)

# サンプルコード

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


namespace DxPlay
{
	internal class DxPlay : IDisposable {
		enum GraphState {
			Stopped,
			Paused,
			Running,
			Exiting
		}
		private string m_sFileName;
		private IFilterGraph2 m_FilterGraph;
		private IMediaControl m_mediaCtrl;
		private IMediaEvent m_mediaEvent;
		ISampleGrabber m_sampGrabber = null;
		private int m_videoWidth;
		private int m_videoHeight;
		private int m_stride;
		private int m_ImageSize;
		private ManualResetEvent m_mre;
		volatile private GraphState m_State = GraphState.Stopped;
		DsROTEntry m_DsRot;
		public void Dispose() {
			CloseInterfaces();
		}
		~DxPlay() {
			CloseInterfaces();
		}
		public event DxPlayEvent StopPlay;
		public delegate void DxPlayEvent(Object sender);
		public DxPlay(Control hWin, string FileName) {
			try
			{
				int hr;
				IntPtr hEvent;
				m_sFileName = FileName;
				SetupGraph(hWin, FileName);
				hr = m_mediaEvent.GetEventHandle(out hEvent);
				DsError.ThrowExceptionForHR(hr);
				m_mre = new ManualResetEvent(false);
#if USING_NET11
				m_mre.Handle = hEvent;
#else
				m_mre.SafeWaitHandle = new Microsoft.Win32.SafeHandles.SafeWaitHandle(hEvent, true);
#endif
				Thread t = new Thread(new ThreadStart(this.EventWait));
				t.Name = "Media Event Thread";
				t.Start();
			}
			catch
			{
				Dispose();
				throw;
			}
		}
		private void EventWait() {
			const int E_ABORT = unchecked((int) 0x80004004);
			int hr;
			IntPtr p1, 
				p2;
			EventCode ec;
			do
			{
				m_mre.WaitOne(-1, true);
				lock(this)
				{
					if (m_State != GraphState.Exiting)
					{
						for (hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0); hr >= 0; hr = m_mediaEvent.GetEvent(out ec, out p1, out p2, 0))
						{
							Debug.WriteLine(ec.ToString());
							if (ec == EventCode.Complete)
							{
								Stop();
								if (StopPlay != null)
								{
									StopPlay(this);
								}
							}
							hr = m_mediaEvent.FreeEventParams(ec, p1, p2);
							DsError.ThrowExceptionForHR(hr);
						}
						if (hr != E_ABORT)
						{
							DsError.ThrowExceptionForHR(hr);
						}
					}
					else
					{
						break;
					}
				}
			} while (true);
		}
		public string FileName {
			get {
				return m_sFileName;
			}
		}
		public void Start() {
			if (m_State == GraphState.Stopped || m_State == GraphState.Paused)
			{
				int hr = m_mediaCtrl.Run();
				DsError.ThrowExceptionForHR(hr);
				m_State = GraphState.Running;
			}
		}
		public void Pause() {
			if (m_State == GraphState.Running)
			{
				int hr = m_mediaCtrl.Pause();
				DsError.ThrowExceptionForHR(hr);
				m_State = GraphState.Paused;
			}
		}
		public void Stop() {
			if (m_State == GraphState.Running || m_State == GraphState.Paused)
			{
				int hr = m_mediaCtrl.Stop();
				DsError.ThrowExceptionForHR(hr);
				m_State = GraphState.Stopped;
			}
		}
		public void Rewind() {
			int hr;
			IMediaPosition imp = m_FilterGraph as IMediaPosition;
			hr = imp.put_CurrentPosition(0);
		}
		public IntPtr SnapShot() {
			int hr;
			IntPtr ip = IntPtr.Zero;
			int iBuffSize = 0;
			hr = m_sampGrabber.GetCurrentBuffer(ref iBuffSize, ip);
			DsError.ThrowExceptionForHR(hr);
			Debug.Assert(iBuffSize == m_ImageSize, "Unexpected buffer size");
			ip = Marshal.AllocCoTaskMem(iBuffSize);
			hr = m_sampGrabber.GetCurrentBuffer(ref iBuffSize, ip);
			DsError.ThrowExceptionForHR(hr);
			return ip;
		}
		public Bitmap IPToBmp(IntPtr ip) {
			int iBufSize = m_videoWidth * m_videoHeight * 3;
			return new Bitmap(m_videoWidth, m_videoHeight, -m_stride, PixelFormat.Format24bppRgb, (IntPtr)(ip.ToInt32() + iBufSize - m_stride));
		}
		private void SetupGraph(Control hWin, string FileName) {
			int hr;
			m_FilterGraph = new FilterGraph() as IFilterGraph2;
			ICaptureGraphBuilder2 icgb2 = new CaptureGraphBuilder2() as ICaptureGraphBuilder2;
			try
			{
				hr = icgb2.SetFiltergraph(m_FilterGraph);
				DsError.ThrowExceptionForHR(hr);
				m_DsRot = new DsROTEntry(m_FilterGraph);
				IBaseFilter	sourceFilter = null;
				hr = m_FilterGraph.AddSourceFilter(FileName, FileName, out sourceFilter);
				DsError.ThrowExceptionForHR(hr);
				m_sampGrabber = (ISampleGrabber) new SampleGrabber();
				IBaseFilter baseGrabFlt = (IBaseFilter) m_sampGrabber;
				ConfigureSampleGrabber(m_sampGrabber);
				hr = m_FilterGraph.AddFilter(baseGrabFlt, "Ds.NET Grabber");
				DsError.ThrowExceptionForHR(hr);
				hr = icgb2.RenderStream(null, null, sourceFilter, baseGrabFlt, null);
				DsError.ThrowExceptionForHR(hr);
				SaveSizeInfo(m_sampGrabber);
				IVideoWindow videoWindow = m_FilterGraph as IVideoWindow;
				ConfigureVideoWindow(videoWindow, hWin);
				m_mediaEvent = m_FilterGraph as IMediaEvent;
				m_mediaCtrl = m_FilterGraph as IMediaControl;
			}
			finally
			{
				if (icgb2 != null)
				{
					Marshal.ReleaseComObject(icgb2);
					icgb2 = null;
				}
			}
			GC.Collect();
			GC.WaitForPendingFinalizers();
		}
		private void ConfigureVideoWindow(IVideoWindow videoWindow, Control hWin) {
			int hr;
			hr = videoWindow.put_Owner(hWin.Handle);
			DsError.ThrowExceptionForHR(hr);
			hr = videoWindow.put_WindowStyle((WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings));
			DsError.ThrowExceptionForHR(hr);
			hr = videoWindow.put_Visible(OABool.True);
			DsError.ThrowExceptionForHR(hr);
			Rectangle rc = hWin.ClientRectangle;
			hr = videoWindow.SetWindowPosition(0, 0, rc.Right, rc.Bottom);
			DsError.ThrowExceptionForHR(hr);
		}
		private void ConfigureSampleGrabber(ISampleGrabber sampGrabber) {
			AMMediaType media;
			int hr;
			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.SetBufferSamples(true);
			DsError.ThrowExceptionForHR(hr);
		}
		private void SaveSizeInfo(ISampleGrabber sampGrabber) {
			int hr;
			AMMediaType media = new AMMediaType();
			hr = sampGrabber.GetConnectedMediaType(media);
			DsError.ThrowExceptionForHR(hr);
			try
			{
				if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
				{
					throw new NotSupportedException("Unknown Grabber Media Format");
				}
				VideoInfoHeader videoInfoHeader = new VideoInfoHeader();
				Marshal.PtrToStructure(media.formatPtr, videoInfoHeader);
				m_videoWidth = videoInfoHeader.BmiHeader.Width;
				m_videoHeight = videoInfoHeader.BmiHeader.Height;
				m_stride = videoInfoHeader.BmiHeader.ImageSize / m_videoHeight;
				m_ImageSize = videoInfoHeader.BmiHeader.ImageSize;
			}
			finally
			{
				DsUtils.FreeAMMediaType(media);
				media = null;
			}
		}
		private void CloseInterfaces() {
			int hr;
			lock (this)
			{
				if (m_State != GraphState.Exiting)
				{
					m_State = GraphState.Exiting;
					if (m_mre != null)
					{
						m_mre.Set();
					}
				}
				if(m_mediaCtrl != null)
				{
					hr = m_mediaCtrl.Stop();
					m_mediaCtrl = null;
				}
				if (m_sampGrabber != null)
				{
					Marshal.ReleaseComObject(m_sampGrabber);
					m_sampGrabber = null;
				}
				if (m_DsRot != null)
				{
					m_DsRot.Dispose();
				}
				if (m_FilterGraph != null)
				{
					Marshal.ReleaseComObject(m_FilterGraph);
					m_FilterGraph = null;
				}
			}
			GC.Collect();
		}
	}
	public class Form1 : System.Windows.Forms.Form {
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Panel panel1;
		private System.Windows.Forms.Button btnStart;
		private System.Windows.Forms.Button btnPause;
		private System.Windows.Forms.Button btnSnap;
		private System.Windows.Forms.TextBox tbFileName;
		private System.ComponentModel.Container components = null;
		public Form1() {
			InitializeComponent();
		}
		protected override void Dispose(bool disposing) {
			if (m_play != null)
			{
				m_play.Dispose();
			}
			if(disposing)
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose(disposing);
		}
		private void InitializeComponent() {
			this.tbFileName = new System.Windows.Forms.TextBox();
			this.btnStart = new System.Windows.Forms.Button();
			this.label1 = new System.Windows.Forms.Label();
			this.panel1 = new System.Windows.Forms.Panel();
			this.btnPause = new System.Windows.Forms.Button();
			this.btnSnap = new System.Windows.Forms.Button();
			this.SuspendLayout();
			this.tbFileName.Location = new System.Drawing.Point(72, 8);
			this.tbFileName.Name = "tbFileName";
			this.tbFileName.Size = new System.Drawing.Size(208, 20);
			this.tbFileName.TabIndex = 9;
			this.tbFileName.Text = "test1.avi";
			this.btnStart.Location = new System.Drawing.Point(16, 40);
			this.btnStart.Name = "btnStart";
			this.btnStart.Size = new System.Drawing.Size(64, 32);
			this.btnStart.TabIndex = 1;
			this.btnStart.Text = "Start";
			this.btnStart.Click += new System.EventHandler(this.btnStart_Click);
			this.label1.Location = new System.Drawing.Point(16, 8);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(56, 16);
			this.label1.TabIndex = 2;
			this.label1.Text = "FileName";
			this.panel1.Location = new System.Drawing.Point(8, 88);
			this.panel1.Name = "panel1";
			this.panel1.Size = new System.Drawing.Size(320, 240);
			this.panel1.TabIndex = 10;
			this.btnPause.Enabled = false;
			this.btnPause.Location = new System.Drawing.Point(96, 40);
			this.btnPause.Name = "btnPause";
			this.btnPause.Size = new System.Drawing.Size(56, 32);
			this.btnPause.TabIndex = 11;
			this.btnPause.Text = "Pause";
			this.btnPause.Click += new System.EventHandler(this.btnPause_Click);
			this.btnSnap.Enabled = false;
			this.btnSnap.Location = new System.Drawing.Point(192, 40);
			this.btnSnap.Name = "btnSnap";
			this.btnSnap.Size = new System.Drawing.Size(56, 32);
			this.btnSnap.TabIndex = 12;
			this.btnSnap.Text = "Snap";
			this.btnSnap.Click += new System.EventHandler(this.btnSnap_Click);
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.ClientSize = new System.Drawing.Size(336, 338);
			this.Controls.Add(this.btnSnap);
			this.Controls.Add(this.btnPause);
			this.Controls.Add(this.panel1);
			this.Controls.Add(this.label1);
			this.Controls.Add(this.btnStart);
			this.Controls.Add(this.tbFileName);
			this.Name = "Form1";
			this.Text = "DxPlay";
			this.ResumeLayout(false);
		}
		enum State {
			Uninit,
			Stopped,
			Paused,
			Playing
		}
		State m_State = State.Uninit;
		DxPlay m_play = null;
		private void btnStart_Click(object sender, System.EventArgs e) {
			if (m_State == State.Stopped)
			{
				if (tbFileName.Text != m_play.FileName)
				{
					m_play.Dispose();
					m_play = null;
					m_State = State.Uninit;
					btnSnap.Enabled = false;
				}
			}
			if (m_play == null)
			{
				try
				{
					m_play = new DxPlay(panel1, tbFileName.Text);
					m_play.StopPlay += new DxPlay.DxPlayEvent(m_play_StopPlay);
					m_State = State.Stopped;
				}
				catch(COMException ce)
				{
					MessageBox.Show("Failed to open file: " + ce.Message, "Open Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
			if (m_State == State.Stopped)
			{
				btnStart.Text = "Stop";
				m_play.Start();
				btnSnap.Enabled = true;
				btnPause.Enabled = true;
				tbFileName.Enabled = false;
				m_State = State.Playing;
			}
			else if (m_State == State.Playing || m_State == State.Paused)
			{
				m_play.Stop();
				btnPause.Enabled = false;
				tbFileName.Enabled = true;
				btnStart.Text = "Start";
				btnPause.Text = "Pause";
				m_State = State.Stopped;
			}
		}
		private void btnPause_Click(object sender, System.EventArgs e) {
			if (m_State == State.Playing)
			{
				m_play.Pause();
				btnPause.Text = "Resume";
				m_State = State.Paused;
			}
			else
			{
				m_play.Start();
				btnPause.Text = "Pause";
				m_State = State.Playing;
			}
		}
		private void btnSnap_Click(object sender, System.EventArgs e) {
			IntPtr ip = m_play.SnapShot();
			try
			{
				Bitmap bmp = m_play.IPToBmp(ip);
				bmp.Save(@"tryme.bmp");
			}
			finally
			{
				Marshal.FreeCoTaskMem(ip);
			}
		}
		private void m_play_StopPlay(Object sender) {
			CheckForIllegalCrossThreadCalls = false;
			btnPause.Enabled = false;
			tbFileName.Enabled = true;
			btnStart.Text = "Start";
			btnPause.Text = "Pause";
			CheckForIllegalCrossThreadCalls = true;
			m_State = State.Stopped;
			m_play.Rewind();
		}
		[STAThread]
		static void Main() {
			Application.Run(new Form1());
		}
	}
}





```

# コンパイル手順

```

>set PATH=C:\Windows\Microsoft.NET\Framework\v4.0.30319;%PATH%


>csc /r:DirectShowLib.dll dxplay.cs

>dxplay

```

以上。