Skip to content

Commit

Permalink
Merge pull request #51 from dokun1/minorRefactoring
Browse files Browse the repository at this point in the history
Minor refactoring
  • Loading branch information
dokun1 authored Nov 21, 2017
2 parents ea225d3 + bf0fb80 commit f1cc93f
Show file tree
Hide file tree
Showing 42 changed files with 2,073 additions and 1,793 deletions.
2 changes: 1 addition & 1 deletion Lumina.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "Lumina"
s.version = "0.11.2"
s.version = "0.12.0"
s.summary = "Lumina gives you a camera for most photo processing needs, including streaming frames for CoreML live detection."
s.homepage = "https://github.com/dokun1/Lumina"
s.license = { :type => "MIT" }
Expand Down
3 changes: 3 additions & 0 deletions Lumina/.swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
disabled_rules:
- line_length
file_length:
warning: 600
error: 1000
158 changes: 147 additions & 11 deletions Lumina/Lumina.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions Lumina/Lumina/Camera/Extensions/CameraActionsExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
//
// CameraActionsExtension.swift
// Lumina
//
// Created by David Okun on 11/20/17.
// Copyright © 2017 David Okun. All rights reserved.
//

import Foundation
import AVFoundation

extension LuminaCamera {
func getPreviewLayer() -> AVCaptureVideoPreviewLayer? {
let previewLayer = AVCaptureVideoPreviewLayer(session: self.session)
previewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
return previewLayer
}

func captureStillImage() {
var settings = AVCapturePhotoSettings()
if #available(iOS 11.0, *) {
if self.photoOutput.availablePhotoCodecTypes.contains(.hevc) {
settings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.hevc])
}
}
settings.isAutoStillImageStabilizationEnabled = true
settings.flashMode = self.torchState ? .on : .off
if self.captureLivePhotos {
let fileName = NSTemporaryDirectory().appending("livePhoto" + Date().iso8601 + ".mov")
settings.livePhotoMovieFileURL = URL(fileURLWithPath: fileName)
}
if self.captureHighResolutionImages {
settings.isHighResolutionPhotoEnabled = true
}
if #available(iOS 11.0, *) {
if self.captureDepthData && self.photoOutput.isDepthDataDeliverySupported {
settings.isDepthDataDeliveryEnabled = true
}
}
self.photoOutput.capturePhoto(with: settings, delegate: self)
}

func startVideoRecording() {
if self.resolution == .photo {
return // TODO: make this function throw an error
}
recordingVideo = true
sessionQueue.async {
if let connection = self.videoFileOutput.connection(with: AVMediaType.video), let videoConnection = self.videoDataOutput.connection(with: AVMediaType.video) {
connection.videoOrientation = videoConnection.videoOrientation
connection.isVideoMirrored = self.position == .front ? true : false
if connection.isVideoStabilizationSupported {
connection.preferredVideoStabilizationMode = .cinematic
}
self.session.commitConfiguration()
}
let fileName = NSTemporaryDirectory().appending(Date().iso8601 + ".mov")
self.videoFileOutput.startRecording(to: URL(fileURLWithPath: fileName), recordingDelegate: self)
}
}

func stopVideoRecording() {
recordingVideo = false
sessionQueue.async {
self.videoFileOutput.stopRecording()
}
}
}
25 changes: 25 additions & 0 deletions Lumina/Lumina/Camera/Extensions/CameraUtilExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// CameraUtilExtension.swift
// Lumina
//
// Created by David Okun on 11/20/17.
// Copyright © 2017 David Okun. All rights reserved.
//

import Foundation

extension Formatter {
static let iso8601: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.timeZone = TimeZone(secondsFromGMT: 0)
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
return formatter
}()
}
extension Date {
var iso8601: String {
return Formatter.iso8601.string(from: self)
}
}
122 changes: 122 additions & 0 deletions Lumina/Lumina/Camera/Extensions/CaptureDeviceHandlerExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// CaptureDeviceHandlerExtension.swift
// Lumina
//
// Created by David Okun on 11/20/17.
// Copyright © 2017 David Okun. All rights reserved.
//

import Foundation
import AVFoundation

extension LuminaCamera {
func getNewVideoInputDevice() -> AVCaptureDeviceInput? {
do {
guard let device = getDevice(with: self.position == .front ? AVCaptureDevice.Position.front : AVCaptureDevice.Position.back) else {
print("could not find valid AVCaptureDevice")
return nil
}
let input = try AVCaptureDeviceInput(device: device)
return input
} catch {
return nil
}
}

func getNewAudioInputDevice() -> AVCaptureDeviceInput? {
do {
guard let device = AVCaptureDevice.default(for: AVMediaType.audio) else {
return nil
}
let deviceInput = try AVCaptureDeviceInput(device: device)
return deviceInput
} catch {
return nil
}
}

func purgeAudioDevices() {
for oldInput in self.session.inputs where oldInput == self.audioInput {
self.session.removeInput(oldInput)
}
}

func purgeVideoDevices() {
for oldInput in self.session.inputs where oldInput == self.videoInput {
self.session.removeInput(oldInput)
}
for oldOutput in self.session.outputs {
if oldOutput == self.videoDataOutput || oldOutput == self.photoOutput || oldOutput == self.metadataOutput || oldOutput == self.videoFileOutput {
self.session.removeOutput(oldOutput)
}
if let dataOutput = oldOutput as? AVCaptureVideoDataOutput {
self.session.removeOutput(dataOutput)
}
if #available(iOS 11.0, *) {
if let depthOutput = oldOutput as? AVCaptureDepthDataOutput {
self.session.removeOutput(depthOutput)
}
}
}
}

func getDevice(with position: AVCaptureDevice.Position) -> AVCaptureDevice? {
#if swift(>=4.0.2)
if #available(iOS 11.1, *), position == .front {
if let device = AVCaptureDevice.default(.builtInTrueDepthCamera, for: .video, position: .front) {
return device
}
}
#endif
if #available(iOS 10.2, *), let device = AVCaptureDevice.default(.builtInDualCamera, for: .video, position: position) {
return device
} else if let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: position) {
return device
}
return nil
}

func configureFrameRate() {
guard let device = self.currentCaptureDevice else {
return
}
for vFormat in device.formats {
let dimensions = CMVideoFormatDescriptionGetDimensions(vFormat.formatDescription)
let ranges = vFormat.videoSupportedFrameRateRanges as [AVFrameRateRange]
guard let frameRate = ranges.first else {
continue
}
if frameRate.maxFrameRate >= Float64(self.frameRate) &&
frameRate.minFrameRate <= Float64(self.frameRate) &&
self.resolution.getDimensions().width == dimensions.width &&
self.resolution.getDimensions().height == dimensions.height &&
CMFormatDescriptionGetMediaSubType(vFormat.formatDescription) == 875704422 { // meant for full range 420f
do {
try device.lockForConfiguration()
device.activeFormat = vFormat as AVCaptureDevice.Format
device.activeVideoMinFrameDuration = CMTimeMake(1, Int32(self.frameRate))
device.activeVideoMaxFrameDuration = CMTimeMake(1, Int32(self.frameRate))
device.unlockForConfiguration()
break
} catch {
continue
}
}
}
}

func updateZoom() {
guard let input = self.videoInput else {
return
}
let device = input.device
do {
try device.lockForConfiguration()
let newZoomScale = min(maxZoomScale, max(Float(1.0), min(currentZoomScale, Float(device.activeFormat.videoMaxZoomFactor))))
device.videoZoomFactor = CGFloat(newZoomScale)
device.unlockForConfiguration()
} catch {
device.unlockForConfiguration()
}
}
}
35 changes: 35 additions & 0 deletions Lumina/Lumina/Camera/Extensions/CapturePhotoExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// CapturePhotoExtension.swift
// Lumina
//
// Created by David Okun on 11/20/17.
// Copyright © 2017 David Okun. All rights reserved.
//

import Foundation
import AVFoundation

@available (iOS 11.0, *)
extension AVCapturePhoto {
func normalizedImage(forCameraPosition position: CameraPosition) -> UIImage? {
guard let cgImage = self.cgImageRepresentation() else {
return nil
}
return UIImage(cgImage: cgImage.takeUnretainedValue(), scale: 1.0, orientation: getImageOrientation(forCamera: position))
}

private func getImageOrientation(forCamera: CameraPosition) -> UIImageOrientation {
switch UIApplication.shared.statusBarOrientation {
case .landscapeLeft:
return forCamera == .back ? .down : .upMirrored
case .landscapeRight:
return forCamera == .back ? .up : .downMirrored
case .portraitUpsideDown:
return forCamera == .back ? .left : .rightMirrored
case .portrait:
return forCamera == .back ? .right : .leftMirrored
case .unknown:
return forCamera == .back ? .right : .leftMirrored
}
}
}
23 changes: 23 additions & 0 deletions Lumina/Lumina/Camera/Extensions/Delegates/DepthDataExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//
// DepthDataExtension.swift
// Lumina
//
// Created by David Okun on 11/20/17.
// Copyright © 2017 David Okun. All rights reserved.
//

import Foundation
import AVFoundation

@available(iOS 11.0, *)
extension LuminaCamera: AVCaptureDepthDataOutputDelegate {
func depthDataOutput(_ output: AVCaptureDepthDataOutput, didOutput depthData: AVDepthData, timestamp: CMTime, connection: AVCaptureConnection) {
DispatchQueue.main.async {
self.delegate?.depthDataCaptured(camera: self, depthData: depthData)
}
}

func depthDataOutput(_ output: AVCaptureDepthDataOutput, didDrop depthData: AVDepthData, timestamp: CMTime, connection: AVCaptureConnection, reason: AVCaptureOutput.DataDroppedReason) {
// place to handle dropped AVDepthData if we need it
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// LuminaCamera+FileOutputRecordingDelegate.swift
// Lumina
//
// Created by David Okun on 11/20/17.
// Copyright © 2017 David Okun. All rights reserved.
//

import Foundation
import AVFoundation

extension LuminaCamera: AVCaptureFileOutputRecordingDelegate {
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
DispatchQueue.main.async {
if error == nil, let delegate = self.delegate {
delegate.videoRecordingCaptured(camera: self, videoURL: outputFileURL)
}
}
}

func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) {
if self.captureLivePhotos {
self.delegate?.cameraBeganTakingLivePhoto(camera: self)
}
}

func photoOutput(_ output: AVCapturePhotoOutput, didFinishRecordingLivePhotoMovieForEventualFileAt outputFileURL: URL, resolvedSettings: AVCaptureResolvedPhotoSettings) {
if self.captureLivePhotos {
self.delegate?.cameraFinishedTakingLivePhoto(camera: self)
}
}

//swiftlint:disable function_parameter_count
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingLivePhotoToMovieFileAt outputFileURL: URL, duration: CMTime, photoDisplayTime: CMTime, resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) {
photoCollectionQueue.sync {
if self.currentPhotoCollection == nil {
var collection = LuminaPhotoCapture()
collection.camera = self
collection.livePhotoURL = outputFileURL
self.currentPhotoCollection = collection
} else {
guard var collection = self.currentPhotoCollection else {
return
}
collection.camera = self
collection.livePhotoURL = outputFileURL
self.currentPhotoCollection = collection
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// MetadataOutputDelegateExtension.swift
// Lumina
//
// Created by David Okun on 11/20/17.
// Copyright © 2017 David Okun. All rights reserved.
//

import Foundation
import AVFoundation

extension LuminaCamera: AVCaptureMetadataOutputObjectsDelegate {
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
guard case self.trackMetadata = true else {
return
}
DispatchQueue.main.async {
self.delegate?.detected(camera: self, metadata: metadataObjects)
}
}
}
Loading

0 comments on commit f1cc93f

Please sign in to comment.