1using System.Runtime.InteropServices;
7internal sealed class VideoFrameMailbox : IDisposable
9 private readonly
object _gate =
new();
10 private byte[] _pixels = [];
11 private int _width, _height;
12 private bool _pending, _clear, _disposed;
14 internal void Publish(VideoFrameReadyEventArgs frame)
18 if (_disposed)
return;
19 int rowBytes = checked(frame.Width * 4);
20 int length = checked(rowBytes * frame.Height);
21 if (frame.Width <= 0 || frame.Height <= 0 || frame.Stride < rowBytes || frame.Pixels == IntPtr.Zero)
22 throw new ArgumentException(
"Invalid video frame dimensions, stride, or pointer.", nameof(frame));
23 if (_pixels.Length != length) _pixels =
new byte[length];
24 for (
int y = 0; y < frame.Height; y++)
26 Marshal.Copy(IntPtr.Add(frame.Pixels, checked(y * frame.Stride)), _pixels, y * rowBytes, rowBytes);
29 for (
int x = y * rowBytes + 3; x < (y + 1) * rowBytes; x += 4) _pixels[x] = 255;
32 _height = frame.Height;
39 lock (_gate) { _pending =
false; _clear =
true; }
44 internal bool Consume(ref SKBitmap? bitmap)
48 if (_disposed)
return false;
49 bool changed = _clear;
50 if (_clear) { bitmap?.Dispose(); bitmap =
null; _clear =
false; }
51 if (!_pending)
return changed;
52 if (bitmap is
null || bitmap.Width != _width || bitmap.Height != _height)
55 bitmap =
new SKBitmap(
new SKImageInfo(_width, _height, SKColorType.Bgra8888, SKAlphaType.Opaque));
57 int rowBytes = checked(_width * 4);
58 for (
int y = 0; y < _height; y++)
59 Marshal.Copy(_pixels, y * rowBytes, IntPtr.Add(bitmap.GetPixels(), y * bitmap.RowBytes), rowBytes);
60 bitmap.NotifyPixelsChanged();
71 lock (_gate) { _disposed =
true; _pending =
false; _pixels = []; }