web-dev-qa-db-ja.com

Swift 3のAVCaptureStillImageOutputとAVCapturePhotoOutputの比較

私は単にビューコントローラーにカメラビューを配置しようとしています。

AVFoundationUIImagePickerControllerDelegateおよびUINavigationControllerDelegateクラスを最初にインポートしました。

ただし、AVCaptureStillImageOutputを使用しようとすると、XcodeはiOS10では非推奨であり、AVCapturePhotoOutputを使用する必要があることを通知します。しかし、stillImageOutput.outputSettingsを呼び出すとすぐに、.outputSettings自体は使用できなくなります。したがって、機能するためにはAVAVCaptureStillImageOutputを使用する必要がありますが、この関数はiOS10で廃止されたため、複数の警告が表示されます。

私は検索して検索しましたが、その周りの解決策は本当に見つかりませんでした。よろしくお願いします。私は学んでいるので、どんな説明でも素晴らしいでしょう!コードは以下のとおりです。

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が廃止されたことは、iOS 10で引き続き使用できることを意味しますが、

  • Appleは、iOS 10がいつまで利用可能であるかについて何の約束もしていません。
  • 新しいハードウェアとソフトウェアの機能がiOS 10以降で追加されると、それらのすべてにアクセスできなくなります。たとえば、canワイドカラー用にAVCaptureStillImageOutputを設定しますが、AVCapturePhotoOutputでワイドカラーを実行する方がはるかに簡単です。 。 RAWキャプチャまたはライブフォトの場合、AVCapturePhotoOutputは町で唯一のゲームです。

サポート終了にもかかわらず問題なく続行できた場合、問題はoutputSettingsが削除されたことではありません— まだ存在しています

ベータ6以降で注意すべき点(ここでは問題ではないことがわかります):明示的なキーと値の型なしでNSDictionaryを使用するAPIは、Swift 3 [AnyHashable: Any]および辞書で使用する可能性のあるFoundationまたはCoreFoundation型は、暗黙的にSwift型にブリッジされていません。(ベータ版6辞書変換に関するその他の 質問の一部) そこから正しい方向に向かうかもしれません。)

ただし、outputSettingsを設定してもコンパイルエラーは発生しません。完全なコードであるか、それをその行の重要な部分に削減するかによって:

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

...私が見る警告は廃止に関するものだけです。

7
rickster

私の完全な実装があります

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