Skip to content

Commit

Permalink
+
Browse files Browse the repository at this point in the history
  • Loading branch information
badhitman committed Dec 11, 2023
1 parent 6edd558 commit 0bb4bd0
Show file tree
Hide file tree
Showing 524 changed files with 143,356 additions and 186 deletions.
21 changes: 18 additions & 3 deletions FlashCap/FlashCap.Core/CaptureDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@ protected virtual Task OnDisposeAsync() =>

protected abstract Task OnInitializeAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct);

public object Identity { get; }
public string Name { get; }

public virtual bool HasPropertyPage => false;

public VideoCharacteristics Characteristics { get; protected set; } = null!;
public bool IsRunning { get; protected set; }

Expand All @@ -70,14 +72,18 @@ protected abstract Task OnInitializeAsync(
protected abstract void OnCapture(
IntPtr pData, int size, long timestampMicroseconds, long frameIndex, PixelBuffer buffer);

protected virtual Task<bool> OnShowPropertyPageAsync(
IntPtr parentWindow, CancellationToken ct) =>
TaskCompat.FromResult(false);

//////////////////////////////////////////////////////////////////////////

internal Task InternalInitializeAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct) =>
this.OnInitializeAsync(characteristics, transcodeIfYUV, frameProcessor, ct);
this.OnInitializeAsync(characteristics, transcodeFormat, frameProcessor, ct);

internal async Task InternalStartAsync(CancellationToken ct)
{
Expand All @@ -101,4 +107,13 @@ internal async Task InternalStopAsync(CancellationToken ct)
internal void InternalOnCapture(
IntPtr pData, int size, long timestampMicroseconds, long frameIndex, PixelBuffer buffer) =>
this.OnCapture(pData, size, timestampMicroseconds, frameIndex, buffer);

internal async Task<bool> InternalShowPropertyPageAsync(
IntPtr parentWindow, CancellationToken ct)
{
using var _ = await locker.LockAsync(ct).
ConfigureAwait(false);

return await this.OnShowPropertyPageAsync(parentWindow, ct);
}
}
32 changes: 25 additions & 7 deletions FlashCap/FlashCap.Core/CaptureDeviceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@ public enum DeviceTypes
V4L2,
}

public enum TranscodeFormats
{
Auto,
DoNotTranscode,
BT601,
BT601FullRange,
BT709,
BT709FullRange,
BT2020,
BT2020FullRange,
}

public delegate void PixelBufferArrivedDelegate(
PixelBufferScope bufferScope);

Expand Down Expand Up @@ -51,7 +63,7 @@ protected CaptureDeviceDescriptor(

protected abstract Task<CaptureDevice> OnOpenWithFrameProcessorAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct);

Expand All @@ -66,24 +78,30 @@ public override string ToString() =>
#endif
internal Task<CaptureDevice> InternalOpenWithFrameProcessorAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct) =>
this.OnOpenWithFrameProcessorAsync(characteristics, transcodeIfYUV, frameProcessor, ct);
this.OnOpenWithFrameProcessorAsync(characteristics, transcodeFormat, frameProcessor, ct);

internal async Task<CaptureDevice> InternalOnOpenWithFrameProcessorAsync(
CaptureDevice preConstructedDevice,
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct)
{
if (characteristics.PixelFormat == PixelFormats.Unknown)
{
throw new ArgumentException(
$"FlashCap: Couldn't use unknown pixel format: {characteristics} ({characteristics.RawPixelFormat})");
}

using var _ = await this.locker.LockAsync(ct);

try
{
await preConstructedDevice.InternalInitializeAsync(
characteristics, transcodeIfYUV, frameProcessor, ct);
characteristics, transcodeFormat, frameProcessor, ct);
}
catch
{
Expand All @@ -95,13 +113,13 @@ await preConstructedDevice.InternalInitializeAsync(

internal async Task<byte[]> InternalTakeOneShotAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
CancellationToken ct)
{
var tcs = new TaskCompletionSource<byte[]>();

using var device = await this.OnOpenWithFrameProcessorAsync(
characteristics, transcodeIfYUV,
characteristics, transcodeFormat,
new DelegatedQueuingProcessor(pixelBuffer =>
{
var image = pixelBuffer.Buffer.InternalExtractImage(
Expand Down
85 changes: 66 additions & 19 deletions FlashCap/FlashCap.Core/Devices/DirectShowDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ [PreserveSig] public int BufferCB(

// DirectShow objects are sandboxed in the working context.
private IndependentSingleApartmentContext? workingContext = new();
private bool transcodeIfYUV;
private TranscodeFormats transcodeFormat;
private FrameProcessor frameProcessor;
private NativeMethods_DirectShow.IGraphBuilder? graphBuilder;
private SampleGrabberSink? sampleGrabberSink;
Expand All @@ -85,31 +85,31 @@ internal DirectShowDevice(object identity, string name) :

protected override Task OnInitializeAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct)
{
var devicePath = (string)this.Identity;

this.transcodeIfYUV = transcodeIfYUV;
this.transcodeFormat = transcodeFormat;
this.frameProcessor = frameProcessor;

return this.workingContext!.InvokeAsync(() =>
{
if (NativeMethods_DirectShow.EnumerateDeviceMoniker(
NativeMethods_DirectShow.CLSID_VideoInputDeviceCategory).
Where(moniker =>
moniker.GetPropertyBag() is { } pb &&
pb.SafeReleaseBlock(pb =>
pb.GetValue("DevicePath", default(string))?.Trim() is { } dp &&
dp.Equals(devicePath))).
Collect(moniker =>
moniker.BindToObject(null, null, in NativeMethods_DirectShow.IID_IBaseFilter, out var captureSource) == 0 ?
captureSource as NativeMethods_DirectShow.IBaseFilter : null).
FirstOrDefault() is { } captureSource)
if (NativeMethods_DirectShow.EnumerateDeviceMoniker(
NativeMethods_DirectShow.CLSID_VideoInputDeviceCategory).
Where(moniker =>
moniker.GetPropertyBag() is { } pb &&
pb.SafeReleaseBlock(pb =>
pb.GetValue("DevicePath", default(string))?.Trim() is { } dp &&
dp.Equals(devicePath))).
Collect(moniker =>
moniker.BindToObject(null, null, in NativeMethods_DirectShow.IID_IBaseFilter, out var captureSource) == 0 ?
captureSource as NativeMethods_DirectShow.IBaseFilter : null).
FirstOrDefault() is { } captureSource)
{
try
{
try
{
if (captureSource.EnumeratePins().
Collect(pin =>
pin.GetPinInfo() is { } pinInfo &&
Expand Down Expand Up @@ -218,7 +218,7 @@ protected override Task OnInitializeAsync(
{
if (this.graphBuilder != null)
{
//Marshal.ReleaseComObject(this.graphBuilder);
Marshal.ReleaseComObject(this.graphBuilder);
}
throw;
}
Expand Down Expand Up @@ -252,7 +252,7 @@ await this.OnStopAsync(default).

await this.workingContext!.InvokeAsync(() =>
{
//Marshal.ReleaseComObject(this.graphBuilder);
Marshal.ReleaseComObject(this.graphBuilder);
this.graphBuilder = null!;
this.sampleGrabberSink = null!;
NativeMethods.FreeMemory(this.pBih);
Expand Down Expand Up @@ -319,5 +319,52 @@ protected override void OnCapture(
IntPtr pData, int size,
long timestampMicroseconds, long frameIndex,
PixelBuffer buffer) =>
buffer.CopyIn(this.pBih, pData, size, timestampMicroseconds, frameIndex, this.transcodeIfYUV);
buffer.CopyIn(this.pBih, pData, size, timestampMicroseconds, frameIndex, this.transcodeFormat);

/////////////////////////////////////////////////////////////////////////////////////////////////

// Property page implementation.
// https://learn.microsoft.com/en-us/windows/win32/directshow/displaying-a-filters-property-pages

public override bool HasPropertyPage => true;

protected override Task<bool> OnShowPropertyPageAsync(
IntPtr parentWindow, CancellationToken ct) =>
this.workingContext!.InvokeAsync(() =>
{
var devicePath = (string)this.Identity;
if (NativeMethods_DirectShow.EnumerateDeviceMoniker(
NativeMethods_DirectShow.CLSID_VideoInputDeviceCategory).
Where(moniker =>
moniker.GetPropertyBag() is { } pb &&
pb.SafeReleaseBlock(pb =>
pb.GetValue("DevicePath", default(string))?.Trim() is { } dp &&
dp.Equals(devicePath))).
Collect(moniker =>
moniker.BindToObject(null, null, in NativeMethods_DirectShow.IID_IBaseFilter, out var captureSource) == 0 ?
captureSource as NativeMethods_DirectShow.IBaseFilter : null).
FirstOrDefault() is { } captureSource)
{
if (captureSource is NativeMethods_DirectShow.ISpecifyPropertyPages specifyPropertyPages &&
captureSource is object sourceAsObject &&
specifyPropertyPages.GetPages(out var pPages) == 0)
{
try
{
NativeMethods_DirectShow.OleCreatePropertyFrame(
parentWindow, 0, 0, this.Name, 1, ref sourceAsObject,
pPages.cElems, pPages.pElems, 0, 0, IntPtr.Zero);
return true;
}
finally
{
Marshal.FreeCoTaskMem(pPages.pElems);
}
}
}
return false;
}, ct);
}
4 changes: 2 additions & 2 deletions FlashCap/FlashCap.Core/Devices/DirectShowDeviceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ internal DirectShowDeviceDescriptor(

protected override Task<CaptureDevice> OnOpenWithFrameProcessorAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct) =>
this.InternalOnOpenWithFrameProcessorAsync(
new DirectShowDevice(this.devicePath, this.Name),
characteristics, transcodeIfYUV, frameProcessor, ct);
characteristics, transcodeFormat, frameProcessor, ct);
}
8 changes: 4 additions & 4 deletions FlashCap/FlashCap.Core/Devices/V4L2Device.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public sealed class V4L2Device : CaptureDevice
private readonly TimestampCounter counter = new();

private string devicePath;
private bool transcodeIfYUV;
private TranscodeFormats transcodeFormat;
private FrameProcessor frameProcessor;

private long frameIndex;
Expand All @@ -50,13 +50,13 @@ internal V4L2Device(object identity, string name) :

protected override unsafe Task OnInitializeAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct)
{
this.devicePath = (string)this.Identity;
this.Characteristics = characteristics;
this.transcodeIfYUV = transcodeIfYUV;
this.transcodeFormat = transcodeFormat;
this.frameProcessor = frameProcessor;

if (!NativeMethods.GetCompressionAndBitCount(
Expand Down Expand Up @@ -426,5 +426,5 @@ protected override void OnCapture(
IntPtr pData, int size,
long timestampMicroseconds, long frameIndex,
PixelBuffer buffer) =>
buffer.CopyIn(this.pBih, pData, size, timestampMicroseconds, frameIndex, this.transcodeIfYUV);
buffer.CopyIn(this.pBih, pData, size, timestampMicroseconds, frameIndex, this.transcodeFormat);
}
4 changes: 2 additions & 2 deletions FlashCap/FlashCap.Core/Devices/V4L2DeviceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ internal V4L2DeviceDescriptor(

protected override Task<CaptureDevice> OnOpenWithFrameProcessorAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct) =>
this.InternalOnOpenWithFrameProcessorAsync(
new V4L2Device(this.devicePath, this.Name),
characteristics, transcodeIfYUV, frameProcessor, ct);
characteristics, transcodeFormat, frameProcessor, ct);
}
6 changes: 2 additions & 4 deletions FlashCap/FlashCap.Core/Devices/V4L2Devices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,9 @@ private static IEnumerable<v4l2_fmtdesc> EnumerateFormatDesc(
fmtdesc.type = (uint)v4l2_buf_type.VIDEO_CAPTURE;
return
ioctl(fd, Interop.VIDIOC_ENUM_FMT, fmtdesc) == 0 &&
IsKnownPixelFormat(fmtdesc.pixelformat) ?
(v4l2_fmtdesc?)fmtdesc : null;
ioctl(fd, Interop.VIDIOC_ENUM_FMT, fmtdesc) == 0 ? (v4l2_fmtdesc?)fmtdesc : null;
}).
ToArray(); // Important: Iteration process must be continuous, avoid ioctl calls with other requests.
ToArray(); // Important: Iteration process must be continuous, avoid ioctl calls with other requests.

private struct FrameSize
{
Expand Down
8 changes: 4 additions & 4 deletions FlashCap/FlashCap.Core/Devices/VideoForWindowsDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public sealed class VideoForWindowsDevice : CaptureDevice
{
private readonly TimestampCounter counter = new();
private int deviceIndex;
private bool transcodeIfYUV;
private TranscodeFormats transcodeFormat;
private FrameProcessor frameProcessor;
private long frameIndex;

Expand All @@ -40,13 +40,13 @@ internal VideoForWindowsDevice(object identity, string name) :

protected override unsafe Task OnInitializeAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct)
{
this.deviceIndex = (int)this.Identity;
this.Characteristics = characteristics;
this.transcodeIfYUV = transcodeIfYUV;
this.transcodeFormat = transcodeFormat;
this.frameProcessor = frameProcessor;

if (!NativeMethods.GetCompressionAndBitCount(
Expand Down Expand Up @@ -285,5 +285,5 @@ protected override Task OnStopAsync(CancellationToken ct)
protected override void OnCapture(
IntPtr pData, int size, long timestampMicroseconds, long frameIndex,
PixelBuffer buffer) =>
buffer.CopyIn(this.pBih, pData, size, timestampMicroseconds, frameIndex, this.transcodeIfYUV);
buffer.CopyIn(this.pBih, pData, size, timestampMicroseconds, frameIndex, this.transcodeFormat);
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ internal VideoForWindowsDeviceDescriptor(

protected override Task<CaptureDevice> OnOpenWithFrameProcessorAsync(
VideoCharacteristics characteristics,
bool transcodeIfYUV,
TranscodeFormats transcodeFormat,
FrameProcessor frameProcessor,
CancellationToken ct) =>
this.InternalOnOpenWithFrameProcessorAsync(
new VideoForWindowsDevice(this.deviceIndex, this.Name),
characteristics, transcodeIfYUV, frameProcessor, ct);
characteristics, transcodeFormat, frameProcessor, ct);
}
5 changes: 3 additions & 2 deletions FlashCap/FlashCap.Core/FlashCap.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0;</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CS0649</NoWarn>
<IsPackable>true</IsPackable>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit 0bb4bd0

Please sign in to comment.