Refactoring of FrameHandler.
This commit is contained in:
parent
98257dc480
commit
16ca93918d
@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// FrameHandler.swift
|
||||||
|
// macamera
|
||||||
|
//
|
||||||
|
// Created by Maxime on 06/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Original Repository : https://github.com/daved01/LiveCameraSwiftUI/tree/main
|
||||||
|
|
||||||
|
import AVFoundation
|
||||||
|
import CoreImage
|
||||||
|
|
||||||
|
class FrameHandler: NSObject, ObservableObject {
|
||||||
|
|
||||||
|
@Published var frame: CGImage?
|
||||||
|
|
||||||
|
private var permissionGranted: Bool = true
|
||||||
|
private let captureSession = AVCaptureSession()
|
||||||
|
private let context = CIContext()
|
||||||
|
|
||||||
|
override init() {
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
Task.detached(priority: .background) {
|
||||||
|
self.permissionGranted = await self.checkPermission()
|
||||||
|
self.setupCaptureSession()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Convenience Methods
|
||||||
|
|
||||||
|
extension FrameHandler {
|
||||||
|
|
||||||
|
private func checkPermission() async -> Bool {
|
||||||
|
switch AVCaptureDevice.authorizationStatus(for: .video) {
|
||||||
|
case .notDetermined:
|
||||||
|
return await AVCaptureDevice.requestAccess(for: .video)
|
||||||
|
case .authorized:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupCaptureSession() {
|
||||||
|
let videoOutput = AVCaptureVideoDataOutput()
|
||||||
|
|
||||||
|
guard permissionGranted else { return }
|
||||||
|
guard let videoDevice = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: .back) else { return }
|
||||||
|
guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else { return }
|
||||||
|
|
||||||
|
guard captureSession.canAddInput(videoDeviceInput) else { return }
|
||||||
|
captureSession.addInput(videoDeviceInput)
|
||||||
|
|
||||||
|
videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue(label: "sampleBufferQueue"))
|
||||||
|
captureSession.addOutput(videoOutput)
|
||||||
|
|
||||||
|
videoOutput.connection(with: .video)?.videoRotationAngle = 90
|
||||||
|
|
||||||
|
captureSession.startRunning()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - AVCaptureVideoDataOutputSampleBufferDelegate
|
||||||
|
|
||||||
|
extension FrameHandler: AVCaptureVideoDataOutputSampleBufferDelegate {
|
||||||
|
|
||||||
|
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
||||||
|
guard let cgImage = imageFromSampleBuffer(sampleBuffer: sampleBuffer) else { return }
|
||||||
|
|
||||||
|
// All UI updates should be/ must be performed on the main queue.
|
||||||
|
DispatchQueue.main.async { [unowned self] in
|
||||||
|
self.frame = cgImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> CGImage? {
|
||||||
|
guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return nil }
|
||||||
|
let ciImage = CIImage(cvPixelBuffer: imageBuffer)
|
||||||
|
guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { return nil }
|
||||||
|
return cgImage
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user