【问题标题】:AVCaptureVideoPreviewLayer is not visible on the screenshotAVCaptureVideoPreviewLayer 在屏幕截图中不可见
【发布时间】:2019-07-11 11:28:51
【问题描述】:

我有一个应用程序,可以在 AV Foundation 相机中添加一些实时动画和图像来预览视图。我可以做“硬件截图”(按住侧边按钮和提高音量按钮),没关系。但是,我需要一个制作屏幕截图的按钮。

所有像UIGraphicsGetImageFromCurrentImageContext(或view.drawHierarchy())这样的截图方法都会导致视频预览出现黑屏。除AVCaptureVideoPreviewLayer 外,所有其他元素都在屏幕截图上,并且图像可见。

请帮助我。我可以做“硬件截图”吗?是否存在该问题的另一种解决方案?

【问题讨论】:

    标签: swift avfoundation screenshot avcapture


    【解决方案1】:

    我处于相同的位置,并针对这个问题研究了两种不同的解决方案。

    1. 将 ViewController 设置为 AVCaptureVideoDataOutputSampleBufferDelegate 并对视频输出进行采样以截取屏幕截图。

    2. 将 ViewController 设置为 AVCapturePhotoCaptureDelegate 并捕获照片。

    在这个问题中描述了设置前者的机制,例如:How to take UIImage of AVCaptureVideoPreviewLayer instead of AVCapturePhotoOutput capture

    我同时实施了这两种方法来检查图像质量是否存在差异(没有差异)。

    如果您只需要相机快照,那么就是这样。但听起来你需要在顶部绘制一个额外的动画。为此,我创建了一个与快照大小相同的容器 UIView,将 UIImageView 与快照一起添加到其中,然后在顶部绘制动画。之后,您可以在容器上使用 UIGraphicsGetImageFromCurrentImageContext 。

    至于使用 (1) 和 (2) 中的哪一个,如果您不需要在应用程序中支持不同的摄像头方向,则可能无关紧要。但是,如果您需要在前后摄像头之间切换并支持不同的摄像头方向,那么您需要知道快照方向才能将动画应用到正确的位置,并且得到正确的结果证明是完全可以忍受的方法(1 )。

    我使用的解决方案:

    1. UIViewController 扩展了 AVCapturePhotoCaptureDelegate

    2. 将照片输出添加到 AVCaptureSession

        private let session = AVCaptureSession()
        private let photoOutput = AVCapturePhotoOutput()
    
        ....
    
        // When configuring the session
        if self.session.canAddOutput(self.photoOutput) {
            self.session.addOutput(self.photoOutput)
            self.photoOutput.isHighResolutionCaptureEnabled = true
        } 
    
    1. 捕获快照
        let settings = AVCapturePhotoSettings()
        let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first!
        let previewFormat = [
            kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
            kCVPixelBufferWidthKey as String: 160,
            kCVPixelBufferHeightKey as String: 160
        ]
        settings.previewPhotoFormat = previewFormat
        photoOutput.capturePhoto(with: settings, delegate: self)
    
    1. 先旋转或翻转快照,然后再进行其他操作
        func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
    
            guard error == nil else {
                // Do something
                // return
            }
    
            if let dataImage = photo.fileDataRepresentation() {
                print(UIImage(data: dataImage)?.size as Any)
    
                let dataProvider = CGDataProvider(data: dataImage as CFData)
                let cgImageRef: CGImage! = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
                //https://developer.apple.com/documentation/uikit/uiimageorientation?language=objc
                let orientation = UIApplication.shared.statusBarOrientation
                var imageOrientation = UIImage.Orientation.right
                switch orientation {
                case .portrait:
                    imageOrientation = self.cameraPosition == .back ? UIImage.Orientation.right : UIImage.Orientation.leftMirrored
                case .landscapeRight:
                    imageOrientation = self.cameraPosition == .back ? UIImage.Orientation.up : UIImage.Orientation.downMirrored
                case .portraitUpsideDown:
                    imageOrientation = self.cameraPosition == .back ? UIImage.Orientation.left : UIImage.Orientation.rightMirrored
                case .landscapeLeft:
                    imageOrientation = self.cameraPosition == .back ? UIImage.Orientation.down : UIImage.Orientation.upMirrored
                case .unknown:
                    imageOrientation = self.cameraPosition == .back ? UIImage.Orientation.right : UIImage.Orientation.leftMirrored
                @unknown default:
                    imageOrientation = self.cameraPosition == .back ? UIImage.Orientation.right : UIImage.Orientation.leftMirrored
                }
                let image = UIImage.init(cgImage: cgImageRef, scale: 1.0, orientation: imageOrientation)
    
                // Do whatever you need to do with the image
    
            } else {
                // Handle error
            }
         }
    

    如果您需要知道图像的大小来定位动画,您可以使用 AVCaptureVideoDataOutputSampleBufferDelegate 策略来检测缓冲区的大小一次。

    【讨论】:

      猜你喜欢
      • 2021-07-12
      • 1970-01-01
      • 1970-01-01
      • 2015-12-02
      • 1970-01-01
      • 2014-03-07
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多