/* * VideoKit * Copyright © 2026 Yusuf Olokoba. All Rights Reserved. */ #nullable enable namespace VideoKit.Sources { using System; using Clocks; using UI; /// /// Media source for generating pixel buffers from a camera device. /// internal sealed class CameraViewSource : IDisposable { #region --Client API-- /// /// Control number of successive camera frames to skip while recording. /// This is very useful for GIF recording, which typically has a lower framerate appearance. /// public int frameSkip; /// /// Create a camera device source. /// /// Camera view to capture pixel buffers from. /// /// Clock for generating pixel buffer timestamps. /// Raised when the camera preview is not running. public CameraViewSource( VideoKitCameraView view, Action handler, IClock? clock = null ) { if (view.texture == null) throw new ArgumentException("Cannot create camera view source because camera manager is not running"); this.handler = handler; this.clock = clock; this.view = view; view.OnPixelBuffer += OnPixelBuffer; } /// /// Stop the camera view source and release resources. /// public void Dispose() => view.OnPixelBuffer -= OnPixelBuffer; #endregion #region --Operations-- private readonly Action handler; private readonly IClock? clock; private readonly VideoKitCameraView view; private int frameIdx; private void OnPixelBuffer(PixelBuffer pixelBuffer) { if (frameIdx++ % (frameSkip + 1) != 0) return; using var outputBuffer = new PixelBuffer( width: pixelBuffer.width, height: pixelBuffer.height, format: pixelBuffer.format, data: pixelBuffer.data, rowStride: pixelBuffer.rowStride, timestamp: clock?.timestamp ?? 0L, mirrored: pixelBuffer.verticallyMirrored ); handler(outputBuffer); } #endregion } }