| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- using System;
- using System.Threading;
- using ivf_tl_CameraHelper;
- namespace IvfTl.Hardware.Impl
- {
- /// <summary>
- /// ICamera 实现,内部包装 control 的 ivf_tl_CameraHelper.Camera(不改其内部逻辑)。
- /// 所有进 native 的调用统一经 ICameraGate 串行化(全进程一把锁,13 §3.5/§②)。
- /// 旧 Camera 内部自带的 static locker 保留(死代码隔离,01 §5);同一线程经两把锁不死锁,
- /// 真正跨调用者互斥由本层 _gate 保证。
- /// 蓝本 af Camera:GetFrameBuffer 做 null 保护;GrabStable 内置"丢残留帧 + 到位延时 + 重试"。
- /// </summary>
- public sealed class CameraImpl : ICamera
- {
- private readonly Camera _camera; // 包装的旧具体相机
- private readonly ICameraGate _gate; // 全进程相机锁
- private readonly int _index;
- private readonly int _width;
- private readonly int _height;
- public CameraImpl(int index, int width, int height, int exposure, ICameraGate gate)
- {
- _index = index;
- _width = width;
- _height = height;
- _gate = gate ?? throw new ArgumentNullException(nameof(gate));
- _camera = new Camera(index, width, height, exposure);
- }
- public int Index => _index;
- public int Width => _width;
- public int Height => _height;
- public int Exposure => _camera.Exposure;
- public string SerialNumber => _camera.NumBer;
- public bool IsInit => _camera.IsInit;
- public bool IsStart => _camera.IsStart;
- public object RawCamera => _camera;
- // ── 生命周期 ──
- public int Init(byte redGain = 25, byte greenGain = 14, byte blueGain = 25)
- {
- // 注:旧 Camera.Init() 固定增益(25/14/25),未暴露参数;此处沿用旧实现。
- // 增益自定义经 SetGain(旧 Camera 暂无该 API,见 SetGain 的 TODO)。
- return _gate.Invoke(() => _camera.Init());
- }
- public int SetOpMode(byte mode = 0, bool strobe = false)
- {
- return _gate.Invoke(() => _camera.SetOpMode());
- }
- public int ReadSerial()
- {
- return _gate.Invoke(() => _camera.GetNumbet());
- }
- public int UnInit()
- {
- return _gate.Invoke(() => _camera.UnInit());
- }
- // ── 参数 ──
- public int SetExposure(int exposure100us)
- {
- return _gate.Invoke(() => _camera.SetPartOfCapInfo(exposure100us));
- }
- public int SetGain(byte red, byte green, byte blue)
- {
- // TODO(M2): control 旧 Camera 未暴露独立 SetGain(增益随 Init 固定);
- // 自动对焦标定若需调增益,需向旧 Camera 补 native SetPartOfCapInfo(含 Gain) 包装,
- // 或在 HAL 内自行构造 capInfoStruct。M1 不需要,留 TODO + 待验证。
- return -1;
- }
- // ── 抓帧(单帧)──
- public int GrabRgb()
- {
- return _gate.Invoke(() => _camera.GetRgbData());
- }
- public byte[] GetFrameBuffer()
- {
- // _pDest 空保护语义(af Camera.cs:137):旧 Camera.SourceBuffer 内部直接 Marshal.Copy(pDest,...),
- // pDest 已释放时会抛异常——此处用 _gate 锁内取并捕获异常返回 null(按抓帧失败重试)。
- return _gate.Invoke(() =>
- {
- try
- {
- return _camera.SourceBuffer;
- }
- catch
- {
- return null;
- }
- });
- }
- public byte[] GrabStable(int preDelayMs = 0, bool discardStale = true, int retry = 2)
- {
- // 13 §3.5(1)(2)(4):抓前到位延时 + 丢残留帧 + 失败重试。
- if (preDelayMs > 0) Thread.Sleep(preDelayMs);
- for (int attempt = 0; attempt <= retry; attempt++)
- {
- // 丢残留帧:运动后旧帧可能滞留缓冲,先抓一帧丢弃(对应 af 双 Grab)。
- if (discardStale)
- {
- GrabRgb();
- }
- int r = GrabRgb();
- if (r == 0)
- {
- var buf = GetFrameBuffer();
- if (buf != null) return buf;
- }
- // 抓帧失败:短暂等待后重试
- Thread.Sleep(50);
- }
- return null;
- }
- // ── 实时预览 ──
- public int StartPreview(IntPtr hostControl, int left, int top, int width, int height)
- {
- return _gate.Invoke(() => _camera.Usb2Start(hostControl, left, top, width, height));
- }
- public int StopPreview()
- {
- return _gate.Invoke(() => _camera.Usb2Stop());
- }
- // ── operate 调试页"无图模式"两步抓帧 + 存图(M1-B2)──
- // 转发到底层具体 Camera 既有方法(GetRawData / RawToRgb / SaveBmpPic),全部经 _gate 串行化。
- public int GrabRaw()
- {
- return _gate.Invoke(() => _camera.GetRawData());
- }
- public int RawToRgb()
- {
- return _gate.Invoke(() => _camera.RawToRgb());
- }
- public bool SavePic(string fullName, int width, int height)
- {
- // 底层 control Camera 无 MVCAPI.SavePic;用其既有 SaveBmpPic(从 SourceBuffer 取 24bpp、
- // RotateFlipY 后按文件扩展名落盘,.jpg 即存 JPEG),与 operate 调试页存图语义等价。
- // 取像素 + 落盘都涉及 native 内存(SourceBuffer→Marshal.Copy),经 _gate 与抓帧/释放互斥。
- return _gate.Invoke(() => _camera.SaveBmpPic(fullName));
- }
- public void Dispose()
- {
- try { UnInit(); } catch { }
- try { _gate.Invoke(() => _camera.DisPose()); } catch { }
- }
- }
- }
|