longitachi / ZLPhotoBrowser

Wechat-like image picker. Support select photos, videos, gif and livePhoto. Support edit image and crop video. 微信样式的图片选择器,支持预览/相册内拍照及录视频、拖拽/滑动选择,编辑图片/视频,支持多语言国际化等功能;
MIT License
4.79k stars 971 forks source link

Bugly上收集到崩溃问题: [AVCaptureDevice setVideoZoomFactor:] #693

Closed ETmanwenhan closed 2 years ago

ETmanwenhan commented 2 years ago

Issue Description

*** -[AVCaptureDevice setVideoZoomFactor:] May not be called without first successfully gaining exclusive ownership of the device using -lockForConfiguration:

Description and Steps

0 Thread

NSGenericException *** -[AVCaptureDevice setVideoZoomFactor:] May not be called without first successfully gaining exclusive ownership of the device using -lockForConfiguration: 解析原始 0 CoreFoundation ___exceptionPreprocess + 228 2 AVFoundation -[AVCaptureFigVideoDevice setVideoZoomFactor:] + 316 3 papaya_anchor switchCameraBtnClick (:0) 4 papaya_anchor switchCameraBtnClick (:0) 5 UIKitCore -[UIApplication sendAction:to:from:forEvent:] + 96

22 libswiftUIKit.dylib _$s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 168 23 papaya_anchor main (PAAlbumRequester.swift:0) 24 libdyld.dylib _start + 4

Info

ZLPhotoBrowser version: e.g. 4.2.1 Device: e.g. iPhone 8 Plus Device version: e.g. iOS 12.4.1 Xcode version: e.g. Xcode 13.1

Configuration code of ZLPhotoConfiguration

    @objc func switchCameraBtnClick() {
        do {
            guard !self.restartRecordAfterSwitchCamera else {
                return
            }

            guard let currInput = self.videoInput else {
                return
            }
            var newVideoInput: AVCaptureDeviceInput?
            if currInput.device.position == .back, let front = self.getCamera(position: .front) {
                newVideoInput = try AVCaptureDeviceInput(device: front)
            } else if currInput.device.position == .front, let back = self.getCamera(position: .back) {
                newVideoInput = try AVCaptureDeviceInput(device: back)
            } else {
                return
            }

            let zoomFactor = currInput.device.videoZoomFactor

            if let ni = newVideoInput {
                self.session.beginConfiguration()
                self.session.removeInput(currInput)
                if self.session.canAddInput(ni) {
                    self.session.addInput(ni)
                    self.videoInput = ni
                    ni.device.videoZoomFactor = zoomFactor
                } else {
                    self.session.addInput(currInput)
                }
                self.session.commitConfiguration()
                if self.movieFileOutput.isRecording {
                    let pauseTime = self.animateLayer.convertTime(CACurrentMediaTime(), from: nil)
                    self.animateLayer.speed = 0
                    self.animateLayer.timeOffset = pauseTime
                    self.restartRecordAfterSwitchCamera = true
                }
            }
        } catch {
            zl_debugPrint("切换摄像头失败 \(error.localizedDescription)")
        }
    }
ETmanwenhan commented 2 years ago

也行需要额外添加锁设备代码:

                    do {
                        try ni.device.lockForConfiguration()
                        ni.device.videoZoomFactor = zoomFactor
                        ni.device.unlockForConfiguration()
                    } catch {
                        zl_debugPrint("调整焦距失败 \(error.localizedDescription)")
                    }
ETmanwenhan commented 2 years ago

也行需要额外添加锁设备代码:

                    do {
                        try ni.device.lockForConfiguration()
                        ni.device.videoZoomFactor = zoomFactor
                        ni.device.unlockForConfiguration()
                    } catch {
                        zl_debugPrint("调整焦距失败 \(error.localizedDescription)")
                    }
longitachi commented 2 years ago

也行需要额外添加锁设备代码:

                    do {
                        try ni.device.lockForConfiguration()
                        ni.device.videoZoomFactor = zoomFactor
                        ni.device.unlockForConfiguration()
                    } catch {
                        zl_debugPrint("调整焦距失败 \(error.localizedDescription)")
                    }

你添加完这块代码后,还会crash吗

ETmanwenhan commented 2 years ago

也行需要额外添加锁设备代码:

                    do {
                        try ni.device.lockForConfiguration()
                        ni.device.videoZoomFactor = zoomFactor
                        ni.device.unlockForConfiguration()
                    } catch {
                        zl_debugPrint("调整焦距失败 \(error.localizedDescription)")
                    }

你添加完这块代码后,还会crash吗

我还没详细测试过,我是根据崩溃提示调整的。有空我再测试一下

ETmanwenhan commented 2 years ago

也行需要额外添加锁设备代码:

                    do {
                        try ni.device.lockForConfiguration()
                        ni.device.videoZoomFactor = zoomFactor
                        ni.device.unlockForConfiguration()
                    } catch {
                        zl_debugPrint("调整焦距失败 \(error.localizedDescription)")
                    }

你添加完这块代码后,还会crash吗

我在我的设备上测试没发现崩溃问题,不管是否添加lockForConfiguration;

但是线上设备出现崩溃问题, ZLPhotoBrowser version: e.g. 4.2.1 Device: e.g. iPhone 8 Plus Device version: e.g. iOS 12.4.1 Xcode version: e.g. Xcode 13.1

ETmanwenhan commented 2 years ago

这个问题重现了,在iPhone 6,我修复方案如下:

    @objc func switchCameraBtnClick() {
        do {
            guard !self.restartRecordAfterSwitchCamera else {
                return
            }

            guard let currInput = self.videoInput else {
                return
            }
            var newVideoInput: AVCaptureDeviceInput?
            if currInput.device.position == .back, let front = self.getCamera(position: .front) {
                newVideoInput = try AVCaptureDeviceInput(device: front)
            } else if currInput.device.position == .front, let back = self.getCamera(position: .back) {
                newVideoInput = try AVCaptureDeviceInput(device: back)
            } else {
                return
            }

            let zoomFactor = currInput.device.videoZoomFactor

            if let ni = newVideoInput {
                self.session.beginConfiguration()
                self.session.removeInput(currInput)
                if self.session.canAddInput(ni) {
                    self.session.addInput(ni)
                    self.videoInput = ni
                    //ni.device.videoZoomFactor = zoomFactor
                    self.setVideoZoomFactor(zoomFactor) // 解决iPhone6拍照切换摄像头崩溃问题
                } else {
                    self.session.addInput(currInput)
                }
                self.session.commitConfiguration()
                if self.movieFileOutput.isRecording {
                    let pauseTime = self.animateLayer.convertTime(CACurrentMediaTime(), from: nil)
                    self.animateLayer.speed = 0
                    self.animateLayer.timeOffset = pauseTime
                    self.restartRecordAfterSwitchCamera = true
                }
            }
        } catch {
            zl_debugPrint("切换摄像头失败 \(error.localizedDescription)")
        }
    }

ZLPhotoBrowser version: 4.2.1 Device: iPhone 6 Device version: iOS 12.5.2 Xcode version: Xcode 13.1

ETmanwenhan commented 2 years ago

修复该问题,麻烦通知一下,谢谢大神!

longitachi commented 2 years ago

下个版本会把这个ni.device.videoZoomFactor = zoomFactor代码去掉,切换镜头重置缩放系数

ETmanwenhan commented 2 years ago

这是来自QQ邮箱的假期自动回复邮件。   您好,谢谢你联系我。我会尽快给您回复。