AVCaptureStillImageOutput vs AVCapturePhotoOutput в Swift 3
Я пытаюсь просто поставить Camera View в свой контроллер просмотра.
Я импортировал AVFoundation
вверху, а также классы UIImagePickerControllerDelegate
и UINavigationControllerDelegate
.
Однако, когда я пытаюсь использовать AVCaptureStillImageOutput
, Xcode сообщает мне, что он устарел в iOS10, и я должен использовать AVCapturePhotoOutput
. Это вполне нормально, однако, как только я хочу позвонить stillImageOutput.outputSettings
, .outputSettings
сам по себе недоступен. Таким образом, я должен использовать AVAVCaptureStillImageOutput
для его работы, но у меня есть несколько предупреждений, потому что эта функция была устарела в iOS10.
Я искал и искал, но не мог найти решение вокруг него. Я бы очень признателен вам за вашу помощь. Я учусь, поэтому любое объяснение будет замечательным! Код ниже.
import UIKit
import AVFoundation
class CameraView: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var captureSession : AVCaptureSession?
var stillImageOutput : AVCaptureStillImageOutput?
var previewLayer : AVCaptureVideoPreviewLayer?
@IBOutlet var cameraView: UIView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
captureSession = AVCaptureSession()
captureSession?.sessionPreset = AVCaptureSessionPreset1920x1080
var backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var error : NSError?
do {
var input = try! AVCaptureDeviceInput (device: backCamera)
if (error == nil && captureSession?.canAddInput(input) != nil) {
captureSession?.addInput(input)
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
if (captureSession?.canAddOutput(stillImageOutput) != nil) {
captureSession?.addOutput(stillImageOutput)
previewLayer = AVCaptureVideoPreviewLayer (session: captureSession)
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspect
previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait
cameraView.layer.addSublayer(previewLayer!)
captureSession?.startRunning()
}
}
} catch {
}
}
}
Ответы
Ответ 1
AVCaptureStillImageOutput
устаревший означает, что вы можете продолжать использовать его в iOS 10, но:
- Apple не делает promises относительно того, как долго IOS 10 останется доступным.
- по мере добавления новых функций аппаратного и программного обеспечения в iOS 10 и далее, вы не получите доступ ко всем из них. Например, вы можете настроить
AVCaptureStillImageOutput
для широкого цвета, но гораздо проще сделать широкий цвет с помощью AVCapturePhotoOutput
. А для съемки RAW или Live Photos AVCapturePhotoOutput
- единственная игра в городе.
Если вы счастливы, несмотря на устаревание, ваша проблема заключается не в том, что outputSettings
удален - он все еще существует.
Что-то, о чем следует знать для бета-версии 6 и выше (хотя это и не проблема): API, которые используют NSDictionary
без явных ключей и типов значений, входят в Swift 3 как [AnyHashable: Any]
, а Foundation или Типы CoreFoundation, которые вы можете использовать в словаре, более неявно соединяются с типами Swift. (Некоторые из других вопросов о конверсиях из бета-версии могут указывать на вас в правильном направлении.)
Однако при настройке outputSettings
я не получаю ошибок компиляции. В вашем полном коде или путем сокращения его до необходимых частей для этой линии:
var stillImageOutput : AVCaptureStillImageOutput?
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput?.outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG]
... только предупреждения, о которых я вижу, относятся к устареванию.
Ответ 2
Есть моя полная реализация
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)
}
}
});
}
}
}