Created
February 21, 2017 09:37
-
-
Save vendruscolo/31fa0914d8c485fee68940960f1e9f37 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CameraView.swift | |
// ALCameraViewController | |
// | |
// Created by Alex Littlejohn on 2015/06/17. | |
// Copyright (c) 2015 zero. All rights reserved. | |
// | |
import UIKit | |
import AVFoundation | |
import Dispatch | |
// Adapted from ALCameraViewController | |
// https://github.com/AlexLittlejohn/ALCameraViewController/blob/fce8499e4ccd52a2389c4b215d718a544b7aba51/ALCameraViewController/Views/CameraView.swift | |
/// CameraView is an object that manages the preview layer of the camera. | |
/// | |
/// Construct one and retrieve the `previewLayer`. Also call the `startSession` | |
/// and `stopSession` when appropriate. | |
class CameraPreviewLayer: NSObject { | |
// MARK: Init | |
init(targetSize: CGSize) { | |
super.init() | |
// AVFoundation boilerplate... | |
session = AVCaptureSession() | |
session.sessionPreset = AVCaptureSessionPresetPhoto | |
device = cameraWithPosition(.back) | |
if let device = device, device.hasFlash { | |
do { | |
try device.lockForConfiguration() | |
device.flashMode = .auto | |
device.unlockForConfiguration() | |
} catch _ {} | |
} | |
let outputSettings = [AVVideoCodecKey: AVVideoCodecJPEG] | |
do { | |
input = try AVCaptureDeviceInput(device: device) | |
} catch let error as NSError { | |
input = nil | |
fatalError("Error: \(error.localizedDescription)") | |
} | |
if session.canAddInput(input) { | |
session.addInput(input) | |
} | |
imageOutput = AVCaptureStillImageOutput() | |
imageOutput.outputSettings = outputSettings | |
session.addOutput(imageOutput) | |
// Create the layer | |
previewLayer = AVCaptureVideoPreviewLayer(session: session) | |
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill | |
previewLayer.frame = CGRect(origin: CGPoint.zero, size: targetSize) | |
// Handle rotation | |
NotificationCenter.default.addObserver( | |
self, | |
selector: #selector(CameraPreviewLayer.deviceOrientationDidChange), | |
name: NSNotification.Name.UIDeviceOrientationDidChange, | |
object: nil | |
) | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
deinit { | |
stopSession() | |
// Zeroing-weak observers? Who knows if that works... | |
NotificationCenter.default.removeObserver(self) | |
} | |
// MARK: Public properties | |
/// The AVCaptureVideoPreviewLayer that shows the camera live feed. | |
var previewLayer: AVCaptureVideoPreviewLayer! | |
// MARK: Public methods | |
/// Starts the AVCaptureSession. If the session is stopped (or not yet | |
/// started) the view will be black. | |
func startSession() { | |
cameraQueue.sync { | |
self.session.startRunning() | |
} | |
// Detect orientation changes | |
UIDevice.current.beginGeneratingDeviceOrientationNotifications() | |
} | |
/// Stops the AVCaptureSession. This will also be called on deinit | |
/// automatically. | |
func stopSession() { | |
// We're no longer insterested in orientation changes | |
UIDevice.current.endGeneratingDeviceOrientationNotifications() | |
cameraQueue.sync { | |
self.session.stopRunning() | |
} | |
} | |
// MARK: Private methods | |
private func cameraWithPosition(_ position: AVCaptureDevicePosition) -> AVCaptureDevice? { | |
guard let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] else { | |
return nil | |
} | |
return devices.filter { $0.position == position }.first | |
} | |
private func rotatePreview() { | |
switch UIDevice.current.orientation { | |
case .portrait: | |
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait | |
case .portraitUpsideDown: | |
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown | |
case .landscapeLeft: | |
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.landscapeRight | |
case .landscapeRight: | |
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.landscapeLeft | |
default: break | |
} | |
} | |
@objc private func deviceOrientationDidChange() { | |
rotatePreview() | |
} | |
// MARK: Private properties | |
var session: AVCaptureSession! | |
var input: AVCaptureDeviceInput! | |
var device: AVCaptureDevice! | |
var imageOutput: AVCaptureStillImageOutput! | |
let cameraQueue = DispatchQueue(label: "com.zero.ALCameraViewController.Queue", attributes: []) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment