首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >拍照前切换AVCaptureSessionPreset

拍照前切换AVCaptureSessionPreset
EN

Stack Overflow用户
提问于 2018-12-18 03:20:39
回答 1查看 680关注 0票数 1

我正在制作实时摄像头滤镜应用程序。

我使用AVCaptureVideoDataOutput将samplebuffer传递给MTKView进行渲染预览,并将AVCapturePhotoOutput传递给捕获照片。

我的应用程序有一些用于捕捉照片的纵横比选项。(包括16:9和4:3)

我想做的是使预览全屏大小(这是16:9,但任何接近这也可以),尽管用户选择4:3的选项。

我计划在预览中显示边框线,这样用户就可以计算出照片的输出大小。

我需要16:9的预置选项,如1280*720的预览和照片预置选项捕捉照片。

我想出的点子很少。

具有两个不同预设的低分辨率照片-->不适合performance

  • Use 1280*720预设用于捕获和裁剪照片输出到4:3宽高比-->低分辨率照片

  • 开关预设恰好在调用photoOutput.capturePhoto方法之前。-->预览在片刻冻结,因为AVCaptureSession必须更新

我决定使用3,但它给了我一个错误。

(如果有更好的方法,请告诉我)

这是我的代码。

代码语言:javascript
复制
@IBAction func takePhoto(_ sender: UIButton) {
    captureSessionQueue.async {
        var photoSettings = AVCapturePhotoSettings()
        photoSettings.isHighResolutionPhotoEnabled = true

        // switch preset from .hd1280*720 to .photo
        self.session.beginConfiguration()
        if self.session.canSetSessionPreset(.photo) {
            self.session.sessionPreset = .photo
        }
        self.session.commitConfiguration()

        self.photoOutput.capturePhoto(with: photoSettings, delegate: self)

        self.session.beginConfiguration()
        self.session.sessionPreset = .hd1280*720
        self.session.commitConfiguration()
    }
}

错误是,

错误Domain=AVFoundationErrorDomain代码=-11800“操作无法完成”UserInfo={发生NSLocalizedFailureReason=An未知错误(-16800),无法完成NSLocalizedDescription=The操作,NSUnderlyingError=0x280013720 {错误Domain=NSOSStatusErrorDomain代码=-16800 "(null)"}}

我想这是因为我在会话完成对新预设的更新之前调用了capturePhoto方法。

当我在commitConfiguration()之后1秒或2秒调用self.photoOutput.capturePhoto方法时,它可以工作。

那么,有没有办法让我知道AVCaptureSession更新的完成情况,或者有没有更好的解决方案来处理视频数据输出和照片输出之间的不同宽高比?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-12-18 17:56:09

为视频和照片输出不同纵横比的最佳方法是在AVCapturePhotoCaptureDelegate委托中处理照片图像数据。你可以像下面这样做。在didFinishProcessingPhoto函数中,您可以裁剪图像并从中创建jpeg数据。您还需要将照片元数据复制到此jpeg数据中。然后,在didFinishCaptureFor函数中,您可以将此数据保存到图片库。

代码语言:javascript
复制
class MyPhotoCaptureDelegate: NSObject, AVCapturePhotoCaptureDelegate {
    func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
        // crop image
        if let cgImage = photo.cgImageRepresentation()?.takeUnretainedValue() {
            let cropRect : CGRect = calculateAspectRatioCrop(cgImage:cgImage, aspectRatio:16.0/9.0)
            if let cgCroppedImage = cgImage.cropping(to:cropRect) {
                let image = UIImage(cgImage:cgCroppedImage)
                if let photoData = image.jpegData(compressionQuality: 0.9) {
                    // add meta data from original image to cropped image data
                    self.photoData = addImageProperties(imageData: photoData, properties: photo.metadata as NSDictionary)
                }
            }
        }
    }

    func photoOutput(_ captureOutput: AVCapturePhotoOutput, didFinishCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) {
        if let error = error {
            print("Error capturing photo: \(error)")
            return
        }

        guard let photoData = photoData else {
            print("No photo data resource")
            return
        }
        savePhotoData()
    }

    func calculateAspectRatioCrop(cgImage : CGImage, aspectRatio: CGFloat) -> CGRect {
        var width = CGFloat(cgImage.width)
        var height = CGFloat(cgImage.height)
        // should be cropped vertically or horizontally?
        if aspectRatio > width/height {
            height = width / aspectRatio
        } else {
            width = height * aspectRatio
        }
        return CGRect(x: (CGFloat(cgImage.width) - width)/2, y: (CGFloat(cgImage.height) - height)/2, width: width, height: height)
    }

    func addImageProperties(imageData: Data, properties: NSDictionary?) -> Data? {
        // create an imagesourceref
        if let source = CGImageSourceCreateWithData(imageData as CFData, nil) {
            // this is of type image
            if let uti = CGImageSourceGetType(source) {
                // create a new data object and write the new image into it
                let destinationData = NSMutableData()
                if let destination = CGImageDestinationCreateWithData(destinationData, uti, 1, nil) {
                    // add the image contained in the image source to the destination, overidding the old metadata with our modified metadata
                    CGImageDestinationAddImageFromSource(destination, source, 0, properties)
                    if CGImageDestinationFinalize(destination) == false {
                        return nil
                    }
                    return destinationData as Data
                }
            }
        }
        return nil
    }

    private var photoData : Data? = nil
}

我让您来填充savePhotoData()函数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53821744

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档