如何检测HDMI线是否插入PCMCIA卡/无信号?

klc*_*r89 20 c# directshow graphedit pci

我正在尝试编写一个简单的帮助应用程序,用于在没有检测到信号的情况下提示用户打开摄像机,这在这种情况下意味着摄像机关闭和/或HDMI电缆没有插入PCMCIA采集卡.如果信号存在,那么我将启动相应的录制应用程序,在本例中为Wirecast.

我怎么可能在VisualStudio中使用C#创建它?

更新

我认为现在我已经接近了一个基于其中一条建议的建议,建议使用GraphEdit并查看硬件上可用的内容.我能够在捕获设备的属性中找到一个"信号检测"标志,如果摄像机打开/关闭或拔掉HDMI电缆,它会从0变为1,这就是我想要的.

现在,我将如何通过代码访问此标志?我想我真的很亲密,但不知道如何访问cElemspElems从中获取结构caGUID.cElems返回值3,这与屏幕截图中显示的GraphEdit属性窗口中显示的选项卡数相同.pElems每次运行应用程序时都会返回不同的值,所以我不确定该结构中发生了什么.我认为我正在寻找的旗帜位于这些结构中的某个位置.

码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using DirectShowLib;

namespace Test
{
    static class Program
    {
        [STAThread]

        static void Main()
        {
            using (System.Threading.Mutex mutex = new System.Threading.Mutex(false, "Global\\" + appGuid))
            {
                if (!mutex.WaitOne(0, false))
                {
                    return;
                }

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

                foreach (var dev in capDevices)
                {
                    if (dev.DevicePath == @"@device:pnp:\\?\pci#ven_1131&dev_7160&subsys_12abf50a&rev_03#6&37bccbbe&0&000800e1#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\{6f814be9-9af6-43cf-9249-c0340100021c}")
                    {
                        IFilterGraph2 m_FilterGraph = (IFilterGraph2)new FilterGraph();

                        IBaseFilter capFilter = null;
                        ICaptureGraphBuilder2 capGraph = null;

                        capGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

                        int hr;

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

                        ISpecifyPropertyPages pProp = capFilter as ISpecifyPropertyPages;

                        FilterInfo filterInfo;
                        hr = capFilter.QueryFilterInfo(out filterInfo);

                        DsCAUUID caGUID;

                        hr = pProp.GetPages(out caGUID);

                        Console.WriteLine(caGUID.cElems);
                        Console.WriteLine(caGUID.pElems);

                        // caGUID.cElems returns '3', which is the correct number of tabs in the property pages shown in GraphEdit.
                        // caGUID.pElems returns a different value every time

                        break;
                    }
                }

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }

        private static string appGuid = "z0a76b5a-02cd-15c5-b9d9-d303zcdde7b9";
    }
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述在此输入图像描述

Bra*_*don 5

我无法转换为 C#,因为我真的不再使用 Windows,但是如果您可以将以下 C++ 转换为 C#,那么您可以使用它..

有这个 WinAPI 调用RegisterDeviceNotification,让您知道设备何时插入或通过 WinProc-Callback 更改其状态。

摘自我的 Github:https : //github.com/Brandon-T/HDMI

另请参阅:https : //msdn.microsoft.com/en-us/library/windows/desktop/aa363480 ( v=vs.85) .aspxhttps://msdn.microsoft.com/en-us/library/窗户/桌面/aa363431(v=vs.85).aspx

我在自己的项目中使用的 GUID 列表:

GUID devices[] = {
    {0x4D36E96E, 0xE325, 0x11CE, 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18},  //PlugNPlay Display
    {0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED},  //GUID_DEVINTERFACE_USB_DEVICE
    {0x0850302A, 0xB344, 0x4FDA, 0x9B, 0xE9, 0x90, 0x57, 0x6B, 0x8D, 0x46, 0xF0},  //GUID_BTHPORT_DEVICE_INTERFACE
    {0xE6F07B5F, 0xEE97, 0x4a90, 0xB0, 0x76, 0x33, 0xF5, 0x7B, 0xF4, 0xEA, 0xA7},  //GUID_DEVINTERFACE_MONITOR
    {0x1CA05180, 0xA699, 0x450A, 0x9A, 0x0C, 0xDE, 0x4F, 0xBE, 0x3D, 0xDD, 0x89},  //GUID_DISPLAY_DEVICE_ARRIVAL
    {0x5B45201D, 0xF2F2, 0x4F3B, 0x85, 0xBB, 0x30, 0xFF, 0x1F, 0x95, 0x35, 0x99},  //GUID_DEVINTERFACE_DISPLAY_ADAPTER
    {0x1AD9E4F0, 0xF88D, 0x4360, 0xBA, 0xB9, 0x4C, 0x2D, 0x55, 0xE5, 0x64, 0xCD},  //GUID_DEVINTERFACE_VIDEO_OUTPUT_ARRIVAL
};
Run Code Online (Sandbox Code Playgroud)

然后我创建一个类来监视特定设备:

#include <windows.h>
#include <dbt.h>
#include <algorithm>

class Device
{
private:
    HDEVNOTIFY hNotify;

public:
    Device() : hNotify(NULL) {}
    Device(HWND window, GUID dev_guid);
    Device(Device&& dev) : hNotify(NULL) {std::swap(hNotify, dev.hNotify);}
    ~Device() {UnregisterDeviceNotification(hNotify);}

    Device(const Device& dev) = delete;
    Device& operator = (const Device& dev) = delete;
    Device& operator = (Device&& dev) {std::swap(hNotify, dev.hNotify);return *this;}
};

Device::Device(HWND window, GUID dev_guid) : hNotify(NULL)
{
    if (window)
    {
        DEV_BROADCAST_DEVICEINTERFACE filter;
        memset(&filter, 0, sizeof(filter));
        filter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE);
        filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
        filter.dbcc_classguid = dev_guid;
        hNotify = RegisterDeviceNotification(window, &filter, DEVICE_NOTIFY_WINDOW_HANDLE); //DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,我创建了一个窗口/消息窗口来监视设备:

int Create()
{
    WNDCLASSEX wx = {0};
    wx.cbSize = sizeof(WNDCLASSEX);
    wx.lpfnWndProc = WndProc;
    wx.hInstance = GetModuleHandle(NULL);
    wx.lpszClassName = "HDMI_MONITOR";
    if (RegisterClassEx(&wx))
    {
        MSG msg = {0};
        CreateWindowEx(0, "HDMI_MONITOR", "HDMI_MONITOR", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
        while(GetMessage(&msg, NULL, 0, 0) > 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return msg.wParam;
    }
    return 0;
}


//The callback function:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static std::unique_ptr<Device> dev;

    switch(msg)
    {
        case WM_CREATE:
        {
            dev.reset(new Device(hwnd, devices[0])); //GUID for plug-n-play devices..
        }
        break;

        case WM_DEVICECHANGE:
        {
            DEV_BROADCAST_DEVICEINTERFACE* info = (DEV_BROADCAST_DEVICEINTERFACE*) lParam;

            switch(wParam)
            {
                case DBT_DEVICEARRIVAL:
                    std::cout<<"Device was plugged in\n";
                    break;

                case DBT_DEVICEREMOVECOMPLETE:
                    std::cout<<"Device was un-plugged in\n";
                    break;

                default:
                    std::cout<<"wParam: "<<(void*)wParam<<"\n";
                    break;
            }
        }
        break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)


klc*_*r89 3

我相信我刚刚想通了!我偶然发现了这个IAMAnalogVideoDecoder方法:get_HorizontalLocked

当摄像机关闭和/或拔下 HDMI 电缆时,此方法为我返回 true 或 false,这非常适合我的需求。

DirectShowLib可以在这里找到: https: //sourceforge.net/projects/directshownet/files/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using DirectShowLib;

namespace Test
{
    static class Program
    {
        [STAThread]

        static void Main()
        {
            using (System.Threading.Mutex mutex = new System.Threading.Mutex(false, "Global\\" + appGuid))
            {
                if (!mutex.WaitOne(0, false))
                {
                    return;
                }

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

                foreach (var device in capDevices)
                {
                    if (device.DevicePath == @"@device:pnp:\\?\pci#ven_1131&dev_7160
                       &subsys_12abf50a&rev_03#6&37bccbbe&0&000800e1#{65e8773d-8f56
                       -11d0-a3b9-00a0c9223196}\{6f814be9-9af6-43cf
                       -9249-c0340100021c}")
                    {
                        IFilterGraph2 m_FilterGraph = (IFilterGraph2)new FilterGraph();

                        IBaseFilter capFilter = null;
                        ICaptureGraphBuilder2 capGraph = null;

                        capGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();

                        int hr;

                        hr = capGraph.SetFiltergraph(m_FilterGraph);
                        hr = m_FilterGraph.AddSourceFilterForMoniker(device.Mon, null, device.Name, out capFilter);

                        IAMAnalogVideoDecoder videoDec = capFilter as IAMAnalogVideoDecoder;

                        bool signalDetected = false;

                        hr = videoDec.get_HorizontalLocked(out signalDetected);

                        if (signalDetected == true)
                        {
                            System.Diagnostics.Process.Start(
                            @"C:\Users\PC\Documents\HIDDEN_FOLDER\WirecastLaunch.wcst");

                            return;
                        }
                        else
                        {
                            // Poll for 'signal' change
                        }

                        break;
                    }
                }

                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }

        private static string appGuid = "z0a76b5a-02cd-15c5-b9d9-d303zcdde7b9";
    }
}
Run Code Online (Sandbox Code Playgroud)