C# 基于Directshow.Net lib库 USB摄像头使用DirectShow.NET获取摄像头视频流

https://blog.csdn.net/u010118312/article/details/91766787

https://download.csdn.net/download/u010118312/11238555

https://github.com/wanglong/DirectShow.NET-Webcam-Barcode-Reader

开源社区提供了DirectShow的.NET版本,为C#开发者提供了便利。这里分享下如何用DirectShow.NET API来启动摄像头,以及获取视频流数据。

参考原文:Read Barcode from Webcam Viewer with DirectShow.NET

作者:Xiao Ling

翻译:yushulx

学习资源

示例:获取视频流数据识别barcode

获取连接设备:

DsDevice[] devices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

获取DirectShow接口:

  1.  
    int hr = 0;
  2.  
     
  3.  
    this.graphBuilder = (IFilterGraph2)new FilterGraph();
  4.  
    this.captureGraphBuilder = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
  5.  
    this.mediaControl = (IMediaControl)this.graphBuilder;
  6.  
    this.videoWindow = (IVideoWindow)this.graphBuilder;
  7.  
    DsError.ThrowExceptionForHR(hr);

把filter graph添加到capture graph中:

  1.  
    hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder);
  2.  
    DsError.ThrowExceptionForHR(hr);

绑定Moniker:

  1.  
    int hr = 0;
  2.  
    IEnumMoniker classEnum = null;
  3.  
    IMoniker[] moniker = new IMoniker[1];
  4.  
    object source = null;
  5.  
     
  6.  
    // Create the system device enumerator
  7.  
    ICreateDevEnum devEnum = (ICreateDevEnum) new CreateDevEnum();
  8.  
     
  9.  
    // Create an enumerator for the video capture devices
  10.  
    hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, 0);
  11.  
    DsError.ThrowExceptionForHR(hr);
  12.  
     
  13.  
    // The device enumerator is no more needed
  14.  
    Marshal.ReleaseComObject(devEnum);
  15.  
     
  16.  
    // If there are no enumerators for the requested type, then
  17.  
    // CreateClassEnumerator will succeed, but classEnum will be NULL.
  18.  
    if (classEnum == null)
  19.  
    {
  20.  
    throw new ApplicationException("No video capture device was detected.\r\n\r\n" +
  21.  
    "This sample requires a video capture device, such as a USB WebCam,\r\n" +
  22.  
    "to be installed and working properly. The sample will now close.");
  23.  
    }
  24.  
     
  25.  
    // Use the first video capture device on the device list.
  26.  
    // Note that if the Next() call succeeds but there are no monikers,
  27.  
    // it will return 1 (S_FALSE) (which is not a failure). Therefore, we
  28.  
    // check that the return code is 0 (S_OK).
  29.  
     
  30.  
    if (classEnum.Next(moniker.Length, moniker, IntPtr.Zero) == 0)
  31.  
    {
  32.  
    // Bind Moniker to a filter object
  33.  
    Guid iid = typeof(IBaseFilter).GUID;
  34.  
    moniker[ 0].BindToObject(null, null, ref iid, out source);
  35.  
    }
  36.  
    else
  37.  
    {
  38.  
    throw new ApplicationException("Unable to access video capture device!");
  39.  
    }
  40.  
     
  41.  
    // Release COM objects
  42.  
    Marshal.ReleaseComObject(moniker[ 0]);
  43.  
    Marshal.ReleaseComObject(classEnum);
  44.  
     
  45.  
    // An exception is thrown if cast fail
  46.  
    return (IBaseFilter)source;

把选择的设备添加到graph中:

  1.  
    hr = this.graphBuilder.AddFilter(sourceFilter, "Video Capture");
  2.  
    DsError.ThrowExceptionForHR(hr);

创建sampleGrabber来设置取视频流回调函数:

  1.  
    sampleGrabber = new SampleGrabber() as ISampleGrabber;
  2.  
     
  3.  
    {
  4.  
    AMMediaType media;
  5.  
    int hr;
  6.  
    // Set the media type to Video/RBG24
  7.  
    media = new AMMediaType();
  8.  
    media.majorType = MediaType.Video;
  9.  
    media.subType = MediaSubType.RGB24;
  10.  
    media.formatType = FormatType.VideoInfo;
  11.  
    hr = sampleGrabber.SetMediaType(media);
  12.  
    DsError.ThrowExceptionForHR(hr);
  13.  
    DsUtils.FreeAMMediaType(media);
  14.  
    media = null;
  15.  
    hr = sampleGrabber.SetCallback( this, 1);
  16.  
    DsError.ThrowExceptionForHR(hr);
  17.  
    }

把SampleGrabber添加到graph中:

  1.  
    hr = this.graphBuilder.AddFilter(sampleGrabber as IBaseFilter, "Frame Callback");
  2.  
    DsError.ThrowExceptionForHR(hr);

初始化视频属性:

  1.  
    private void SetConfigParams(ICaptureGraphBuilder2 capGraph, IBaseFilter capFilter, int iFrameRate, int iWidth, int iHeight)
  2.  
    {
  3.  
    int hr;
  4.  
    object config;
  5.  
    AMMediaType mediaType;
  6.  
    // Find the stream config interface
  7.  
    hr = capGraph.FindInterface(
  8.  
    PinCategory.Capture, MediaType.Video, capFilter, typeof(IAMStreamConfig).GUID, out config);
  9.  
     
  10.  
    IAMStreamConfig videoStreamConfig = config as IAMStreamConfig;
  11.  
    if (videoStreamConfig == null)
  12.  
    {
  13.  
    throw new Exception("Failed to get IAMStreamConfig");
  14.  
    }
  15.  
     
  16.  
    // Get the existing format block
  17.  
    hr = videoStreamConfig.GetFormat( out mediaType);
  18.  
    DsError.ThrowExceptionForHR(hr);
  19.  
     
  20.  
    // copy out the videoinfoheader
  21.  
    VideoInfoHeader videoInfoHeader = new VideoInfoHeader();
  22.  
    Marshal.PtrToStructure(mediaType.formatPtr, videoInfoHeader);
  23.  
     
  24.  
    // if overriding the framerate, set the frame rate
  25.  
    if (iFrameRate > 0)
  26.  
    {
  27.  
    videoInfoHeader.AvgTimePerFrame = 10000000 / iFrameRate;
  28.  
    }
  29.  
     
  30.  
    // if overriding the width, set the width
  31.  
    if (iWidth > 0)
  32.  
    {
  33.  
    videoInfoHeader.BmiHeader.Width = iWidth;
  34.  
    }
  35.  
     
  36.  
    // if overriding the Height, set the Height
  37.  
    if (iHeight > 0)
  38.  
    {
  39.  
    videoInfoHeader.BmiHeader.Height = iHeight;
  40.  
    }
  41.  
     
  42.  
    // Copy the media structure back
  43.  
    Marshal.StructureToPtr(videoInfoHeader, mediaType.formatPtr, false);
  44.  
     
  45.  
    // Set the new format
  46.  
    hr = videoStreamConfig.SetFormat(mediaType);
  47.  
    DsError.ThrowExceptionForHR(hr);
  48.  
     
  49.  
    DsUtils.FreeAMMediaType(mediaType);
  50.  
    mediaType = null;
  51.  
    }

绘制画面:

  1.  
    hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, (sampleGrabber as IBaseFilter), null);
  2.  
    DsError.ThrowExceptionForHR(hr);

设置视频输出窗口,调整视频位置:

  1.  
    int hr = 0;
  2.  
    // Set the video window to be a child of the PictureBox
  3.  
    hr = this.videoWindow.put_Owner(pictureBox1.Handle);
  4.  
    DsError.ThrowExceptionForHR(hr);
  5.  
     
  6.  
    hr = this.videoWindow.put_WindowStyle(WindowStyle.Child);
  7.  
    DsError.ThrowExceptionForHR(hr);
  8.  
     
  9.  
    // Make the video window visible, now that it is properly positioned
  10.  
    hr = this.videoWindow.put_Visible(OABool.True);
  11.  
    DsError.ThrowExceptionForHR(hr);
  12.  
     
  13.  
    // Set the video position
  14.  
    Rectangle rc = pictureBox1.ClientRectangle;
  15.  
    hr = videoWindow.SetWindowPosition( 0, 0, _previewWidth, _previewHeight);
  16.  
    DsError.ThrowExceptionForHR(hr);

启动摄像头预览画面:

  1.  
    rot = new DsROTEntry(this.graphBuilder);
  2.  
    hr = this.mediaControl.Run();
  3.  
    DsError.ThrowExceptionForHR(hr);

获取视频流数据,异步读取barcode:

  1.  
    public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
  2.  
    {
  3.  
     
  4.  
    Bitmap v = new Bitmap(_previewWidth, _previewHeight, _previewStride,
  5.  
    PixelFormat.Format24bppRgb, pBuffer);
  6.  
    v.RotateFlip(RotateFlipType.Rotate180FlipX);
  7.  
     
  8.  
    if (isFinished)
  9.  
    {
  10.  
    this.BeginInvoke((MethodInvoker)delegate
  11.  
    {
  12.  
    isFinished = false;
  13.  
    ReadBarcode(v);
  14.  
    isFinished = true;
  15.  
    });
  16.  
    }
  17.  
    return 0;
  18.  
    }

源码

https://github.com/yushulx/DirectShow.NET-Webcam-Barcode-Reader

C# 基于Directshow.Net lib库 USB摄像头硬件按钮捕获程序采用无窗模式显示

经过半个月的学习,虽然对Directshow还知之甚少,但总算完成了自己的需求,故mark,希望可以帮助有需要的;

       先说点闲篇,本人不是专业程序员出身,属于半路出家,学了C#,搞了点应用开发;之前是做电路设计的,所以我的程序说好听点叫移植,说白了就是东拼西凑出来,能实现功能是我的最大追求,至于效率等更高层次的,还不是我现在能搞定的,代码肯定有很多需要修改的,大家自己看着用;

       首先,我的项目需求原先是客户的USB摄像头,上面带了个硬件按钮,客户按下按钮,需要捕获一张图片,然后再做其他的分析;程序需求2个显示串口,可以在不同的tab下显示,所以我需要2个可以获取视屏的显示窗口,同时这两个窗口还需要显示视屏流,同时中间可以停止,并显示图片,处理图片,处理完再接通视屏流;一开始我是用的是OPENCV,C#版,但是OPENCV好像没有找到可以捕获USB摄像头的硬件按钮的函数接口,实在没办法,网上搜索,发现用Directshow 的Still功能可以实现,所以才有了半个月的Directshow学习;同样为了实现目的,我用了4个panel控件,2个用于显示视屏流,2个用于显示按键捕获的图片;

       先说一下无窗模式,因为之前用的是有窗模式显示,但是用4个显示时,有2个不显示在Panel上,而单独弹出显示窗口,后来才发现可以使用无窗模式;

我的程序主要采用的是C# Directshow.net lib实现,程序是基于该库的Sample实例,整合拼凑而来;库和实例地址如下:

库:https://sourceforge.net/projects/directshownet/

示例:https://sourceforge.net/projects/directshownet/files/DirectShowSamples/2010-February/

当然这些都是好几年前的,很久没有跟新了,不过对我来说还能用,还是很不错的,我才基于Sample示例里面的Capwmv和VMR9Snapper 2个示例合成并加以改编完成的;先来看一下显示界面:

上面2个Panel显示的是视屏流,一个为Capture一个为Preview;

下面2个为捕获显示图片,用于后续图像处理;

Filter设置如下:

USB camera一般有2个Output pin,一个捕获(capture),一个静态(still),捕获用有试试显示视频流,still用于按钮抓取图像,Smart tee用于将2个1个输入视频流转成2个,中间的MJPEG 和Color Space 不需要;但EditGrhap会自动添加;

不多说了,程序代碼如下:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using DirectShowLib;

using Microsoft.Win32;
using System.Diagnostics;
using System.IO;

namespace DirectShowLib.Sample
{
public class MainForm : System.Windows.Forms.Form, ISampleGrabberCB, IDisposable
{
private System.Windows.Forms.MainMenu mainMenu;
private System.Windows.Forms.OpenFileDialog openFileDialog;
private System.Windows.Forms.MenuItem menuFile;
private System.Windows.Forms.MenuItem menuItem1;
private System.Windows.Forms.MenuItem menuFileExit;
private IContainer components;

// Used to snap picture on Still pin
private IAMVideoControl m_VidControl = null;
private IPin pPreviewOut = null;
private IPin pPreviewOutStill = null;
private int m_videoWidth;
private int m_videoHeight;
private int m_stride;

#if DEBUG
// Allow you to "Connect to remote graph" from GraphEdit
DsROTEntry m_rot = null;
#endif
// DirectShow stuff
private IFilterGraph2 graphBuilder = null;
private IMediaControl mediaControl = null;
private IBaseFilter vmr9 = null;
private IBaseFilter vmr9_2 = null;
private IBaseFilter vmr9_3 = null;
private IBaseFilter vmr9_4 = null;

private IVMRWindowlessControl9 windowlessCtrl = null;
private IVMRWindowlessControl9 windowlessCtrl_2 = null;
private IVMRWindowlessControl9 windowlessCtrl_3 = null;
private IVMRWindowlessControl9 windowlessCtrl_4 = null;

private SaveFileDialog saveFileDialog;
private Panel panel1; // Needed to remove delegates
private Panel panel2;
private Panel panel3;
private Panel panel4;

private IntPtr m_ipBuffer = IntPtr.Zero;
public delegate void Changepicturebox(int num, bool visible, Bitmap bitmap1); //picbox
public delegate void Changeimagebox(int num, bool visible); //imagebox
public Changepicturebox changepicbox1;
public Changeimagebox changeimgbox1;

string file_name_image = null;
int count_pic = 0;

// Menus stuff
private MenuItem menuSnap;

public MainForm()
{
InitializeComponent();
changepicbox1 = FunChangepicture;
}

/// <summary>
/// Nettoyage des ressources utilis閑s.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
// Clean-up DirectShow interfaces
CloseInterfaces();
base.Dispose( disposing );
}

#region Code g閚閞?par le Concepteur Windows Form
/// <summary>
/// M閠hode requise pour la prise en charge du concepteur - ne modifiez pas
/// le contenu de cette m閠hode avec l'閐iteur de code.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
this.mainMenu = new System.Windows.Forms.MainMenu(this.components);
this.menuFile = new System.Windows.Forms.MenuItem();
this.menuSnap = new System.Windows.Forms.MenuItem();
this.menuItem1 = new System.Windows.Forms.MenuItem();
this.menuFileExit = new System.Windows.Forms.MenuItem();
this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
this.saveFileDialog = new System.Windows.Forms.SaveFileDialog();
this.panel1 = new System.Windows.Forms.Panel();
this.panel2 = new System.Windows.Forms.Panel();
this.panel3 = new System.Windows.Forms.Panel();
this.panel4 = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// mainMenu
//
this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuFile});
//
// menuFile
//
this.menuFile.Index = 0;
this.menuFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
this.menuSnap,
this.menuItem1,
this.menuFileExit});
this.menuFile.Text = "File";
//
// menuSnap
//
this.menuSnap.Index = 0;
this.menuSnap.Text = "Save image...";
this.menuSnap.Click += new System.EventHandler(this.menuSnap_Click);
//
// menuItem1
//
this.menuItem1.Index = 1;
this.menuItem1.Text = "-";
//
// menuFileExit
//
this.menuFileExit.Index = 2;
this.menuFileExit.Text = "Exit";
this.menuFileExit.Click += new System.EventHandler(this.menuFileExit_Click);
//
// openFileDialog
//
this.openFileDialog.Filter = resources.GetString("openFileDialog.Filter");
//
// panel1
//
this.panel1.BackColor = System.Drawing.SystemColors.ControlDarkDark;
this.panel1.Location = new System.Drawing.Point(3, 3);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(639, 475);
this.panel1.TabIndex = 1;
//
// panel2
//
this.panel2.BackColor = System.Drawing.SystemColors.ControlDarkDark;
this.panel2.Location = new System.Drawing.Point(654, 3);
this.panel2.Name = "panel2";
this.panel2.Size = new System.Drawing.Size(639, 475);
this.panel2.TabIndex = 1;
//
// panel3
//
this.panel3.BackColor = System.Drawing.SystemColors.ControlDarkDark;
this.panel3.Location = new System.Drawing.Point(3, 493);
this.panel3.Name = "panel3";
this.panel3.Size = new System.Drawing.Size(639, 475);
this.panel3.TabIndex = 2;
//
// panel4
//
this.panel4.BackColor = System.Drawing.SystemColors.ControlDarkDark;
this.panel4.Location = new System.Drawing.Point(654, 493);
this.panel4.Name = "panel4";
this.panel4.Size = new System.Drawing.Size(639, 475);
this.panel4.TabIndex = 3;
//
// MainForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
this.ClientSize = new System.Drawing.Size(1305, 980);
this.Controls.Add(this.panel2);
this.Controls.Add(this.panel1);
this.Controls.Add(this.panel4);
this.Controls.Add(this.panel3);
this.Menu = this.mainMenu;
this.Name = "MainForm";
this.Text = "VMR Snapper";
this.Load += new System.EventHandler(this.MainForm_Load);
this.ResumeLayout(false);

}
#endregion
private void CloseInterfaces()
{
if (mediaControl != null)
mediaControl.Stop();

if (vmr9 != null)
{
Marshal.ReleaseComObject(vmr9);
vmr9 = null;
windowlessCtrl = null;
}
if (vmr9_2 != null)
{
Marshal.ReleaseComObject(vmr9_2);
vmr9_2 = null;
windowlessCtrl_2 = null;
}

if (graphBuilder != null)
{
Marshal.ReleaseComObject(graphBuilder);
graphBuilder = null;
mediaControl = null;
}

}

private void ConfigureVMR9InWindowlessMode()
{
int hr = 0;

IVMRFilterConfig9 filterConfig = (IVMRFilterConfig9) vmr9;

// Not really needed for VMR9 but don't forget calling it with VMR7
hr = filterConfig.SetNumberOfStreams(1);
DsError.ThrowExceptionForHR(hr);

// Change VMR9 mode to Windowless
hr = filterConfig.SetRenderingMode(VMR9Mode.Windowless);
DsError.ThrowExceptionForHR(hr);

windowlessCtrl = (IVMRWindowlessControl9) vmr9;

// Set "Parent" window
hr = windowlessCtrl.SetVideoClippingWindow(this.panel1.Handle);
DsError.ThrowExceptionForHR(hr);

// Set Aspect-Ratio
hr = windowlessCtrl.SetAspectRatioMode(VMR9AspectRatioMode.LetterBox);
DsError.ThrowExceptionForHR(hr);

if (windowlessCtrl != null)
{
hr = windowlessCtrl.SetVideoPosition(null, DsRect.FromRectangle(this.panel1.ClientRectangle));
}
}

private void ConfigureVMR9InWindowlessMode_2()
{
int hr = 0;

IVMRFilterConfig9 filterConfig = (IVMRFilterConfig9)vmr9_2;

// Not really needed for VMR9 but don't forget calling it with VMR7
hr = filterConfig.SetNumberOfStreams(1);
DsError.ThrowExceptionForHR(hr);

// Change VMR9 mode to Windowless
hr = filterConfig.SetRenderingMode(VMR9Mode.Windowless);
DsError.ThrowExceptionForHR(hr);

windowlessCtrl_2 = (IVMRWindowlessControl9)vmr9_2;

// Set "Parent" window
hr = windowlessCtrl_2.SetVideoClippingWindow(this.panel2.Handle);
DsError.ThrowExceptionForHR(hr);

// Set Aspect-Ratio
hr = windowlessCtrl_2.SetAspectRatioMode(VMR9AspectRatioMode.LetterBox);
DsError.ThrowExceptionForHR(hr);

if (windowlessCtrl_2 != null)
{
hr = windowlessCtrl_2.SetVideoPosition(null, DsRect.FromRectangle(this.panel2.ClientRectangle));
}
}

private void ConfigureVMR9InWindowlessMode_3()
{
int hr = 0;

IVMRFilterConfig9 filterConfig = (IVMRFilterConfig9)vmr9_3;

// Not really needed for VMR9 but don't forget calling it with VMR7
hr = filterConfig.SetNumberOfStreams(1);
DsError.ThrowExceptionForHR(hr);

// Change VMR9 mode to Windowless
hr = filterConfig.SetRenderingMode(VMR9Mode.Windowless);
DsError.ThrowExceptionForHR(hr);

windowlessCtrl_3 = (IVMRWindowlessControl9)vmr9_3;

// Set "Parent" window
hr = windowlessCtrl_3.SetVideoClippingWindow(this.panel3.Handle);
DsError.ThrowExceptionForHR(hr);

// Set Aspect-Ratio
hr = windowlessCtrl_3.SetAspectRatioMode(VMR9AspectRatioMode.LetterBox);
DsError.ThrowExceptionForHR(hr);

if (windowlessCtrl_3 != null)
{
hr = windowlessCtrl_3.SetVideoPosition(null, DsRect.FromRectangle(this.panel3.ClientRectangle));
}
}

private void ConfigureVMR9InWindowlessMode_4()
{
int hr = 0;

IVMRFilterConfig9 filterConfig = (IVMRFilterConfig9)vmr9_4;

// Not really needed for VMR9 but don't forget calling it with VMR7
hr = filterConfig.SetNumberOfStreams(1);
DsError.ThrowExceptionForHR(hr);

// Change VMR9 mode to Windowless
hr = filterConfig.SetRenderingMode(VMR9Mode.Windowless);
DsError.ThrowExceptionForHR(hr);

windowlessCtrl_4 = (IVMRWindowlessControl9)vmr9_4;

// Set "Parent" window
hr = windowlessCtrl_4.SetVideoClippingWindow(this.panel4.Handle);
DsError.ThrowExceptionForHR(hr);

// Set Aspect-Ratio
hr = windowlessCtrl_4.SetAspectRatioMode(VMR9AspectRatioMode.LetterBox);
DsError.ThrowExceptionForHR(hr);

if (windowlessCtrl_4 != null)
{
hr = windowlessCtrl_4.SetVideoPosition(null, DsRect.FromRectangle(this.panel4.ClientRectangle));
}
}

private void menuFileExit_Click(object sender, System.EventArgs e)
{
CloseInterfaces();
this.Dispose();
}

[STAThread]
static void Main()
{
using (MainForm form = new MainForm())
{
Application.Run(form);
}
}

private void menuSnap_Click(object sender, EventArgs e)
{
count_pic++;
snapImage();
panel3.BackgroundImage = Image.FromFile(file_name_image);
panel4.BackgroundImage = Image.FromFile(file_name_image);
}

// 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;
}
}

private void SetConfigParmsStill(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;
}
}
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);
}
private void ConfigureSampleGrabberStill(ISampleGrabber sampGrabberStill)
{
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 = sampGrabberStill.SetMediaType(media);
DsError.ThrowExceptionForHR(hr);

DsUtils.FreeAMMediaType(media);
media = null;

// Configure the samplegrabber
hr = sampGrabberStill.SetCallback(this, 1);
DsError.ThrowExceptionForHR(hr);
}
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;
}
private void SetupGraph(DsDevice dev, int iWidth, int iHeight, short iBPP)
{
int hr;
ISampleGrabber sampGrabber = null;
ISampleGrabber sampGrabberStill = null; //add by tim

IBaseFilter capFilter = null;
IPin pCaptureOut = null;
IPin pCaptureOutStill = null; //add by tim
IPin pStill = null; //add by tim
IPin pSampleIn = null;
IPin pSampleOut = null;

IPin pSampleInStill = null; //add by tim
IPin pSampleOutStill = null; //add by tim

IPin pRenderIn = null;
IPin pRenderIn_2 = null;

IPin pRenderIn_3 = null; //add by tim
IPin pRenderIn_4 = null; //add by tim

// Get the graphbuilder object
graphBuilder = new FilterGraph() as IFilterGraph2;
try
{
#if DEBUG
m_rot = new DsROTEntry(graphBuilder);
#endif
// add the video input device
hr = graphBuilder.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out capFilter);
DsError.ThrowExceptionForHR(hr);

IPin pRaw = null;
IPin pSmart = null;

IPin pRawStill = null; //add by tim
IPin pSmartStill = null; //add by tim

// There is no still pin
m_VidControl = null;
// Add a splitter
IBaseFilter iSmartTee = (IBaseFilter)new SmartTee();
IBaseFilter iSmartTeeStill = (IBaseFilter)new SmartTee(); //add by tim
try
{
hr = graphBuilder.AddFilter(iSmartTee, "SmartTee");
DsError.ThrowExceptionForHR(hr);

hr = graphBuilder.AddFilter(iSmartTeeStill, "SmartTeeStill"); //add by tim
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 = graphBuilder.Connect(pRaw, pSmart);
DsError.ThrowExceptionForHR(hr);

pStill = DsFindPin.ByCategory(capFilter, PinCategory.Still, 0); // by tim
pSmartStill = DsFindPin.ByDirection(iSmartTeeStill, PinDirection.Input, 0); // by tim

hr = graphBuilder.Connect(pStill, pSmartStill); // by tim
DsError.ThrowExceptionForHR(hr); // by tim

// Now set the capture and still pins (from the splitter)
pPreviewOut = DsFindPin.ByName(iSmartTee, "Preview");
pCaptureOut = DsFindPin.ByName(iSmartTee, "Capture");

pPreviewOutStill = DsFindPin.ByName(iSmartTeeStill, "Preview");
pCaptureOutStill = DsFindPin.ByName(iSmartTeeStill, "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);
SetConfigParms(pStill, iWidth, iHeight, iBPP);
}
}
finally
{
if (pRaw != null)
{
Marshal.ReleaseComObject(pRaw);
}
if (pRaw != pSmart)
{
Marshal.ReleaseComObject(pSmart);
}
if (pRaw != iSmartTee)
{
Marshal.ReleaseComObject(iSmartTee);
}

if (pStill != null) // by tim
{
Marshal.ReleaseComObject(pStill);
}
if (pStill != pSmartStill) // by tim
{
Marshal.ReleaseComObject(pSmartStill);
}
if (pStill != iSmartTeeStill) // by tim
{
Marshal.ReleaseComObject(iSmartTeeStill);
}
}

// 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);
pSampleOut = DsFindPin.ByDirection(baseGrabFlt, PinDirection.Output, 0);

// Get the SampleGrabber interface
sampGrabberStill = new SampleGrabber() as ISampleGrabber; // by tim
// Configure the sample grabber Still
IBaseFilter baseGrabFlt_Still = sampGrabberStill as IBaseFilter; // by tim
ConfigureSampleGrabberStill(sampGrabberStill);
pSampleInStill = DsFindPin.ByDirection(baseGrabFlt_Still, PinDirection.Input, 0); // by tim
pSampleOutStill = DsFindPin.ByDirection(baseGrabFlt_Still, PinDirection.Output, 0); // by tim


// Get the default video renderer
vmr9 = (IBaseFilter)new VideoMixingRenderer9();
ConfigureVMR9InWindowlessMode();
hr = graphBuilder.AddFilter(vmr9, "Video Mixing Renderer 9");
DsError.ThrowExceptionForHR(hr);
pRenderIn = DsFindPin.ByDirection(vmr9, PinDirection.Input, 0);

// Get the default video renderer
vmr9_2 = (IBaseFilter)new VideoMixingRenderer9();
ConfigureVMR9InWindowlessMode_2();
hr = graphBuilder.AddFilter(vmr9_2, "Video Mixing Renderer 9_2");
DsError.ThrowExceptionForHR(hr);
pRenderIn_2 = DsFindPin.ByDirection(vmr9_2, PinDirection.Input, 0);


// Get the default video renderer
vmr9_3 = (IBaseFilter)new VideoMixingRenderer9(); // by tim
ConfigureVMR9InWindowlessMode_3();
hr = graphBuilder.AddFilter(vmr9_3, "Video Mixing Renderer 9_3");
DsError.ThrowExceptionForHR(hr);
pRenderIn_3 = DsFindPin.ByDirection(vmr9_3, PinDirection.Input, 0);

// Get the default video renderer
vmr9_4 = (IBaseFilter)new VideoMixingRenderer9(); // by tim
ConfigureVMR9InWindowlessMode_4();
hr = graphBuilder.AddFilter(vmr9_4, "Video Mixing Renderer 9_4");
DsError.ThrowExceptionForHR(hr);
pRenderIn_4 = DsFindPin.ByDirection(vmr9_4, PinDirection.Input, 0);


hr = graphBuilder.AddFilter(baseGrabFlt, "Ds.NET Grabber");
DsError.ThrowExceptionForHR(hr);

hr = graphBuilder.AddFilter(baseGrabFlt_Still, "Still"); //Still
DsError.ThrowExceptionForHR(hr);

// Connect the Still pin to the sample grabber
hr = graphBuilder.Connect(pPreviewOut, pSampleIn);
DsError.ThrowExceptionForHR(hr);

// Connect the Still pin to the sample grabber
hr = graphBuilder.Connect(pPreviewOutStill, pSampleInStill); // by tim
DsError.ThrowExceptionForHR(hr);

// Connect the capture pin to the renderer
hr = graphBuilder.Connect(pCaptureOut, pRenderIn_2);
DsError.ThrowExceptionForHR(hr);

// Connect the capture pin to the renderer
hr = graphBuilder.Connect(pSampleOut, pRenderIn);
DsError.ThrowExceptionForHR(hr);

// Connect the capture pin to the renderer
hr = graphBuilder.Connect(pCaptureOutStill, pRenderIn_4); // by tim
DsError.ThrowExceptionForHR(hr);

// Connect the capture pin to the renderer
hr = graphBuilder.Connect(pSampleOutStill, pRenderIn_3); // by tim
DsError.ThrowExceptionForHR(hr);

SaveSizeInfo(sampGrabber);
SaveSizeInfo(sampGrabberStill); // by tim
mediaControl = (IMediaControl)graphBuilder;
hr = mediaControl.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;
}
if (sampGrabberStill != null)
{
Marshal.ReleaseComObject(sampGrabberStill);
sampGrabberStill = null;
}
if (pCaptureOutStill != null)
{
Marshal.ReleaseComObject(pCaptureOutStill);
pCaptureOutStill = null;
}
if (pRenderIn_3 != null)
{
Marshal.ReleaseComObject(pRenderIn_3);
pRenderIn_3 = null;
}
if (pRenderIn_4 != null)
{
Marshal.ReleaseComObject(pRenderIn_4);
pRenderIn_4 = null;
}
if (pSampleInStill != null)
{
Marshal.ReleaseComObject(pSampleInStill);
pSampleInStill = null;
}
}
}

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)
{
//按钮捕获的图片及后续处理可以在此执行
//{.....}

return 0;
}


public void FunChangepicture(int num, bool visible, Bitmap bitmap1)
{
if (num == 1)
{
panel3.BackgroundImage = bitmap1;
}
else if (num == 2)
{
panel4.BackgroundImage = bitmap1;
}
}
private void snapImage()
{
if (windowlessCtrl != null)
{
IntPtr currentImage = IntPtr.Zero;
Bitmap bmp = null;

try
{
int hr = windowlessCtrl.GetCurrentImage(out currentImage);
DsError.ThrowExceptionForHR(hr);

if (currentImage != IntPtr.Zero)
{
BitmapInfoHeader structure = new BitmapInfoHeader();
Marshal.PtrToStructure(currentImage, structure);

bmp = new Bitmap(structure.Width, structure.Height, (structure.BitCount / 8) * structure.Width, System.Drawing.Imaging.PixelFormat.Format32bppArgb, new IntPtr(currentImage.ToInt64() + 40));
bmp.RotateFlip(RotateFlipType.RotateNoneFlipY);
file_name_image = Application.StartupPath + "\\Image\\pic" + DateTime.Now.ToString("yyyyMMdd") + count_pic.ToString("D4") + ".jpg";
bmp.Save(file_name_image, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (Exception anyException)
{
MessageBox.Show("Failed getting image: " + anyException.Message);
}
finally
{
if (bmp != null)
{
bmp.Dispose();
}
Marshal.FreeCoTaskMem(currentImage);
}
}
}

private void MainForm_Load(object sender, EventArgs e)
{
Capture(0,640, 480, 24);
}
public void Capture(int iDeviceNum, int iWidth, int iHeight, short iBPP)
{
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);
}
catch
{
Dispose();
throw;
}
}
}
}
源码下载:https://download.csdn.net/download/u010118312/11238555

如果运行有错误,请重新添加引用Directshow-2005.lib,因为路径不同;
————————————————
版权声明:本文为CSDN博主「秦风古韵」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u010118312/article/details/91766787

猜你喜欢

转载自www.cnblogs.com/Leo_wl/p/11435277.html