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?
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";
}
}
To fix the HDMI no signal problem, check for any loose connections or frayed wires. If the cable is not damaged, change the input source and enable the HDMI connection setting. In addition to this, I have also mentioned other solutions such as updating the chipset and graphics of the TV and performing a power cycle.
The most likely cause is the cable used to connect your monitor and video card, as it might either be faulty or even plugged into the wrong port. The monitor display mode and video card slot on your monitor could also potentially cause the problem.
Look, if an HDMI port is displayed, there. If you see the HDMI port right, click it and press Properties. Under properties, look for Device Status. If it displays “The device is working properly”, there is nothing wrong with the HDMI port itself.
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With