Last active
February 17, 2025 12:01
-
-
Save LucasHayashi/1002ec7a8cfab0f62ed7480983559da8 to your computer and use it in GitHub Desktop.
Check if a webcam is available on Windows/Citrix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Runtime.InteropServices; | |
using System.Windows.Forms; | |
using DirectShowLib; | |
namespace WindowsFormsApp1 | |
{ | |
public partial class Form1 : Form | |
{ | |
public Form1() | |
{ | |
InitializeComponent(); | |
Stopwatch stopwatch = new Stopwatch(); | |
// Medindo o tempo da função original | |
stopwatch.Start(); | |
bool webcamDisponivelOriginal = VerificarWebcamDisponivel(); | |
stopwatch.Stop(); | |
long tempoOriginal = stopwatch.ElapsedMilliseconds; | |
// Medindo o tempo da nova função (verifica se há pelo menos uma resolução) | |
stopwatch.Restart(); | |
bool webcamComResolucao = VerificarWebcamDisponivelv2(); | |
stopwatch.Stop(); | |
long tempoResolucao = stopwatch.ElapsedMilliseconds; | |
Console.WriteLine($"Webcam disponível (Original): {webcamDisponivelOriginal} - Tempo: {tempoOriginal}ms"); | |
Console.WriteLine($"Webcam disponível (V2):: {webcamComResolucao} - Tempo: {tempoResolucao}ms"); | |
Environment.Exit(0); | |
} | |
static bool VerificarWebcamDisponivel() | |
{ | |
DsDevice[] dispositivos = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice); | |
foreach (var dispositivo in dispositivos) | |
{ | |
if (GetAllAvailableResolution(dispositivo).Count > 0) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
static bool VerificarWebcamDisponivelv2() | |
{ | |
DsDevice[] dispositivos = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice); | |
foreach (var dispositivo in dispositivos) | |
{ | |
if (GetFirstAvailableResolution(dispositivo) != null) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
private static List<string> GetAllAvailableResolution(DsDevice vidDev) | |
{ | |
try | |
{ | |
int hr, bitCount = 0; | |
IBaseFilter sourceFilter = null; | |
var m_FilterGraph2 = new FilterGraph() as IFilterGraph2; | |
hr = m_FilterGraph2.AddSourceFilterForMoniker(vidDev.Mon, null, vidDev.Name, out sourceFilter); | |
var pRaw2 = DsFindPin.ByCategory(sourceFilter, PinCategory.Capture, 0); | |
var AvailableResolutions = new List<string>(); | |
if (pRaw2 == null) | |
{ | |
return AvailableResolutions; // Retorna a lista vazia | |
} | |
VideoInfoHeader v = new VideoInfoHeader(); | |
IEnumMediaTypes mediaTypeEnum; | |
hr = pRaw2.EnumMediaTypes(out mediaTypeEnum); | |
AMMediaType[] mediaTypes = new AMMediaType[1]; | |
IntPtr fetched = IntPtr.Zero; | |
hr = mediaTypeEnum.Next(1, mediaTypes, fetched); | |
while (fetched != null && mediaTypes[0] != null) | |
{ | |
Marshal.PtrToStructure(mediaTypes[0].formatPtr, v); | |
if (v.BmiHeader.Size != 0 && v.BmiHeader.BitCount != 0) | |
{ | |
if (v.BmiHeader.BitCount > bitCount) | |
{ | |
AvailableResolutions.Clear(); | |
bitCount = v.BmiHeader.BitCount; | |
} | |
AvailableResolutions.Add(v.BmiHeader.Width + "x" + v.BmiHeader.Height); | |
} | |
hr = mediaTypeEnum.Next(1, mediaTypes, fetched); | |
} | |
return AvailableResolutions; | |
} | |
catch (Exception) | |
{ | |
return new List<string>(); | |
} | |
} | |
private static string GetFirstAvailableResolution(DsDevice vidDev) | |
{ | |
try | |
{ | |
int hr; | |
IBaseFilter sourceFilter = null; | |
var m_FilterGraph2 = new FilterGraph() as IFilterGraph2; | |
hr = m_FilterGraph2.AddSourceFilterForMoniker(vidDev.Mon, null, vidDev.Name, out sourceFilter); | |
var pRaw2 = DsFindPin.ByCategory(sourceFilter, PinCategory.Capture, 0); | |
if (pRaw2 == null) | |
{ | |
return null; | |
} | |
VideoInfoHeader v = new VideoInfoHeader(); | |
IEnumMediaTypes mediaTypeEnum; | |
hr = pRaw2.EnumMediaTypes(out mediaTypeEnum); | |
AMMediaType[] mediaTypes = new AMMediaType[1]; | |
IntPtr fetched = IntPtr.Zero; | |
hr = mediaTypeEnum.Next(1, mediaTypes, fetched); | |
if (fetched != null && mediaTypes[0] != null) | |
{ | |
Marshal.PtrToStructure(mediaTypes[0].formatPtr, v); | |
if (v.BmiHeader.Size != 0 && v.BmiHeader.BitCount != 0) | |
{ | |
return v.BmiHeader.Width + "x" + v.BmiHeader.Height; | |
} | |
} | |
return null; | |
} | |
catch (Exception) | |
{ | |
return null; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Meu objetivo era identificar se há pelo menos uma webcam conectada no Citrix. Não basta apenas verificar a existência de um dispositivo, pois, em algumas sessões, o sistema retornava o dispositivo genérico
"Citrix HDX Webcam"
, o que não garante que a webcam esteja realmente conectada. Para assegurar isso, é necessário verificar se o dispositivo possui alguma resolução disponível.Para essa verificação, desenvolvi duas funções:
VerificarWebcamDisponivel
, que percorre todas as resoluções disponíveis.VerificarWebcamDisponivel2
, que verifica se há pelo menos uma resolução disponível e retorna imediatamente, melhorando o desempenho.My goal was to determine whether at least one webcam is connected in Citrix. Simply checking for the presence of a device is not enough, as in some sessions, the system would return the generic "Citrix HDX Webcam" device, which does not necessarily mean that a webcam is actually connected. To ensure this, it is necessary to check if the device has any available resolution.
To perform this check, I developed two functions:
VerificarWebcamDisponivel
, which scans all available resolutions.VerificarWebcamDisponivel2
, which checks if at least one resolution is available and returns immediately, improving performance.