首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 攝像頭開發:基於 avicap32.dll 的影像擷取完整實作

     編輯:關於C#

傳統 Windows 攝像頭開發透過 Video for Windows (VFW) API (avicap32.dll) 實作影像預覽、擷取。雖然 .NET 後期有 DirectShow (DirectX.Capture) 與 Media Foundation 封裝,但 VFW 因簡單輕量仍常用於簡易應用。本文提供完整 P/Invoke 封裝與 WinForms 整合範例。

核心 P/Invoke 封裝


using System;
using System.Runtime.InteropServices;

public static class Avicap32
{
    public const int WM_USER = 0x400;
    public const int WM_CAP_DRIVER_CONNECT = WM_USER + 10;
    public const int WM_CAP_DRIVER_DISCONNECT = WM_USER + 11;
    public const int WM_CAP_SET_PREVIEW = WM_USER + 50;
    public const int WM_CAP_SET_PREVIEWRATE = WM_USER + 52;
    public const int WM_CAP_SET_CALLBACK_FRAME = WM_USER + 5;
    public const int WM_CAP_SET_VIDEOFORMAT = WM_USER + 45;
    public const int WS_CHILD = 0x40000000;
    public const int WS_VISIBLE = 0x10000000;

    [DllImport("avicap32.dll", EntryPoint = "capCreateCaptureWindowA")]
    public static extern IntPtr CreateCaptureWindow(string name, int style, int x, int y, int w, int h, IntPtr parent, int id);

    [DllImport("avicap32.dll", EntryPoint = "capGetDriverDescriptionA")]
    public static extern bool GetDriverDescription(short index, StringBuilder name, int nameSize, StringBuilder ver, int verSize);

    [DllImport("user32.dll", EntryPoint = "SendMessage")]
    public static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
    [DllImport("user32.dll", EntryPoint = "SendMessage")]
    public static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, FrameCallback lParam);
    [DllImport("user32.dll", EntryPoint = "SendMessage")]
    public static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, ref BitmapInfo lParam);

    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern int SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int y, int cx, int cy, int flags);

    [StructLayout(LayoutKind.Sequential)]
    public struct BitmapInfoHeader
    {
        public int biSize, biWidth, biHeight;
        public short biPlanes, biBitCount;
        public int biCompression, biSizeImage, biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct BitmapInfo
    {
        public BitmapInfoHeader bmiHeader;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
        public int[] bmiColors;
    }
    [StructLayout(LayoutKind.Sequential)]
    public struct VideoHdr
    {
        public IntPtr lpData;
        public int dwBufferLength, dwBytesUsed, dwTimeCaptured, dwUser, dwFlags;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
        public int[] dwReserved;
    }

    public delegate void FrameCallback(IntPtr hWnd, IntPtr lpVHdr);
}

WebCamera 封裝類別


public class WebCamera
{
    private IntPtr _capHwnd;
    private readonly IntPtr _parentHandle;
    private readonly int _width, _height;
    private Avicap32.FrameCallback _frameCallback;

    public event Action FrameReceived;

    public WebCamera(IntPtr parentHandle, int width, int height)
    {
        _parentHandle = parentHandle;
        _width = width; _height = height;
    }

    public void Start()
    {
        StringBuilder name = new StringBuilder(100), ver = new StringBuilder(100);
        Avicap32.GetDriverDescription(0, name, 100, ver, 100);

        _capHwnd = Avicap32.CreateCaptureWindow(name.ToString(),
            Avicap32.WS_VISIBLE | Avicap32.WS_CHILD, 0, 0, _width, _height, _parentHandle, 0);

        if (Send(Avicap32.WM_CAP_DRIVER_CONNECT, 0))
        {
            Send(Avicap32.WM_CAP_SET_PREVIEWRATE, 66); // ~15fps
            Send(Avicap32.WM_CAP_SET_PREVIEW, 1);

            var bmi = new Avicap32.BitmapInfo();
            bmi.bmiHeader.biSize = Marshal.SizeOf(typeof(Avicap32.BitmapInfoHeader));
            bmi.bmiHeader.biWidth = 352;
            bmi.bmiHeader.biHeight = 288;
            bmi.bmiHeader.biPlanes = 1;
            bmi.bmiHeader.biBitCount = 24;
            Send(Avicap32.WM_CAP_SET_VIDEOFORMAT, ref bmi);

            _frameCallback = OnFrameCallback;
            Send(Avicap32.WM_CAP_SET_CALLBACK_FRAME, _frameCallback);

            Avicap32.SetWindowPos(_capHwnd, 0, 0, 0, _width, _height, 6);
        }
    }

    public void Stop()
    {
        if (_capHwnd != IntPtr.Zero)
            Send(Avicap32.WM_CAP_DRIVER_DISCONNECT);
    }

    private bool Send(int msg, int param) => Avicap32.SendMessage(_capHwnd, msg, param, 0);
    private bool Send(int msg, ref Avicap32.BitmapInfo param) => Avicap32.SendMessage(_capHwnd, msg, 0, ref param);
    private bool Send(int msg, Avicap32.FrameCallback cb) => Avicap32.SendMessage(_capHwnd, msg, 0, cb);

    private void OnFrameCallback(IntPtr hWnd, IntPtr lpVHdr)
    {
        var vh = (Avicap32.VideoHdr)Marshal.PtrToStructure(lpVHdr, typeof(Avicap32.VideoHdr));
        byte[] data = new byte[vh.dwBytesUsed];
        Marshal.Copy(vh.lpData, data, 0, vh.dwBytesUsed);
        FrameReceived?.Invoke(data);
    }
}

WinForms 使用範例


public partial class MainForm : Form
{
    private WebCamera _cam;
    private Bitmap _currentFrame;

    public MainForm()
    {
        InitializeComponent();
        _cam = new WebCamera(panelPreview.Handle, panelPreview.Width, panelPreview.Height);
        _cam.FrameReceived += OnFrameReceived;
    }

    private void BtnStart_Click(object sender, EventArgs e)
    {
        _cam.Start();
        btnStart.Enabled = false; btnStop.Enabled = true;
    }

    private void BtnStop_Click(object sender, EventArgs e)
    {
        _cam.Stop();
        btnStart.Enabled = true; btnStop.Enabled = false;
    }

    private void OnFrameReceived(byte[] data)
    {
        if (IsDisposed) return;
        using (var ms = new MemoryStream(data))
        {
            Bitmap bmp = new Bitmap(ms);
            // 於 UI 執行緒更新
            BeginInvoke((Action)(() => {
                if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
                pictureBox1.Image = bmp;
            }));
        }
    }

    protected override void OnFormClosed(FormClosedEventArgs e)
    {
        _cam?.Stop();
        base.OnFormClosed(e);
    }
}

現代替代方案

  • AForge.NET / Accord.NET:封裝 DirectShow,支援多種編碼器、濾鏡、影像處理。
  • OpenCvSharp:OpenCV 官方 .NET 繫結,功能最強大,適合電腦視覺應用。
  • MediaCapture (UWP/WinRT):Windows 10+ 原生 API,支援硬體加速、低延遲。

VFW 僅支援舊式類比/早期 USB 攝像頭,解析度、格式受限,新專案建議採用上述現代框架。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved