From 955a411c09c0f4af7f54027563d0681ed234b290 Mon Sep 17 00:00:00 2001 From: afriscic Date: Wed, 24 Jan 2024 17:41:28 +0100 Subject: [PATCH] 1.2.4 --- .../BarcodeScanning.Native.Maui.csproj | 8 +- .../Platforms/Android/BarcodeAnalyzer.cs | 35 ++-- .../Platforms/Android/CameraViewHandler.cs | 20 +- .../Platforms/iOS/BarcodeAnalyzer.cs | 29 ++- .../Platforms/iOS/CameraViewHandler.cs | 196 +++++++++++------- 5 files changed, 159 insertions(+), 129 deletions(-) diff --git a/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj b/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj index 8ee2184..4849726 100644 --- a/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj +++ b/BarcodeScanning.Native.Maui/BarcodeScanning.Native.Maui.csproj @@ -5,7 +5,7 @@ true true enable - 1.2.3 + 1.2.4 Alen Friščić MIT README.md @@ -28,9 +28,9 @@ - - - + + + diff --git a/BarcodeScanning.Native.Maui/Platforms/Android/BarcodeAnalyzer.cs b/BarcodeScanning.Native.Maui/Platforms/Android/BarcodeAnalyzer.cs index e3eb7cc..9f62303 100644 --- a/BarcodeScanning.Native.Maui/Platforms/Android/BarcodeAnalyzer.cs +++ b/BarcodeScanning.Native.Maui/Platforms/Android/BarcodeAnalyzer.cs @@ -15,14 +15,14 @@ internal class BarcodeAnalyzer : Java.Lang.Object, ImageAnalysis.IAnalyzer private readonly IBarcodeScanner _barcodeScanner; private readonly CameraView _cameraView; - private readonly PreviewView _previewView; private readonly CameraViewHandler _cameraViewHandler; + private readonly PreviewView _previewView; internal BarcodeAnalyzer(CameraView cameraView, PreviewView previewView, CameraViewHandler cameraViewHandler) { _cameraView = cameraView; - _previewView = previewView; _cameraViewHandler = cameraViewHandler; + _previewView = previewView; _barcodeScanner = Xamarin.Google.MLKit.Vision.BarCode.BarcodeScanning.GetClient(new BarcodeScannerOptions.Builder() .SetBarcodeFormats(Methods.ConvertBarcodeFormats(_cameraView.BarcodeSymbologies)) @@ -82,31 +82,20 @@ public async void Analyze(IImageProxy proxy) if (_barcodeResults is not null && _cameraView is not null) _cameraView.DetectionFinished(_barcodeResults); - } - catch (Java.Lang.Exception) - { - } catch (Exception) { - } finally { - SafeCloseImageProxy(proxy, _cameraViewHandler); - } - } - - private static void SafeCloseImageProxy(IImageProxy proxy, CameraViewHandler cameraViewHandler) - { - try - { - proxy?.Close(); - } - catch (Exception) - { - MainThread.BeginInvokeOnMainThread(() => cameraViewHandler.Start()); + try + { + proxy?.Close(); + } + catch (Exception) + { + MainThread.BeginInvokeOnMainThread(_cameraViewHandler.Start); + } } - } - -} + } +} \ No newline at end of file diff --git a/BarcodeScanning.Native.Maui/Platforms/Android/CameraViewHandler.cs b/BarcodeScanning.Native.Maui/Platforms/Android/CameraViewHandler.cs index f711d10..ebf25ef 100644 --- a/BarcodeScanning.Native.Maui/Platforms/Android/CameraViewHandler.cs +++ b/BarcodeScanning.Native.Maui/Platforms/Android/CameraViewHandler.cs @@ -17,7 +17,7 @@ public partial class CameraViewHandler private PreviewView _previewView; private readonly int _delay = 200; - private bool _cameraStarted = false; + private bool _cameraRunning = false; protected override BarcodeView CreatePlatformView() { @@ -40,11 +40,12 @@ protected override BarcodeView CreatePlatformView() return _barcodeView; } - public void Start() - { + internal void Start() + { if (_cameraController is not null) { _cameraController.Unbind(); + _cameraRunning = false; ILifecycleOwner lifecycleOwner = null; if (Context is ILifecycleOwner) @@ -57,10 +58,15 @@ public void Start() if (lifecycleOwner is null) return; + if (_cameraController.CameraSelector is null) + UpdateCamera(); + if (_cameraController.ImageAnalysisTargetSize is null) + UpdateResolution(); + UpdateAnalyzer(); _cameraController.BindToLifecycle(lifecycleOwner); - _cameraStarted = true; + _cameraRunning = true; } } @@ -70,7 +76,7 @@ private void Stop() { _cameraController.EnableTorch(false); _cameraController.Unbind(); - _cameraStarted = false; + _cameraRunning = false; } } @@ -117,12 +123,14 @@ private void UpdateCamera() } + //TODO Implement setImageAnalysisResolutionSelector + //https://developer.android.com/reference/androidx/camera/view/CameraController#setImageAnalysisResolutionSelector(androidx.camera.core.resolutionselector.ResolutionSelector) private void UpdateResolution() { if (_cameraController is not null) _cameraController.ImageAnalysisTargetSize = new CameraController.OutputSize(Methods.TargetResolution(VirtualView?.CaptureQuality)); - if (_cameraStarted) + if (_cameraRunning) Start(); } diff --git a/BarcodeScanning.Native.Maui/Platforms/iOS/BarcodeAnalyzer.cs b/BarcodeScanning.Native.Maui/Platforms/iOS/BarcodeAnalyzer.cs index 90f77ce..70edba1 100644 --- a/BarcodeScanning.Native.Maui/Platforms/iOS/BarcodeAnalyzer.cs +++ b/BarcodeScanning.Native.Maui/Platforms/iOS/BarcodeAnalyzer.cs @@ -8,17 +8,20 @@ internal class BarcodeAnalyzer : AVCaptureVideoDataOutputSampleBufferDelegate { private readonly AVCaptureVideoPreviewLayer _previewLayer; private readonly CameraView _cameraView; + private readonly CameraViewHandler _cameraViewHandler; private readonly VNDetectBarcodesRequest _barcodeRequest; private readonly VNSequenceRequestHandler _sequenceRequestHandler; private HashSet _barcodeResults; - internal BarcodeAnalyzer(CameraView cameraView, AVCaptureVideoPreviewLayer previewLayer) + internal BarcodeAnalyzer(CameraView cameraView, AVCaptureVideoPreviewLayer previewLayer, CameraViewHandler cameraViewHandler) { _cameraView = cameraView; + _cameraViewHandler = cameraViewHandler; _previewLayer = previewLayer; _sequenceRequestHandler = new VNSequenceRequestHandler(); - _barcodeRequest = new VNDetectBarcodesRequest((request, error) => { + _barcodeRequest = new VNDetectBarcodesRequest((request, error) => + { if (error is null) _barcodeResults = Methods.ProcessBarcodeResult(request.GetResults(), _previewLayer); }); @@ -64,23 +67,17 @@ public override void DidOutputSampleBuffer(AVCaptureOutput captureOutput, CMSamp } catch (Exception) { - } finally { - SafeCloseSampleBuffer(sampleBuffer); - } - } - - private static void SafeCloseSampleBuffer(CMSampleBuffer buffer) - { - try - { - buffer?.Dispose(); - } - catch (Exception) - { - + try + { + sampleBuffer?.Dispose(); + } + catch (Exception) + { + MainThread.BeginInvokeOnMainThread(_cameraViewHandler.Start); + } } } } diff --git a/BarcodeScanning.Native.Maui/Platforms/iOS/CameraViewHandler.cs b/BarcodeScanning.Native.Maui/Platforms/iOS/CameraViewHandler.cs index b10cc05..f4bed27 100644 --- a/BarcodeScanning.Native.Maui/Platforms/iOS/CameraViewHandler.cs +++ b/BarcodeScanning.Native.Maui/Platforms/iOS/CameraViewHandler.cs @@ -1,6 +1,5 @@ using AVFoundation; using CoreFoundation; -using CoreVideo; using Foundation; using UIKit; @@ -18,6 +17,9 @@ public partial class CameraViewHandler private BarcodeView _barcodeView; private UITapGestureRecognizer _uITapGestureRecognizer; + private readonly object _syncLock = new(); + private readonly object _configLock = new(); + protected override BarcodeView CreatePlatformView() { _captureSession = new AVCaptureSession(); @@ -36,14 +38,24 @@ protected override BarcodeView CreatePlatformView() return _barcodeView; } - private void Start() + internal void Start() { if (_captureSession is not null) { if (_captureSession.Running) _captureSession.StopRunning(); - - _captureSession.StartRunning(); + + if (_captureSession.Inputs.Length == 0) + UpdateCamera(); + if (_captureSession.Outputs.Length == 0) + UpdateAnalyzer(); + if (_captureSession.SessionPreset is null) + UpdateResolution(); + + lock (_syncLock) + { + _captureSession.StartRunning(); + } } } @@ -51,7 +63,7 @@ private void Stop() { if (_captureSession is not null) { - if (_captureDevice is not null && _captureDevice.TorchMode == AVCaptureTorchMode.On) + if (_captureDevice is not null && _captureDevice.TorchActive) CaptureDeviceLock(() => _captureDevice.TorchMode = AVCaptureTorchMode.Off); if (_captureSession.Running) @@ -73,94 +85,104 @@ private void UpdateResolution() { var quality = VirtualView?.CaptureQuality ?? CaptureQuality.Medium; - _captureSession.BeginConfiguration(); - - while (!_captureSession.CanSetSessionPreset(GetCaptureSessionResolution(quality)) && quality != CaptureQuality.Low) + lock (_syncLock) { - quality -= 1; - } + _captureSession.BeginConfiguration(); + + while (!_captureSession.CanSetSessionPreset(GetCaptureSessionResolution(quality)) && quality != CaptureQuality.Low) + { + quality -= 1; + } + _captureSession.SessionPreset = GetCaptureSessionResolution(quality); - _captureSession.SessionPreset = GetCaptureSessionResolution(quality); - _captureSession.CommitConfiguration(); + _captureSession.CommitConfiguration(); + } } } private void UpdateAnalyzer() { if (_captureSession is not null) { - _captureSession.BeginConfiguration(); - - if (_videoDataOutput is not null) + lock (_syncLock) { - if (_captureSession.Outputs.Length > 0 && _captureSession.Outputs.Contains(_videoDataOutput)) - _captureSession.RemoveOutput(_videoDataOutput); + _captureSession.BeginConfiguration(); - _videoDataOutput.Dispose(); - } + if (_videoDataOutput is not null) + { + if (_captureSession.Outputs.Length > 0 && _captureSession.Outputs.Contains(_videoDataOutput)) + _captureSession.RemoveOutput(_videoDataOutput); - _videoDataOutput = new AVCaptureVideoDataOutput() - { - AlwaysDiscardsLateVideoFrames = true, - WeakVideoSettings = new CVPixelBufferAttributes { PixelFormatType = CVPixelFormatType.CV32BGRA }.Dictionary - }; + _videoDataOutput.Dispose(); + } - if (VirtualView is not null && _videoPreviewLayer is not null && _queue is not null) - { - _barcodeAnalyzer?.Dispose(); - _barcodeAnalyzer = new BarcodeAnalyzer(VirtualView, _videoPreviewLayer); - _videoDataOutput.SetSampleBufferDelegate(_barcodeAnalyzer, _queue); - } + _videoDataOutput = new AVCaptureVideoDataOutput() + { + AlwaysDiscardsLateVideoFrames = true + }; + + if (VirtualView is not null && _videoPreviewLayer is not null && _queue is not null) + { + _barcodeAnalyzer?.Dispose(); + _barcodeAnalyzer = new BarcodeAnalyzer(VirtualView, _videoPreviewLayer, this); + _videoDataOutput.SetSampleBufferDelegate(_barcodeAnalyzer, _queue); + } - if (_captureSession.CanAddOutput(_videoDataOutput)) - _captureSession.AddOutput(_videoDataOutput); + if (_captureSession.CanAddOutput(_videoDataOutput)) + _captureSession.AddOutput(_videoDataOutput); - _captureSession.CommitConfiguration(); + _captureSession.CommitConfiguration(); + } } } private void UpdateCamera() { if (_captureSession is not null) { - _captureSession.BeginConfiguration(); - - if (_captureInput is not null) + lock (_syncLock) { - if (_captureSession.Inputs.Length > 0 && _captureSession.Inputs.Contains(_captureInput)) - _captureSession.RemoveInput(_captureInput); - - _captureInput.Dispose(); - } + _captureSession.BeginConfiguration(); - _captureDevice?.Dispose(); - if (VirtualView?.CameraFacing == CameraFacing.Front) - { - _captureDevice = AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInWideAngleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Front); - } - else - { - _captureDevice = AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInTripleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); - _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInDualWideCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); - _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInDualCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); - _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInWideAngleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); - } - _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVMediaTypes.Video); + _captureSession.SessionPreset = AVCaptureSession.Preset1280x720; - if (_captureDevice is not null) - { - if (_captureDevice.IsFocusModeSupported(AVCaptureFocusMode.ContinuousAutoFocus)) - CaptureDeviceLock(() => _captureDevice.FocusMode = AVCaptureFocusMode.ContinuousAutoFocus); - else - CaptureDeviceLock(() => _captureDevice.FocusMode = AVCaptureFocusMode.AutoFocus); + if (_captureInput is not null) + { + if (_captureSession.Inputs.Length > 0 && _captureSession.Inputs.Contains(_captureInput)) + _captureSession.RemoveInput(_captureInput); - _captureInput = new AVCaptureDeviceInput(_captureDevice, out _); + _captureInput.Dispose(); + } - if (_captureSession.CanAddInput(_captureInput)) - _captureSession.AddInput(_captureInput); + _captureDevice?.Dispose(); + if (VirtualView?.CameraFacing == CameraFacing.Front) + { + _captureDevice = AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInWideAngleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Front); + } + else + { + _captureDevice = AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInTripleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); + _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInDualWideCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); + _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInDualCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); + _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVCaptureDeviceType.BuiltInWideAngleCamera, AVMediaTypes.Video, AVCaptureDevicePosition.Back); + } + _captureDevice ??= AVCaptureDevice.GetDefaultDevice(AVMediaTypes.Video); + + if (_captureDevice is not null) + { + if (_captureDevice.IsFocusModeSupported(AVCaptureFocusMode.ContinuousAutoFocus)) + CaptureDeviceLock(() => _captureDevice.FocusMode = AVCaptureFocusMode.ContinuousAutoFocus); + else + CaptureDeviceLock(() => _captureDevice.FocusMode = AVCaptureFocusMode.AutoFocus); + + _captureInput = new AVCaptureDeviceInput(_captureDevice, out _); + + if (_captureSession.CanAddInput(_captureInput)) + _captureSession.AddInput(_captureInput); + } + + _captureSession.CommitConfiguration(); } UpdateResolution(); - - _captureSession.CommitConfiguration(); } } @@ -169,9 +191,17 @@ private void UpdateTorch() if (_captureDevice is not null && _captureDevice.HasTorch && _captureDevice.TorchAvailable) { if (VirtualView?.TorchOn ?? false) - CaptureDeviceLock(() => _captureDevice.TorchMode = AVCaptureTorchMode.On); + CaptureDeviceLock(() => + { + if(_captureDevice.IsTorchModeSupported(AVCaptureTorchMode.On)) + _captureDevice.TorchMode = AVCaptureTorchMode.On; + }); else - CaptureDeviceLock(() => _captureDevice.TorchMode = AVCaptureTorchMode.Off); + CaptureDeviceLock(() => + { + if(_captureDevice.IsTorchModeSupported(AVCaptureTorchMode.Off)) + _captureDevice.TorchMode = AVCaptureTorchMode.Off; + }); } } @@ -201,7 +231,7 @@ private void FocusOnTap() } } - private NSString GetCaptureSessionResolution(CaptureQuality quality) + private static NSString GetCaptureSessionResolution(CaptureQuality quality) { return quality switch { @@ -214,19 +244,25 @@ private NSString GetCaptureSessionResolution(CaptureQuality quality) } private void CaptureDeviceLock(Action handler) { - try + MainThread.BeginInvokeOnMainThread(() => { - if (_captureDevice.LockForConfiguration(out _)) - handler(); - } - catch (Exception) - { - - } - finally - { - _captureDevice?.UnlockForConfiguration(); - } + lock (_configLock) + { + try + { + _captureDevice.LockForConfiguration(out _); + handler(); + } + catch (Exception) + { + + } + finally + { + _captureDevice?.UnlockForConfiguration(); + } + } + }); } internal void Current_MainDisplayInfoChanged(object sender, DisplayInfoChangedEventArgs e)