これを理解することはできません。アプリがアクティブなときはすべて正常に機能します。時々アプリをバックグラウンドに移動したとき(ホームボタンを押したとき)に戻ると、プレビューレイヤーがフリーズ/スタックします。セットアップにviewWillAppearとviewDidAppearを使用しています。これは私がすべてを設定する方法です:
var backCamera = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)
var global_device : AVCaptureDevice!
var captureSession: AVCaptureSession?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
captureSession = AVCaptureSession()
captureSession!.sessionPreset = AVCaptureSessionPresetPhoto
CorrectPosition = AVCaptureDevicePosition.Back
for device in backCamera {
if device.position == AVCaptureDevicePosition.Back {
global_device = device as! AVCaptureDevice
CorrectPosition = AVCaptureDevicePosition.Back
break
}
}
configureCamera()
var error: NSError?
var input = AVCaptureDeviceInput(device: global_device, error: &error)
if error == nil && captureSession!.canAddInput(input) {
captureSession!.addInput(input)
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
if captureSession!.canAddOutput(stillImageOutput) {
captureSession!.addOutput(stillImageOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
var bounds:CGRect = camera_Preview.layer.bounds
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
previewLayer?.bounds = bounds
previewLayer?.position = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds))
camera_Preview.layer.addSublayer(previewLayer)
self.view.bringSubviewToFront(camera_Preview)
self.view.bringSubviewToFront(nan_view)
captureSession!.startRunning()
}
}
ViewDidAppear:
var previewLayer: AVCaptureVideoPreviewLayer?
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
previewLayer!.frame = camera_Preview.bounds
}
将来の読者のために:これは、アプリ内にカメラを設定するための正しいプロセスです。
まず第一に、時間をかけて私を助けてくれた上記の人々に感謝します。彼らは両方とも私を正しい方向に導きます。ビルはviewDidLoad
理論について誤解していましたが、彼は解決策Appleプロジェクトを提供しました。
このカメラのセットアップ(正しい方法)は、私が思っていたよりも少し複雑です。ドキュメントに従うと、優れた結果が得られました。したがって、Objective-Cコーダーの場合:
アンドレアの答えについて、彼はあなたがこの種のアプリを作成するときに考慮すべきいくつかの素晴らしい指針を述べました。それらをチェックしてください-それらは非常に関連性があります(彼がAppleプロジェクト内でも言ったことのほとんど)。
ロイ、
あなたの問題は、viewWillAppearですべてのセッションセットアップなどを行っていることだと思います。 CaptureSessionとpreviewLayerの両方が割り当てられ、正しく機能しているとしましょう。ここで、アプリをバックグラウンドに配置して戻します。
すぐに、新しいcaptureSessionと新しいpreviewLayerを作成しようとします。古いものと新しいものが絡み合っているのではないかと思います。
Apple AVCamの例では、viewDidLoadでセットアップを実行します。これにより、セットアップは1回だけ実行されます。
すべてのセットアップをメソッドに移動してから、viewDidLoadからメソッドを呼び出す必要があります。
ビル
ちょっとした更新2017年に誰かがそのようなことを考えすぎて苦しんでいるなら、
同じことをしますが、
stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
に置き換えます
stillImageOutput!.outputSettings = [((kCVPixelBufferPixelFormatTypeKey as NSString) as String):NSNumber(value:kCVPixelFormatType_32BGRA)]
それは問題を解決します。そうでない場合は、ここに戻って書き留めてください:))
Swift 4ソリューション
ユーザーが背景に入ったときにカメラ入力を削除し、戻ったときに復元する必要があります。このコードを見てください:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
createCameraPreview() //Call the setup of the camera here so that if the user enters the view controller from another view controller, the camera is established.
notificationCenter() //Call the notification center function to determine when the user enters and leaves the background.
}
func notificationCenter() {
NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: .UIApplicationWillResignActive , object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(openedAgain), name: .UIApplicationDidBecomeActive, object: nil)
}
@objc func openedAgain() {
createCameraPreview() // This is your function that contains the setup for your camera.
}
@objc func willResignActive() {
print("Entered background")
let inputs = captureSession!.inputs
for oldInput:AVCaptureInput in inputs {
captureSession?.removeInput(oldInput)
}
}
Swift 4.2:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setupCamera()
//createCameraPreview() //Call the setup of the camera here so that if the user enters the view controller from another view controller, the camera is established.
notificationCenter() //Call the notification center function to determine when the user enters and leaves the background.
}
func notificationCenter() {
NotificationCenter.default.addObserver(self, selector: #selector(willResignActive), name: UIApplication.willResignActiveNotification , object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(openedAgain), name: UIApplication.didBecomeActiveNotification, object: nil)
}
@objc func openedAgain() {
setupCamera() //This is your function that contains the setup for your camera.
}
@objc func willResignActive() {
print("Entered background")
let inputs = captureSession.inputs
for oldInput:AVCaptureInput in inputs {
captureSession.removeInput(oldInput)
}
}
問題を引き起こす可能性のあるさまざまなことがあると思います。
-beginConfiguration
_および_-commitConfiguration
_ブロックのコードでラップする必要があります。セッションで何かをセットアップするたびに、それを行うのに時間がかかります。これらのメソッド間で構成コードをラップすると、すべての変更が1回のショットでコミットされ、セッション全体の作成時間が短縮されます。UIApplicationDidEnterBackground
とUIApplicationWillEnterForeground
に登録して、セッションを一時停止して再開します。-viewWillAppear
_でセッションを作成しますが、セッションを削除すると、コードからは明確になりません。セッションの作成と破棄を分離してバランスを取る必要があります。 _-setupSession
_メソッドと_-tearDownSession
_メソッドを提供します。アクティブなセッションがない場合にのみセットアップが呼び出されることを確認し、セッションが不要になったときにteardownSession
を呼び出してセッションを削除するようにします。 Swiftでは、@ lazy変数を使用し、deinit()
または_-viewWillDisappear
_でセッションを破棄します。それが大きなリファクタリングであることは理解できませんが、このようにして、将来的に問題が少なくなると確信しています。
私もこの問題に直面しました。これをviewWillAppearとviewWillDissapearに追加して修正しました。お役に立てれば
var session = AVCaptureSession()
override func viewWillAppear(_ animated: Bool) {
session.startRunning()
}
override func viewWillDisappear(_ animated: Bool) {
session.stopRunning()
}