锐英源软件
第一信赖

精通

英语

开源

擅长

开发

培训

胸怀四海 

第一信赖

当前位置:锐英源 / 流媒体开源 / Web摄像头控件
服务方向
人工智能数据处理
人工智能培训
kaldi数据准备
小语种语音识别
语音识别标注
语音识别系统
语音识别转文字
kaldi开发技术服务
软件开发
运动控制卡上位机
机械加工软件
软件开发培训
Java 安卓移动开发
VC++
C#软件
汇编和破解
驱动开发
联系方式
固话:0371-63888850
手机:138-0381-0136
Q Q:396806883
微信:ryysoft

锐英源精品开源心得,禁止转载,违法必究。

Web摄像头控件


前言

用C#开发自定义控件相对C++来说容易,不过结合了流媒体的处理就复杂了.摄像头数据从捕获到显示要通过好几层,中间是有难度的.本文对开发过程进行了完善的翻译,适合大家学习

Introduction

In this article you will find yet another implementation of a web camera control. The control is a simple and easy to use one: no additional dependencies and a minimalistic interface.

The control provides the following functionalities:

  1. Gets a list of available web camera devices on a system.
  2. Displays a video stream from a web camera device.
  3. Gets the current image being captured.
  4. 在本文中,您将找到另一种网络摄像头控件的实现。该控件是一个简单易用的控件:没有额外的依赖关系和界面简约。

    该控件提供以下功能:

    1. 获取系统上可用的Web 摄像头设备列表。
    2. 显示来自网络摄像头设备的视频流。
    3. 获取当前捕获的图像。

Requirements

  1. The WinForms version of the control is implemented using .NET Framework 2.0.
  2. The WPF version of the control is implemented using .NET Framework 4 Client Profile.
  3. The control uses the VMR-9 renderer filter available since Windows XP SP2.

The control supports both x86 and x64 platform targets.

  1. 控件的WinForms版本使用.NET Framework 2.0实现。
  2. 控件的WPF版本使用.NET Framework 4 Client Profile实现。
  3. 该控件使用自Windows XP SP2以来可用的VMR-9渲染器过滤器。

该控件支持x86和x64平台目标。

Background

There are a number of ways to capture a video stream in Windows. Not mentioning all of them, the basic are DirectShow framework and AVICap library. We will use the DirectShow based approach, as it is more powerful and flexible.

The DirectShow framework operates using such concepts as a graph, filters and pins. The filters form a capture graph, through which a media stream flows. The filters in the graph are connected to each other using pins. A web camera is the capture filter a video stream starts from. The control’s window is passed to a renderer filter, which receives and shows the video stream. There are other in-the-middle filters possible, for example, color space conversion filters. That is all about the capture graph. See MSDN DirectShow documentation for more information.

有许多方法可以在Windows中捕获视频流。不提及所有这些,基本是DirectShow框架和AVICap库。我们将使用基于DirectShow的方法,因为它更强大和灵活。

DirectShow框架使用连接图,过滤器和引脚等概念进行操作。过滤器形成连接图,媒体流通过该连接图流动。连接图中的过滤器使用引脚相互连接。网络摄像头是视频流开始的捕获过滤器。控件的窗口将传递给渲染器过滤器,该过滤器接收并显示视频流。还可以使用其他中间滤波器,例如,色彩空间转换滤波器。这就是捕获图。有关更多信息,请参阅MSDN DirectShow文档

Implementation Details

If you are not interested in implementation details, then you can skip this section.

The implementation is divided into three layers.

  1. The bottom layer is implemented as a native DLL module, which forwards our calls to the DirectShow framework.
  2. For distribution convenience, the native DLL module is embedded into the control’s assembly as a resource. On runtime stage, the DLL module will be extracted to a temporary file on disk and used via late binding technique. Once the control is disposed, the temporary file will be deleted. In other words, the control is distributed as a single file. All those operations are implemented by the middle layer.
  3. The top layer implements the control class itself and the WebCameraId class used to identify a web camera device.

The following diagram shows a logical structure of the implementation.

如果您对实现细节不感兴趣,那么您可以跳过本节。

实施分为三层。

  1. 底层实现为本机DLL模块,它将我们的调用转发给DirectShow框架。
  2. 为了方便分发,本机DLL模块作为资源嵌入到控件的程序集中。在运行时阶段,DLL模块将被提取到磁盘上的临时文件,并通过后期绑定技术使用。处理完控件后,将删除临时文件。换句话说,控件作为单个文件分发。所有这些操作都由中间层实现。
  3. 顶层实现控件类本身以及用于标识Web 摄像头设备的类。WebCameraId

下图显示了实现的逻辑结构。

控件架构

Only the top layer is supposed to be used by clients.客户端应该只使用顶层。

The Bottom Layer

The bottom layer implements the following utilities to work with the capture graph.

/// <summary>
/// Enumerates video input devices in a system.
/// </summary>
/// <param name="callback">A callback method.</param>
DSUTILS_API void __stdcall EnumVideoInputDevices(EnumVideoInputDevicesCallback callback);

/// <summary>
/// Builds a video capture graph.
/// </summary>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall BuildCaptureGraph();

/// <summary>
/// Adds a renderer filter to a video capture graph,
/// which renders a video stream within a container window.
/// </summary>
/// <param name="hWnd">A container window that video should be clipped to.</param>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall AddRenderFilter(HWND hWnd);

/// <summary>
/// Adds a video stream source to a video capture graph.
/// </summary>
/// <param name="devicePath">A device path of a video capture filter to add.</param>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall AddCaptureFilter(BSTR devicePath);

/// <summary>
/// Removes a video stream source from a video capture graph.
/// </summary>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall ResetCaptureGraph();

/// <summary>
/// Runs all the filters in a video capture graph. While the graph is running,
/// data moves through the graph and is rendered.
/// </summary>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall Start();

/// <summary>
/// Stops all the filters in a video capture graph.
/// </summary>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall Stop();

/// <summary>
/// Retrieves the current image being displayed by the renderer filter.
/// </summary>
/// <param name="ppDib">Address of a pointer to a BYTE that will receive the DIB.</param>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall GetCurrentImage(BYTE **ppDib);

/// <summary>
/// Retrieves the unstretched video size.
/// </summary>
/// <param name="lpWidth">A pointer to a LONG that will receive the width.</param>
/// <param name="lpHeight">A pointer to a LONG that will receive the height.</param>
/// <returns>If the function succeeds, the return value is zero.</returns>
DSUTILS_API int __stdcall GetVideoSize(LONG *lpWidth, LONG *lpHeight);

/// <summary>
/// Destroys a video capture graph.
/// </summary>
DSUTILS_API void __stdcall DestroyCaptureGraph();


The Middle Layer

The middle layer is implemented in the DirectShowProxy class.

First, what we should do is extract the capture graph utilities DLL module from the resources and save it to a temporary file.

中间层在DirectShowProxy 类中实现。

首先,我们应该做的是从资源中提取捕获连接图实用程序DLL模块并将其保存到临时文件中。

_dllFile = Path.GetTempFileName();
using (FileStream stream = new FileStream(_dllFile, FileMode.Create, FileAccess.Write))
{
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write(IsX86Platform ?
Resources.DirectShowFacade : Resources.DirectShowFacade64);
}
}

Then we load our DLL module into the address space of the calling process.然后我们将DLL模块加载到调用进程的地址空间中。

_hDll = LoadLibrary(_dllFile);
  if (_hDll == IntPtr.Zero)  {
      throw new Win32Exception(Marshal.GetLastWin32Error());
  }

And bind the DLL module functions to the class instance methods.并将DLL模块函数绑定到类实例方法。

private delegate Int32 BuildCaptureGraphDelegate();
  private BuildCaptureGraphDelegate _buildCaptureGraph;
    // ...    IntPtr pProcPtr = GetProcAddress(_hDll, "BuildCaptureGraph");
  _buildCaptureGraph =      (BuildCaptureGraphDelegate)Marshal.GetDelegateForFunctionPointer(pProcPtr,
        typeof(BuildCaptureGraphDelegate));

When the control is being disposed, we unload the DLL module and delete it.当处理控件时,我们卸载DLL模块并将其删除。

public void Dispose()
{
if (_hDll != IntPtr.Zero)
{
FreeLibrary(_hDll);
_hDll = IntPtr.Zero;
}

if (File.Exists(_dllFile))
{
File.Delete(_dllFile);
}
}

The Top Layer

The top layer is implemented in the WebCameraControl class with the following interface.顶层在类中实现,具有以下接口。WebCameraControl

/// <summary>
/// Gets a list of available video capture devices.
/// </summary>
/// <exception cref="Win32Exception">Failed to load the DirectShow utilities dll.</exception>
public IEnumerable<WebCameraId> GetVideoCaptureDevices();

/// <summary>
/// Gets a value indicating whether the control is capturing a video stream.
/// </summary>
public Boolean IsCapturing { get; }

/// <summary>
/// Starts a capture.
/// </summary>
/// <param name="camera">The camera to capture from.</param>
/// <exception cref="ArgumentNullException">A null reference is passed as an argument.</exception>
/// <exception cref="Win32Exception">Failed to load the DirectShow utilities dll.</exception>
/// <exception cref="DirectShowException">Failed to run a video capture graph.</exception>
public void StartCapture(WebCameraId camera);

/// <summary>
/// Retrieves the unstretched image being captured.
/// </summary>
/// <returns>The current image.</returns>
/// <exception cref="InvalidOperationException">The control is not capturing a video stream.</exception>
/// <exception cref="DirectShowException">Failed to get the current image.</exception>
public Bitmap GetCurrentImage();

/// <summary>
/// Gets the unstretched video size.
/// </summary>
public Size VideoSize { get; }

/// <summary>
/// Stops a capture.
/// </summary>
/// <exception cref="InvalidOperationException">The control is not capturing a video stream.</exception>
/// <exception cref="DirectShowException">Failed to stop a video capture graph.</exception>
public void StopCapture();

Usage

Open the Package Manager Console and add a nuget package to your project:打开包管理器控制台并将nuget包添加到项目中:

Install-Package WebEye.Controls.WinForms.WebCameraControl

First, we need to add the control to the Visual Studio Designer Toolbox, using a right-click and then the "Choose Items..." menu item. Then we place the control on a form at desired location and with desired size. The default name of the control instance variable will be webCameraControl1.

Then, on run-time stage, we need to get a list of web cameras available on the system.首先,我们需要将控件添加到Visual Studio Designer工具箱,使用右键单击,然后选择“选择项目...”菜单项。然后我们将控件放在所需位置和所需尺寸的表格上。控件实例变量的默认名称为。webCameraControl1

然后,在运行时阶段,我们需要获得系统上可用的网络摄像头列表。

List<WebCameraId> cameras = new List<WebCameraId>(webCameraControl1.GetVideoCaptureDevices());

The following code starts a capture from the first camera in the list.以下代码从列表中的第一个摄像头开始捕获。

webCameraControl1.StartCapture(cameras[0]); 

Please note that the control's window has to be created in order to start a capture, otherwise you will get an exception due to the fact that there is no output pin for the video stream. The common mistake is to start a capture in the Form.Load event handler, when the control's window have not yet been created.

To get an image being captured just call the GetCurrentImage() method. The resolution and quality of the image depend on your camera device characteristics.

请注意,必须创建控件的窗口才能开始捕获,否则由于视频流没有输出引脚,您将获得异常。常见错误是在Form.Load尚未创建控件窗口时在事件处理程序中启动捕获。

要获取捕获的图像,只需调用该GetCurrentImage()方法即可。图像的分辨率和质量取决于相机设备的特性。

Bitmap image = webCameraControl1.GetCurrentImage();

To stop the capture the StopCapture() method is used.要停止捕获,请StopCapture()使用该方法。

webCameraControl1.StopCapture();

You can always ask the capture state using the following code.您始终可以使用以下代码询问捕获状态。

if (webCameraControl1.IsCapturing)  {      webCameraControl1.StopCapture();  }

To start the capture from another web camera just call the StartCapture method again.要从其他网络摄像头开始捕获,请StartCapture再次调用该方法。

webCameraControl1.StartCapture(cameras[1]);

To report errors, exceptions are used, so do not forget to wrap your code in a try/catch block. That is all about using it. To see the complete example please check the demo application sources.要报告错误,请使用异常,因此不要忘记将代码包装在try/ catchblock中。这就是使用它。要查看完整示例,请查看演示应用程序源。

WPF Version

In WPF user controls do not have a WinAPI window handle (HWND) associated with them and this is a problem, because the DirectShow framework requires a window handle in order to output the video stream. The VideoWindow class has been introduced to workaround this problem.在WPF中,用户控件没有HWND与它们关联的WinAPI窗口句柄(),这是一个问题,因为DirectShow框架需要窗口句柄才能输出视频流。引入了VideoWindow类来解决此问题。

<UserControl x:Class="WebCamera.WebCameraControl"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                mc:Ignorable="d"
                d:DesignHeight="300" d:DesignWidth="300"
               xmlns:local="clr-namespace:WebCamera">
      <local:VideoWindow x:Name="_videoWindow" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
  </UserControl>  

To add a WPF version of the control to your project use the following nuget command:要将WPF版本的控件添加到项目,请使用以下nuget命令:

Install-Package WebEye.Controls.Wpf.WebCameraControl
友情链接
版权所有 Copyright(c)2004-2021 锐英源软件
公司注册号:410105000449586 豫ICP备08007559号 最佳分辨率 1024*768
地址:郑州大学北校区院(文化路97号院)内