Коды ошибок AVFoundation - PullRequest
       16

Коды ошибок AVFoundation

0 голосов
/ 02 мая 2018

Я получаю следующие два сообщения об ошибке при съемке RAW, а также фотографий в формате JPEG. У меня нет возможности диагностировать это:

Ошибка при захвате фотографии: Ошибка домена = AVFoundationError- Домен Код = -11800 «Операция не может быть завершена» Userlnfo = {NSLocalizedFailur-eReason = Произошла неизвестная ошибка (42686), NSLocalizedDescription: Операция не может быть завершена, NSUnderlyingError = 0x1c804bfa0 {Ошибка домена = NSOSStatusError-Domain Код = -12686 "(ноль)"}}

тоже ...

Ошибка при захвате фотографии: Ошибка домена = AVFoundationError-Domain Код = -11800 Операция не может быть завершена " UserInfo. {NSLocalized-FailureReason = Произошла неизвестная ошибка (-16802), NSLocalizedDescription = Операция не может быть завершена, NSUnderlyingEr-ror = 0x1c4243f30 {Ошибка домена = NSOSStatusError-Domain Код = -16802 "(ноль)"}}

Это, кажется, происходит сразу после этой функции в AVCapturePhotoCaptureDelegate :

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

Кажется, что это происходит случайно при повторном захвате фотографий.

UPDATE

RAW Setup

       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 файл отлично подходит.

1 Ответ

0 голосов
/ 06 мая 2018

UPDATE

Вы звоните updatePhotoSettings() до завершения захвата изображения, что вызывает ошибки. Попробуйте сделать это из обработчика завершения или перед тем, как сделать снимок.

p.s. На самом деле AVFoundation должен был сделать эту ошибку труднее сделать или, по крайней мере, прояснить, что это не сработает.

предыдущий, неверные догадки

Вы не показываете, как настроить AVCaptureSession, что важно, но

  1. если вы включите AVCapturePhotoSettings isHighResolutionPhotoEnabled, вам также необходимо включить isHighResolutionCaptureEnabled (может быть highResolutionCaptureEnabled для вас - какую версию swift вы используете?):

    self.photoOutput.isHighResolutionCaptureEnabled = true
    
  2. ваш PhotoCaptureDelegate выглядит так, как будто он выходит из области видимости, что не поможет. Присвойте его переменной-члену, чтобы продлить его жизнь.

  3. установить предустановку .photo на AVCaptureSession

...