Подтвердить что ты не робот

Как определить, подключен ли кабель HDMI к плате PCMCIA/нет сигнала?

Я пытаюсь написать простое вспомогательное приложение, которое используется, чтобы побудить пользователя включить видеокамеру, если сигнал не обнаружен, что в данном случае означает, что видеокамера выключена и/или кабель HDMI не подключен в карту захвата PCMCIA. Если сигнал присутствует, я запускаю соответствующее приложение для записи, в этом случае Wirecast.

Как я могу, возможно, начать создавать это с помощью С# в VisualStudio?

Update

Я думаю, что теперь я намного ближе, попробовав предложение, основанное на одном из комментариев, предлагающем использовать GraphEdit и видя, что доступно на аппаратном обеспечении. Я смог найти в свойствах устройства захвата, флаг "Signal Detected", который изменяется от 0 до 1, если видеокамера включена/выключена, или кабель HDMI отсоединен, и это то, что я хочу.

Теперь, как мне получить доступ к этому флагу через код? Я думаю, что я действительно близко, но не знаю, как получить доступ к структуре cElems и pElems из 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";
    }
}

введите описание изображения здесь введите описание изображения здесь

4b9b3361

Ответ 1

Полагаю, я просто понял это! Я наткнулся на метод IAMAnalogVideoDecoder: get_HorizontalLocked.

Этот метод возвращает true или false для меня, когда видеокамера выключена и/или кабель HDMI отсоединен, что идеально подходит для моих нужд.

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

Ответ 2

Я не могу перевести на С#, потому что я больше не использую Windows, но если у вас все в порядке с переводом следующего С++ на С#, вы можете его использовать.

Этот WinAPI называется RegisterDeviceNotification, который позволяет вам узнать, когда устройство подключено или его состояние изменилось с помощью WinProc-Callback..

Взято из моего Гитуба: https://github.com/Brandon-T/HDMI

Смотрите также: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx а также https://msdn.microsoft.com/en-us/library/windows/desktop/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
};

Затем я создаю класс для мониторинга определенного устройства:

#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
    }
}

Наконец, я создаю окно/окно сообщений для мониторинга устройств:

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

Ответ 3

Это действительно зависит от поставщика, но при тестировании с помощью аналогичного устройства поставщик записывает в специальный раздел реестра, когда устройство подключено и удалено.

  • Чтобы обнаружить изменения реестра до и после события, я использую RegShot, есть удобный учебник по здесь, который описывает процесс.
  • Из этого, как только вы, надеюсь, определили, какой ключ они обновляют, вы можете подписаться через WMI в реестр. Ознакомьтесь с этим ответом, как это сделать