web-dev-qa-db-fra.com

AVCaptureStillImageOutput vs AVCapturePhotoOutput dans Swift 3

J'essaie simplement de mettre une vue de caméra dans mon contrôleur de vue.

J'ai importé AVFoundation en haut, ainsi que les classes UIImagePickerControllerDelegate et UINavigationControllerDelegate.

Cependant, chaque fois que j'essaie d'utiliser AVCaptureStillImageOutput, Xcode me dit qu'il est obsolète dans iOS10 et que je devrais utiliser AVCapturePhotoOutput. C'est très bien, cependant, dès que je veux appeler stillImageOutput.outputSettings, .outputSettings lui-même n'est pas disponible. Ainsi, je dois utiliser AVAVCaptureStillImageOutput pour que cela fonctionne, mais j'ai plusieurs avertissements car cette fonction est obsolète dans iOS10.

J'ai cherché et cherché, mais je n'ai pas vraiment trouvé la solution. J'apprécierais vraiment votre aide. J'apprends donc toute explication serait formidable! Le code est ci-dessous.

import UIKit
import AVFoundation

class CameraView: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {

    var captureSession : AVCaptureSession?
    var stillImageOutput : AVCaptureStillImageOutput?
    var previewLayer : AVCaptureVideoPreviewLayer?

    @IBOutlet var cameraView: UIView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        captureSession = AVCaptureSession()
        captureSession?.sessionPreset = AVCaptureSessionPreset1920x1080

        var backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
        var error : NSError?

        do {
            var input = try! AVCaptureDeviceInput (device: backCamera)
            if (error == nil && captureSession?.canAddInput(input) != nil) {

                captureSession?.addInput(input)

                stillImageOutput = AVCaptureStillImageOutput()
                stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]

                if (captureSession?.canAddOutput(stillImageOutput) != nil) {
                    captureSession?.addOutput(stillImageOutput)

                    previewLayer = AVCaptureVideoPreviewLayer (session: captureSession)
                    previewLayer?.videoGravity = AVLayerVideoGravityResizeAspect
                    previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait
                    cameraView.layer.addSublayer(previewLayer!)
                    captureSession?.startRunning()
                }
            }
        } catch {

        }
    }
}
16
Andriyas Redel

AVCaptureStillImageOutput étant obsolète, vous pouvez continuer à l'utiliser dans iOS 10, mais:

  • Apple ne fait aucune promesse quant à la durée de disponibilité d'iOS 10.
  • à mesure que de nouvelles fonctionnalités matérielles et logicielles sont ajoutées dans iOS 10 et au-delà, vous n'aurez pas accès à toutes. Par exemple, vous pouvez configurer AVCaptureStillImageOutput pour une couleur large mais il est beaucoup plus facile de faire une couleur large avec AVCapturePhotoOutput . Et pour la capture RAW ou Live Photos, AVCapturePhotoOutput est le seul jeu en ville.

Si vous êtes content de continuer malgré la dépréciation, votre problème n'est pas que outputSettings soit supprimé - il est toujours là .

Quelque chose à savoir pour la version bêta 6 et au-delà (bien que cela ne soit pas un problème ici): les API qui utilisent NSDictionary sans types de clé et de valeur explicites entrent dans Swift 3 comme [AnyHashable: Any] et les types Foundation ou CoreFoundation que vous pourriez utiliser dans un dictionnaire ne sont plus implicitement liés à Swift types. (Certaines des autres questions sur les conversions de dictionnaire bêta 6 pourrait vous indiquer la bonne direction.)

Cependant, je ne reçois aucune erreur de compilation pour la configuration de outputSettings. Que ce soit dans votre code complet ou en le réduisant aux éléments essentiels de cette ligne:

var stillImageOutput : AVCaptureStillImageOutput?
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]

... les seuls avertissements que je vois concernent la dépréciation.

7
rickster

Il y a ma mise en œuvre complète

import UIKit
import AVFoundation

class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {

    var captureSesssion : AVCaptureSession!
    var cameraOutput : AVCapturePhotoOutput!
    var previewLayer : AVCaptureVideoPreviewLayer!

    @IBOutlet weak var capturedImage: UIImageView!
    @IBOutlet weak var previewView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        captureSesssion = AVCaptureSession()
        captureSesssion.sessionPreset = AVCaptureSessionPresetPhoto
        cameraOutput = AVCapturePhotoOutput()

        let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)

        if let input = try? AVCaptureDeviceInput(device: device) {
            if captureSesssion.canAddInput(input) {
                captureSesssion.addInput(input)
                if captureSesssion.canAddOutput(cameraOutput) {
                    captureSesssion.addOutput(cameraOutput)
                    previewLayer = AVCaptureVideoPreviewLayer(session: captureSesssion)
                    previewLayer.frame = previewView.bounds
                    previewView.layer.addSublayer(previewLayer)
                    captureSesssion.startRunning()
                }
            } else {
                print("issue here : captureSesssion.canAddInput")
            }
        } else {
            print("some problem here")
        }
    }

    // Take picture button
    @IBAction func didPressTakePhoto(_ sender: UIButton) {
        let settings = AVCapturePhotoSettings()
        let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first!
        let previewFormat = [
            kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
            kCVPixelBufferWidthKey as String: 160,
            kCVPixelBufferHeightKey as String: 160
        ]
        settings.previewPhotoFormat = previewFormat
        cameraOutput.capturePhoto(with: settings, delegate: self)
    }

    // callBack from take picture
    func capture(_ captureOutput: AVCapturePhotoOutput,  didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?,  previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings:  AVCaptureResolvedPhotoSettings, bracketSettings:   AVCaptureBracketedStillImageSettings?, error: Error?) {

        if let error = error {
            print("error occure : \(error.localizedDescription)")
        }

        if  let sampleBuffer = photoSampleBuffer,
            let previewBuffer = previewPhotoSampleBuffer,
            let dataImage =  AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer:  sampleBuffer, previewPhotoSampleBuffer: previewBuffer) {
            print(UIImage(data: dataImage)?.size as Any)

            let dataProvider = CGDataProvider(data: dataImage as CFData)
            let cgImageRef: CGImage! = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
            let image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right)

            self.capturedImage.image = image
        } else {
            print("some error here")
        }
    }

    // This method you can use somewhere you need to know camera permission   state
    func askPermission() {
        print("here")

        let cameraPermissionStatus =  AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)

        switch cameraPermissionStatus {
        case .authorized:
            print("Already Authorized")

        case .denied:
            print("denied")

            let alert = UIAlertController(title: "Sorry :(" , message: "But could you please grant permission for camera within device settings",  preferredStyle: .alert)
            let action = UIAlertAction(title: "Ok", style: .cancel,  handler: nil)
            alert.addAction(action)
            present(alert, animated: true, completion: nil)

        case .restricted:
            print("restricted")

        default:
            AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo) {
                [weak self]
                (granted :Bool) -> Void in

                if granted == true {
                    // User granted
                    print("User granted")
                    DispatchQueue.main.async() {
                        // Do smth that you need in main thread   
                    } 
                } else {
                    // User Rejected
                    print("User Rejected")

                    DispatchQueue.main.async() {
                        let alert = UIAlertController(title: "WHY?" , message: "Camera it is the main feature of our application", preferredStyle: .alert)
                        let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
                        alert.addAction(action)
                        self?.present(alert, animated: true, completion: nil)  
                    }
                }
            }
        }
    }
}
13