Skip to content

Commit

Permalink
Enabled transcoder option.
Browse files Browse the repository at this point in the history
  • Loading branch information
kekyo committed Nov 5, 2023
1 parent 7ee39fd commit a0a894f
Show file tree
Hide file tree
Showing 15 changed files with 402 additions and 79 deletions.
199 changes: 188 additions & 11 deletions FSharp.FlashCap/CaptureDeviceDescriptorExtension.fs

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions FSharp.FlashCap/CaptureDeviceExtension.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@ module public CaptureDeviceExtension =

type public CaptureDevice with

member self.startAsync(?ct: CancellationToken) =
member self.start(?ct: CancellationToken) =
self.InternalStartAsync(asCT ct) |> Async.AwaitTask

member self.stopAsync(?ct: CancellationToken) =
member self.stop(?ct: CancellationToken) =
self.InternalStopAsync(asCT ct) |> Async.AwaitTask

[<Obsolete("start method will be deprecated. Switch to use startAsync method.")>]
member self.start() =
self.InternalStartAsync(CancellationToken()) |> ignore
[<Obsolete("This function is obsoleted, please use `start` instead.")>]
member self.startAsync(?ct: CancellationToken) =
self.InternalStartAsync(asCT ct) |> Async.AwaitTask

[<Obsolete("stop method will be deprecated. Switch to use stopAsync method.")>]
member self.stop() =
self.InternalStopAsync(CancellationToken()) |> ignore
[<Obsolete("This function is obsoleted, please use `stop` instead.")>]
member self.stopAsync(?ct: CancellationToken) =
self.InternalStopAsync(asCT ct) |> Async.AwaitTask
16 changes: 8 additions & 8 deletions FSharp.FlashCap/ObservableCaptureDeviceExtension.fs
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ module public ObservableCaptureDeviceExtension =

type public ObservableCaptureDevice with

member self.startAsync(?ct: CancellationToken) =
member self.start(?ct: CancellationToken) =
self.InternalStartAsync(asCT ct) |> Async.AwaitTask

member self.stopAsync(?ct: CancellationToken) =
member self.stop(?ct: CancellationToken) =
self.InternalStopAsync(asCT ct) |> Async.AwaitTask

[<Obsolete("start method will be deprecated. Switch to use startAsync method.")>]
member self.start() =
self.InternalStartAsync(CancellationToken()) |> ignore
[<Obsolete("This function is obsoleted, please use `start` instead.")>]
member self.startAsync(?ct: CancellationToken) =
self.InternalStartAsync(asCT ct) |> Async.AwaitTask

[<Obsolete("stop method will be deprecated. Switch to use stopAsync method.")>]
member self.stop() =
self.InternalStopAsync(CancellationToken()) |> ignore
[<Obsolete("This function is obsoleted, please use `stop` instead.")>]
member self.stopAsync(?ct: CancellationToken) =
self.InternalStopAsync(asCT ct) |> Async.AwaitTask

member self.subscribe(observer: IObserver<PixelBufferScope>) =
self.InternalSubscribe(observer)
6 changes: 3 additions & 3 deletions FlashCap.Core/CaptureDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected virtual Task OnDisposeAsync() =>

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

Expand All @@ -74,10 +74,10 @@ protected abstract void OnCapture(

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 Down
20 changes: 13 additions & 7 deletions FlashCap.Core/CaptureDeviceDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ public enum DeviceTypes
V4L2,
}

public enum TranscodeFormats
{
DoNotTranscode,
BT709,
}

public delegate void PixelBufferArrivedDelegate(
PixelBufferScope bufferScope);

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

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

Expand All @@ -66,15 +72,15 @@ 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)
{
Expand All @@ -89,7 +95,7 @@ internal async Task<CaptureDevice> InternalOnOpenWithFrameProcessorAsync(
try
{
await preConstructedDevice.InternalInitializeAsync(
characteristics, transcodeIfYUV, frameProcessor, ct);
characteristics, transcodeFormat, frameProcessor, ct);
}
catch
{
Expand All @@ -101,13 +107,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
8 changes: 4 additions & 4 deletions 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,13 +85,13 @@ 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(() =>
Expand Down Expand Up @@ -319,5 +319,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.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.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.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);
}
8 changes: 4 additions & 4 deletions 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);
}
4 changes: 2 additions & 2 deletions FlashCap.Core/Devices/VideoForWindowsDeviceDescriptor.cs
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);
}
17 changes: 17 additions & 0 deletions FlashCap.Core/Internal/BackwardCompat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ public static T[] Empty<T>() =>
}
#endif

#if NETFRAMEWORK || NETSTANDARD1_3
namespace System
{
internal readonly struct ValueTuple<T1, T2>
{
public readonly T1 Item1;
public readonly T2 Item2;

public ValueTuple(T1 item1, T2 item2)
{
this.Item1 = item1;
this.Item2 = item2;
}
}
}
#endif

namespace System.Linq
{
internal static partial class EnumerableExtension
Expand Down
27 changes: 15 additions & 12 deletions FlashCap.Core/Internal/BitmapTranscoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ internal static class BitmapTranscoder

// Preffered article: https://docs.microsoft.com/en-us/windows/win32/medfound/recommended-8-bit-yuv-formats-for-video-rendering#420-formats-16-bits-per-pixel

private static unsafe void TranscodeFromUYVY(
int width, int height, bool performFullRange,
private static unsafe void TranscodeFromBT709UYVY(
int width, int height,
bool performFullRange, // TODO: Use in future.
byte* pFrom, byte* pTo)
{
var scatter = height / scatteringBase;
Expand Down Expand Up @@ -58,8 +59,9 @@ private static unsafe void TranscodeFromUYVY(
});
}

private static unsafe void TranscodeFromYUYV(
int width, int height, bool performFullRange,
private static unsafe void TranscodeFromBT709YUYV(
int width, int height,
bool performFullRange, // TODO: Use in future.
byte* pFrom, byte* pTo)
{
var scatter = height / scatteringBase;
Expand Down Expand Up @@ -122,18 +124,19 @@ private static byte Clip(int value) =>

public static unsafe void Transcode(
int width, int height,
NativeMethods.Compression compression, bool performFullRange,
NativeMethods.Compression compression,
TranscodeFormats transcodeFormat,
byte* pFrom, byte* pTo)
{
switch (compression)
switch (compression, transcodeFormat)
{
case NativeMethods.Compression.UYVY:
case NativeMethods.Compression.HDYC:
TranscodeFromUYVY(width, height, performFullRange, pFrom, pTo);
case (NativeMethods.Compression.UYVY, TranscodeFormats.BT709):
case (NativeMethods.Compression.HDYC, TranscodeFormats.BT709):
TranscodeFromBT709UYVY(width, height, false, pFrom, pTo);
break;
case NativeMethods.Compression.YUYV:
case NativeMethods.Compression.YUY2:
TranscodeFromYUYV(width, height, performFullRange, pFrom, pTo);
case (NativeMethods.Compression.YUYV, TranscodeFormats.BT709):
case (NativeMethods.Compression.YUY2, TranscodeFormats.BT709):
TranscodeFromBT709YUYV(width, height, false, pFrom, pTo);
break;
default:
throw new ArgumentException();
Expand Down
Loading

0 comments on commit a0a894f

Please sign in to comment.