C# Grabber Service
選取GrabberService專案按下滑鼠右鍵並選取管理NuGet套件
安裝Newtonsoft.Json套件
專案新增appsettings.json
選取GrabberService專案按下滑鼠右鍵並選取"加入",接著選取"新增項目"
輸入名稱: appsettings.json
滑鼠雙擊開啟appsettings.json
GrabberService/FrameHeader.cs
using System.Runtime.InteropServices; namespace GrabberService; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct FrameHeader { public ulong FrameId; public ulong TimestampNs; public uint Width; public uint Height; public uint Stride; public uint PixelFormat; public uint ImageSize; public uint CameraIndex; public uint Flags; }
GrabberService/SharedMemoryPublisher.cs
using System.IO.MemoryMappedFiles; using System.Runtime.InteropServices; namespace GrabberService; public sealed class SharedMemoryPublisher : IDisposable { private readonly string _mapName; private readonly int _capacity; private readonly MemoryMappedFile _mmf; private readonly MemoryMappedViewAccessor _accessor; private readonly object _lock = new(); public SharedMemoryPublisher(string mapName, int capacity) { _mapName = mapName; _capacity = capacity; _mmf = MemoryMappedFile.CreateOrOpen(_mapName, _capacity, MemoryMappedFileAccess.ReadWrite); _accessor = _mmf.CreateViewAccessor(0, _capacity, MemoryMappedFileAccess.ReadWrite); } public void Publish(FrameHeader header, byte[] image) { int headerSize = Marshal.SizeOf<FrameHeader>(); if (headerSize + image.Length > _capacity) { throw new InvalidOperationException("Shared memory capacity is too small."); } lock (_lock) { _accessor.Write(0, ref header); _accessor.WriteArray(headerSize, image, 0, image.Length); } } public void Dispose() { _accessor.Dispose(); _mmf.Dispose(); } }
GrabberService/CameraSimulator.cs
namespace GrabberService; public sealed class CameraSimulator { private readonly int _width; private readonly int _height; private ulong _frameId = 0; private int _tick = 0; public CameraSimulator(int width, int height) { _width = width; _height = height; } public (FrameHeader header, byte[] image) Grab() { byte[] img = new byte[_width * _height]; int cx = (_tick * 7) % _width; int cy = (_tick * 5) % _height; for (int y = 0; y < _height; y++) { for (int x = 0; x < _width; x++) { int idx = y * _width + x; int dx = x - cx; int dy = y - cy; int r2 = dx * dx + dy * dy; byte v = (byte)((x + y + _tick) % 256); if (r2 < 30 * 30) v = 255; img[idx] = v; } } var header = new FrameHeader { FrameId = ++_frameId, TimestampNs = (ulong)DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() * 1_000_000UL, Width = (uint)_width, Height = (uint)_height, Stride = (uint)_width, PixelFormat = 1, ImageSize = (uint)img.Length, CameraIndex = 0, Flags = 0 }; _tick++; return (header, img); } }
必裝 NuGet 套件
在 GrabberService 專案 → 右鍵 → 管理 NuGet 套件
搜尋並安裝:NetMQ
搜尋並安裝:Microsoft.Extensions.Hosting
搜尋並安裝:Microsoft.Extensions.Logging
GrabberService/CommandServer.cs
using System; using System.Collections.Generic; using System.Text.Json; using Microsoft.Extensions.Logging; using NetMQ; using NetMQ.Sockets; namespace GrabberService; public sealed class CommandServer : IDisposable { private readonly string _bindAddress; private readonly ILogger<CommandServer> _logger; private readonly ResponseSocket _socket; public bool IsGrabbing { get; private set; } = false; public CommandServer(string bindAddress, ILogger<CommandServer> logger) { _bindAddress = bindAddress; _logger = logger; AsyncIO.ForceDotNet.Force(); _socket = new ResponseSocket(); _socket.Bind(_bindAddress); } public bool PollOnce() { if (!_socket.TryReceiveFrameString(TimeSpan.FromMilliseconds(1), out var msg)) return false; Dictionary<string, object?> response; try { var req = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(msg) ?? new Dictionary<string, JsonElement>(); var cmd = req.TryGetValue("cmd", out var cmdEl) ? cmdEl.GetString() : string.Empty; response = cmd switch { "start" => StartResponse(), "stop" => StopResponse(), "status" => StatusResponse(), "heartbeat" => Ok("alive"), _ => Error($"Unknown command: {cmd}") }; } catch (Exception ex) { response = Error(ex.Message); } _socket.SendFrame(JsonSerializer.Serialize(response)); return true; } private Dictionary<string, object?> StartResponse() { IsGrabbing = true; _logger.LogInformation("Grab started"); return Ok("started"); } private Dictionary<string, object?> StopResponse() { IsGrabbing = false; _logger.LogInformation("Grab stopped"); return Ok("stopped"); } private Dictionary<string, object?> StatusResponse() { return new Dictionary<string, object?> { ["ok"] = true, ["grabbing"] = IsGrabbing }; } private static Dictionary<string, object?> Ok(string message) { return new Dictionary<string, object?> { ["ok"] = true, ["message"] = message }; } private static Dictionary<string, object?> Error(string message) { return new Dictionary<string, object?> { ["ok"] = false, ["message"] = message }; } public void Dispose() { _socket?.Dispose(); NetMQConfig.Cleanup(); } }
文章標籤
全站熱搜

留言功能已依作者設定調整顯示方式