Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/Baballonia.VFTCapture/Baballonia.VFTCapture.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,22 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
<DefineConstants>WINDOWS</DefineConstants>
</PropertyGroup>

<PropertyGroup Condition=" '$(OS)' == 'Unix' ">
<DefineConstants>LINUX</DefineConstants>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Baballonia.SDK\Baballonia.SDK.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="blluc.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
28 changes: 25 additions & 3 deletions src/Baballonia.VFTCapture/VFTCapture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@

using System.Net;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
Expand All @@ -17,8 +17,15 @@ public sealed class VftCapture(string source, ILogger logger) : Capture(source,

public override bool CanConnect(string connectionString)
{
var lowered = connectionString.ToLower();
return lowered.StartsWith("/dev/video") && OperatingSystem.IsLinux();
if (OperatingSystem.IsLinux())
{
var lowered = connectionString.ToLower();
return lowered.StartsWith("/dev/video");
} else if (OperatingSystem.IsWindows())
{
return true;
}
return false;
}

/// <summary>
Expand All @@ -39,9 +46,18 @@ public override async Task<bool> StartCapture()
// Initialize VideoCapture with URL, timeout for robustness
// Set capture mode to YUYV
// Prevent automatic conversion to RGB
#if LINUX
_videoCapture = await Task.Run(() => new VideoCapture(Source, VideoCaptureAPIs.V4L2), cts.Token);
_videoCapture.Set(VideoCaptureProperties.Mode, 3);
_videoCapture.Set(VideoCaptureProperties.ConvertRgb, 0);
#else
if (int.TryParse(Source, out var index))
{
_videoCapture = await Task.Run(() => VideoCapture.FromCamera(index, VideoCaptureAPIs.DSHOW), cts.Token);
_videoCapture.Set(VideoCaptureProperties.Mode, 3);
_videoCapture.Set(VideoCaptureProperties.ConvertRgb, 0);
}
#endif

_loop = true;
_ = Task.Run(VideoCapture_UpdateLoop);
Expand Down Expand Up @@ -98,9 +114,13 @@ private Task VideoCapture_UpdateLoop()
private void SetTrackerState(bool setActive)
{
// Prev: var fd = ViveFacialTracker.open(Url, ViveFacialTracker.FileOpenFlags.O_RDWR);
#if LINUX
var vftFileStream = File.Open(Source, FileMode.Open, FileAccess.ReadWrite);
var fd = vftFileStream.SafeFileHandle.DangerousGetHandle();
if (fd != IntPtr.Zero)
#elif WINDOWS
int fd = 0;
#endif
{
try
{
Expand All @@ -113,8 +133,10 @@ private void SetTrackerState(bool setActive)
}
finally
{
#if LINUX
// Prev: ViveFacialTracker.close((int)fd);
vftFileStream.Close();
#endif
}
}
}
Expand Down
12 changes: 10 additions & 2 deletions src/Baballonia.VFTCapture/VFTCaptureFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,16 @@ public Capture Create(string address)

public bool CanConnect(string address)
{
var lowered = address.ToLower();
return lowered.StartsWith("/dev/video");
if (OperatingSystem.IsLinux())
{
var lowered = address.ToLower();
return lowered.StartsWith("/dev/video");
}
else if (OperatingSystem.IsWindows())
{
return true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what is supposed to set the capture backend, if this returns true then it gets added as a valid backend, but I'm not sure what address resolves to. If we have to, we can change this to also pass in the full name of the camera.

}
return false;
}

public string GetProviderName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Baballonia.VFTCapture;

#if LINUX
public partial class ViveFacialTracker
{
public enum FileOpenFlags
Expand Down Expand Up @@ -308,3 +309,4 @@ public static bool deactivate_tracker(int fd)
return true;
}
}
#endif
33 changes: 33 additions & 0 deletions src/Baballonia.VFTCapture/ViveFacialTracker_Windows.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Runtime.InteropServices;

namespace Baballonia.VFTCapture;

#if WINDOWS
public partial class ViveFacialTracker
{
public enum ViveFacialTrackerError_t
{
VFT_OK = 0,
VFT_COM_ERR = -1,
VFT_TRACKER_NOT_FOUND = -2,
VFT_FAIL = -3,
};

private const string UsbCommunicatorLibrary = "blluc";

[LibraryImport(UsbCommunicatorLibrary)]
public static partial int enableViveFacialTracker();
[LibraryImport(UsbCommunicatorLibrary)]
public static partial int disableViveFacialTracker();

public static bool activate_tracker(int fd)
{
return enableViveFacialTracker() == (int)ViveFacialTrackerError_t.VFT_OK;
}

public static bool deactivate_tracker(int fd)
{
return disableViveFacialTracker() == (int)ViveFacialTrackerError_t.VFT_OK;
}
}
#endif
Binary file added src/Baballonia.VFTCapture/blluc.dll
Binary file not shown.
5 changes: 4 additions & 1 deletion src/Baballonia/ViewModels/SplitViewPane/HomePageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,10 @@ public async Task StartCamera(CameraControllerModel model)
var backend = model.SelectedCaptureMethod;
if (!model.CaptureMethodVisible)
backend = "";

if (OperatingSystem.IsWindows() && address == "HTC Multimedia Camera" && string.IsNullOrEmpty(backend))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not how you're supposed to set the backend.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm aware the current solution is hacky. The main issue I encountered was that the OpenCV backend is preferred over the VFT backend. I can play with the factory all I want but Babballonia will still prefer OpenCV over ViveFacialTracker on Windows at least.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to select the VFT capture with the preferred backend dropdown.

{
backend = "VFTCapture";
}

bool success = false;
switch (model.Camera)
Expand Down