Skip to content

Commit 824b51e

Browse files
author
Žymantas Paulas
committed
Faster Image Capture
Faster Image Capture
1 parent 5e88643 commit 824b51e

File tree

1 file changed

+26
-46
lines changed

1 file changed

+26
-46
lines changed

Sources/CodeScanner/ScannerViewController.swift

Lines changed: 26 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,13 @@ import UIKit
1414
extension CodeScannerView {
1515

1616
public final class ScannerViewController: UIViewController, UINavigationControllerDelegate {
17-
private let photoOutput = AVCapturePhotoOutput()
18-
private var isCapturing = false
1917
private var handler: ((UIImage?) -> Void)?
2018
var parentView: CodeScannerView!
2119
var codesFound = Set<String>()
2220
var didFinishScanning = false
2321
var lastTime = Date(timeIntervalSince1970: 0)
2422
private let showViewfinder: Bool
25-
23+
private var latestSampleBuffer: CMSampleBuffer?
2624
let fallbackVideoCaptureDevice = AVCaptureDevice.default(for: .video)
2725

2826
private var isGalleryShowing: Bool = false {
@@ -265,12 +263,15 @@ extension CodeScannerView {
265263
return
266264
}
267265
let metadataOutput = AVCaptureMetadataOutput()
266+
let videoOutput = AVCaptureVideoDataOutput()
268267

269268
if captureSession!.canAddOutput(metadataOutput) {
270269
captureSession!.addOutput(metadataOutput)
271-
captureSession!.addOutput(photoOutput)
270+
captureSession!.addOutput(videoOutput)
272271
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
273272
metadataOutput.metadataObjectTypes = parentView.codeTypes
273+
274+
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "com.hackingwithswift.codeScanner.videoQueue"))
274275
} else {
275276
didFail(reason: .badOutput)
276277
return
@@ -433,6 +434,25 @@ extension CodeScannerView {
433434
}
434435
}
435436

437+
// MARK: - AVCaptureVideoDataOutputSampleBufferDelegate
438+
@available(macCatalyst 14.0, *)
439+
extension CodeScannerView.ScannerViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
440+
public func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
441+
latestSampleBuffer = sampleBuffer
442+
}
443+
444+
func processFrame(_ sampleBuffer: CMSampleBuffer) {
445+
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
446+
447+
let ciImage = CIImage(cvPixelBuffer: imageBuffer)
448+
449+
let context = CIContext()
450+
if let cgImage = context.createCGImage(ciImage, from: ciImage.extent) {
451+
handler?(UIImage(cgImage: cgImage))
452+
}
453+
}
454+
}
455+
436456
// MARK: - AVCaptureMetadataOutputObjectsDelegate
437457

438458
@available(macCatalyst 14.0, *)
@@ -443,7 +463,6 @@ extension CodeScannerView.ScannerViewController: AVCaptureMetadataOutputObjectsD
443463
guard let metadataObject = metadataObjects.first,
444464
!parentView.isPaused,
445465
!didFinishScanning,
446-
!isCapturing,
447466
let readableObject = metadataObject as? AVMetadataMachineReadableCodeObject,
448467
let stringValue = readableObject.stringValue else {
449468

@@ -484,9 +503,8 @@ extension CodeScannerView.ScannerViewController: AVCaptureMetadataOutputObjectsD
484503
}
485504
}
486505

487-
if parentView.requiresPhotoOutput {
488-
isCapturing = true
489-
photoOutput.capturePhoto(with: AVCapturePhotoSettings(), delegate: self)
506+
if parentView.requiresPhotoOutput, let latestSampleBuffer {
507+
self.processFrame(latestSampleBuffer)
490508
} else {
491509
handler?(nil)
492510
}
@@ -551,44 +569,6 @@ extension CodeScannerView.ScannerViewController: UIAdaptivePresentationControlle
551569
}
552570
}
553571

554-
// MARK: - AVCapturePhotoCaptureDelegate
555-
556-
@available(macCatalyst 14.0, *)
557-
extension CodeScannerView.ScannerViewController: AVCapturePhotoCaptureDelegate {
558-
559-
public func photoOutput(
560-
_ output: AVCapturePhotoOutput,
561-
didFinishProcessingPhoto photo: AVCapturePhoto,
562-
error: Error?
563-
) {
564-
isCapturing = false
565-
guard let imageData = photo.fileDataRepresentation() else {
566-
print("Error while generating image from photo capture data.");
567-
return
568-
}
569-
guard let qrImage = UIImage(data: imageData) else {
570-
print("Unable to generate UIImage from image data.");
571-
return
572-
}
573-
handler?(qrImage)
574-
}
575-
576-
public func photoOutput(
577-
_ output: AVCapturePhotoOutput,
578-
willCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings
579-
) {
580-
AudioServicesDisposeSystemSoundID(1108)
581-
}
582-
583-
public func photoOutput(
584-
_ output: AVCapturePhotoOutput,
585-
didCapturePhotoFor resolvedSettings: AVCaptureResolvedPhotoSettings
586-
) {
587-
AudioServicesDisposeSystemSoundID(1108)
588-
}
589-
590-
}
591-
592572
// MARK: - AVCaptureDevice
593573

594574
@available(macCatalyst 14.0, *)

0 commit comments

Comments
 (0)