AVCaptureVideoPreviewLayer在屏幕截图上不可见 [英] AVCaptureVideoPreviewLayer is not visible on the screenshot

查看:146
本文介绍了AVCaptureVideoPreviewLayer在屏幕截图上不可见的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,该应用程序添加了一些实时动画和图像以在AV Foundation相机中预览视图.我可以进行硬件屏幕截图"(按住侧面"按钮和调高音量"按钮),并且可以.但是,我需要一个用于截屏的按钮.

I have an application that adds some live animations and images to preview view in AV Foundation camera. I can do "hardware screenshot" (holding the Side button and Volume Up button) and it's ok. However, I need a button that makes a screenshot.

所有获取屏幕截图的方法(例如UIGraphicsGetImageFromCurrentImageContext(或view.drawHierarchy()))都会在视频预览所在的黑屏中显示.屏幕上的所有其他元素都在屏幕快照上,并且除了AVCaptureVideoPreviewLayer以外,其他图像均可见.

All the methods of taking screenshot like UIGraphicsGetImageFromCurrentImageContext (or view.drawHierarchy() ) result in black screen where video preview is. All other elements are on the screenshot and images are visible except AVCaptureVideoPreviewLayer.

请帮助我.我可以做硬件截图"吗?是否存在解决该问题的另一种方法?

Please help me. Can I do "hardware screenshot"? Is exist another solution to that problem?

推荐答案

我处于同一位置,并且研究了针对此问题的两种单独的解决方案.

I was in the same position, and researched two separate solutions to this problem.

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

  1. Set up the ViewController as an AVCaptureVideoDataOutputSampleBufferDelegate and sample the video output to take the screenshot.

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

Set up the ViewController as an AVCapturePhotoCaptureDelegate and capture the photo.

在此问题中描述了设置前者的机制,例如:

The mechanism for setting up the former is described in this question for example: How to take UIImage of AVCaptureVideoPreviewLayer instead of AVCapturePhotoOutput capture

我都实施了这两种方法,以检查图像质量是否存在差异(没有).

I implemented both to check if there was any difference in the quality of the image (there wasn't).

如果只需要摄影机快照,就可以了.但这听起来像您需要在顶部绘制一个额外的动画.为此,我创建了一个与快照大小相同的容器UIView,向其中添加了带有快照的UIImageView,然后在顶部绘制了动画.之后,您可以在容器上使用UIGraphicsGetImageFromCurrentImageContext.

If all you need is the camera snapshot, then that's it. But it sounds like you need to draw an additional animation on top. For this, I created a container UIView of the same size as the snapshot, added a UIImageView to it with the snapshot and then drew the animation on top. After that you can use UIGraphicsGetImageFromCurrentImageContext on the container.

关于使用哪种解决方案(1)和(2),如果您不需要在应用程序中支持不同的相机方向,则可能无关紧要.但是,如果您需要在前后摄像头之间切换并支持不同的摄像头方向,则需要知道快照的方向,以便在正确的位置应用动画,而正确地使用方法(1 ).

As for which of solutions (1) and (2) to use, if you don't need to support different camera orientations in the app, it probably doesn't matter. However, if you need to switch between front and back camera and support different camera orientations, then you need to know the snapshot orientation to apply the animation in the right place, and getting that right turned out to be a total bear with method (1).

我使用的解决方案:

  1. UIViewController扩展了AVCapturePhotoCaptureDelegate

  1. UIViewController extends AVCapturePhotoCaptureDelegate

将照片输出添加到AVCaptureSession

Add photo output to the 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策略来一次检测缓冲区的大小.

If you need to know the size of the image to position the animations you can use the AVCaptureVideoDataOutputSampleBufferDelegate strategy to detect the size of the buffer once.

这篇关于AVCaptureVideoPreviewLayer在屏幕截图上不可见的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆