Showing posts with label graphedit. Show all posts
Showing posts with label graphedit. Show all posts

Sunday, April 17, 2016

How to detect if HDMI cable is plugged into PCMCIA card / no signal?

Leave a Comment

I'm trying to write a simple helper application that is used to prompt the user to turn on a camcorder if no signal is detected, which in this case would mean the camcorder is off and/or the HDMI cable is not plugged into the PCMCIA capture card. If the signal is present, then I launch the respective recording application, in this case Wirecast.

How could I perhaps go about creating this using C# in VisualStudio?

Update

I think I'm alot closer now by trying a suggestion based in one of the comments suggesting to use GraphEdit and seeing what is available on the hardware. I was able to find within the properties of the capture device, a 'Signal Detected' flag that changes from 0 to 1 if the camcorder is on/off or the HDMI cable is unplugged, which is what I want.

Now, How would I go about accessing this flag through code? I think I'm really close, but don't know how to access the structure of cElems and pElems from the caGUID. cElems returns a value of 3, which is the same number of tabs displayed in the GraphEdit property window shown below in a screenshot. pElems returns a different value every time I run the app, so I'm not sure what's going on in that structure. I would think the flag I'm looking for lies somewhere within those structures.

Code:

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

enter image description hereenter image description here

3 Answers

Answers 1

I can't translate to C# because I no longer use Windows really, but if you are fine with translating the following C++ to C# then you can use it..

There is this WinAPI called RegisterDeviceNotification that lets you know when a device is plugged in or its state changed via a WinProc-Callback..

Taken from my Github: https://github.com/Brandon-T/HDMI

See also: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx and https://msdn.microsoft.com/en-us/library/windows/desktop/aa363431(v=vs.85).aspx

List of GUID's that I've used in my own projects:

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

Then I create a class to monitor a specific device:

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

Finally, I create a window/message-window to monitor the devices:

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

Answers 2

This really may depend on the vendor, but testing with a similar device, the vendor is writing to a custom registry key when the device is plugged in and removed.

  • To detect registry changes before and after an event I use RegShot, there is a handy tutorial over here that describes the process.
  • From this, once you have hopefully determined what key they are updating, you can subscribe via WMI to the Registry. Check out this answer for how to do this

Answers 3

I believe I just figured it out! I stumbled upon the IAMAnalogVideoDecoder method: get_HorizontalLocked.

This method returns true or false for me when the camcorder is off and/or the HDMI cable is unplugged, which is perfect for my needs.

DirectShowLib can be found here: 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";     } } 
Read More