-
Notifications
You must be signed in to change notification settings - Fork 29
/
MainForm.cs
129 lines (110 loc) · 4.76 KB
/
MainForm.cs
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
////////////////////////////////////////////////////////////////////////////
//
// FlashCap - Independent camera capture library.
// Copyright (c) Kouji Matsui (@kozy_kekyo, @[email protected])
//
// Licensed under Apache-v2: https://opensource.org/licenses/Apache-2.0
//
////////////////////////////////////////////////////////////////////////////
using FlashCap.Utilities;
using System;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
namespace FlashCap.WindowsForms;
public partial class MainForm : Form
{
private SynchronizationContext synchContext;
// Constructed capture device.
private CaptureDevice captureDevice;
public MainForm() =>
this.InitializeComponent();
private async void MainForm_Load(object sender, EventArgs e)
{
this.synchContext = SynchronizationContext.Current;
////////////////////////////////////////////////
// Initialize and start capture device
// Enumerate capture devices:
var devices = new CaptureDevices();
var descriptors = devices.EnumerateDescriptors().
// You could filter by device type and characteristics.
//Where(d => d.DeviceType == DeviceTypes.DirectShow). // Only DirectShow device.
Where(d => d.Characteristics.Length >= 1). // One or more valid video characteristics.
ToArray();
// Use first device.
var descriptor0 = descriptors.ElementAtOrDefault(0);
if (descriptor0 != null)
{
#if false
// Request video characteristics strictly:
// Will raise exception when parameters are not accepted.
var characteristics = new VideoCharacteristics(
PixelFormats.JPEG, 1920, 1080, 60);
#else
// Or, you could choice from device descriptor:
// Hint: Show up video characteristics into ComboBox and like.
var characteristics = descriptor0.Characteristics.
FirstOrDefault(c => c.PixelFormat != PixelFormats.Unknown);
#endif
if (characteristics != null)
{
// Show status.
this.deviceLabel.Text = descriptor0.ToString();
this.characteristicsLabel.Text = characteristics.ToString();
// Open capture device:
this.captureDevice = await descriptor0.OpenAsync(
characteristics,
this.OnPixelBufferArrived);
// Start capturing.
await this.captureDevice.StartAsync();
}
}
}
private void OnPixelBufferArrived(PixelBufferScope bufferScope)
{
////////////////////////////////////////////////
// Pixel buffer has arrived.
// NOTE: Perhaps this thread context is NOT UI thread.
// HACK: I have seen reports of Windows Forms `Image.FromStream()` throwing an exception
// in the worker thread in some environments (see #67 and others).
// This is a totally mysterious behavior, since it works fine in worker thread in my environment.
// Since I have no choice, I decided to copy it to a byte array immediately here
// and do the conversion to `Image` on the UI thread.
// The disadvantage of this operation is that it will consume time on the worker thread
// that FlashCap uses for capturing, which might cause frame drops at fast FPS.
// Get image data binary:
byte[] image = bufferScope.Buffer.CopyImage();
// `bitmap` is copied, so we can release pixel buffer now.
bufferScope.ReleaseNow();
// Switch to UI thread.
// HACK: Here is using `SynchronizationContext.Post()` instead of `Control.Invoke()`.
// Because in sensitive states when the form is closing,
// `Control.Invoke()` can fail with exception.
this.synchContext.Post(_ =>
{
// Convert to Stream (using FlashCap.Utilities)
using (var stream = image.AsStream())
{
// Decode image data to a bitmap:
var bitmap = Image.FromStream(stream);
// HACK: on .NET Core, will be leaked (or delayed GC?)
// So we could release manually before updates.
var oldImage = this.BackgroundImage;
if (oldImage != null)
{
this.BackgroundImage = null;
oldImage.Dispose();
}
// Update a bitmap.
this.BackgroundImage = bitmap;
}
}, null);
}
private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
{
// Discard capture device.
this.captureDevice?.Dispose();
this.captureDevice = null;
}
}