移动到背景和返回后,AVCaptureVideoPreviewLayer(相机预览)冻结/卡住

时间:2015-05-30 00:12:19

标签: ios camera preview avcapturesession avcapturedevice

无法想出这一个。 当应用程序处于活动状态时,一切正常,而当我将应用程序移动到后台(按下主页按钮)时,有时,而不是返回,预览层会冻结/卡住。 我使用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
    }

6 个答案:

答案 0 :(得分:3)

对于未来的读者:这是在您的应用中设置相机的正确过程。

首先,感谢上面那些花时间尝试帮助我的人们。他们都指引我走向正确的方向。虽然比尔错误地认为viewDidLoad理论,但他确实给出了Apple Project的解决方案。

这个设置相机 - 正确的方法 - 比我想象的复杂一点,按照文档给了我很好的结果。所以对于Objective-C编码器:

Objective C cam project

Swift cam project

关于Andrea的答案,他确实说过在创建这种应用程序时应该考虑的一些很好的指示。检查它们 - 它们是高度相关的(他在Apple项目中也说过的大部分内容)。

答案 1 :(得分:3)

快速更新2017年如果有人遭遇过度思考这样的事情,

做同样的事情,但改变你的

stillImageOutput!.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]

替换为

stillImageOutput!.outputSettings = [((kCVPixelBufferPixelFormatTypeKey as NSString) as String):NSNumber(value:kCVPixelFormatType_32BGRA)]

它将解决问题。如果没有,那么回到这里写下来:))

答案 2 :(得分:2)

投资回报率,

我认为您的问题是您正在进行所有会话设置,例如viewWillAppear。让我们说captureSession和previewLayer都是alloc并且正常工作。现在,您将应用程序放入后台并返回。

您将立即尝试创建一个新的captureSession和一个新的previewLayer。我怀疑旧的和新的都在纠结。

在Apple AVCam示例中,他们在viewDidLoad中进行设置。这样它只做一次。

您应该将所有设置内容移动到方法,然后从viewDidLoad调用该方法。

纸币

答案 3 :(得分:1)

我认为有不同的事情可能导致问题:

  1. 您应该在-beginConfiguration-commitConfiguration代码块中包装您正在执行的所有配置。每次在会话中设置某些内容时,都需要时间。在这些方法之间包装配置代码将保证一次性提交所有更改,从而减少整个会话创建时间
  2. 当你去后台时暂停会话是一件好事。以UIApplicationDidEnterBackgroundUIApplicationWillEnterForeground的观察者身份注册您的课程,暂停并重新开始会话。
  3. 每次调用此方法时,您都会在-viewWillAppear中创建会话,但是如果您将其删除,则无法从代码中清楚地看到该会话。您应该分离和平衡会话创建和销毁。提供-setupSession-tearDownSession方法。确保只有在没有活动会话的情况下才会调用设置,并确保当您不再需要会话时,可以通过调用teardownSession来解除它。在SWIFT中你可以使用@lazy变量并在deinit()-viewWillDisappear中销毁会话。
  4. 创建或使用SYNC队列非常有用创建和销毁会话是一项密集型任务,您通常更喜欢将其放在后台队列中,还有助于同步涉及会话的所有方法。创建自己的同步队列将保证例如设置会话呼叫和拆除呼叫之间的同步,只有当另一个完成时才会调用。
  5. 我认为这是一个巨大的重构,但我是这样的,我很确定你将来会遇到更少的问题。

答案 4 :(得分:1)

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)
        }
    }

答案 5 :(得分:0)

我也遇到了这个问题,我通过将其添加到viewWillAppear和viewWillDissapear中来修复了我的问题。希望这会有所帮助

var session = AVCaptureSession()

override func viewWillAppear(_ animated: Bool) {
        session.startRunning()

    }

override func viewWillDisappear(_ animated: Bool) {
        session.stopRunning()
    }