我正在制作实时摄像头滤镜应用程序。
我使用AVCaptureVideoDataOutput
将samplebuffer传递给MTKView
进行渲染预览,并将AVCapturePhotoOutput
传递给捕获照片。
我的应用程序有一些用于捕捉照片的纵横比选项。(包括16:9和4:3)
我想做的是使预览全屏大小(这是16:9,但任何接近这也可以),尽管用户选择4:3的选项。
我计划在预览中显示边框线,这样用户就可以计算出照片的输出大小。
我需要16:9的预置选项,如1280*720的预览和照片预置选项捕捉照片。
我想出的点子很少。
具有两个不同预设的低分辨率照片-->不适合performance
photoOutput.capturePhoto
方法之前。-->预览在片刻冻结,因为AVCaptureSession
必须更新我决定使用3,但它给了我一个错误。
(如果有更好的方法,请告诉我)
这是我的代码。
@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
更新的完成情况,或者有没有更好的解决方案来处理视频数据输出和照片输出之间的不同宽高比?
发布于 2018-12-18 17:56:09
为视频和照片输出不同纵横比的最佳方法是在AVCapturePhotoCaptureDelegate委托中处理照片图像数据。你可以像下面这样做。在didFinishProcessingPhoto函数中,您可以裁剪图像并从中创建jpeg数据。您还需要将照片元数据复制到此jpeg数据中。然后,在didFinishCaptureFor函数中,您可以将此数据保存到图片库。
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()函数。
https://stackoverflow.com/questions/53821744
复制相似问题