您的位置:首页 > 编程语言 > C#

C# WinForm DirectShow视频采集及图片抓取实例DxSnap

2013-09-19 15:04 501 查看
C# WinForm DirectShow视频采集及图片抓取实例DxSnap


DirectShowSamples-2007-July\Samples\Capture\DxSnap

Capture.cs

/****************************************************************************

While the underlying libraries are covered by LGPL, this sample is released

as public domain. It is distributed in the hope that it will be useful, but

WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY

or FITNESS FOR A PARTICULAR PURPOSE.

*****************************************************************************/

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

{

/// <summary> Summary description for MainForm. </summary>

internal class Capture : ISampleGrabberCB, IDisposable

{

#region Member variables

/// <summary> graph builder interface. </summary>

private IFilterGraph2 m_FilterGraph = null;

// Used to snap picture on Still pin

private IAMVideoControl m_VidControl = null;

private IPin m_pinStill = null;

/// <summary> so we can wait for the async job to finish </summary>

private ManualResetEvent m_PictureReady = null;

private bool m_WantOne = false;

/// <summary> Dimensions of the image, calculated once in constructor for perf. </summary>

private int m_videoWidth;

private int m_videoHeight;

private int m_stride;

/// <summary> buffer for bitmap data. Always release by caller</summary>

private IntPtr m_ipBuffer = IntPtr.Zero;

#if DEBUG

// Allow you to "Connect to remote graph" from GraphEdit

DsROTEntry m_rot = null;

#endif

#endregion

#region APIs

[DllImport("Kernel32.dll", EntryPoint="RtlMoveMemory")]

private static extern void CopyMemory(IntPtr Destination, IntPtr Source, [MarshalAs(UnmanagedType.U4)] int Length);

#endregion

// Zero based device index and device params and output window

public Capture(int iDeviceNum, int iWidth, int iHeight, short iBPP, Control hControl)

{

DsDevice [] capDevices;

// Get the collection of video devices

capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

if (iDeviceNum + 1 > capDevices.Length)

{

throw new Exception("No video capture devices found at that index!");

}

try

{

// Set up the capture graph

SetupGraph( capDevices[iDeviceNum], iWidth, iHeight, iBPP, hControl);

// tell the callback to ignore new images

m_PictureReady = new ManualResetEvent(false);

}

catch

{

Dispose();

throw;

}

}

/// <summary> release everything. </summary>

public void Dispose()

{

#if DEBUG

if (m_rot != null)

{

m_rot.Dispose();

}

#endif

CloseInterfaces();

if (m_PictureReady != null)

{

m_PictureReady.Close();

}

}

// Destructor

~Capture()

{

Dispose();

}

/// <summary>

/// Get the image from the Still pin. The returned image can turned into a bitmap with

/// Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);

/// If the image is upside down, you can fix it with

/// b.RotateFlip(RotateFlipType.RotateNoneFlipY);

/// </summary>

/// <returns>Returned pointer to be freed by caller with Marshal.FreeCoTaskMem</returns>

public IntPtr Click()

{

int hr;

// get ready to wait for new image

m_PictureReady.Reset();

m_ipBuffer = Marshal.AllocCoTaskMem(Math.Abs(m_stride) * m_videoHeight);

try

{

m_WantOne = true;

// If we are using a still pin, ask for a picture

if (m_VidControl != null)

{

// Tell the camera to send an image

hr = m_VidControl.SetMode(m_pinStill, VideoControlFlags.Trigger);

DsError.ThrowExceptionForHR( hr );

}

// Start waiting

if ( ! m_PictureReady.WaitOne(9000, false) )

{

throw new Exception("Timeout waiting to get picture");

}

}

catch

{

Marshal.FreeCoTaskMem(m_ipBuffer);

m_ipBuffer = IntPtr.Zero;

throw;

}

// Got one

return m_ipBuffer;

}

public int Width

{

get

{

return m_videoWidth;

}

}

public int Height

{

get

{

return m_videoHeight;

}

}

public int Stride

{

get

{

return m_stride;

}

}

/// <summary> build the capture graph for grabber. </summary>

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;

// Get the graphbuilder object

m_FilterGraph = new FilterGraph() as IFilterGraph2;

try

{

#if DEBUG

m_rot = new DsROTEntry(m_FilterGraph);

#endif

// add the video input device

hr = m_FilterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);

DsError.ThrowExceptionForHR( hr );

// Find the still pin

m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0);

// Didn't find one. Is there a preview pin?

if (m_pinStill == null)

{

m_pinStill = DsFindPin.ByCategory(capFilter, PinCategory.Preview, 0);

}

// Still haven't found one. Need to put a splitter in so we have

// one stream to capture the bitmap from, and one to display. Ok, we

// don't *have* to do it that way, but we are going to anyway.

if (m_pinStill == null)

{

IPin pRaw = null;

IPin pSmart = null;

// There is no still pin

m_VidControl = null;

// Add a splitter

IBaseFilter iSmartTee = (IBaseFilter)new SmartTee();

try

{

hr = m_FilterGraph.AddFilter(iSmartTee, "SmartTee");

DsError.ThrowExceptionForHR( hr );

// Find the find the capture pin from the video device and the

// input pin for the splitter, and connnect them

pRaw = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);

pSmart = DsFindPin.ByDirection(iSmartTee, PinDirection.Input, 0);

hr = m_FilterGraph.Connect(pRaw, pSmart);

DsError.ThrowExceptionForHR( hr );

// Now set the capture and still pins (from the splitter)

m_pinStill = DsFindPin.ByName(iSmartTee, "Preview");

pCaptureOut = DsFindPin.ByName(iSmartTee, "Capture");

// If any of the default config items are set, perform the config

// on the actual video device (rather than the splitter)

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

{

// Get a control pointer (used in Click())

m_VidControl = capFilter as IAMVideoControl;

pCaptureOut = DsFindPin.ByCategory(capFilter, PinCategory.Capture, 0);

// If any of the default config items are set

if (iHeight + iWidth + iBPP > 0)

{

SetConfigParms(m_pinStill, iWidth, iHeight, iBPP);

}

}

// Get the SampleGrabber interface

sampGrabber = new SampleGrabber() as ISampleGrabber;

// Configure the sample grabber

IBaseFilter baseGrabFlt = sampGrabber as IBaseFilter;

ConfigureSampleGrabber(sampGrabber);

pSampleIn = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Input, 0);

// Get the default video renderer

IBaseFilter pRenderer = new VideoRendererDefault() as IBaseFilter;

hr = m_FilterGraph.AddFilter(pRenderer, "Renderer");

DsError.ThrowExceptionForHR( hr );

pRenderIn = DsFindPin.ByDirection(pRenderer, PinDirection.Input, 0);

// Add the sample grabber to the graph

hr = m_FilterGraph.AddFilter( baseGrabFlt, "Ds.NET Grabber" );

DsError.ThrowExceptionForHR( hr );

if (m_VidControl == null)

{

// Connect the Still pin to the sample grabber

hr = m_FilterGraph.Connect(m_pinStill, pSampleIn);

DsError.ThrowExceptionForHR( hr );

// Connect the capture pin to the renderer

hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn);

DsError.ThrowExceptionForHR( hr );

}

else

{

// Connect the capture pin to the renderer

hr = m_FilterGraph.Connect(pCaptureOut, pRenderIn);

DsError.ThrowExceptionForHR( hr );

// Connect the Still pin to the sample grabber

hr = m_FilterGraph.Connect(m_pinStill, pSampleIn);

DsError.ThrowExceptionForHR( hr );

}

// Learn the video properties

SaveSizeInfo(sampGrabber);

ConfigVideoWindow(hControl);

// Start the graph

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;

// Get the media type from the SampleGrabber

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" );

}

// Grab the size info

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;

}

// Set the video window within the control specified by hControl

private void ConfigVideoWindow(Control hControl)

{

int hr;

IVideoWindow ivw = m_FilterGraph as IVideoWindow;

// Set the parent

hr = ivw.put_Owner(hControl.Handle);

DsError.ThrowExceptionForHR( hr );

// Turn off captions, etc

hr = ivw.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren | WindowStyle.ClipSiblings);

DsError.ThrowExceptionForHR( hr );

// Yes, make it visible

hr = ivw.put_Visible( OABool.True );

DsError.ThrowExceptionForHR( hr );

// Move to upper left corner

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();

// Set the media type to Video/RBG24

media.majorType = MediaType.Video;

media.subType = MediaSubType.RGB24;

media.formatType = FormatType.VideoInfo;

hr = sampGrabber.SetMediaType( media );

DsError.ThrowExceptionForHR( hr );

DsUtils.FreeAMMediaType(media);

media = null;

// Configure the samplegrabber

hr = sampGrabber.SetCallback( this, 1 );

DsError.ThrowExceptionForHR( hr );

}

// Set the Framerate, and video size

private void SetConfigParms(IPin pStill, int iWidth, int iHeight, short iBPP)

{

int hr;

AMMediaType media;

VideoInfoHeader v;

IAMStreamConfig videoStreamConfig = pStill as IAMStreamConfig;

// Get the existing format block

hr = videoStreamConfig.GetFormat(out media);

DsError.ThrowExceptionForHR(hr);

try

{

// copy out the videoinfoheader

v = new VideoInfoHeader();

Marshal.PtrToStructure( media.formatPtr, v );

// if overriding the width, set the width

if (iWidth > 0)

{

v.BmiHeader.Width = iWidth;

}

// if overriding the Height, set the Height

if (iHeight > 0)

{

v.BmiHeader.Height = iHeight;

}

// if overriding the bits per pixel

if (iBPP > 0)

{

v.BmiHeader.BitCount = iBPP;

}

// Copy the media structure back

Marshal.StructureToPtr( v, media.formatPtr, false );

// Set the new format

hr = videoStreamConfig.SetFormat( media );

DsError.ThrowExceptionForHR( hr );

}

finally

{

DsUtils.FreeAMMediaType(media);

media = null;

}

}

/// <summary> Shut down capture </summary>

private void CloseInterfaces()

{

int hr;

try

{

if( m_FilterGraph != null )

{

IMediaControl mediaCtrl = m_FilterGraph as IMediaControl;

// Stop the graph

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;

}

}

/// <summary> sample callback, NOT USED. </summary>

int ISampleGrabberCB.SampleCB( double SampleTime, IMediaSample pSample )

{

Marshal.ReleaseComObject(pSample);

return 0;

}

/// <summary> buffer callback, COULD BE FROM FOREIGN THREAD. </summary>

int ISampleGrabberCB.BufferCB( double SampleTime, IntPtr pBuffer, int BufferLen )

{

// Note that we depend on only being called once per call to Click. Otherwise

// a second call can overwrite the previous image.

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");

// Save the buffer

CopyMemory(m_ipBuffer, pBuffer, BufferLen);

// Picture is ready.

m_PictureReady.Set();

}

return 0;

}

}

}

Form1.cs

/****************************************************************************

While the underlying libraries are covered by LGPL, this sample is released

as public domain. It is distributed in the hope that it will be useful, but

WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY

or FITNESS FOR A PARTICULAR PURPOSE.

*****************************************************************************/

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Runtime.InteropServices;

using System.Drawing.Imaging;

namespace SnapShot

{

/// <summary>

/// Summary description for Form1.

/// </summary>

public class Form1 : System.Windows.Forms.Form

{

private System.Windows.Forms.Button button1;

private System.Windows.Forms.PictureBox pictureBox1;

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.Container components = null;

private System.Windows.Forms.PictureBox pictureBox2;

private Capture cam;

public Form1()

{

//

// Required for Windows Form Designer support

//

InitializeComponent();

const int VIDEODEVICE = 0; // zero based index of video capture device to use

const int VIDEOWIDTH = 640; // Depends on video device caps

const int VIDEOHEIGHT = 480; // Depends on video device caps

const int VIDEOBITSPERPIXEL = 24; // BitsPerPixel values determined by device

cam = new Capture(VIDEODEVICE, VIDEOWIDTH, VIDEOHEIGHT, VIDEOBITSPERPIXEL, pictureBox2);

}

/// <summary>

/// Clean up any resources being used.

/// </summary>

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;

}

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

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();

//

// button1

//

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);

//

// pictureBox1

//

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;

//

// pictureBox2

//

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;

//

// Form1

//

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);

}

#endregion

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main()

{

Application.Run(new Form1());

}

IntPtr m_ip = IntPtr.Zero;

private void button1_Click(object sender, System.EventArgs e)

{

Cursor.Current = Cursors.WaitCursor;

// Release any previous buffer

if (m_ip != IntPtr.Zero)

{

Marshal.FreeCoTaskMem(m_ip);

m_ip = IntPtr.Zero;

}

// capture image

m_ip = cam.Click();

Bitmap b = new Bitmap(cam.Width, cam.Height, cam.Stride, PixelFormat.Format24bppRgb, m_ip);

// If the image is upsidedown

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;

}

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: