0

我正在尝试使用 AVCapturePhotoOutput 从连接的 iPad 截取屏幕截图,但是当 capturePhoto 调用我的委托didFinishingProcessingPhoto方法时,它会给出未知错误。我想我遵循了 AVFoundation 文档中关于如何捕获照片的说明,但似乎没有一个描述屏幕捕获,而且大部分都集中在 iOS 上。任何想法如何避免这个错误(甚至它可能意味着什么?)

下面的相关代码和输出。

//
//  AVCapture.swift
//  presenterMode
//
//  Created by Ben Jones on 1/8/22.
//

import Foundation
import AVFoundation
import CoreMediaIO
import Combine

class AVDeviceManager : NSObject, ObservableObject {
    
    @Published var avWrappers : [AVWrapper] = []
    private var delegates : [DevicePhotoDelegate] = []
    
    private let connectionPublisher = NotificationCenter.default
        .publisher(for: NSNotification.Name.AVCaptureDeviceWasConnected)
    private var subscriptionHandle : AnyCancellable? = nil
    //let disconnectionPublisher = NotificationCenter.default
    //        .publisher(for: NSNotification.Name.AVCaptureDeviceWasDisconnected)
    
    override init(){
        super.init()
        //without this ipads won't show up as capture dvices
        //From https://stackoverflow.com/questions/48646470/ios-device-not-listed-by-avcapturedevice-devices-unless-quicktime-is-opened
        var prop = CMIOObjectPropertyAddress(
            mSelector: CMIOObjectPropertySelector(kCMIOHardwarePropertyAllowScreenCaptureDevices),
            mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal),
            mElement: CMIOObjectPropertyElement(kCMIOObjectPropertyElementMaster))
        
        var allow : UInt32 = 1
        let dataSize : UInt32 = 4
        let zero : UInt32 = 0
        CMIOObjectSetPropertyData(CMIOObjectID(kCMIOObjectSystemObject), &prop, zero, nil, dataSize, &allow)
        
        getCaptureDevices()
        
        subscriptionHandle = connectionPublisher.sink { (message) in
            print("got a message from the connection publisher")
            let device : AVCaptureDevice = message.object as! AVCaptureDevice;
            print(device.deviceType, " localized name: ", device.localizedName, " model id", device.modelID)
            var session = AVCaptureSession();
            
            let photoOutput = AVCapturePhotoOutput()
            
            session.beginConfiguration()
            
            guard session.canAddOutput(photoOutput) else { return }
            session.sessionPreset = .photo
            session.addOutput(photoOutput)
            print("output added to session")
            do {
                try session.addInput(AVCaptureDeviceInput(device: device));
                print("input added to session")
                session.commitConfiguration();
                session.startRunning();
                print("session running")
                
                let photoSettings = AVCapturePhotoSettings()
                
                
                print("about to try to capture a photo with",  device.localizedName)
                
                let del = DevicePhotoDelegate(dev: device, man: self)
                self.delegates.append(del)
                photoOutput.capturePhoto(with: photoSettings, delegate: del)
                
            } catch {
                print("couldn't add capture device as input")
            }
        }
    }
    
   
    
    func getCaptureDevices() -> Void {
    //not relevant for the ipad capture since the ipad doesn't show up in this list at startup
        AVCaptureDevice.requestAccess(for: .video) { granted in
            if granted {
                let discoverySession = AVCaptureDevice.DiscoverySession(deviceTypes:
                                                                            [.externalUnknown, .builtInWideAngleCamera], mediaType: .video, position: .unspecified)
                self.avWrappers = discoverySession.devices.map({dev -> AVWrapper in
                    return AVWrapper(dev: dev, im: GlobalViewModel.staticImage)
                })
                print(self.avWrappers);
            }
        }
    }
}

struct AVWrapper : Identifiable {
    
    
    let device: AVCaptureDevice
    let imagePreview :CGImage
    
    let id: ObjectIdentifier
    init(dev: AVCaptureDevice, im : CGImage){
        device = dev
        imagePreview = im
        id = ObjectIdentifier(device)
    }
}

class DevicePhotoDelegate : NSObject, AVCapturePhotoCaptureDelegate {
    let device : AVCaptureDevice
    let manager : AVDeviceManager
    
    init(dev : AVCaptureDevice, man : AVDeviceManager){
        device = dev
        manager = man
    }
    
    @objc(captureOutput:didFinishProcessingPhoto:error:) func photoOutput(_ output: AVCapturePhotoOutput,
                     didFinishProcessingPhoto photo: AVCapturePhoto,
                     error: Error?){
        print("got the ipad photo!")
        if (error != nil) {
            print("Error: ", error)
        }
        manager.avWrappers.append(AVWrapper(dev: device,
                                            im: photo.cgImageRepresentation()!))
        
    }
    
    func photoOutput(_: AVCapturePhotoOutput, willBeginCaptureFor: AVCaptureResolvedPhotoSettings){
        print("will begin capture")
    }
    
    func photoOutput(_: AVCapturePhotoOutput, willCapturePhotoFor: AVCaptureResolvedPhotoSettings){
        print("will capture photo")
    }
    func photoOutput(_: AVCapturePhotoOutput, didFinishCaptureFor: AVCaptureResolvedPhotoSettings, error: Error?){
        print("capture complete")
        if (error != nil) {
            print("Error: ", error)
        }
        
    }
    
    
}

输出:

got a message from the connection publisher
AVCaptureDeviceType(_rawValue: AVCaptureDeviceTypeExternalUnknown)  localized name:  Ben’s iPad  model id iOS Device
output added to session
input added to session
2022-01-08 20:26:51.990119-0700 presenterMode[71468:6611851] [] CMIOHardware.cpp:379:CMIOObjectGetPropertyData Error: 2003332927, failed
2022-01-08 20:26:51.990198-0700 presenterMode[71468:6611851] [] CMIO_DALA_Object.cpp:518:GetPropertyData Error: 2003332927, got an error getting the property data mObjectID 39
2022-01-08 20:26:51.994027-0700 presenterMode[71468:6611851] [] CMIOHardware.cpp:420:CMIOObjectSetPropertyData property isn't settable pft  glob
2022-01-08 20:26:51.994117-0700 presenterMode[71468:6611851] [] CMIOHardware.cpp:450:CMIOObjectSetPropertyData Error: 1852797029, failed
2022-01-08 20:26:51.995318-0700 presenterMode[71468:6611851] [] CMIOHardware.cpp:379:CMIOObjectGetPropertyData Error: 2003332927, failed
2022-01-08 20:26:51.995525-0700 presenterMode[71468:6611851] [] CMIOHardware.cpp:379:CMIOObjectGetPropertyData Error: 2003332927, failed
2022-01-08 20:26:51.995552-0700 presenterMode[71468:6611851] [] CMIO_DALA_Object.cpp:518:GetPropertyData Error: 2003332927, got an error getting the property data mObjectID 39
session running
about to try to capture a photo with Ben’s iPad
will begin capture
will capture photo
got the ipad photo!
Error:  Optional(Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedDescription=The operation could not be completed, NSLocalizedFailureReason=An unknown error occurred (-11800)})
presenterMode/AVCapture.swift:123: Fatal error: Unexpectedly found nil while unwrapping an Optional value
2022-01-08 20:26:55.542549-0700 presenterMode[71468:6611851] presenterMode/AVCapture.swift:123: Fatal error: Unexpectedly found nil while unwrapping an Optional value
4

0 回答 0