Navaron Bracke

fix nil capture session bug

## 4.0.1
Bugs fixed:
* [iOS] Fixed a crash with a nil capture session when starting the camera. (thanks @navaronbracke !)
## 4.0.0
BREAKING CHANGES:
* [Android] compileSdk has been upgraded to version 34.
... ...
... ... @@ -17,7 +17,7 @@ typealias ZoomScaleChangeCallback = ((Double?) -> ())
public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate, FlutterTexture {
/// Capture session of the camera
var captureSession: AVCaptureSession!
var captureSession: AVCaptureSession?
/// The selected camera
var device: AVCaptureDevice!
... ... @@ -173,7 +173,7 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
/// Start scanning for barcodes
func start(barcodeScannerOptions: BarcodeScannerOptions?, returnImage: Bool, cameraPosition: AVCaptureDevice.Position, torch: Bool, detectionSpeed: DetectionSpeed, completion: @escaping (MobileScannerStartParameters) -> ()) throws {
self.detectionSpeed = detectionSpeed
if (device != nil) {
if (device != nil || captureSession != nil) {
throw MobileScannerError.alreadyStarted
}
... ... @@ -216,17 +216,17 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
device.unlockForConfiguration()
} catch {}
captureSession.beginConfiguration()
captureSession!.beginConfiguration()
// Add device input
do {
let input = try AVCaptureDeviceInput(device: device)
captureSession.addInput(input)
captureSession!.addInput(input)
} catch {
throw MobileScannerError.cameraError(error)
}
captureSession.sessionPreset = AVCaptureSession.Preset.photo
captureSession!.sessionPreset = AVCaptureSession.Preset.photo
// Add video output.
let videoOutput = AVCaptureVideoDataOutput()
... ... @@ -237,17 +237,21 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
// calls captureOutput()
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
captureSession.addOutput(videoOutput)
captureSession!.addOutput(videoOutput)
for connection in videoOutput.connections {
connection.videoOrientation = .portrait
if cameraPosition == .front && connection.isVideoMirroringSupported {
connection.isVideoMirrored = true
}
}
captureSession.commitConfiguration()
captureSession!.commitConfiguration()
backgroundQueue.async {
self.captureSession.startRunning()
guard let captureSession = self.captureSession else {
return
}
captureSession.startRunning()
// After the capture session started, turn on the torch (if requested)
// and reset the zoom scale back to the default.
... ... @@ -299,15 +303,16 @@ public class MobileScanner: NSObject, AVCaptureVideoDataOutputSampleBufferDelega
/// Stop scanning for barcodes
func stop() throws {
if (device == nil) {
if (device == nil || captureSession == nil) {
throw MobileScannerError.alreadyStopped
}
captureSession.stopRunning()
for input in captureSession.inputs {
captureSession.removeInput(input)
captureSession!.stopRunning()
for input in captureSession!.inputs {
captureSession!.removeInput(input)
}
for output in captureSession.outputs {
captureSession.removeOutput(output)
for output in captureSession!.outputs {
captureSession!.removeOutput(output)
}
latestBuffer = nil
... ...
... ... @@ -15,7 +15,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
var textureId: Int64!
// Capture session of the camera
var captureSession: AVCaptureSession!
var captureSession: AVCaptureSession?
// The selected camera
weak var device: AVCaptureDevice!
... ... @@ -239,7 +239,7 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
}
func start(_ call: FlutterMethodCall, _ result: @escaping FlutterResult) {
if (device != nil) {
if (device != nil || captureSession != nil) {
result(FlutterError(code: "MobileScanner",
message: "Called start() while already started!",
details: nil))
... ... @@ -289,17 +289,17 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
}
device.addObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode), options: .new, context: nil)
captureSession.beginConfiguration()
captureSession!.beginConfiguration()
// Add device input
do {
let input = try AVCaptureDeviceInput(device: device)
captureSession.addInput(input)
captureSession!.addInput(input)
} catch {
result(FlutterError(code: "MobileScanner", message: error.localizedDescription, details: nil))
return
}
captureSession.sessionPreset = AVCaptureSession.Preset.photo
captureSession!.sessionPreset = AVCaptureSession.Preset.photo
// Add video output.
let videoOutput = AVCaptureVideoDataOutput()
... ... @@ -307,15 +307,15 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
videoOutput.alwaysDiscardsLateVideoFrames = true
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)
captureSession.addOutput(videoOutput)
captureSession!.addOutput(videoOutput)
for connection in videoOutput.connections {
// connection.videoOrientation = .portrait
if position == .front && connection.isVideoMirroringSupported {
connection.isVideoMirrored = true
}
}
captureSession.commitConfiguration()
captureSession.startRunning()
captureSession!.commitConfiguration()
captureSession!.startRunning()
let dimensions = CMVideoFormatDescriptionGetDimensions(device.activeFormat.formatDescription)
let size = ["width": Double(dimensions.width), "height": Double(dimensions.height)]
let answer: [String : Any?] = ["textureId": textureId, "size": size, "torchable": device.hasTorch]
... ... @@ -374,17 +374,17 @@ public class MobileScannerPlugin: NSObject, FlutterPlugin, FlutterStreamHandler,
// }
func stop(_ result: FlutterResult) {
if (device == nil) {
if (device == nil || captureSession == nil) {
result(nil)
return
}
captureSession.stopRunning()
for input in captureSession.inputs {
captureSession.removeInput(input)
captureSession!.stopRunning()
for input in captureSession!.inputs {
captureSession!.removeInput(input)
}
for output in captureSession.outputs {
captureSession.removeOutput(output)
for output in captureSession!.outputs {
captureSession!.removeOutput(output)
}
device.removeObserver(self, forKeyPath: #keyPath(AVCaptureDevice.torchMode))
registry.unregisterTexture(textureId)
... ...
name: mobile_scanner
description: A universal barcode and QR code scanner for Flutter based on MLKit. Uses CameraX on Android, AVFoundation on iOS and Apple Vision & AVFoundation on macOS.
version: 4.0.0
version: 4.0.1
repository: https://github.com/juliansteenbakker/mobile_scanner
screenshots:
... ...