-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathLivePhotoCapture.swift
159 lines (126 loc) · 4.76 KB
/
LivePhotoCapture.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//
// LivePhotoCapture.swift
//
// Created by Edwin Wilson on 31/03/2020.
//
import UIKit
import AVFoundation
fileprivate let infoPlistEntryNotMade = """
'Privacy - Camera Usage Description' , with value as reason for the access inside you application Info.plist as per Apple mandate
"""
protocol LivePhotoCapture:AVCapturePhotoCaptureDelegate where Self: UIViewController {
var captureSession: AVCaptureSession? {get set}
var cameraPreviewLayer: AVCaptureVideoPreviewLayer? {get set}
var photoOutput: AVCapturePhotoOutput? {get set}
/*!
@note this call has to be implemented in conforming class, otherwise it will result in a crash
implementation can not done inside protocol extenstion due to language limitations
@method captureOutput:didFinishProcessingPhoto:error:
@abstract
A callback fired when photos are ready to be delivered to you (RAW or processed).
@param output
The calling instance of AVCapturePhotoOutput.
@param photo
An instance of AVCapturePhoto.
@param error
An error indicating what went wrong. If the photo was processed successfully, nil is returned.
@discussion
This callback fires resolvedSettings.expectedPhotoCount number of times for a given capture request. Note that the photo parameter is always non nil, even if an error is returned. The delivered AVCapturePhoto's rawPhoto property can be queried to know if it's a RAW image or processed image.
*/
func photoOutput(
_ output: AVCapturePhotoOutput,
didFinishProcessingPhoto photo: AVCapturePhoto,
error: Error?
)
}
extension LivePhotoCapture {
func capturePhoto() {
let photosettings = AVCapturePhotoSettings()
photoOutput?.capturePhoto(with: photosettings, delegate: self)
}
func prepareForPhotoCapture(onView: UIView?, cameraPosition: AVCaptureDevice.Position = .unspecified) {
if Bundle.main.infoDictionary?["NSCameraUsageDescription"] == nil {
fatalError(infoPlistEntryNotMade)
}
DispatchQueue.global().async {
self.intilizePhotoCapture(onView, cameraPosition: cameraPosition)
}
}
func startSession() {
DispatchQueue.global().sync {
captureSession?.startRunning()
}
}
func stopSession() {
DispatchQueue.global().async {
self.captureSession?.stopRunning()
}
}
}
//MARK: -
extension LivePhotoCapture {
func processPhoto( photo: AVCapturePhoto) -> UIImage? {
if let imageData = photo.fileDataRepresentation() {
return UIImage(data: imageData)
}
return nil
}
}
//MARK: - Private
extension LivePhotoCapture {
fileprivate func intilizePhotoCapture(_ onView: UIView?, cameraPosition: AVCaptureDevice.Position) {
captureSession = AVCaptureSession()
photoOutput = AVCapturePhotoOutput()
cameraPreviewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession!)
cameraPreviewLayer!.videoGravity = .resizeAspectFill
setupDevice(cameraPosition: cameraPosition)
setupPreview(onView)
startSession()
}
private func setupDevice(cameraPosition: AVCaptureDevice.Position) {
if let camera = AVCaptureDevice.DiscoverySession(
deviceTypes: [.builtInWideAngleCamera, .builtInDualCamera, .builtInTrueDepthCamera],
mediaType: .video,
position: cameraPosition
).devices.first {
setupInputOutput(camera: camera)
} else {
print("Failed to Find Camera")
}
}
private func setupInputOutput(camera: AVCaptureDevice) {
do
{
let captureDeviceInput = try AVCaptureDeviceInput(device: camera)
captureSession?.sessionPreset = AVCaptureSession.Preset.photo
captureSession?.addInput(captureDeviceInput)
photoOutput?.setPreparedPhotoSettingsArray(
[AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.jpeg])],
completionHandler: nil
)
if let output = photoOutput {
captureSession?.addOutput(output)
}
}
catch
{
print(error)
}
}
private func setupPreview(_ onView: UIView?) {
guard let previewLayer = cameraPreviewLayer else { return }
if !Thread.isMainThread {
DispatchQueue.main.async {
self.setupPreview(onView)
}
return
}
if let view = onView {
view.layer.addSublayer(previewLayer)
cameraPreviewLayer?.frame = view.frame
} else {
view.layer.addSublayer(previewLayer)
cameraPreviewLayer?.frame = view.frame
}
}
}