pip 控制器和视图控制器中的 AVCaptureVideoPreviewLayer 不起作用

问题描述 投票:0回答:1

我正在尝试将 PiP(画中画)控制器与视图控制器中的相机预览一起集成。但是,相机预览仅在第一次指定的视图中可见(另一个视图会变黑)。是否可以对两个视图使用相同的

AVCaptureVideoPreviewLayer
实例?或者这里需要改变什么?

class ViewController: UIViewController {

    let captureSession = AVCaptureSession()
    let captureSessionQueue = DispatchQueue(label: "Capture Session Queue")

    var pipVideoCallViewController: AVPictureInPictureVideoCallViewController!
    var pipController: AVPictureInPictureController!

    override func viewDidLoad() {
        super.viewDidLoad()

        let previewView = PreviewView(captureSession)

        let previewLayer = previewView.previewLayer
        previewLayer.frame = view.layer.bounds
        previewLayer.videoGravity = .resizeAspectFill
        previewLayer.connection?.videoOrientation = .landscapeLeft
        view.layer.addSublayer(previewLayer)

        pipVideoCallViewController = .init(previewView,
                                           preferredContentSize: CGSize(width: 1080, height: 1920))

        let pipContentSource = AVPictureInPictureController.ContentSource(
                                    activeVideoCallSourceView: view,
                                    contentViewController: pipVideoCallViewController)

        pipController = AVPictureInPictureController(contentSource: pipContentSource)
        pipController.delegate = self
        pipController.canStartPictureInPictureAutomaticallyFromInline = true

        startSession()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)

        if !pipController.isPictureInPictureActive {
            pipController.startPictureInPicture()
        }
    }

    private func startSession() {
        captureSessionQueue.async { [unowned self] in
            let device = AVCaptureDevice.default(for: .video)!
            captureSession.addInput(try! AVCaptureDeviceInput(device: device))
            captureSession.sessionPreset = .hd1920x1080
            captureSession.isMultitaskingCameraAccessEnabled = captureSession.isMultitaskingCameraAccessSupported
            captureSession.startRunning()
        }
    }

}

extension ViewController: AVPictureInPictureControllerDelegate {

    func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
        print(error.localizedDescription)
    }
}

class PreviewView: UIView {
    override class var layerClass: AnyClass {
        AVCaptureVideoPreviewLayer.self
    }

    var previewLayer: AVCaptureVideoPreviewLayer {
        layer as! AVCaptureVideoPreviewLayer
    }

    init(_ session: AVCaptureSession) {
        super.init(frame: .zero)

        previewLayer.session = session
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension AVPictureInPictureVideoCallViewController {

    convenience init(_ previewView: PreviewView, preferredContentSize: CGSize) {

        // Initialize.
        self.init()

        // Set the preferredContentSize.
        self.preferredContentSize = preferredContentSize

        // Configure the PreviewView.
        previewView.translatesAutoresizingMaskIntoConstraints = false
        previewView.frame = self.view.frame

        self.view.addSubview(previewView)

        NSLayoutConstraint.activate([
            previewView.topAnchor.constraint(equalTo: self.view.topAnchor),
            previewView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
            previewView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
            previewView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor)
        ])
    }

}
ios swift avcapturesession avkit picture-in-picture
1个回答
0
投票

AVCaptureVideoPreviewLayer 只能添加到单个视图,创建单个 AVCaptureVideoPreviewLayer 将其作为子层添加到两个视图

var previewLayer: AVCaptureVideoPreviewLayer?

viewDidLoad 将 AV 添加到两者

override func viewDidLoad() {
    super.viewDidLoad()

    let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
    previewLayer.frame = view.layer.bounds
    previewLayer.videoGravity = .resizeAspectFill
    previewLayer.connection?.videoOrientation = .landscapeLeft
    view.layer.addSublayer(previewLayer)
    self.previewLayer = previewLayer

    pipVideoCallViewController = .init(previewLayer: previewLayer,
                                       preferredContentSize: CGSize(width: 1080, height: 1920))

    let pipContentSource = AVPictureInPictureController.ContentSource(
        activeVideoCallSourceView: view,
        contentViewController: pipVideoCallViewController)

    pipController = AVPictureInPictureController(contentSource: pipContentSource)
    pipController.delegate = self
    pipController.canStartPictureInPictureAutomaticallyFromInline = true

    startSession()
}

更新控制器

convenience init(previewLayer: AVCaptureVideoPreviewLayer, preferredContentSize: CGSize) {
    self.init()
    self.preferredContentSize = preferredContentSize
    previewLayer.frame = view.frame
    view.layer.addSublayer(previewLayer)
}
© www.soinside.com 2019 - 2024. All rights reserved.