chore: move CameraView logic to itself

This commit is contained in:
2026-01-23 08:42:58 +03:00
parent 8896629ce2
commit d4e7c300f4
8 changed files with 100 additions and 139 deletions
+12 -26
View File
@@ -680,7 +680,7 @@ public class CameraService : IDisposable
var result = request.AddBuffer(_viewFinderStream, buffer); var result = request.AddBuffer(_viewFinderStream, buffer);
if (result < 0) if (result < 0)
throw new Exception("Error while request create"); throw new Exception("Error while request create");
_logger.LogDebug("Request(s) created"); // _logger.LogDebug("Request(s) created");
effectiveCancellationToken.ThrowIfCancellationRequested(); effectiveCancellationToken.ThrowIfCancellationRequested();
@@ -694,20 +694,20 @@ public class CameraService : IDisposable
if (buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameError || if (buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameError ||
buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameStartup) buffer.Metadata.Status == FrameMetadata.StatusEnum.FrameStartup)
{ {
_logger.LogDebug("Request buffers status: {}", buffer.Metadata.Status); // _logger.LogDebug("Request buffers status: {}", buffer.Metadata.Status);
e.Request.Reuse(Request.ReuseFlagEnum.ReuseBuffers); e.Request.Reuse(Request.ReuseFlagEnum.ReuseBuffers);
var result = _camera.QueueRequest(e.Request); var result = _camera.QueueRequest(e.Request);
if (result >= 0) if (result >= 0)
return; 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 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: \n\tStatus: {} \n\tCookie: {} \n\tSequence: {} \n\tTimestamp: {}", buffer.Metadata.Status, buffer.Cookie, buffer.Metadata.Sequence, buffer.Metadata.Timestamp);
_logger.LogDebug("Request buffer planes: "); // _logger.LogDebug("Request buffer planes: ");
foreach (var (i, plane) in buffer.Metadata.Planes.Enumerate()) // foreach (var (i, plane) in buffer.Metadata.Planes.Enumerate())
_logger.LogDebug("Plane[{}]: bytes used: 0x{:X}", i, plane.BytesUsed); // _logger.LogDebug("Plane[{}]: bytes used: 0x{:X}", i, plane.BytesUsed);
foreach (var (i, plane) in buffer.Planes.Enumerate()) // 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("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();
@@ -722,26 +722,12 @@ public class CameraService : IDisposable
_camera.RequestCompleted -= RequestCompleted; _camera.RequestCompleted -= RequestCompleted;
throw new Exception("Error while request queue"); throw new Exception("Error while request queue");
} }
_logger.LogDebug("Request queued"); // _logger.LogDebug("Request queued");
await cts.Task.WaitAsync(effectiveCancellationToken); await cts.Task.WaitAsync(effectiveCancellationToken);
_camera.RequestCompleted -= RequestCompleted; _camera.RequestCompleted -= RequestCompleted;
_logger.LogDebug("Request complited"); // _logger.LogDebug("Request complited");
return new (buffer, _viewFinderStreamConfiguration); return new(buffer, _viewFinderStreamConfiguration);
}
public void Test()
{
var config = _viewFinderStreamConfiguration!;
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;
_logger.LogInformation($"Cannot find decoder for fourcc=0x{fourcc:X}({new string(BitConverter.GetBytes(fourcc).Select(b => (char)b).ToArray())}) modifier=0x{modifier:X} primariesEnum={primariesEnum} transferFunctionEnum={transferFunctionEnum} ycbcrEncodingEnum={ycbcrEncodingEnum} rangeEnum={rangeEnum}");
} }
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
+31 -5
View File
@@ -72,7 +72,7 @@ class VkRenderer
SType = StructureType.FenceCreateInfo SType = StructureType.FenceCreateInfo
}; };
context.Api.CreateFence(context.Device, &fenceInfo, null, out var fence).ThrowOnError(); context.Api.CreateFence(context.Device, &fenceInfo, null, out var fence).ThrowOnError();
var (importImage, importMemoryReqirements, importMemory) = ImportImage(fdDup, width, height, stride); var (importImage, importMemoryReqirements, importMemory) = ImportImage(fdDup, width, height, stride);
var (exportImage, exportMemoryReqirements, exportMemory) = CreateExportImage(width, height); var (exportImage, exportMemoryReqirements, exportMemory) = CreateExportImage(width, height);
@@ -380,6 +380,7 @@ public partial class CameraView : Control
private bool _compositionRequested; private bool _compositionRequested;
private VkRenderer? _renerer; private VkRenderer? _renerer;
private VkImage? _latestImage; private VkImage? _latestImage;
private System.Timers.Timer? _updateTimer;
public CameraView() public CameraView()
{ } { }
@@ -388,11 +389,40 @@ public partial class CameraView : Control
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
Initialize(); Initialize();
if (!_initialized)
return;
int i = 0;
_updateTimer = new System.Timers.Timer(100)
{
AutoReset = true
};
_updateTimer.Elapsed += async (_, _) =>
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
var viewModel = DataContext as CameraViewModel;
if (viewModel is null)
return;
var result = await viewModel.CaptureImage(i++);
if (result is not null)
{
var (frameBuffer, streamConfiguration) = result.Value;
if (frameBuffer.Metadata.Status == FrameMetadata.StatusEnum.FrameSuccess)
Update(frameBuffer, streamConfiguration);
}
});
};
_updateTimer.Start();
} }
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{ {
if (_initialized) if (_initialized)
{
_updateTimer?.Stop();
_updateTimer?.Dispose();
Surface?.Dispose(); Surface?.Dispose();
}
_initialized = false; _initialized = false;
base.OnDetachedFromLogicalTree(e); base.OnDetachedFromLogicalTree(e);
@@ -425,10 +455,6 @@ public partial class CameraView : Control
_visual.Size = new Vector(Bounds.Width, Bounds.Height); _visual.Size = new Vector(Bounds.Width, Bounds.Height);
Update(); Update();
} }
if (change.Property == DataContextProperty)
{
(DataContext as CameraViewModel)?.Update += (_, ea) => Update(ea.FrameBuffer, ea.StreamConfiguration);
}
base.OnPropertyChanged(change); base.OnPropertyChanged(change);
} }
+17 -17
View File
@@ -1,32 +1,32 @@
using GSS2.Core.Hardware;
using LibCameraSharp; using LibCameraSharp;
namespace GSS2.Test; namespace GSS2.Test;
public class CameraViewModel : ViewModelBase public class CameraViewModel : ViewModelBase
{ {
public class UpdateEventArgs : EventArgs private readonly CameraService _cameraService;
{
public FrameBuffer? FrameBuffer { get; }
public StreamConfiguration? StreamConfiguration { get; }
public UpdateEventArgs(FrameBuffer? frameBuffer = null, StreamConfiguration? streamConfiguration = null)
{
FrameBuffer = frameBuffer;
StreamConfiguration = streamConfiguration;
}
}
private readonly ILogger<CameraViewModel> _logger; private readonly ILogger<CameraViewModel> _logger;
public event EventHandler<UpdateEventArgs>? Update; public CameraViewModel(CameraService cameraService, ILogger<CameraViewModel> logger)
public CameraViewModel(ILogger<CameraViewModel> logger)
{ {
_cameraService = cameraService;
_logger = logger; _logger = logger;
_logger.LogInformation("Initialized");
} }
public void CallUpdate(FrameBuffer? frameBuffer = null, StreamConfiguration? streamConfiguration = null) public async Task<(FrameBuffer, StreamConfiguration)?> CaptureImage(int bufferId)
{ {
Update?.Invoke(this, new UpdateEventArgs(frameBuffer, streamConfiguration)); (FrameBuffer, StreamConfiguration)? result = null;
try
{
result = await _cameraService.CaptureViewFinderBuffer(bufferId, CancellationToken.None);
}
catch (Exception e)
{
_logger.LogError(e, "Error while image capture");
}
return result;
} }
} }
+1 -17
View File
@@ -1,4 +1,5 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Threading;
namespace GSS2.Test; namespace GSS2.Test;
@@ -7,22 +8,5 @@ public partial class MainWindow : Window
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
int i = 0;
PointerPressed += async (_, _) =>
{
var viewModel = DataContext as MainWindowViewModel;
if (viewModel is null)
return;
var result = await viewModel.CaptureImage(i++);
if (result is not null)
{
var (frameBuffer, streamConfiguration) = result.Value;
if (frameBuffer.Metadata.Status == LibCameraSharp.FrameMetadata.StatusEnum.FrameSuccess)
// cameraView.Update(frameBuffer, streamConfiguration);
(cameraView.Content as CameraViewModel)?.CallUpdate(frameBuffer, streamConfiguration);
}
};
} }
} }
-35
View File
@@ -27,40 +27,5 @@ public partial class MainWindowViewModel : ViewModelBase
_lightsService = lightsService; _lightsService = lightsService;
_logger = logger; _logger = logger;
CameraViewModel = cameraViewModel; CameraViewModel = cameraViewModel;
_logger.LogInformation("Initialized");
}
public async Task<(LibCameraSharp.FrameBuffer, LibCameraSharp.StreamConfiguration)?> CaptureImage(int bufferId)
{
_logger.LogInformation("Capture image");
_lightsService.CpuLoad(0.5, 1, System.Drawing.Color.Aqua);
(LibCameraSharp.FrameBuffer, LibCameraSharp.StreamConfiguration)? result = null;
try
{
// _illuminatorService.SetIntensity(0.01, 0, 0);
// _illuminatorService.TurnOn();
result = await _cameraService.CaptureViewFinderBuffer(bufferId, CancellationToken.None);
_lightsService.Flash(0.5, 2, System.Drawing.Color.Green);
}
catch (Exception e)
{
_logger.LogError(e, "Error while image capture");
_lightsService.Flash(0.5, 2, System.Drawing.Color.Red);
}
finally
{
// _illuminatorService.TurnOff();
}
var snowfallTimer = new System.Timers.Timer(3000);
snowfallTimer.Elapsed += (_, _) =>
{
_lightsService.Snowfall(0.3, 1, System.Drawing.Color.Aqua);
snowfallTimer.Dispose();
};
snowfallTimer.Start();
return result;
} }
} }
+37 -37
View File
@@ -1,49 +1,49 @@
using System.Drawing; // using System.Drawing;
using GSS2.Core.Analysis.AmineContent.Database; // using GSS2.Core.Analysis.AmineContent.Database;
using GSS2.Core.Hardware; // using GSS2.Core.Hardware;
namespace GSS2.Test; // namespace GSS2.Test;
public class Worker( // public class Worker(
ILogger<Worker> logger, // ILogger<Worker> logger,
IHostApplicationLifetime applicationLifetime, // IHostApplicationLifetime applicationLifetime,
AmineContentCalibrationContext amineCalibrationContext, // AmineContentCalibrationContext amineCalibrationContext,
AmineContentResultsContext amineResultsContext, // AmineContentResultsContext amineResultsContext,
LightsService lightsService, // LightsService lightsService,
IlluminatorService illuminatorService, // IlluminatorService illuminatorService,
CameraService cameraService // CameraService cameraService
) : BackgroundService // ) : BackgroundService
{ // {
private readonly ILogger<Worker> _logger = logger; // private readonly ILogger<Worker> _logger = logger;
private readonly IHostApplicationLifetime _applicationLifetime = applicationLifetime; // private readonly IHostApplicationLifetime _applicationLifetime = applicationLifetime;
private readonly AmineContentCalibrationContext _amineCalibrationContext = amineCalibrationContext; // private readonly AmineContentCalibrationContext _amineCalibrationContext = amineCalibrationContext;
private readonly AmineContentResultsContext _amineResultsContext = amineResultsContext; // private readonly AmineContentResultsContext _amineResultsContext = amineResultsContext;
private readonly LightsService _lightsService = lightsService; // private readonly LightsService _lightsService = lightsService;
private readonly IlluminatorService _illuminatorService = illuminatorService; // private readonly IlluminatorService _illuminatorService = illuminatorService;
private readonly CameraService _cameraService = cameraService; // private readonly CameraService _cameraService = cameraService;
protected override async Task ExecuteAsync(CancellationToken cancellationToken) // protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{ // {
_cameraService.Test(); // // _cameraService.Test();
// _ = _lightsService.Run(cancellationToken); // // _ = _lightsService.Run(cancellationToken);
// _ = _lightsService.SnowfallAsync(0.3, 1, Color.Aqua, cancellationToken); // // _ = _lightsService.SnowfallAsync(0.3, 1, Color.Aqua, cancellationToken);
// _illuminatorService.SetIntensity(0.01, 0, 0); // // _illuminatorService.SetIntensity(0.01, 0, 0);
// _illuminatorService.TurnOn(); // // _illuminatorService.TurnOn();
// await Task.Delay(1000); // // await Task.Delay(1000);
// var img = await _cameraService.CaptureImage(cancellationToken, 50); // // var img = await _cameraService.CaptureImage(cancellationToken, 50);
// // img?.SaveImage("IMAGE.png"); // // // img?.SaveImage("IMAGE.png");
// await Task.Delay(1000); // // await Task.Delay(1000);
// _illuminatorService.TurnOff(); // // _illuminatorService.TurnOff();
// await _lightsService.DisconnectAsync(cancellationToken); // // await _lightsService.DisconnectAsync(cancellationToken);
applicationLifetime.StopApplication(); // applicationLifetime.StopApplication();
} // }
} // }
+1 -1
View File
@@ -38,7 +38,7 @@
}, },
"Camera": { "Camera": {
"CameraId": "", "CameraId": "",
"ViewFinderFrameBufferCount": 2, "ViewFinderFrameBufferCount": 30,
"ViewFinderWidth": 1920, "ViewFinderWidth": 1920,
"ViewFinderHeight": 1080, "ViewFinderHeight": 1080,
"ViewFinderFps": 30, "ViewFinderFps": 30,
+1 -1
View File
@@ -11,7 +11,7 @@ public static class VulkanExtensions
{ {
public static void ThrowOnError(this Result result, [CallerMemberName] string callerMemberName = "", [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = -1) public static void ThrowOnError(this Result result, [CallerMemberName] string callerMemberName = "", [CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = -1)
{ {
Console.WriteLine($"{callerFilePath} {callerMemberName} {callerLineNumber} {result}"); // Console.WriteLine($"{callerFilePath} {callerMemberName} {callerLineNumber} {result}");
if (result != Result.Success) if (result != Result.Success)
throw new Exception($"Unexpected API error \"{result}\""); throw new Exception($"Unexpected API error \"{result}\"");
} }