三、视频设备的枚举以及插拔检测

这篇具有很好参考价值的文章主要介绍了三、视频设备的枚举以及插拔检测。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

        本章主要讲述,如何获取设备名称以及guid,采集设备的采集格式识别,设备的插拔

        设备列表以及属性的获取使用的directshow(后续的MediaFoundation无法获取OBS摄像头)

        设备的插拔使用的是QT 捕获系统消息,捕获到设备插拔后,重新获取下设备列表(这里并没有动态的添加或者删除,考虑的主要是维护UI显示时 设备顺序的一致性)

二、设备列表的获取

        ICreateDevEnum 接口,创建特定的类(如视频捕获设备,音频捕获设备,视频压缩等)的一个枚举器 ,可以使用CLSID_SystemDeviceEnum来得到该指针。

CreateDevEnum::CreateClassEnumerator(
REFCLSID clsidDeviceClass, //设备类别
IEnumMoniker **ppEnumMoniker, //输出参数,IEnumMoniker ××
DWORD dwFlags 
);

        IEnumMoniker 接口,  表示特定的设备枚举类

        IMoniker::Enum 方法获取指向 IEnumMoniker 实现的指针,该实现可以通过名字对象的组件向前或向后枚举。

        IRunningObjectTable::EnumRunning 方法返回一个指向 IEnumMoniker 实现的指针,该实现可以枚举在运行对象表中注册的名字对象。

        IEnumMoniker::Next  此方法检索枚举序列中下一个设备是否存在

struct CameraDevice
{
    int                  nIndex;                    // index
    std::string          uid;                       // 硬件层uniqueId mac中为BuiltInMicrophoneDevice  
    std::string          name;                      // 设备名称
};


std::map<std::string, CameraDevice> VideoCoreDevice::getVideoDeviceList()
{
    if(!m_pDevEnum)
    {
         ::CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void**)&m_pDevEnum);
    }
    std::map<std::string, CameraDevice> devices;
    if (!m_bCoUninitializeIsRequired)
    {
        goto END;
    }

    HRESULT hr = m_pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &m_pMonikerDevEnum, 0);
    if (hr != NOERROR)
    {
		std::cout << "CreateClassEnumerator failed" << std::endl;
        goto END;
    }
    m_pMonikerDevEnum->Reset();
    ULONG cFetched;
    IMoniker* pM;
    int index = 0;
    while (S_OK == m_pMonikerDevEnum->Next(1, &pM, &cFetched)) 
    {
        IPropertyBag* pBag;
        hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);
        if (S_OK == hr) 
        {
            // Find the description or friendly name.
            VARIANT varName;
            VariantInit(&varName);
            hr = pBag->Read(L"Description", &varName, 0);
            if (FAILED(hr)) 
            {
                hr = pBag->Read(L"FriendlyName", &varName, 0);
            }
            if (SUCCEEDED(hr)) 
            {
                // ignore all VFW drivers
                if ((wcsstr(varName.bstrVal, (L"(VFW)")) == NULL) &&
                    (_wcsnicmp(varName.bstrVal, (L"Google Camera Adapter"), 21) != 0)) 
                {
                    // Found a valid device.
                    {
                        char device_name[256] = { 0 };
                        char unique_name[256] = { 0 };
                        char product_name[256] = { 0 };

                        int convResult = WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1, (char*)device_name, sizeof(device_name), NULL, NULL);
                        if (convResult == 0)
                        {
							std::cout << "WideCharToMultiByte failed" << std::endl;
							goto END;
                        }
                        hr = pBag->Read(L"DevicePath", &varName, 0);
                        if (FAILED(hr))
                        {
                            strncpy_s((char*)unique_name, sizeof(unique_name),
                                (char*)device_name, convResult);
                        }
                        else
                        {
                            convResult = WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1, (char*)unique_name, sizeof(unique_name), NULL, NULL);
                            if (convResult == 0)
                            {
								std::cout << "WideCharToMultiByte failed" << std::endl;
                                goto END;
                            }
                        }
                        GetProductId(unique_name, product_name, sizeof(product_name));

                        CameraDevice camera;
                        camera.nIndex = index;
                        camera.name = device_name;
                        camera.uid = unique_name;

                        devices.insert(std::make_pair(camera.uid, camera));
                    }
                    ++index;  // increase the number of valid devices
                }
            }
            VariantClear(&varName);
            pBag->Release();
            pM->Release();
        }
    }

END:
    return devices;
}

// 不同获取方式得到的ID不一致,通过处理得到相同的ID
void GetProductId(const char* devicePath, char* productUniqueIdUTF8, uint32_t productUniqueIdUTF8Length)
{
    *productUniqueIdUTF8 = '\0';
    char* startPos = strstr((char*)devicePath, "\\\\?\\");
    if (!startPos) 
    {
        strncpy_s((char*)productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
        std::cout << "Failed to get the product Id" << std::endl;
        return;
    }
    startPos += 4;

    char* pos = strchr(startPos, '&');
    if (!pos || pos >= (char*)devicePath + strlen((char*)devicePath)) 
    {
        strncpy_s((char*)productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
        std::cout << "Failed to get the product Id" << std::endl;
        return;
    }
    // Find the second occurrence.
    pos = strchr(pos + 1, '&');
    uint32_t bytesToCopy = (uint32_t)(pos - startPos);
    if (pos && (bytesToCopy < productUniqueIdUTF8Length) &&
        bytesToCopy <= kVideoCaptureProductIdLength) 
    {
        strncpy_s((char*)productUniqueIdUTF8, productUniqueIdUTF8Length,
            (char*)startPos, bytesToCopy);
    }
    else
    {
        strncpy_s((char*)productUniqueIdUTF8, productUniqueIdUTF8Length, "", 1);
        std::cout << "Failed to get the product Id" << std::endl;
    }
}

三、设备的插拔检测

        目前使用的是Qt::nativeEventFilter 过滤设备插拔信息,然后去响应设备列表

// 头文件
#pragma once
#include <QWidget>
#include <QUuid>
#include <QAbstractNativeEventFilter>
#include <Windows.h>
#include <QHash>

class VideoNotificationClient : public QAbstractNativeEventFilter, public QWidget
{
public:
    class Listener
    {
    public:
        virtual void onDeviceAdded(const std::string& uid) = 0;
        virtual void onDeviceRemoved(const std::string& uid) = 0;
    };

public:
    void initialized();
    void uninstallFilter();
    bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override;

public:
    VideoNotificationClient(VideoNotificationClient::Listener* listener);
    ~VideoNotificationClient();


private:
    bool                                                     m_bInitialized;
    QHash<QUuid, HDEVNOTIFY>                                 m_hSevNotifys;
    VideoNotificationClient::Listener*                       m_pListener;
};
//源文件
#include "VideoNotificationClient.h"
#include <QDebug>
#include <iostream>
#include <Windows.h>
#include <Dbt.h>
#include <devguid.h>
//具体的设备guid如usbiodef需要initguid
#include <initguid.h>
//USB设备
//GUID_DEVINTERFACE_USB_DEVICE
#include <usbiodef.h>
//HID人机交互设备-鼠标键盘等
#include <hidclass.h>
//GUID_DEVINTERFACE_KEYBOARD
#include <ntddkbd.h>
//GUID_DEVINTERFACE_MOUSE
#include <ntddmou.h>
#include <QCoreApplication>
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "setupapi.lib")

static const GUID GUID_DEVINTERFACE_LIST[] =
{
    // GUID_DEVINTERFACE_CAMERA_DEVICE 
    { 0x65E8773D, 0x8F56, 0x11D0, { 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96 } },

    // GUID_DEVINTERFACE_USB_DEVICE  
    { 0xA5DCBF10, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } },

    // GUID_DEVINTERFACE_DISK  
    { 0x53f56307, 0xb6bf, 0x11d0, { 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b } },

    // GUID_DEVINTERFACE_HID,   
    { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } },

    // GUID_NDIS_LAN_CLASS  
    { 0xad498944, 0x762f, 0x11d0, { 0x8d, 0xcb, 0x00, 0xc0, 0x4f, 0xc3, 0x35, 0x8c } },

    // GUID_DEVINTERFACE_COMPORT
    { 0x86e0d1e0, 0x8089, 0x11d0, { 0x9c, 0xe4, 0x08, 0x00, 0x3e, 0x30, 0x1f, 0x73 } },

    // GUID_DEVINTERFACE_SERENUM_BUS_ENUMERATOR
    { 0x4D36E978, 0xE325, 0x11CE, { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } },

    // GUID_DEVINTERFACE_PARALLEL
    { 0x97F76EF0, 0xF883, 0x11D0, { 0xAF, 0x1F, 0x00, 0x00, 0xF8, 0x00, 0x84, 0x5C } },

    // GUID_DEVINTERFACE_PARCLASS
    { 0x811FC6A5, 0xF728, 0x11D0, { 0xA5, 0x37, 0x00, 0x00, 0xF8, 0x75, 0x3E, 0xD1 } }
};

VideoNotificationClient::VideoNotificationClient(VideoNotificationClient::Listener *listener)
    : QWidget(nullptr)
    , m_bInitialized(false)
    , m_pListener(listener)
{
    this->hide();
    qApp->installNativeEventFilter(this);
}

VideoNotificationClient::~VideoNotificationClient()
{
    uninstallFilter();
    qApp->removeNativeEventFilter(this);
} 

void VideoNotificationClient::initialized()
{
    HANDLE winid = (HANDLE)this->winId();
    if (!winid)
    {
        return;
    }

    //注册插拔事件
    HDEVNOTIFY hDevNotify;
    DEV_BROADCAST_DEVICEINTERFACE NotifacationFiler;
    ZeroMemory(&NotifacationFiler, sizeof(DEV_BROADCAST_DEVICEINTERFACE));
    NotifacationFiler.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
    NotifacationFiler.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;

    for (int i = 0; i < sizeof(GUID_DEVINTERFACE_LIST) / sizeof(GUID); i++)
    {
        NotifacationFiler.dbcc_classguid = GUID_DEVINTERFACE_LIST[i];

        hDevNotify = RegisterDeviceNotification(winid, &NotifacationFiler, DEVICE_NOTIFY_WINDOW_HANDLE);
        if (!hDevNotify)
        {
            qDebug() << "注册失败" << endl;
            m_bInitialized = false;
            return;
        }
        m_hSevNotifys.insert(QUuid(NotifacationFiler.dbcc_classguid), hDevNotify);
    }
    m_bInitialized = true;

}

void VideoNotificationClient::uninstallFilter()
{
    for (HDEVNOTIFY handle : qAsConst(m_hSevNotifys))
    {
        ::UnregisterDeviceNotification(handle);
    }
    m_hSevNotifys.clear();
}

bool VideoNotificationClient::nativeEventFilter(const QByteArray& eventType, void* message, long* result)
{
    Q_UNUSED(result);

    MSG* msg = reinterpret_cast<MSG*>(message);
    int msgType = msg->message;
    if (msgType == WM_DEVICECHANGE)
    {
        PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)msg->lParam;
        switch (msg->wParam) {
        case DBT_DEVICEARRIVAL:
            if (lpdb->dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE)
            {
                PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
                GUID cameraGuid = { 0x65E8773D, 0x8F56, 0x11D0, { 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96 } };
                if (cameraGuid == pDevInf->dbcc_classguid)
                {
                    QString devicePath = QString::fromWCharArray(pDevInf->dbcc_name);
                    QStringList parts = devicePath.split('#');
                    if (parts.length() != 4)
                    {
                        qDebug() << "camera logic error";
                        return false;
                    }
                    QString usbPortStr = parts[2];
                    QStringList usbPortParts = usbPortStr.split('&');
                    if (usbPortParts.length() != 4)
                    {
                        qDebug() << "camera logic error";
                        return false;
                    }   
                    if ("0000" != usbPortParts[3])
                    {
                        return false;
                    }
                    devicePath = devicePath.toLower();

                    m_pListener->onDeviceAdded(devicePath.toStdString());
                    //emit cameraPlugged(true, devicePath);
                }
            }
            break;
        case DBT_DEVICEREMOVECOMPLETE:
            if (lpdb->dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE)
            {
                PDEV_BROADCAST_DEVICEINTERFACE pDevInf = (PDEV_BROADCAST_DEVICEINTERFACE)lpdb;
                GUID cameraGuid = { 0x65E8773D, 0x8F56, 0x11D0, { 0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96 } };
                if (cameraGuid == pDevInf->dbcc_classguid)
                {
                    // USB拔出马上触发
                    QString devicePath = QString::fromWCharArray(pDevInf->dbcc_name);
                    QStringList parts = devicePath.split('#');
                    if (parts.length() != 4)
                    {
                        qDebug() << "camera logic error";
                        return false;
                    }
                    QString usbPortStr = parts[2];
                    QStringList usbPortParts = usbPortStr.split('&');
                    if (usbPortParts.length() != 4)
                    {
                        qDebug() << "camera logic error";
                        return false;
                    }
                    if ("0000" != usbPortParts[3])
                    {
                        return false;
                    }
                    devicePath = devicePath.toLower();
                    m_pListener->onDeviceRemoved(devicePath.toStdString());
                }
            }
            break;
        }
    }
    return false;
}

四、设备插拔库设计

项目完整代码,在后续的文章中给出

三、视频设备的枚举以及插拔检测,视频采集模块,音视频,视频采集文章来源地址https://www.toymoban.com/news/detail-725902.html

// camra
struct CameraDevice
{
	int                  nIndex = 0;                     // index
	std::string          uid = "";                       // 硬件层uniqueId mac中为BuiltInMicrophoneDevice  
	std::string          name = "";                      // 设备名称
};

// IVideoCore
class VIDEODEVICE_SHARED_EXPORT IVideoCore
{
public:
	static IVideoCore* getInstance();
	virtual void addListener(IVideoDeviceListner* listner) = 0;
	virtual void removeListener(IVideoDeviceListner* listner) = 0;
	virtual std::map<std::string, CameraDevice> getVideoDevicesList() = 0;
};

// IVideoDevice
class VIDEODEVICE_SHARED_EXPORT IVideoDevice
{
public:
    virtual bool initlized() = 0;
    virtual std::map<std::string, CameraDevice> getVideoDevicesList() = 0;
    virtual void addListener(IVideoDeviceListner* listener) = 0;
    virtual void removeListener(IVideoDeviceListner* listener) = 0;

};

// IVideoDeviceListner
class VIDEODEVICE_SHARED_EXPORT IVideoDeviceListner
{
public:
    virtual void onDeviceAdded(CameraDevice device) = 0;
    virtual void onDeviceRemoved(CameraDevice device) = 0;
    virtual void onDeviceListUpdate(std::map<std::string, CameraDevice> cameraList) = 0;
};


class VideoNotificationClient 
{
public:
    class Listener
    {
    public:
        virtual void onDeviceAdded(const std::string& uid) = 0;
        virtual void onDeviceRemoved(const std::string& uid) = 0;
    };
}

到了这里,关于三、视频设备的枚举以及插拔检测的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 视频汇聚/视频云存储/视频监控管理平台EasyCVR添加萤石云设备详细操作来啦!

    安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力,也具备接入

    2024年02月12日
    浏览(52)
  • 音视频会议需要哪些设备配置

    音视频会议需要哪些设备配置?音视频会议需要:视频会议摄像头、麦克风、扬声器、显示设备、网络连接设备、视频会议服务器、视频会议软件等。 1. 视频会议摄像头:用于捕捉与传输视频图像,可以选择高清摄像头,提供更出色、灵活和安全的协作体验。根据不同的使用

    2024年02月09日
    浏览(41)
  • Web端接入视频设备(NVR/IPC)

    本文主要介绍视频监控设备,视频监控设备接入,常用的开源流媒体及接入过程中的一些问题。 目前常见的视频监控设备主要有NVR和IPC,以海康为例。 IPC即IP Camera,可以接入网络的摄像头,如下图。 NVR即Network Video Recorder,网络视频录像机,可以进行视频流存储和转发,管理

    2024年02月02日
    浏览(38)
  • 视频云存储/安防监控/视频汇聚EasyCVR平台新增设备经纬度选取

    视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。音视频流媒体视频平台EasyCVR拓展性强,视频能力丰富,具体可实现视频监控直播、视频轮播、视频录像、云存储、回放与检索、

    2024年02月12日
    浏览(49)
  • 电脑硬盘 视频计算机存储设备

    1、容量 作为计算机系统的数据存储器,容量是硬盘最主要的参数。 硬盘的容量以兆字节Megabyte(MB)、千兆字节Gigabyte(GB)或太字节Terabyte(TB)为单位,1GB=1024MB,1TB=1024GB。但硬盘厂商在标称硬盘容量时通常取1GB=1000MB,因此我们在BIOS中或在格式化硬盘时看到的容量会比厂家

    2024年04月28日
    浏览(42)
  • ov2640子设备视频操作详细分析

    这段代码定义了一个名为ov2640_subdev_video_ops的结构体变量,该变量是struct v4l2_subdev_video_ops类型的,用于配置与视频子设备相关的操作。 这个结构体包含了多个成员函数,每个函数都对应一个特定的操作: .s_stream: 用于开始流传输的函数,对应的函数名是ov2640_s_stream。 .g_mbus

    2024年02月13日
    浏览(39)
  • 安防视频管理平台GB设备接入EasyCVR, 如何获取RTMP与RTSP视频流

    安防视频监控平台EasyCVR可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力,比如:视频监控直播、云端录像、云存储、录

    2024年02月15日
    浏览(43)
  • 前端基础(三十六):读取本地音视频设备并进行播放

    请求媒体输入和输出设备的列表,例如麦克风,摄像机,耳机设备等 会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等

    2024年02月15日
    浏览(51)
  • 【C++】开源:Linux端V4L2视频设备库

    😏 ★,° :.☆( ̄▽ ̄)/$: .°★ 😏 这篇文章主要介绍Linux端V4L2视频设备库。 无专精则不能成,无涉猎则不能通。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更新不迷路🥞 Video4Linux2( V4L2 )是一个用于Linux操作系统的视频设备驱动框

    2024年02月11日
    浏览(35)
  • 视频云存储/安防监控EasyCVR视频汇聚平台接入GB国标设备时,无法显示通道信息该如何解决?

    安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力,也具备接入

    2024年02月11日
    浏览(61)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包