-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathVideoCaptureDevices.cs
More file actions
148 lines (127 loc) · 6.13 KB
/
Copy pathVideoCaptureDevices.cs
File metadata and controls
148 lines (127 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
using DirectShowLib;
using Serilog;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
namespace libVideoCapture
{
/// <summary>
/// A class for information for the video capture devices.
/// Currently the name and the available resolutions are retrieved.
/// </summary>
public class VideoCaptureDevices
{
private static readonly ILogger logger = Log.Logger.ForContext (typeof (VideoCaptureDevices));
/// <summary>
/// A video input device struct which has the device
/// and the available resolutions of the device
/// </summary>
public struct DsVideoInputDevice
{
public DsDevice VideoInputDevice { get; set; }
public List<Size> AvailableResolutions { get; set; }
public override string ToString () =>
$"VideoInputDevice: {VideoInputDevice.Name} ({VideoInputDevice.DevicePath}), " +
$"AvailableResolutions: {string.Join (", ", AvailableResolutions)}";
}
public DsVideoInputDevice[] VideoInputDevices { get; private set; } = { };
public VideoCaptureDevices ()
{
GetAvailableVideoInputDevicesWithResolutions ();
}
/// <summary>
/// Get available video input devices and their resolutions
/// </summary>
private void GetAvailableVideoInputDevicesWithResolutions ()
{
DsDevice[] videoInputDevices = DsDevice.GetDevicesOfCat (FilterCategory.VideoInputDevice);
VideoInputDevices = new DsVideoInputDevice[videoInputDevices.Length];
int i = 0;
foreach (DsDevice videoInputDevice in videoInputDevices) {
VideoInputDevices[i].VideoInputDevice = videoInputDevice;
VideoInputDevices[i].AvailableResolutions = GetVideoCapabilities (videoInputDevice);
i++;
}
}
/// <summary>
/// Get a list of available resolutions for a specific device.
/// </summary>
/// <param name="videoInputDevice">The device to get the capabilities</param>
/// <returns>On success, the list of resolutions. On failure, an empty list</returns>
private List<Size> GetVideoCapabilities (DsDevice videoInputDevice)
{
logger.Debug ($"videoInputDevice: {videoInputDevice.Name}, {videoInputDevice.DevicePath}");
List<Size> availableResolutions = new List<Size> ();
IFilterGraph2 filterGraph = null;
IBaseFilter sourceFilter = null;
IPin pinRaw = null;
IEnumMediaTypes mediaTypeEnum = null;
AMMediaType[] mediaTypes = new AMMediaType[1];
try {
filterGraph = new FilterGraph () as IFilterGraph2;
if (filterGraph == null) {
throw new InvalidOperationException ("Failed to create FilterGraph.");
}
int hr = filterGraph.AddSourceFilterForMoniker (videoInputDevice.Mon, null, videoInputDevice.Name, out sourceFilter);
DsError.ThrowExceptionForHR (hr);
pinRaw = DsFindPin.ByDirection (sourceFilter, PinDirection.Output, 0);
if (pinRaw == null) {
logger.Warning ("No output pin found on source filter.");
return availableResolutions;
}
hr = pinRaw.EnumMediaTypes (out mediaTypeEnum);
DsError.ThrowExceptionForHR (hr);
int max = 0;
int bitCount = 0;
VideoInfoHeader videoInfoHeader = new VideoInfoHeader ();
// Check media types. Next returns 0 (S_OK) if it retrieves the requested number of items (1),
// or 1 (S_FALSE) if it retrieves fewer.
hr = mediaTypeEnum.Next (1, mediaTypes, IntPtr.Zero);
while (hr == 0 && mediaTypes[0] != null) {
try {
if (mediaTypes[0].formatPtr != IntPtr.Zero) {
Marshal.PtrToStructure (mediaTypes[0].formatPtr, videoInfoHeader);
if (videoInfoHeader.BmiHeader.Size != 0 && videoInfoHeader.BmiHeader.BitCount != 0) {
if (videoInfoHeader.BmiHeader.BitCount > bitCount) {
availableResolutions.Clear ();
max = 0;
bitCount = videoInfoHeader.BmiHeader.BitCount;
}
availableResolutions.Add (new Size (videoInfoHeader.BmiHeader.Width, videoInfoHeader.BmiHeader.Height));
if (videoInfoHeader.BmiHeader.Width > max || videoInfoHeader.BmiHeader.Height > max) {
max = Math.Max (videoInfoHeader.BmiHeader.Width, videoInfoHeader.BmiHeader.Height);
}
}
}
} finally {
DsUtils.FreeAMMediaType (mediaTypes[0]);
mediaTypes[0] = null;
}
hr = mediaTypeEnum.Next (1, mediaTypes, IntPtr.Zero);
}
logger.Debug ($"Resolutions: {string.Join (", ", availableResolutions)}");
} catch (Exception ex) {
logger.Error ($"Error: {ex.Message}");
} finally {
if (mediaTypes[0] != null) {
DsUtils.FreeAMMediaType (mediaTypes[0]);
mediaTypes[0] = null;
}
if (mediaTypeEnum != null) {
Marshal.ReleaseComObject (mediaTypeEnum);
}
if (pinRaw != null) {
Marshal.ReleaseComObject (pinRaw);
}
if (sourceFilter != null) {
Marshal.ReleaseComObject (sourceFilter);
}
if (filterGraph != null) {
Marshal.ReleaseComObject (filterGraph);
}
}
return availableResolutions;
}
}
}