Skip to content

Instantly share code, notes, and snippets.

@kkebo
Last active April 4, 2019 18:22
Show Gist options
  • Save kkebo/79881b14e447b83e7e542c4a39f9cd83 to your computer and use it in GitHub Desktop.
Save kkebo/79881b14e447b83e7e542c4a39f9cd83 to your computer and use it in GitHub Desktop.
Swift Playgrounds 3.0 でカメラデバイスを使うときのテンプレート
import AVFoundation
import UIKit
import PlaygroundSupport
class ViewController: UIViewController {
lazy var session: AVCaptureSession = {
let deviceResult = getDefaultDevice()
var device: AVCaptureDevice
switch deviceResult {
case let .success(value):
device = value
case let .failure(error):
fatalError(error.localizedDescription)
}
if case let .failure(error) = configureDevice(device: device) {
fatalError(error.localizedDescription)
}
let sessionResult = self.createSession(device: device)
switch sessionResult {
case let .success(session):
return session
case let .failure(error):
fatalError(error.localizedDescription)
}
}()
let previewLayer: AVSampleBufferDisplayLayer = {
let layer = AVSampleBufferDisplayLayer()
layer.videoGravity = .resizeAspect
return layer
}()
lazy var previewView: UIView = {
let view = UIView()
view.layer.addSublayer(self.previewLayer)
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view = self.previewView
self.session.startRunning()
}
override func viewWillLayoutSubviews() {
self.previewLayer.frame = self.view.bounds
}
func createSession(device: AVCaptureDevice) -> Result<AVCaptureSession, Error> {
let session = AVCaptureSession()
session.sessionPreset = .hd1280x720
let inputResult = Result { try AVCaptureDeviceInput(device: device) }
switch inputResult {
case let .success(input) where session.canAddInput(input):
session.beginConfiguration()
session.addInput(input)
session.commitConfiguration()
case let .failure(error):
return .failure(error)
default: break
}
let output = AVCaptureVideoDataOutput()
if session.canAddOutput(output) {
let cameraQueue = DispatchQueue(label: "Camera Queue")
session.beginConfiguration()
session.addOutput(output)
output.videoSettings = [kCVPixelBufferPixelFormatTypeKey as String : kCVPixelFormatType_32BGRA]
output.setSampleBufferDelegate(self, queue: cameraQueue)
output.alwaysDiscardsLateVideoFrames = true
if let connection = output.connection(with: .video) {
if connection.isVideoStabilizationSupported {
connection.preferredVideoStabilizationMode = .auto
}
if connection.isVideoOrientationSupported {
connection.videoOrientation = .landscapeLeft
}
}
session.commitConfiguration()
}
return .success(session)
}
}
extension ViewController: AVCaptureVideoDataOutputSampleBufferDelegate {
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
DispatchQueue.main.async {
self.previewLayer.enqueue(sampleBuffer)
}
}
}
enum GetDefaultDeviceError: Error {
case unavailable
}
func getDefaultDevice() -> Result<AVCaptureDevice, GetDefaultDeviceError> {
if let device = AVCaptureDevice.default(.builtInDualCamera , for: .video, position: .back) {
return .success(device)
} else if let device = AVCaptureDevice.default(.builtInWideAngleCamera , for: .video, position: .back) {
return .success(device)
} else {
return .failure(.unavailable)
}
}
enum ConfigureDeviceError: Error {
case formatNotFound
case deviceLockFailed
}
func configureDevice(device: AVCaptureDevice) -> Result<(), ConfigureDeviceError> {
var bestFormat: AVCaptureDevice.Format? = nil
var bestFrameRateRange: AVFrameRateRange? = nil
for format in device.formats {
for range in format.videoSupportedFrameRateRanges {
if range.maxFrameRate > bestFrameRateRange?.maxFrameRate ?? -Float64.greatestFiniteMagnitude {
bestFormat = format
bestFrameRateRange = range
}
}
}
guard let format = bestFormat, let range = bestFrameRateRange else {
return .failure(.formatNotFound)
}
let lock = Result { try device.lockForConfiguration() }
guard case .success = lock else {
return .failure(.deviceLockFailed)
}
device.activeFormat = format
device.activeVideoMinFrameDuration = range.maxFrameDuration
device.activeVideoMaxFrameDuration = range.maxFrameDuration
device.unlockForConfiguration()
return .success(())
}
PlaygroundPage.current.wantsFullScreenLiveView = true
PlaygroundPage.current.liveView = ViewController()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment