forked from amkovkov/GranuSightSoftware2
feat: CameraService camera image capture
Add GSS2.FrameDecoders project for image decoding realizations Add IFrameDecoder interface and FrameDecoderHelper class Add CameraService.CaptureImage method
This commit is contained in:
@@ -269,10 +269,10 @@ public class CameraService : IDisposable
|
||||
}
|
||||
private void ImageCaptureFrameBuffersMap(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_frameBufferAllocator is null)
|
||||
throw new InvalidOperationException("FrameBufferAllocator not initialized");
|
||||
if (_imageCaptureStream is null)
|
||||
throw new InvalidOperationException("ImageCaptureStream not initialized");
|
||||
if (_frameBufferAllocator is null)
|
||||
throw new InvalidOperationException("FrameBufferAllocator not initialized");
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -304,7 +304,7 @@ public class CameraService : IDisposable
|
||||
if (address == new IntPtr(-1))
|
||||
{
|
||||
int error = Marshal.GetLastWin32Error();
|
||||
throw new InvalidOperationException($"mmap failed for fd={fd}, error={error}");
|
||||
throw new InvalidOperationException($"Error while buffers mapping, mmap failed for fd={fd}, error={error}");
|
||||
}
|
||||
|
||||
_mappedBuffers.Add(new MappedBuffer
|
||||
@@ -320,6 +320,95 @@ public class CameraService : IDisposable
|
||||
_state |= State.ImageCaptureFrameBuffersMapped;
|
||||
}
|
||||
|
||||
public async Task<OpenCvSharp.Mat?> CaptureImage(CancellationToken cancellationToken)
|
||||
{
|
||||
if (_camera is null)
|
||||
throw new InvalidOperationException("Camera not initialized");
|
||||
if (_imageCaptureStream is null)
|
||||
throw new InvalidOperationException("ImageCaptureStream not initialized");
|
||||
if (_frameBufferAllocator is null)
|
||||
throw new InvalidOperationException("FrameBufferAllocator not initialized");
|
||||
if (_mappedBuffers is null)
|
||||
throw new InvalidOperationException("Buffers not mapped");
|
||||
|
||||
var effectiveCancellationToken = CancellationTokenSource
|
||||
.CreateLinkedTokenSource(_disposeCts.Token, cancellationToken)
|
||||
.Token;
|
||||
|
||||
OpenCvSharp.Mat? image = null;
|
||||
|
||||
try
|
||||
{
|
||||
effectiveCancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var buffers = _frameBufferAllocator.Buffers(_imageCaptureStream);
|
||||
var buffer = buffers.Where(b => b.Metadata.Status == FrameMetadata.StatusEnum.FrameStartup || b.Metadata.Status == FrameMetadata.StatusEnum.FrameSuccess).First();
|
||||
var request = _camera.CreateRequest(checked((ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()));
|
||||
var result = request.AddBuffer(_imageCaptureStream, buffer);
|
||||
|
||||
if (result < 0)
|
||||
throw new Exception("Error while request create");
|
||||
|
||||
effectiveCancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var cts = new TaskCompletionSource();
|
||||
void RequestCompleted(object? sender, Camera.RequestCompletedEventArgs e)
|
||||
{
|
||||
if (e.Request.Handle == request.Handle)
|
||||
cts.SetResult();
|
||||
};
|
||||
|
||||
_camera.RequestCompleted += RequestCompleted;
|
||||
await cts.Task.WaitAsync(effectiveCancellationToken);
|
||||
_camera.RequestCompleted -= RequestCompleted;
|
||||
|
||||
var planesData = new List<Memory<byte>>();
|
||||
foreach (var plane in buffer.Planes)
|
||||
{
|
||||
effectiveCancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var pointer = GetPlanePointer(plane);
|
||||
var data = new byte[plane.Length];
|
||||
Marshal.Copy(pointer, data, 0, checked((int)plane.Length));
|
||||
planesData.Add(new Memory<byte>(data));
|
||||
}
|
||||
|
||||
effectiveCancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var config = _imageCaptureStream.Configuration();
|
||||
var size = config.Size;
|
||||
var fourcc = config.PixelFormat.Fourcc;
|
||||
var modifier = config.PixelFormat.Modifier;
|
||||
var primariesEnum = config.ColorSpace!.Primaries;
|
||||
var transferFunctionEnum = config.ColorSpace.TransferFunction;
|
||||
var ycbcrEncodingEnum = config.ColorSpace.YcbcrEncoding;
|
||||
var rangeEnum = config.ColorSpace.Range;
|
||||
var stride = config.Stride;
|
||||
|
||||
effectiveCancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var decoder = FrameDecoderHelper.FindDecoder(fourcc, modifier, primariesEnum, transferFunctionEnum, ycbcrEncodingEnum, rangeEnum);
|
||||
if (decoder is null)
|
||||
throw new Exception($"Cannot find decoder for fourcc={fourcc} modifier={modifier} primariesEnum={primariesEnum} transferFunctionEnum={transferFunctionEnum} ycbcrEncodingEnum={ycbcrEncodingEnum} rangeEnum={rangeEnum}");
|
||||
|
||||
effectiveCancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
try
|
||||
{
|
||||
image = decoder.Decode(checked((int)size.Width), checked((int)size.Height), checked((int)stride), planesData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while image decode");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while image capture");
|
||||
}
|
||||
return image;
|
||||
}
|
||||
private IntPtr GetPlanePointer(FrameBuffer.Plane plane)
|
||||
{
|
||||
if (_mappedBuffers is null)
|
||||
@@ -373,8 +462,10 @@ public class CameraService : IDisposable
|
||||
_frameBufferAllocator?.Dispose();
|
||||
_cameraManager?.Dispose();
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Error while CameraService cleanup");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_cameraManager = null;
|
||||
@@ -386,5 +477,4 @@ public class CameraService : IDisposable
|
||||
_state = State.NotInitialized;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user