feat: CameraView + CameraService fences

This commit is contained in:
2026-01-29 12:10:59 +03:00
parent 3283d73b3b
commit dc3c195c21
4 changed files with 136 additions and 104 deletions
+1 -1
View File
@@ -21,7 +21,7 @@
<PackageReference Include="OpenCvSharp4.runtime.linux-arm" Version="4.11.0.20250506" />
<PackageReference Include="System.Device.Gpio" Version="4.0.1" />
<PackageReference Include="Iot.Device.Bindings" Version="4.0.1" />
<PackageReference Include="LibCameraSharp" Version="0.5.2-20260129-5" />
<PackageReference Include="LibCameraSharp" Version="0.5.2-20260129-7" />
</ItemGroup>
<ItemGroup>
+47 -31
View File
@@ -9,13 +9,15 @@ namespace GSS2.Core.Hardware;
public class CameraService : IDisposable
{
private static class LibC
public static class LibC
{
public const int PROT_READ = 0x01;
public const int MAP_SHARED = 0x0001;
[DllImport("libc", SetLastError = true)] public static extern IntPtr mmap(IntPtr address, ulong length, int prot, int flags, int fd, ulong offset);
[DllImport("libc", SetLastError = true)] public static extern int munmap(IntPtr address, ulong length);
[DllImport("libc", SetLastError = true)] public static extern int close(int fd);
[DllImport("libc", SetLastError = true)] public static extern int memfd_create(string name, uint flags);
}
private sealed class MappedBuffer
{
@@ -677,53 +679,67 @@ public class CameraService : IDisposable
var buffer = buffers.Skip(bufferId % buffers.Count()).First();
var request = _camera.CreateRequest(checked((ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()));
var result = request.AddBuffer(_viewFinderStream, buffer);
int fd = LibC.memfd_create($"buffer_fence_{bufferId % buffers.Count()}", 0x0002U);
if (fd < 0)
{
throw new Exception($"memfd_create error: {Marshal.GetLastPInvokeError()} {Marshal.GetLastPInvokeErrorMessage()}");
}
Console.WriteLine($"Created fd {fd}");
var fence = new Fence(new UniqueFD(fd));
var result = request.AddBuffer(_viewFinderStream, buffer, fence);
if (result < 0)
{
var fenceFd = buffer.ReleaseFence()?.Fd?.Release();
Console.WriteLine($"Request queue failed, closing fd {fenceFd}");
if (fenceFd is not null)
LibC.close(fenceFd.Value);
throw new Exception("Error while request create");
}
// _logger.LogDebug("Request(s) created");
effectiveCancellationToken.ThrowIfCancellationRequested();
var cts = new TaskCompletionSource();
void RequestCompleted(object? sender, Camera.RequestCompletedEventArgs e)
{
if (request.Handle != e.Request.Handle)
return;
// var cts = new TaskCompletionSource();
// void RequestCompleted(object? sender, Camera.RequestCompletedEventArgs e)
// {
// if (request.Handle != e.Request.Handle)
// return;
var buffer = e.Request.FindBuffer(_viewFinderStream);
if (buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameError ||
buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameStartup)
{
// _logger.LogDebug("Request buffers status: {}", buffer.Metadata.Status);
e.Request.Reuse(Request.ReuseFlagEnum.ReuseBuffers);
var result = _camera.QueueRequest(e.Request);
if (result >= 0)
return;
}
// var buffer = e.Request.FindBuffer(_viewFinderStream);
// if (buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameError ||
// buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameStartup)
// {
// // _logger.LogDebug("Request buffers status: {}", buffer.Metadata.Status);
// e.Request.Reuse(Request.ReuseFlagEnum.ReuseBuffers);
// var result = _camera.QueueRequest(e.Request);
// if (result >= 0)
// return;
// }
// _logger.LogDebug("Request complited: \n\tStatus: {}\n\tCookie: {}\n\tSequence: {}\n\tHasPendingBuffers: {}", e.Request.Status, e.Request.Cookie, e.Request.Sequence, e.Request.HasPendingBuffers);
// _logger.LogDebug("Request buffer: \n\tStatus: {} \n\tCookie: {} \n\tSequence: {} \n\tTimestamp: {}", buffer.Metadata.Status, buffer.Cookie, buffer.Metadata.Sequence, buffer.Metadata.Timestamp);
// _logger.LogDebug("Request buffer planes: ");
// foreach (var (i, plane) in buffer.Metadata.Planes.Enumerate())
// _logger.LogDebug("Plane[{}]: bytes used: 0x{:X}", i, plane.BytesUsed);
// foreach (var (i, plane) in buffer.Planes.Enumerate())
// _logger.LogDebug("Plane[{}]: \n\tFd: 0x{:X} \n\tOffset: 0x{:X} \n\tLength: 0x{:X} \n\tKInvalidOffset: 0x{:X}", i, plane.Fd.Get(), plane.Offset, plane.Length, plane.KInvalidOffset);
// // _logger.LogDebug("Request complited: \n\tStatus: {}\n\tCookie: {}\n\tSequence: {}\n\tHasPendingBuffers: {}", e.Request.Status, e.Request.Cookie, e.Request.Sequence, e.Request.HasPendingBuffers);
// // _logger.LogDebug("Request buffer: \n\tStatus: {} \n\tCookie: {} \n\tSequence: {} \n\tTimestamp: {}", buffer.Metadata.Status, buffer.Cookie, buffer.Metadata.Sequence, buffer.Metadata.Timestamp);
// // _logger.LogDebug("Request buffer planes: ");
// // foreach (var (i, plane) in buffer.Metadata.Planes.Enumerate())
// // _logger.LogDebug("Plane[{}]: bytes used: 0x{:X}", i, plane.BytesUsed);
// // foreach (var (i, plane) in buffer.Planes.Enumerate())
// // _logger.LogDebug("Plane[{}]: \n\tFd: 0x{:X} \n\tOffset: 0x{:X} \n\tLength: 0x{:X} \n\tKInvalidOffset: 0x{:X}", i, plane.Fd.Get(), plane.Offset, plane.Length, plane.KInvalidOffset);
effectiveCancellationToken.ThrowIfCancellationRequested();
// effectiveCancellationToken.ThrowIfCancellationRequested();
cts.SetResult();
}
// cts.SetResult();
// }
_camera.RequestCompleted += RequestCompleted;
// _camera.RequestCompleted += RequestCompleted;
result = _camera.QueueRequest(request);
if (result < 0)
{
_camera.RequestCompleted -= RequestCompleted;
// _camera.RequestCompleted -= RequestCompleted;
throw new Exception("Error while request queue");
}
// _logger.LogDebug("Request queued");
await cts.Task.WaitAsync(effectiveCancellationToken);
_camera.RequestCompleted -= RequestCompleted;
// await cts.Task.WaitAsync(effectiveCancellationToken);
// _camera.RequestCompleted -= RequestCompleted;
// _logger.LogDebug("Request complited");
return new(buffer, _viewFinderStreamConfiguration);