ios - AVCaptureVideoPreviewLayer(vista previa de la cámara) se bloquea/bloquea después de pasar al fondo y volver
camera avcapturesession (5)
No puedo resolver esto. Todo funciona bien cuando la aplicación está activa y, a veces, cuando muevo la aplicación al fondo (presionando el botón de inicio) y al regresar, la capa de vista previa se bloquea / bloquea. Estoy usando viewWillAppear y viewDidAppear para la configuración. Así es como configuro todo:
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
}
Creo que hay diferentes cosas que podrían causar el problema:
- Debería envolver toda la configuración que está haciendo en un bloque de código
-beginConfiguration
y-commitConfiguration
. Cada vez que configure algo en la sesión, tomará tiempo hacerlo. Ajustar su código de configuración entre esos métodos garantizará que todos los cambios se confirmen de una sola vez, reduciendo el tiempo total de creación de la sesión. - Pausar la sesión es bueno cuando vas al fondo. Registre su clase como observador en
UIApplicationDidEnterBackground
yUIApplicationWillEnterForeground
para pausar y comenzar de nuevo la sesión. - Crea la sesión en
-viewWillAppear
cada vez que se llama a este método, creas una sesión, pero no queda muy claro en tu código si te deshaces de él. Debes separar y equilibrar la creación de sesión y destruir. Proporcione los métodos-setupSession
y-tearDownSession
. Asegúrese de que se llame a la configuración solo si no hay una sesión activa y de que cuando ya no necesite la sesión, deshágase de ella llamando a la sesiónteardownSession
. En SWIFT no usarás una variable @lazy y destruirás la sesión endeinit()
o-viewWillDisappear
. - Podría ser muy útil crear o utilizar una cola SYNC. La creación y destrucción de una sesión es una tarea intensiva y, por lo general, prefiere ponerla en una cola de fondo, además, ayuda a sincronizar todos los métodos que involucran la sesión. La creación de su propia cola de sincronización garantizará, por ejemplo, la sincronización entre una llamada de sesión de configuración y una llamada de desmontaje, una se llama solo cuando la otra finaliza.
Comprendo que es un gran refactor, pero de esta manera estoy bastante seguro de que experimentará menos problemas en el futuro.
Para futuros lectores: este es el proceso correcto para configurar la cámara dentro de su aplicación.
En primer lugar, gracias por la gente de arriba que se tomaron su tiempo y trataron de ayudarme. Ambos me dirigen en la dirección correcta. Aunque Bill estaba equivocado acerca de la teoría viewDidLoad
, sí dio la solución Apple Project.
Esta configuración de la cámara, de la manera correcta, es un poco más complicada de lo que pensaba; seguir la documentación me dio excelentes resultados. Así que para los codificadores de Objective-C:
Acerca de la respuesta de Andrea, él dijo algunos consejos importantes que debe tener en cuenta cuando cree este tipo de aplicación. Échales un vistazo: son muy relevantes (la mayoría de las cosas que dijo en el proyecto de Apple también).
Roi,
Creo que su problema es que está haciendo toda la configuración de la sesión y eso en el viewWillAppear. Digamos que la captureSession y el previewLayer se asignaron y funcionaron correctamente. Ahora, pones la aplicación en el fondo y la traes de vuelta.
Inmediatamente intentará crear una nueva sesión de captura y un nuevo previewLayer. Sospecho que los viejos y los nuevos se están enredando.
En el ejemplo de Apple AVCam, hacen la configuración en viewDidLoad. De esa manera solo se hace una vez.
Debes mover todas tus cosas de configuración a un método y luego llamar al método desde viewDidLoad.
cuenta
Solo una actualización rápida En 2017, si alguien que sufre demasiado piensa en eso,
Haz lo mismo pero cambia tu
stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
reemplazarlo con
stillImageOutput!.outputSettings = [((kCVPixelBufferPixelFormatTypeKey as NSString) as String):NSNumber(value:kCVPixelFormatType_32BGRA)]
Se solucionará el problema. Si no, entonces vuelve aquí y escribe :))
Solución Swift 4
Debe eliminar la entrada de la cámara cuando el usuario ingresa el fondo, luego restaurarla cuando regrese. Echa un vistazo a este código:
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)
}
}