AVCaptureVideoPreviewLayer (предварительный просмотр камеры) зависает/застревает после перемещения на задний план и обратно
Не могу изобразить это.
Все работает нормально, когда приложение активно, и иногда, когда я перемещаю приложение в фоновый режим (нажатие кнопки "домой" ), а затем возвращается, предварительный просмотр замораживается/застревает.
Im использует 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
}
Ответы
Ответ 1
Для будущих читателей: это правильный процесс настройки камеры внутри вашего приложения.
Прежде всего, спасибо, что люди, вышедшие из этого, не спешили и попробовали помочь мне. Они оба направляют меня в правильном направлении. Хотя Билл ошибался в теории viewDidLoad
, он дал решение Apple Project.
Эта настройка камеры - правильный путь - немного сложнее, чем я думал, следуя документации дал мне отличные результаты. Итак, для кодеров Objective-C:
Проект Objective C cam
Проект Swift cam
Об Андреа ответьте, он сказал несколько отличных указателей, которые вы должны учитывать при создании такого приложения. Проверьте их - они очень актуальны (большинство вещей, которые он сказал в проекте Apple также).
Ответ 2
Руа,
Я думаю, ваша проблема в том, что вы выполняете всю настройку сеанса и т.д. в viewWillAppear. Допустим, что captureSession и previewLayer были как alloc'd, так и корректно работают. Теперь вы помещаете приложение в фоновый режим и возвращаете.
Вы сразу же попытаетесь создать новую captureSession и новый файл предварительного просмотра. Я подозреваю, что старые и новые запутались.
В примере Apple AVCam они выполняют настройку в viewDidLoad. Таким образом, это делается только один раз.
Вы должны перенести все свои материалы настройки в метод, а затем вызвать метод из viewDidLoad.
банкнота
Ответ 3
Просто быстрое обновление. В 2017 году, если кто-то страдает от чрезмерного мышления такой вещи,
Сделайте то же самое, но измените свой
stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
замените его на
stillImageOutput!.outputSettings = [((kCVPixelBufferPixelFormatTypeKey as NSString) as String):NSNumber(value:kCVPixelFormatType_32BGRA)]
он решит проблему. Если нет, вернитесь сюда и запишите:))
Ответ 4
Я думаю, что есть разные вещи, которые могут вызвать проблему:
- Вы должны обернуть всю конфигурацию, которую вы выполняете в блоке кода
-beginConfiguration
и -commitConfiguration
. Каждый раз, когда вы настраиваете что-то в сеансе, для этого потребуется время. Объединение кода конфигурации между этими методами гарантирует, что все изменения будут совершены за один снимок, что уменьшит общее время создания сеанса.
- Приостановка сеанса - это хорошо, когда вы идете на задний план. Зарегистрируйте свой класс в качестве наблюдателя в
UIApplicationDidEnterBackground
и UIApplicationWillEnterForeground
для приостановки и начала сеанса.
- Вы создаете сеанс в
-viewWillAppear
каждый раз, когда этот метод вызывается, вы создаете сеанс, но на самом деле не совсем ясно из вашего кода, если вы избавитесь от него. Вы должны разделить и сбалансировать создание сеанса и уничтожить его. Предоставьте методы -setupSession
и -tearDownSession
. Убедитесь, что настройка вызывается только в том случае, если нет активного сеанса, и убедитесь, что, когда вам больше не нужен сеанс, вы избавитесь от него, вызвав teardownSession
. В SWIFT вы используете переменную @lazy и уничтожаете сеанс в deinit()
или -viewWillDisappear
.
- Было бы очень полезно создавать или использовать очередь SYNC, создавая и разрушая сеанс, является интенсивной задачей, и вы обычно предпочитаете помещать ее в фоновый режим, а также помогает синхронизировать все методы, связанные с сеансом. Создание собственной очереди синхронизации гарантирует, например, синхронизацию между сеансом настройки сеанса и разрывом вызова, один вызывается только тогда, когда другой заканчивается.
Я понял, что это огромный рефактор, но я так уверен, что в будущем у вас будет меньше проблем.
Ответ 5
Swift 4 Solution
Вы должны удалить вход камеры, когда пользователь вводит фон, а затем восстановить его, когда он вернется. Посмотрите на этот код:
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)
}
}
Ответ 6
Я тоже столкнулся с этой проблемой, я исправил мою, добавив ее в мои viewWillAppear и viewWillDissapear. Надеюсь это поможет
var session = AVCaptureSession()
override func viewWillAppear(_ animated: Bool) {
session.startRunning()
}
override func viewWillDisappear(_ animated: Bool) {
session.stopRunning()
}