【问题标题】:AVFoundation Error CodesAVFoundation 错误代码
【发布时间】:2018-05-02 14:36:20
【问题描述】:

在拍摄 RAW 和 JPEG 照片时,我收到以下两条错误消息。我无法诊断这些:

拍摄照片时出错:Error Domain=AVFoundationError- Domain Code=-11800 "操作无法完成" UserInfo={NSLocalizedFailureReason=发生未知错误 (42686), NSLocalizedDescription:操作无法完成, NSUnderlyingError=0x1c804bfa0 {错误域=NSOSStatusError-域 代码=-12686 "(null)"}}

还有……

拍摄照片时出错:Error Domain=AVFoundationError-Domain Code=-11800 操作无法完成” UserInfo.{NSLocalized-FailureReason=发生未知错误 (-16802), NSLocalizedDescription=操作无法完成, NSUnderlyingEr-ror=0x1c4243f30 {错误域=NSOSStatusError-Domain 代码=-16802 "(null)"}}

这似乎发生在 AVCapturePhotoCaptureDelegate 中的这个函数之后:

optional func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?)  

这些似乎是在重复拍摄照片时随机发生的。

更新

RAW 设置

       func updatePhotoSettings () {
self.photoOutput.setPreparedPhotoSettingsArray([])

let newPhotoSettings = AVCapturePhotoSettings(rawPixelFormatType: OSType(self.photoOutput.availableRawPhotoPixelFormatTypes.first!),
                                                          processedFormat: [AVVideoCodecKey : AVVideoCodecJPEG])
            newPhotoSettings.previewPhotoFormat = [kCVPixelBufferPixelFormatTypeKey as String: self.photoOutput.availablePhotoPixelFormatTypes[0]]
            if #available(iOS 11.0, *) {
                newPhotoSettings.embeddedThumbnailPhotoFormat =  [AVVideoCodecKey: self.photoOutput.availablePhotoCodecTypes[0]]
            }
            newPhotoSettings.isHighResolutionPhotoEnabled = true
            newPhotoSettings.flashMode = self.flashMode
            newPhotoSettings.isAutoStillImageStabilizationEnabled = false
            newPhotoSettings.livePhotoMovieFileURL = nil
            self.photoOutput.photoSettingsForSceneMonitoring = newPhotoSettings

            self.photoOutput.setPreparedPhotoSettingsArray([newPhotoSettings])

}

捕获呼叫:

final func snapImage () {

            let photoCaptureDelegate = PhotoCaptureDelegate(with: self.photoOutput.preparedPhotoSettingsArray.first!,
                                       willCapturePhotoAnimation: {
                //Shutter animation
                DispatchQueue.main.async { [unowned self] in
                    self.previewView.videoPreviewLayer.opacity = 0
                    UIView.animate(withDuration: 0.1, animations: {
                        self.previewView.videoPreviewLayer.opacity = 1
                    })
                }

            }, didCapturePhoto: {

                //Photo Saved animation

            }, completed:  { [unowned self] photoCaptureDelegate in
                self.inProgressPhotoCaptureDelegates[photoCaptureDelegate.requestedPhotoSettings.uniqueID] = nil
            })


            self.inProgressPhotoCaptureDelegates[photoCaptureDelegate.requestedPhotoSettings.uniqueID] = photoCaptureDelegate

            self.photoOutput.capturePhoto(with: self.photoOutput.preparedPhotoSettingsArray.first!, delegate: photoCaptureDelegate)

            DispatchQueue.main.async {
                //Goes to update photo settings for next shot
                self.updatePhotoSettings()
            }
        }
    }

拍照代表

import AVFoundation
import Photos
import MobileCoreServices

class PhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {


         private(set) var requestedPhotoSettings     : AVCapturePhotoSettings

         private let willCapturePhotoAnimation       : () -> ()
         private let didCapturePhoto                 : () -> ()
         private let completed                       : (PhotoCaptureDelegate) -> ()

         private var jpegPhotoData                   : Data?

         private var dngPhotoData                    : Data?


    // MARK: - Initialization
    init(with requestedPhotoSettings: AVCapturePhotoSettings,
        willCapturePhotoAnimation: @escaping () -> (),
        didCapturePhoto: @escaping () -> (),
        completed: @escaping (PhotoCaptureDelegate) -> ())
    {
        self.requestedPhotoSettings = requestedPhotoSettings
        self.willCapturePhotoAnimation = willCapturePhotoAnimation
        self.didCapturePhoto = didCapturePhoto
        self.completed = completed
    }


    private final func didFinish() {
        self.completed(self)
    }

    // MARK: - Will Capture
    final func capture(_ captureOutput: AVCapturePhotoOutput, willCapturePhotoForResolvedSettings resolvedSettings: AVCaptureResolvedPhotoSettings) {
        willCapturePhotoAnimation()
    }

    final func capture(_ output: AVCapturePhotoOutput, willBeginCaptureForResolvedSettings resolvedSettings: AVCaptureResolvedPhotoSettings) {

    }


    // MARK: - iOS 11 Did Finish Photo
    @available(iOS 11.0, *)
    final func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {

            if let error = error {

                PhotoCaptureDelegate.showError(sentMessage: "Error processing photo: \(error)")
                self.didCapturePhoto()

            } else {

                if photo.isRawPhoto {
                    self.dngPhotoData = photo.fileDataRepresentation()
                    return

                } else {
                    if self.jpegPhotoData == nil {
                        self.jpegPhotoData = photo.fileDataRepresentation()
                        self.didCapturePhoto()
                        return
                    }
                }
            }
    }


    // MARK: - Did Finish Capture
    final func capture(_ captureOutput: AVCapturePhotoOutput, didFinishCaptureForResolvedSettings resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) {

        if let error = error {
            PhotoCaptureDelegate.showError(sentMessage: "Error capturing photo: \(error)")
            didFinish()
            return


        if PHPhotoLibrary.authorizationStatus() == .authorized {

                var temporaryDNGFileURL : URL? = nil
                self.dngPhotoData != nil {
                        temporaryDNGFileURL = URL(fileURLWithPath: NSTemporaryDirectory().appending("\(resolvedSettings.uniqueID).dng"))
                        do {
                            try self.dngPhotoData!.write(to: temporaryDNGFileURL!, options: [.atomic])
                        } catch let error as NSError {
                            PhotoCaptureDelegate.showError(sentMessage: "Could not write DNG Data: \(error)")
                            return
                        }
                }

                PHPhotoLibrary.shared().performChanges({
                    let creationRequest = PHAssetCreationRequest.forAsset()
                    if (self.jpegPhotoData != nil) {

                        creationRequest.addResource(with: .photo, data: self.jpegPhotoData!, options: nil)

                        if let temporaryDNGFileURL = temporaryDNGFileURL {

                            let companionDNGResourceOptions = PHAssetResourceCreationOptions()
                            companionDNGResourceOptions.shouldMoveFile = true
                            creationRequest.addResource(with: .alternatePhoto, fileURL: temporaryDNGFileURL, options: companionDNGResourceOptions)

                        }
                    }
                }, completionHandler: { [unowned self] success, error in

                    if let error = error {
                        PhotoCaptureDelegate.showError(sentMessage: "Error occurered while saving photo to photo library: \(error)")
                    }
                    if (temporaryDNGFileURL != nil) {
                        if FileManager.default.fileExists(atPath: temporaryDNGFileURL!.path) {
                            do {
                                try FileManager.default.removeItem(at: temporaryDNGFileURL!)
                            } catch let error as NSError {
                                PhotoCaptureDelegate.showError(sentMessage: "Could not remove DNG File: \(error)")
                            }
                        }
                    }

                })


            }

        else {
            PhotoCaptureDelegate.showError(sentMessage: "Not authorized to save photo")
            self.didFinish()
            return
        }

}



    private static func showError (sentMessage: String) {
        let alertController = UIAlertController(title: nil, message: sentMessage, preferredStyle: UIAlertControllerStyle.alert)
        let cancelAction = UIAlertAction(title: NSLocalizedString("OK", comment: "Alert button title."), style: UIAlertActionStyle.cancel, handler: nil)
        alertController.addAction(cancelAction)
        let appDelegate  = UIApplication.shared.delegate as! AppDelegate
        appDelegate.window!.rootViewController!.present(alertController, animated: true, completion: nil)
    }

}

注意事项

  1. Apple 的 AVCam 示例代码紧随其后。
  2. 仅在成功拍摄一张照片后才会发生此崩溃。生成的 RAW 文件非常好。

【问题讨论】:

  • 你能展示设置捕获会话并拍照的代码吗?
  • 更新了原帖。

标签: ios swift error-handling avfoundation avcapturephotosettings


【解决方案1】:

更新

您在图像捕获完成之前调用updatePhotoSettings(),这会导致错误。尝试从完成处理程序中或在拍摄图像之前执行此操作。

附言真的,AVFoundation 应该让这个错误更难发生,或者至少更清楚地表明这是行不通的。

先前的错误猜测

您没有展示如何配置AVCaptureSession,这很重要,但是

  1. 如果您启用AVCapturePhotoSettingsisHighResolutionPhotoEnabled,您还需要启用isHighResolutionCaptureEnabled(可能是highResolutionCaptureEnabled - 您使用的是什么版本的swift?):

    self.photoOutput.isHighResolutionCaptureEnabled = true
    
  2. 您的 PhotoCaptureDelegate 看起来超出范围,这无济于事。将其分配给成员变量以延长其寿命。

  3. 在您的 AVCaptureSession 上设置 .photo 预设

【讨论】:

  • 1. 我在设置会话时启用了 self.photoOutput.isHighResolutionCaptureEnabled = true。 2.这似乎很有趣。如果这样做,这将违反 Apple 的示例代码。但会尝试。所以只是对它有一个弱引用? 3. 我确实有 .photo 用于 AVCaptureSession 的预设。
  • 那是什么示例代码?我认为您需要显示更多代码,例如会话配置以及重复捕获的方式 - 从您显示的内容来看,两次调用 snapImage() 会导致异常消息“[AVCapturePhotoOutput capturePhotoWithSettings:delegate:] Settings may not被重复使用”。
  • 对于重复捕获,重复调用 snapImage()。在 snapImage() 结束时,调用 updatePhotoSettings (),它将为下一次拍摄准备照片设置。我消除了这个 self.photoOutput.setPreparedPhotoSettingsArray() 是一个问题,因为如果我把它拿出来并在捕捉之前在 snapImage() 中进行设置,同样的问题仍然存在。
  • 问题可能是您在图像捕获完成之前调用updatePhotoSettings() 吗?在忙时重新配置AVCapturePhotoOutput 听起来会导致意外错误。
  • 完成 - 我现在还看到您的代表的范围已在 inProgressPhotoCaptureDelegates 中扩展。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多