環境
- Xcode 8.1
- えるたそ (OS X El Capitan 10.11.6)
- Swift 3.0.1
- iOS 10.1 (iPhoneSE)
画面構成
正方形の previewView (UIView)が配置されていて、
changeUseCamera: アクションボタンと pushShutter: アクションボタンが設置されています。
サンプルソースコード
ViewController.swift
import UIKit
import AVFoundation
class ViewController: UIViewController {
@IBOutlet weak var previewView: UIView!
var isBackCamera: Bool = true
var captureSession: AVCaptureSession!
var cameraDevices: AVCaptureDevice!
var imageOutput: AVCaptureStillImageOutput!
// MARK: - Life Cycle
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.setupCamera(isBack: self.isBackCamera)
}
// MARK: - Private Method
fileprivate func setupCamera(isBack: Bool) {
guard let devices = AVCaptureDevice.devices() else {
return
}
for device in devices {
// isBack == True -> Back Camera
// iSBack == False -> Front Camera
let devicePosition: AVCaptureDevicePosition = isBack ? .back : .front
if (device as AnyObject).position == devicePosition {
self.cameraDevices = device as! AVCaptureDevice
}
}
let videoInput: AVCaptureInput!
do {
videoInput = try AVCaptureDeviceInput.init(device: self.cameraDevices)
} catch {
videoInput = nil
}
self.captureSession = AVCaptureSession()
self.captureSession.addInput(videoInput)
self.imageOutput = AVCaptureStillImageOutput()
self.captureSession.addOutput(self.imageOutput)
let captureVideoLayer = AVCaptureVideoPreviewLayer.init(session: self.captureSession)
let layerRect = CGRect(x: self.previewView.frame.origin.x,
y: 0,
width: UIScreen.main.bounds.size.width,
height: UIScreen.main.bounds.size.width)
captureVideoLayer?.frame = layerRect
captureVideoLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
guard let videoLayer = captureVideoLayer else {
return
}
self.previewView.layer.addSublayer(videoLayer)
// 開始
self.captureSession.startRunning()
}
// MARK: - IBAction
// Change Camera
@IBAction func changeUseCamera(_ sender: Any) {
self.isBackCamera = !self.isBackCamera
setupCamera(isBack: self.isBackCamera)
}
// Save taken photo
@IBAction func pushShutter(_ sender: Any) {
let captureVideoConnection = imageOutput.connection(withMediaType: AVMediaTypeVideo)
self.imageOutput.captureStillImageAsynchronously(from: captureVideoConnection) { [weak self] (imageDataBuffer, error) -> Void in
let capturedImageData: Data = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataBuffer) as Data
guard let image = UIImage(data: capturedImageData),
let wself = self else {
return
}
UIImageWriteToSavedPhotosAlbum(image, wself, nil, nil)
}
}
}
補足
このままだと、一度アプリから離脱をしてしまうとカメラのセッションが切れてしまうので AppDelegate.swift
の applicationDidBecomeActive: 等のメソッドを使って通知してセッションを再始動しないとダメなようです。