需求:用macOS的攝像頭作為二維碼掃描器掃描二維碼獲取信息
基本流程:
1、創(chuàng)建session(捕捉會話)
let session = captureSession
2具垫、創(chuàng)建設(shè)備
guard let videoDevice = AVCaptureDevice.default(for: .video) else {
print("No video device")
return
}
3鹉勒、創(chuàng)建device input(捕捉設(shè)備輸入)
guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice),
session.canAddInput(videoDeviceInput)
else {
print("Unable to determine video device input")
return
}
4俱笛、預(yù)覽view
self.layer = AVCaptureVideoPreviewLayer()
5、創(chuàng)建capture output(捕捉的輸出)
let videoOutput = videoDataOutput
6赴恨、拍照商玫、錄視頻箕憾、掃描二維碼(從視頻圖像中選取某一幀畫面,轉(zhuǎn)化為圖片拳昌,識別相應(yīng)圖片上的二維碼)
具體代碼:
let cameraPreview = CameraPreview()
fileprivate var captureSession = AVCaptureSession()
fileprivate var videoDataOutput = AVCaptureVideoDataOutput()
struct CameraManageView: View {
@State var startMovieRunning = false
var body: some View {
VStack(alignment: .leading, spacing: nil){
CameraPreviewHolder()
Divider()
Spacer()
HStack(alignment: .center){
Spacer()
Button(action: {
print("二維碼")
cameraPreview.scan()
}, label: {
Text("二維碼")
}).padding()
Spacer()
}
}
}
}
struct CameraPreviewHolder: NSViewRepresentable{
typealias NSViewType = CameraPreview
func makeNSView(context: NSViewRepresentableContext<CameraPreviewHolder>) -> CameraPreview {
let cameraPreview = CameraPreview()
return cameraPreview
}
func updateNSView(_ nsView: CameraPreview, context: NSViewRepresentableContext<CameraPreviewHolder>) {
}
}
final class CameraPreview: NSView {
private var tmp:URL?
init() {
super.init(frame: .zero)
var allowedAccess = false
let blocker = DispatchGroup()
blocker.enter()
AVCaptureDevice.requestAccess(for: .video) { flag in
allowedAccess = flag
blocker.leave()
}
blocker.wait()
guard allowedAccess else {
print("No camera access")
return
}
showCameraViewSeting()
}
func showCameraViewSeting() {
let session = captureSession
session.beginConfiguration()
//分辨率
session.sessionPreset = AVCaptureSession.Preset.high
guard let videoDevice = AVCaptureDevice.default(for: .video) else {
print("No video device")
return
}
guard let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice),
session.canAddInput(videoDeviceInput)
else {
print("Unable to determine video device input")
return
}
session.addInput(videoDeviceInput)
let videoOutput = videoDataOutput
videoOutput.alwaysDiscardsLateVideoFrames = true
if session.canAddOutput(videoOutput) {
session.addOutput(videoOutput)
}
session.commitConfiguration()
captureSession = session
self.wantsLayer = true
self.layer = AVCaptureVideoPreviewLayer()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var videoPreviewLayer: AVCaptureVideoPreviewLayer {
return self.layer as! AVCaptureVideoPreviewLayer
}
override func viewDidMoveToSuperview() { // on iOS .didMoveToSuperview
super.viewDidMoveToSuperview()
if nil != self.superview {
self.videoPreviewLayer.session = captureSession
self.videoPreviewLayer.videoGravity = .resizeAspect
captureSession.startRunning()
} else {
captureSession.stopRunning()
}
}
func scan(){
videoDataOutput.setSampleBufferDelegate(cameraCaptureDelegate, queue: DispatchQueue.main)
}
func removeCameraPreview() {
self.removeFromSuperview()
}
}
class CameraCaptureDelegate: NSObject, AVCaptureVideoDataOutputSampleBufferDelegate{
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
let cgImage:CGImage = imageFromSampleBuffer(sampleBuffer: sampleBuffer)
print("\(cgImage)")
//獲取的圖片經(jīng)過EFQRCode(GitHub上搜這個庫)識別袭异,如果含有二維碼,即可識別出二維碼數(shù)據(jù)
// let result = EFQRCode.recognize(image: cgImage)
// print("didOutput : \(String(describing: result))")
}
func captureOutput(_ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
print("didDrop sampleBuffer")
}
}
func imageFromSampleBuffer(sampleBuffer: CMSampleBuffer) -> CGImage {
let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)!
let ciImage : CIImage = CIImage(cvPixelBuffer: imageBuffer)
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(ciImage, from: ciImage.extent)!
return cgImage
}