ios 如何使用 AVCapturePhotoOutput
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37869963/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use AVCapturePhotoOutput
提问by Pranav Wadhwa
I have been working on using a custom camera, and I recently upgraded to Xcode 8 beta along with Swift 3. I originally had this:
我一直在研究使用自定义相机,最近我升级到 Xcode 8 beta 和 Swift 3。我最初有这个:
var stillImageOutput: AVCaptureStillImageOutput?
However, I am now getting the warning:
但是,我现在收到警告:
'AVCaptureStillImageOutput' was deprecated in iOS 10.0: Use AVCapturePhotoOutput instead
'AVCaptureStillImageOutput' 在 iOS 10.0 中被弃用:改用 AVCapturePhotoOutput
As this is fairly new, I have not seen much information on this. Here is my current code:
由于这是相当新的,我没有看到太多关于此的信息。这是我当前的代码:
var captureSession: AVCaptureSession?
var stillImageOutput: AVCaptureStillImageOutput?
var previewLayer: AVCaptureVideoPreviewLayer?
func clickPicture() {
if let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo) {
videoConnection.videoOrientation = .portrait
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (sampleBuffer, error) -> Void in
if sampleBuffer != nil {
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
let dataProvider = CGDataProvider(data: imageData!)
let cgImageRef = CGImage(jpegDataProviderSource: dataProvider!, decode: nil, shouldInterpolate: true, intent: .defaultIntent)
let image = UIImage(cgImage: cgImageRef!, scale: 1, orientation: .right)
}
})
}
}
I have tried to look at AVCapturePhotoCaptureDelegate
, but I am not quite sure how to use it. Does anybody know how to use this? Thanks.
我曾尝试查看AVCapturePhotoCaptureDelegate
,但我不太确定如何使用它。有人知道如何使用这个吗?谢谢。
回答by BilalReffas
Updated to Swift 4Hi it's really easy to use AVCapturePhotoOutput
.
更新到 Swift 4嗨,它真的很容易使用AVCapturePhotoOutput
。
You need the AVCapturePhotoCaptureDelegate
which returns the CMSampleBuffer
.
您需要AVCapturePhotoCaptureDelegate
返回 CMSampleBuffer
.
You can get as well a preview image if you tell the AVCapturePhotoSettings
the previewFormat
如果您告诉AVCapturePhotoSettings
previewFormat,您也可以获得预览图像
class CameraCaptureOutput: NSObject, AVCapturePhotoCaptureDelegate {
let cameraOutput = AVCapturePhotoOutput()
func capturePhoto() {
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
self.cameraOutput.capturePhoto(with: settings, delegate: self)
}
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
if let error = error {
print(error.localizedDescription)
}
if let sampleBuffer = photoSampleBuffer, let previewBuffer = previewPhotoSampleBuffer, let dataImage = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: sampleBuffer, previewPhotoSampleBuffer: previewBuffer) {
print("image: \(UIImage(data: dataImage)?.size)") // Your Image
}
}
}
For more information visit https://developer.apple.com/reference/AVFoundation/AVCapturePhotoOutput
有关更多信息,请访问https://developer.apple.com/reference/AVFoundation/AVCapturePhotoOutput
Note: You have to add the AVCapturePhotoOutput
to the AVCaptureSession
before taking the picture. So something like: session.addOutput(output)
, and then: output.capturePhoto(with:settings, delegate:self)
Thanks @BigHeadCreations
注意:您必须在拍照前将AVCapturePhotoOutput
加到 中AVCaptureSession
。所以像:session.addOutput(output)
,然后:output.capturePhoto(with:settings, delegate:self)
谢谢@BigHeadCreations
回答by Aleksey Timoshchenko
There is my full implementation
有我的完整实现
import UIKit
import AVFoundation
class ViewController: UIViewController, AVCapturePhotoCaptureDelegate {
var captureSesssion : AVCaptureSession!
var cameraOutput : AVCapturePhotoOutput!
var previewLayer : AVCaptureVideoPreviewLayer!
@IBOutlet weak var capturedImage: UIImageView!
@IBOutlet weak var previewView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
captureSesssion = AVCaptureSession()
captureSesssion.sessionPreset = AVCaptureSessionPresetPhoto
cameraOutput = AVCapturePhotoOutput()
let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
if let input = try? AVCaptureDeviceInput(device: device) {
if (captureSesssion.canAddInput(input)) {
captureSesssion.addInput(input)
if (captureSesssion.canAddOutput(cameraOutput)) {
captureSesssion.addOutput(cameraOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSesssion)
previewLayer.frame = previewView.bounds
previewView.layer.addSublayer(previewLayer)
captureSesssion.startRunning()
}
} else {
print("issue here : captureSesssion.canAddInput")
}
} else {
print("some problem here")
}
}
// Take picture button
@IBAction func didPressTakePhoto(_ sender: UIButton) {
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
cameraOutput.capturePhoto(with: settings, delegate: self)
}
// callBack from take picture
func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
if let error = error {
print("error occure : \(error.localizedDescription)")
}
if let sampleBuffer = photoSampleBuffer,
let previewBuffer = previewPhotoSampleBuffer,
let dataImage = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: sampleBuffer, previewPhotoSampleBuffer: previewBuffer) {
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)
let image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.right)
self.capturedImage.image = image
} else {
print("some error here")
}
}
// This method you can use somewhere you need to know camera permission state
func askPermission() {
print("here")
let cameraPermissionStatus = AVCaptureDevice.authorizationStatus(forMediaType: AVMediaTypeVideo)
switch cameraPermissionStatus {
case .authorized:
print("Already Authorized")
case .denied:
print("denied")
let alert = UIAlertController(title: "Sorry :(" , message: "But could you please grant permission for camera within device settings", preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(action)
present(alert, animated: true, completion: nil)
case .restricted:
print("restricted")
default:
AVCaptureDevice.requestAccess(forMediaType: AVMediaTypeVideo, completionHandler: {
[weak self]
(granted :Bool) -> Void in
if granted == true {
// User granted
print("User granted")
DispatchQueue.main.async(){
//Do smth that you need in main thread
}
}
else {
// User Rejected
print("User Rejected")
DispatchQueue.main.async(){
let alert = UIAlertController(title: "WHY?" , message: "Camera it is the main feature of our application", preferredStyle: .alert)
let action = UIAlertAction(title: "Ok", style: .cancel, handler: nil)
alert.addAction(action)
self?.present(alert, animated: true, completion: nil)
}
}
});
}
}
}
回答by Jeni Khant
In iOS 11 "photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {}" is deprecated
.
在 iOS 11 中"photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {}" is deprecated
。
Use following method:
使用以下方法:
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
let imageData = photo.fileDataRepresentation()
if let data = imageData, let img = UIImage(data: data) {
print(img)
}
}
回答by productioncoder
I took @Aleksey Timoshchenko'sexcellent answer and updated it to Swift 4.x
.
我接受了@Aleksey Timoshchenko 的出色回答并将其更新为Swift 4.x
.
Note that for my use-case I allow the user to take multiple photos which is why I save them in the images
array.
请注意,对于我的用例,我允许用户拍摄多张照片,这就是我将它们保存在images
数组中的原因。
Note that you need to wire up the @IBAction takePhoto
method via your storyboard
or in code. In my case, I use a storyboard
.
请注意,您需要@IBAction takePhoto
通过您的storyboard
或 在代码中连接该方法。就我而言,我使用storyboard
.
As of iOS 11
, the AVCapturePhotoOutput.jpegPhotoDataRepresentation
that is used in @Aleksey Timoshchenko'sanswer is deprecated.
由于iOS 11
中,AVCapturePhotoOutput.jpegPhotoDataRepresentation
即在使用@Aleksey Timoshchenko的答案被弃用。
Swift 4.x
斯威夫特 4.x
class CameraVC: UIViewController {
@IBOutlet weak var cameraView: UIView!
var images = [UIImage]()
var captureSession: AVCaptureSession!
var cameraOutput: AVCapturePhotoOutput!
var previewLayer: AVCaptureVideoPreviewLayer!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
startCamera()
}
func startCamera() {
captureSession = AVCaptureSession()
captureSession.sessionPreset = AVCaptureSession.Preset.photo
cameraOutput = AVCapturePhotoOutput()
if let device = AVCaptureDevice.default(for: .video),
let input = try? AVCaptureDeviceInput(device: device) {
if (captureSession.canAddInput(input)) {
captureSession.addInput(input)
if (captureSession.canAddOutput(cameraOutput)) {
captureSession.addOutput(cameraOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = cameraView.bounds
cameraView.layer.addSublayer(previewLayer)
captureSession.startRunning()
}
} else {
print("issue here : captureSesssion.canAddInput")
}
} else {
print("some problem here")
}
}
@IBAction func takePhoto(_ sender: UITapGestureRecognizer) {
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
cameraOutput.capturePhoto(with: settings, delegate: self)
}
}
extension CameraVC : AVCapturePhotoCaptureDelegate {
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
if let error = error {
print("error occured : \(error.localizedDescription)")
}
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)
let image = UIImage(cgImage: cgImageRef, scale: 1.0, orientation: UIImage.Orientation.right)
/**
save image in array / do whatever you want to do with the image here
*/
self.images.append(image)
} else {
print("some error here")
}
}
}
回答by dsunku
The capture
delegate function has been changed to photoOutput
. Here's the updated function for Swift 4.
该capture
委托功能已更改为photoOutput
。这是 Swift 4 的更新功能。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
if let error = error {
print(error.localizedDescription)
}
if let sampleBuffer = photoSampleBuffer, let previewBuffer = previewPhotoSampleBuffer, let dataImage = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: sampleBuffer, previewPhotoSampleBuffer: previewBuffer) {
print("image: \(String(describing: UIImage(data: dataImage)?.size))") // Your Image
}
}
回答by mobibob
I found this project in GitHub that helped me understand the initialization of the device and capture-session.
我在 GitHub 上找到了这个项目,它帮助我理解了设备的初始化和捕获会话。