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
7 changes: 7 additions & 0 deletions Baballonia.sln
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Baballonia.FastCorruptionDe
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Baballonia.CaptureBin.IO", "src\Baballonia.CaptureBin.IO\Baballonia.CaptureBin.IO.csproj", "{8D298C1C-774E-4BF0-A107-D5D3985C7A9B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Baballonia.LibUVCCapture", "src\Baballonia.LibUVCCapture\Baballonia.LibUVCCapture.csproj", "{03715536-9789-4282-82A1-02693A5FE696}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -120,6 +122,10 @@ Global
{8D298C1C-774E-4BF0-A107-D5D3985C7A9B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8D298C1C-774E-4BF0-A107-D5D3985C7A9B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8D298C1C-774E-4BF0-A107-D5D3985C7A9B}.Release|Any CPU.Build.0 = Release|Any CPU
{03715536-9789-4282-82A1-02693A5FE696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03715536-9789-4282-82A1-02693A5FE696}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03715536-9789-4282-82A1-02693A5FE696}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03715536-9789-4282-82A1-02693A5FE696}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -135,6 +141,7 @@ Global
{575BB586-5394-4F94-A178-DF4062EC44A1} = {82C6A0B4-5014-4BE4-9F52-7DC1989134E3}
{4B08BDE8-099A-405F-AB71-094E8FC24AB1} = {82C6A0B4-5014-4BE4-9F52-7DC1989134E3}
{8D298C1C-774E-4BF0-A107-D5D3985C7A9B} = {82C6A0B4-5014-4BE4-9F52-7DC1989134E3}
{03715536-9789-4282-82A1-02693A5FE696} = {82C6A0B4-5014-4BE4-9F52-7DC1989134E3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8D6643ED-DDC1-4236-9471-024DCCFC81F6}
Expand Down
5 changes: 5 additions & 0 deletions src/Baballonia.Desktop/Baballonia.Desktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<PackageReference Include="Project-Babble.OpenCvSharp4.mini.runtime.ubuntu.22.04-arm64" Version="4.11.0.1" Condition="$([MSBuild]::IsOSPlatform('Linux')) And $(RuntimeIdentifier.Contains('arm'))" />
<PackageReference Include="Microsoft.ML.OnnxRuntime" Version="1.22.0" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux" Version="3.119.0" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
<PackageReference Include="Project-Babble.Uvc.NET" Version="1.0.4" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Baballonia.CaptureBin.IO\Baballonia.CaptureBin.IO.csproj" />
Expand All @@ -53,6 +54,7 @@
<ProjectReference Include="..\Baballonia.SerialCameraCapture\Baballonia.SerialCameraCapture.csproj"/>
<ProjectReference Include="..\Baballonia.IPCameraCapture\Baballonia.IPCameraCapture.csproj"/>
<ProjectReference Include="..\Baballonia.VFTCapture\Baballonia.VFTCapture.csproj"/>
<ProjectReference Include="..\Baballonia.LibUVCCapture\Baballonia.LibUVCCapture.csproj" Condition="$([MSBuild]::IsOSPlatform('Linux'))"/>
<ProjectReference Include="..\Baballonia\Baballonia.csproj" />
</ItemGroup>

Expand Down Expand Up @@ -135,10 +137,12 @@
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.OpenCVCapture.dll')" Include="$(OutputPath)Baballonia.OpenCVCapture.dll" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.IPCameraCapture.dll')" Include="$(OutputPath)Baballonia.IPCameraCapture.dll" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.VFTCapture.dll')" Include="$(OutputPath)Baballonia.VFTCapture.dll" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.LibUVCCapture.dll') And $([MSBuild]::IsOSPlatform('Linux'))" Include="$(OutputPath)Baballonia.LibUVCCapture.dll" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.SerialCameraCapture.pdb')" Include="$(OutputPath)Baballonia.SerialCameraCapture.pdb" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.OpenCVCapture.pdb')" Include="$(OutputPath)Baballonia.OpenCVCapture.pdb" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.IPCameraCapture.pdb')" Include="$(OutputPath)Baballonia.IPCameraCapture.pdb" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.VFTCapture.pdb')" Include="$(OutputPath)Baballonia.VFTCapture.pdb" />
<ModuleDlls Condition="Exists('$(OutputPath)Baballonia.LibUVCCapture.pdb') And $([MSBuild]::IsOSPlatform('Linux'))" Include="$(OutputPath)Baballonia.LibUVCCapture.pdb" />
</ItemGroup>
<Move SourceFiles="@(ModuleDlls)" DestinationFolder="$(OutputPath)Modules\" />
</Target>
Expand All @@ -149,6 +153,7 @@
<PublishModuleDlls Include="$(OutputPath)\publish\Baballonia.OpenCVCapture.dll" />
<PublishModuleDlls Include="$(OutputPath)\publish\Baballonia.IPCameraCapture.dll" />
<PublishModuleDlls Include="$(OutputPath)\publish\Baballonia.VFTCapture.dll" />
<PublishModuleDlls Include="$(OutputPath)\publish\Baballonia.LibUVCCapture.dll" Condition="$([MSBuild]::IsOSPlatform('Linux'))" />
</ItemGroup>
<Move SourceFiles="@(PublishModuleDlls)" DestinationFolder="$(OutputPath)\publish\Modules\" />
</Target>
Expand Down
13 changes: 13 additions & 0 deletions src/Baballonia.LibUVCCapture/Baballonia.LibUVCCapture.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Baballonia.SDK\Baballonia.SDK.csproj" />
<PackageReference Include="Project-Babble.Uvc.NET" Version="1.0.4" />
</ItemGroup>

</Project>
126 changes: 126 additions & 0 deletions src/Baballonia.LibUVCCapture/LibUVCCapture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Baballonia.SDK;
using Microsoft.Extensions.Logging;
using OpenCvSharp;
using Uvc.Net;

namespace Baballonia.LibUVCCapture;

public sealed class LibUVCCapture(string source, ILogger<LibUVCCapture> logger) : Capture(source, logger)
{
private Context _context;
private Device _device;
private DeviceHandle _deviceHandle;
private bool _connected;

public override Task<bool> StartCapture()
{
_context = new Context();
_device = FindDeviceByPath(Source, _context);
if (_device is null)
{
_context.Dispose();
_context = null;
return Task.FromResult(false);
}
return Task.Run(() =>
{
var open = _device.Open();
try
{
var formats = open.GetStreamControlFormats().ToArray().OrderBy(i => i.Width).ToList();
var formatIndex = formats.FindIndex(i => i is { Width: > 256, Height: > 256, Format: FrameFormat.Mjpeg });
if (formatIndex == -1)
{
Logger.LogInformation("Couldn't find format index");
open.Dispose();
_device.Dispose();
_device = null;
_context.Dispose();
_context = null;
return false;
}
Logger.LogInformation("Found format index");
var format = formats[formatIndex];
var control = open.GetStreamControlFormatSize(format.Format, format.Width, format.Height, 0);
try
{
Logger.LogInformation("Starting stream");
open.StartStreaming(ref control, Callback);
Logger.LogInformation("Started stream");
_deviceHandle = open;
_connected = true;
Logger.LogInformation("Blah");
return true;
}
catch
{
open.StopStreaming();

open.Dispose();
_device.Dispose();
_device = null;
_context.Dispose();
_context = null;
return false;
}
}
catch
{
open.Dispose();
_device?.Dispose();
_device = null;
_context?.Dispose();
_context = null;
return false;
}
});
}

public override Task<bool> StopCapture()
{
_connected = false;
if (_deviceHandle is null) return Task.FromResult(true);

_deviceHandle.StopStreaming();
_deviceHandle.Dispose();
_deviceHandle = null;

_context.Dispose();
_context = null;

return Task.FromResult(true);
}

private void Callback(ref Frame frame, IntPtr userPtr)
{
Logger.LogInformation("Callback called");
if (!_connected) return;
Logger.LogInformation("IsConnected");
if (frame.FrameFormat is not FrameFormat.Mjpeg) return;
Logger.LogInformation("CorrectFormat");
var data = frame.GetData();
if (data.Length == 0) return;
Logger.LogInformation("HasData");
SetRawMat(Mat.FromImageData(data));
}

public static Device FindDeviceByPath(string path, Context context)
{
if (!path.Contains("/dev/video")) return null;
var videoIndex = path.Replace("/dev/", "");
var ueventFilePath = $"/sys/class/video4linux/{videoIndex}/device/uevent";
if (!File.Exists(ueventFilePath)) return null;
var ueventText = File.ReadAllLines(ueventFilePath);
var line = ueventText.FirstOrDefault(i => i.StartsWith("PRODUCT="));
if (line is null) return null;
var numbers = line.Replace("PRODUCT=", "").Split('/').Select(i => Convert.ToUInt16(i, 16)).ToArray();
if (numbers.Length < 2) return null;
var vendor = numbers[0];
var product = numbers[1];
return context.FindDevice(vendor, product);
}
}
18 changes: 18 additions & 0 deletions src/Baballonia.LibUVCCapture/LibUVCCaptureFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;
using Baballonia.SDK;
using Microsoft.Extensions.Logging;

namespace Baballonia.LibUVCCapture;

public class LibUVCCaptureFactory : ICaptureFactory
{
private readonly ILoggerFactory _loggerFactory;

public LibUVCCaptureFactory(ILoggerFactory loggerFactory) => _loggerFactory = loggerFactory;

public Capture Create(string address) => new LibUVCCapture(address, _loggerFactory.CreateLogger<LibUVCCapture>());

public bool CanConnect(string address) => address.StartsWith("/dev/video");

public string GetProviderName() => nameof(LibUVCCapture);
}