@capacitor-community/camera-preview 1.1.3 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/esm/web.js CHANGED
@@ -1,12 +1,3 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import { WebPlugin } from "@capacitor/core";
11
2
  export class CameraPreviewWeb extends WebPlugin {
12
3
  constructor() {
@@ -15,85 +6,109 @@ export class CameraPreviewWeb extends WebPlugin {
15
6
  platforms: ["web"],
16
7
  });
17
8
  }
18
- start(options) {
19
- return __awaiter(this, void 0, void 0, function* () {
20
- return new Promise((resolve, reject) => {
21
- navigator.mediaDevices.getUserMedia({ audio: true, video: true });
22
- const video = document.getElementById("video");
23
- const parent = document.getElementById(options.parent);
24
- if (!video) {
25
- const videoElement = document.createElement("video");
26
- videoElement.id = "video";
27
- videoElement.setAttribute("class", options.className || "");
9
+ async start(options) {
10
+ return new Promise(async (resolve, reject) => {
11
+ await navigator.mediaDevices.getUserMedia({
12
+ audio: !options.disableAudio,
13
+ video: true
14
+ }).then((stream) => {
15
+ // Stop any existing stream so we can request media with different constraints based on user input
16
+ stream.getTracks().forEach((track) => track.stop());
17
+ }).catch(error => {
18
+ reject(error);
19
+ });
20
+ const video = document.getElementById("video");
21
+ const parent = document.getElementById(options.parent);
22
+ if (!video) {
23
+ const videoElement = document.createElement("video");
24
+ videoElement.id = "video";
25
+ videoElement.setAttribute("class", options.className || "");
26
+ // Don't flip video feed if camera is rear facing
27
+ if (options.position !== 'rear') {
28
28
  videoElement.setAttribute("style", "-webkit-transform: scaleX(-1); transform: scaleX(-1);");
29
- parent.appendChild(videoElement);
30
- if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
31
- // Not adding `{ audio: true }` since we only want video now
32
- navigator.mediaDevices.getUserMedia({ video: true }).then(function (stream) {
33
- //video.src = window.URL.createObjectURL(stream);
34
- videoElement.srcObject = stream;
35
- videoElement.play();
36
- resolve();
37
- }, (err) => {
38
- reject(err);
39
- });
40
- }
41
29
  }
42
- else {
43
- reject({ message: "camera already started" });
30
+ const userAgent = navigator.userAgent.toLowerCase();
31
+ const isSafari = userAgent.includes('safari') && !userAgent.includes('chrome');
32
+ // Safari on iOS needs to have the autoplay, muted and playsinline attributes set for video.play() to be successful
33
+ // Without these attributes videoElement.play() will throw a NotAllowedError
34
+ // https://developer.apple.com/documentation/webkit/delivering_video_content_for_safari
35
+ if (isSafari) {
36
+ videoElement.setAttribute('autoplay', 'true');
37
+ videoElement.setAttribute('muted', 'true');
38
+ videoElement.setAttribute('playsinline', 'true');
44
39
  }
45
- });
46
- });
47
- }
48
- stop() {
49
- return __awaiter(this, void 0, void 0, function* () {
50
- const video = document.getElementById("video");
51
- if (video) {
52
- video.pause();
53
- const st = video.srcObject;
54
- const tracks = st.getTracks();
55
- for (var i = 0; i < tracks.length; i++) {
56
- var track = tracks[i];
57
- track.stop();
40
+ parent.appendChild(videoElement);
41
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
42
+ const constraints = {
43
+ video: true,
44
+ };
45
+ if (options.position === 'rear') {
46
+ constraints.video = { facingMode: 'environment' };
47
+ this.isBackCamera = true;
48
+ }
49
+ else {
50
+ this.isBackCamera = false;
51
+ }
52
+ navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
53
+ //video.src = window.URL.createObjectURL(stream);
54
+ videoElement.srcObject = stream;
55
+ videoElement.play();
56
+ resolve({});
57
+ }, (err) => {
58
+ reject(err);
59
+ });
58
60
  }
59
- video.remove();
61
+ }
62
+ else {
63
+ reject({ message: "camera already started" });
60
64
  }
61
65
  });
62
66
  }
63
- capture(_options) {
64
- return __awaiter(this, void 0, void 0, function* () {
65
- return new Promise((resolve, _) => {
66
- const video = document.getElementById("video");
67
- const canvas = document.createElement("canvas");
68
- // video.width = video.offsetWidth;
69
- const context = canvas.getContext("2d");
70
- canvas.width = video.videoWidth;
71
- canvas.height = video.videoHeight;
67
+ async stop() {
68
+ const video = document.getElementById("video");
69
+ if (video) {
70
+ video.pause();
71
+ const st = video.srcObject;
72
+ const tracks = st.getTracks();
73
+ for (var i = 0; i < tracks.length; i++) {
74
+ var track = tracks[i];
75
+ track.stop();
76
+ }
77
+ video.remove();
78
+ }
79
+ }
80
+ async capture(_options) {
81
+ return new Promise((resolve, _) => {
82
+ const video = document.getElementById("video");
83
+ const canvas = document.createElement("canvas");
84
+ // video.width = video.offsetWidth;
85
+ const context = canvas.getContext("2d");
86
+ canvas.width = video.videoWidth;
87
+ canvas.height = video.videoHeight;
88
+ // flip horizontally back camera isn't used
89
+ if (!this.isBackCamera) {
72
90
  context.translate(video.videoWidth, 0);
73
91
  context.scale(-1, 1);
74
- context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
75
- resolve({
76
- value: canvas
77
- .toDataURL("image/png")
78
- .replace("data:image/png;base64,", ""),
79
- });
92
+ }
93
+ context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
94
+ resolve({
95
+ value: canvas
96
+ .toDataURL("image/png")
97
+ .replace("data:image/png;base64,", ""),
80
98
  });
81
99
  });
82
100
  }
83
- getSupportedFlashModes() {
84
- return __awaiter(this, void 0, void 0, function* () {
85
- throw new Error('getSupportedFlashModes not supported under the web platform');
86
- });
101
+ async captureSample(_options) {
102
+ return this.capture(_options);
87
103
  }
88
- setFlashMode(_options) {
89
- return __awaiter(this, void 0, void 0, function* () {
90
- throw new Error('setFlashMode not supported under the web platform');
91
- });
104
+ async getSupportedFlashModes() {
105
+ throw new Error('getSupportedFlashModes not supported under the web platform');
92
106
  }
93
- flip() {
94
- return __awaiter(this, void 0, void 0, function* () {
95
- throw new Error('flip not supported under the web platform');
96
- });
107
+ async setFlashMode(_options) {
108
+ throw new Error('setFlashMode not supported under the web platform');
109
+ }
110
+ async flip() {
111
+ throw new Error('flip not supported under the web platform');
97
112
  }
98
113
  }
99
114
  const CameraPreview = new CameraPreviewWeb();
@@ -1 +1 @@
1
- {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ class CameraController: NSObject {
17
17
  var frontCamera: AVCaptureDevice?
18
18
  var frontCameraInput: AVCaptureDeviceInput?
19
19
 
20
+ var dataOutput: AVCaptureVideoDataOutput?
20
21
  var photoOutput: AVCapturePhotoOutput?
21
22
 
22
23
  var rearCamera: AVCaptureDevice?
@@ -26,6 +27,13 @@ class CameraController: NSObject {
26
27
 
27
28
  var flashMode = AVCaptureDevice.FlashMode.off
28
29
  var photoCaptureCompletionBlock: ((UIImage?, Error?) -> Void)?
30
+
31
+ var sampleBufferCaptureCompletionBlock: ((UIImage?, Error?) -> Void)?
32
+
33
+ var highResolutionOutput: Bool = false
34
+
35
+ var audioDevice: AVCaptureDevice?
36
+ var audioInput: AVCaptureDeviceInput?
29
37
  }
30
38
 
31
39
  extension CameraController {
@@ -33,209 +41,237 @@ extension CameraController {
33
41
  func createCaptureSession() {
34
42
  self.captureSession = AVCaptureSession()
35
43
  }
36
-
44
+
37
45
  func configureCaptureDevices() throws {
38
-
46
+
39
47
  let session = AVCaptureDevice.DiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaType.video, position: .unspecified)
40
-
48
+
41
49
  let cameras = session.devices.compactMap { $0 }
42
50
  guard !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable }
43
-
51
+
44
52
  for camera in cameras {
45
53
  if camera.position == .front {
46
54
  self.frontCamera = camera
47
55
  }
48
-
56
+
49
57
  if camera.position == .back {
50
58
  self.rearCamera = camera
51
-
59
+
52
60
  try camera.lockForConfiguration()
53
61
  camera.focusMode = .continuousAutoFocus
54
62
  camera.unlockForConfiguration()
55
63
  }
56
64
  }
65
+ self.audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)
57
66
  }
58
-
67
+
59
68
  func configureDeviceInputs() throws {
60
69
  guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }
61
-
70
+
62
71
  if cameraPosition == "rear" {
63
72
  if let rearCamera = self.rearCamera {
64
73
  self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)
65
-
74
+
66
75
  if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) }
67
-
76
+
68
77
  self.currentCameraPosition = .rear
69
78
  }
70
79
  } else if cameraPosition == "front" {
71
80
  if let frontCamera = self.frontCamera {
72
81
  self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)
73
-
82
+
74
83
  if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) }
75
84
  else { throw CameraControllerError.inputsAreInvalid }
76
-
85
+
77
86
  self.currentCameraPosition = .front
78
87
  }
79
88
  } else { throw CameraControllerError.noCamerasAvailable }
89
+
90
+ // Add audio input
91
+ if let audioDevice = self.audioDevice {
92
+ self.audioInput = try AVCaptureDeviceInput(device: audioDevice)
93
+ if captureSession.canAddInput(self.audioInput!) {
94
+ captureSession.addInput(self.audioInput!)
95
+ } else {
96
+ throw CameraControllerError.inputsAreInvalid
97
+ }
98
+ }
80
99
  }
81
-
100
+
82
101
  func configurePhotoOutput() throws {
83
102
  guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }
84
-
103
+
85
104
  self.photoOutput = AVCapturePhotoOutput()
86
105
  self.photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecType.jpeg])], completionHandler: nil)
106
+ self.photoOutput?.isHighResolutionCaptureEnabled = self.highResolutionOutput
87
107
  if captureSession.canAddOutput(self.photoOutput!) { captureSession.addOutput(self.photoOutput!) }
88
108
  captureSession.startRunning()
89
109
  }
90
-
110
+
111
+ func configureDataOutput() throws {
112
+ guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing }
113
+
114
+ self.dataOutput = AVCaptureVideoDataOutput()
115
+ self.dataOutput?.videoSettings = [
116
+ (kCVPixelBufferPixelFormatTypeKey as String): NSNumber(value: kCVPixelFormatType_32BGRA as UInt32)
117
+ ]
118
+ self.dataOutput?.alwaysDiscardsLateVideoFrames = true
119
+ if captureSession.canAddOutput(self.dataOutput!) {
120
+ captureSession.addOutput(self.dataOutput!)
121
+ }
122
+
123
+ captureSession.commitConfiguration()
124
+
125
+ let queue = DispatchQueue(label: "DataOutput", attributes: [])
126
+ self.dataOutput?.setSampleBufferDelegate(self, queue: queue)
127
+ }
128
+
91
129
  DispatchQueue(label: "prepare").async {
92
130
  do {
93
131
  createCaptureSession()
94
132
  try configureCaptureDevices()
95
133
  try configureDeviceInputs()
96
134
  try configurePhotoOutput()
135
+ try configureDataOutput()
136
+ //try configureVideoOutput()
97
137
  }
98
-
138
+
99
139
  catch {
100
140
  DispatchQueue.main.async {
101
141
  completionHandler(error)
102
142
  }
103
-
143
+
104
144
  return
105
145
  }
106
-
146
+
107
147
  DispatchQueue.main.async {
148
+ self.updateVideoOrientation()
149
+
108
150
  completionHandler(nil)
109
151
  }
110
152
  }
111
153
  }
112
-
154
+
113
155
  func displayPreview(on view: UIView) throws {
114
156
  guard let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing }
115
-
157
+
116
158
  self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
117
159
  self.previewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
118
-
119
- let orientation: UIDeviceOrientation = UIDevice.current.orientation
120
- let statusBarOrientation = UIApplication.shared.statusBarOrientation
121
- switch (orientation) {
160
+
161
+ view.layer.insertSublayer(self.previewLayer!, at: 0)
162
+ self.previewLayer?.frame = view.frame
163
+ }
164
+
165
+ func updateVideoOrientation() {
166
+ assert(Thread.isMainThread) // UIApplication.statusBarOrientation requires the main thread.
167
+
168
+ let videoOrientation: AVCaptureVideoOrientation
169
+ switch UIDevice.current.orientation {
122
170
  case .portrait:
123
- self.previewLayer?.connection?.videoOrientation = .portrait
124
- case .landscapeRight:
125
- self.previewLayer?.connection?.videoOrientation = .landscapeLeft
171
+ videoOrientation = .portrait
126
172
  case .landscapeLeft:
127
- self.previewLayer?.connection?.videoOrientation = .landscapeRight
173
+ videoOrientation = .landscapeRight
174
+ case .landscapeRight:
175
+ videoOrientation = .landscapeLeft
128
176
  case .portraitUpsideDown:
129
- self.previewLayer?.connection?.videoOrientation = .portraitUpsideDown
130
- case .faceUp, .faceDown:
131
- switch (statusBarOrientation) {
177
+ videoOrientation = .portraitUpsideDown
178
+ case .faceUp, .faceDown, .unknown:
179
+ fallthrough
180
+ @unknown default:
181
+ switch UIApplication.shared.statusBarOrientation {
132
182
  case .portrait:
133
- self.previewLayer?.connection?.videoOrientation = .portrait
134
- case .landscapeRight:
135
- self.previewLayer?.connection?.videoOrientation = .landscapeRight
183
+ videoOrientation = .portrait
136
184
  case .landscapeLeft:
137
- self.previewLayer?.connection?.videoOrientation = .landscapeLeft
185
+ videoOrientation = .landscapeLeft
186
+ case .landscapeRight:
187
+ videoOrientation = .landscapeRight
138
188
  case .portraitUpsideDown:
139
- self.previewLayer?.connection?.videoOrientation = .portraitUpsideDown
140
- default:
141
- self.previewLayer?.connection?.videoOrientation = .portrait
189
+ videoOrientation = .portraitUpsideDown
190
+ case .unknown:
191
+ fallthrough
192
+ @unknown default:
193
+ videoOrientation = .portrait
142
194
  }
143
- default:
144
- self.previewLayer?.connection?.videoOrientation = .portrait
145
195
  }
146
-
147
- view.layer.insertSublayer(self.previewLayer!, at: 0)
148
- self.previewLayer?.frame = view.frame
196
+
197
+ previewLayer?.connection?.videoOrientation = videoOrientation
198
+ dataOutput?.connections.forEach { $0.videoOrientation = videoOrientation }
149
199
  }
150
-
200
+
151
201
  func switchCameras() throws {
152
202
  guard let currentCameraPosition = currentCameraPosition, let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing }
153
-
203
+
154
204
  captureSession.beginConfiguration()
155
-
205
+
156
206
  func switchToFrontCamera() throws {
157
-
207
+
158
208
  guard let rearCameraInput = self.rearCameraInput, captureSession.inputs.contains(rearCameraInput),
159
209
  let frontCamera = self.frontCamera else { throw CameraControllerError.invalidOperation }
160
-
210
+
161
211
  self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera)
162
-
212
+
163
213
  captureSession.removeInput(rearCameraInput)
164
-
214
+
165
215
  if captureSession.canAddInput(self.frontCameraInput!) {
166
216
  captureSession.addInput(self.frontCameraInput!)
167
-
217
+
168
218
  self.currentCameraPosition = .front
169
219
  }
170
-
220
+
171
221
  else {
172
222
  throw CameraControllerError.invalidOperation
173
223
  }
174
224
  }
175
-
225
+
176
226
  func switchToRearCamera() throws {
177
-
227
+
178
228
  guard let frontCameraInput = self.frontCameraInput, captureSession.inputs.contains(frontCameraInput),
179
229
  let rearCamera = self.rearCamera else { throw CameraControllerError.invalidOperation }
180
-
230
+
181
231
  self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera)
182
-
232
+
183
233
  captureSession.removeInput(frontCameraInput)
184
-
234
+
185
235
  if captureSession.canAddInput(self.rearCameraInput!) {
186
236
  captureSession.addInput(self.rearCameraInput!)
187
-
237
+
188
238
  self.currentCameraPosition = .rear
189
239
  }
190
-
240
+
191
241
  else { throw CameraControllerError.invalidOperation }
192
242
  }
193
-
243
+
194
244
  switch currentCameraPosition {
195
245
  case .front:
196
246
  try switchToRearCamera()
197
-
247
+
198
248
  case .rear:
199
249
  try switchToFrontCamera()
200
250
  }
201
-
251
+
202
252
  captureSession.commitConfiguration()
203
253
  }
204
-
254
+
205
255
  func captureImage(completion: @escaping (UIImage?, Error?) -> Void) {
206
256
  guard let captureSession = captureSession, captureSession.isRunning else { completion(nil, CameraControllerError.captureSessionIsMissing); return }
207
257
  let settings = AVCapturePhotoSettings()
258
+
208
259
  settings.flashMode = self.flashMode
209
- let currentDevice: UIDevice = .current
210
- let deviceOrientation: UIDeviceOrientation = currentDevice.orientation
211
- let statusBarOrientation = UIApplication.shared.statusBarOrientation
212
- if deviceOrientation == .portrait {
213
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.portrait
214
- }else if (deviceOrientation == .landscapeLeft){
215
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
216
- }else if (deviceOrientation == .landscapeRight){
217
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
218
- }else if (deviceOrientation == .portraitUpsideDown){
219
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
220
- }else if (deviceOrientation == .faceUp || deviceOrientation == .faceDown){
221
- switch (statusBarOrientation) {
222
- case .portrait:
223
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.portrait
224
- case .landscapeRight:
225
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
226
- case .landscapeLeft:
227
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
228
- case .portraitUpsideDown:
229
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
230
- default:
231
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.portrait
232
- }
233
- }else {
234
- self.photoOutput?.connection(with: AVMediaType.video)?.videoOrientation = AVCaptureVideoOrientation.portrait
235
- }
260
+ settings.isHighResolutionPhotoEnabled = self.highResolutionOutput;
261
+
236
262
  self.photoOutput?.capturePhoto(with: settings, delegate: self)
237
263
  self.photoCaptureCompletionBlock = completion
238
264
  }
265
+
266
+ func captureSample(completion: @escaping (UIImage?, Error?) -> Void) {
267
+ guard let captureSession = captureSession,
268
+ captureSession.isRunning else {
269
+ completion(nil, CameraControllerError.captureSessionIsMissing)
270
+ return
271
+ }
272
+
273
+ self.sampleBufferCaptureCompletionBlock = completion
274
+ }
239
275
 
240
276
  func getSupportedFlashModes() throws -> [String] {
241
277
  var currentCamera: AVCaptureDevice?
@@ -353,6 +389,31 @@ extension CameraController {
353
389
  }
354
390
 
355
391
  }
392
+
393
+ func captureVideo(completion: @escaping (URL?, Error?) -> Void) {
394
+ guard let captureSession = self.captureSession, captureSession.isRunning else {
395
+ completion(nil, CameraControllerError.captureSessionIsMissing)
396
+ return
397
+ }
398
+ let path = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)[0]
399
+ let identifier = UUID()
400
+ let randomIdentifier = identifier.uuidString.replacingOccurrences(of: "-", with: "")
401
+ let finalIdentifier = String(randomIdentifier.prefix(8))
402
+ let fileName="cpcp_video_"+finalIdentifier+".mp4"
403
+
404
+ let fileUrl = path.appendingPathComponent(fileName)
405
+ try? FileManager.default.removeItem(at: fileUrl)
406
+ /*videoOutput!.startRecording(to: fileUrl, recordingDelegate: self)
407
+ self.videoRecordCompletionBlock = completion*/
408
+ }
409
+
410
+ func stopRecording(completion: @escaping (Error?) -> Void) {
411
+ guard let captureSession = self.captureSession, captureSession.isRunning else {
412
+ completion(CameraControllerError.captureSessionIsMissing)
413
+ return
414
+ }
415
+ //self.videoOutput?.stopRecording()
416
+ }
356
417
  }
357
418
 
358
419
  extension CameraController: AVCapturePhotoCaptureDelegate {
@@ -371,6 +432,48 @@ extension CameraController: AVCapturePhotoCaptureDelegate {
371
432
  }
372
433
  }
373
434
 
435
+ extension CameraController: AVCaptureVideoDataOutputSampleBufferDelegate {
436
+ func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
437
+ guard let completion = sampleBufferCaptureCompletionBlock else { return }
438
+
439
+ guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
440
+ completion(nil, CameraControllerError.unknown)
441
+ return
442
+ }
443
+
444
+ CVPixelBufferLockBaseAddress(imageBuffer, .readOnly)
445
+ defer { CVPixelBufferUnlockBaseAddress(imageBuffer, .readOnly) }
446
+
447
+ let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)
448
+ let bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer)
449
+ let width = CVPixelBufferGetWidth(imageBuffer)
450
+ let height = CVPixelBufferGetHeight(imageBuffer)
451
+ let colorSpace = CGColorSpaceCreateDeviceRGB()
452
+ let bitmapInfo: UInt32 = CGBitmapInfo.byteOrder32Little.rawValue |
453
+ CGImageAlphaInfo.premultipliedFirst.rawValue
454
+
455
+ let context = CGContext(
456
+ data: baseAddress,
457
+ width: width,
458
+ height: height,
459
+ bitsPerComponent: 8,
460
+ bytesPerRow: bytesPerRow,
461
+ space: colorSpace,
462
+ bitmapInfo: bitmapInfo
463
+ )
464
+
465
+ guard let cgImage = context?.makeImage() else {
466
+ completion(nil, CameraControllerError.unknown)
467
+ return
468
+ }
469
+
470
+ let image = UIImage(cgImage: cgImage)
471
+ completion(image.fixedOrientation(), nil)
472
+
473
+ sampleBufferCaptureCompletionBlock = nil
474
+ }
475
+ }
476
+
374
477
 
375
478
 
376
479
 
@@ -473,3 +576,13 @@ extension UIImage {
473
576
  return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
474
577
  }
475
578
  }
579
+
580
+ extension CameraController: AVCaptureFileOutputRecordingDelegate {
581
+ func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
582
+ /*if error == nil {
583
+ self.videoRecordCompletionBlock?(outputFileURL, nil)
584
+ } else {
585
+ self.videoRecordCompletionBlock?(nil, error)
586
+ }*/
587
+ }
588
+ }
@@ -7,7 +7,10 @@ CAP_PLUGIN(CameraPreview, "CameraPreview",
7
7
  CAP_PLUGIN_METHOD(start, CAPPluginReturnPromise);
8
8
  CAP_PLUGIN_METHOD(stop, CAPPluginReturnPromise);
9
9
  CAP_PLUGIN_METHOD(capture, CAPPluginReturnPromise);
10
+ CAP_PLUGIN_METHOD(captureSample, CAPPluginReturnPromise);
10
11
  CAP_PLUGIN_METHOD(flip, CAPPluginReturnPromise);
11
12
  CAP_PLUGIN_METHOD(getSupportedFlashModes, CAPPluginReturnPromise);
12
13
  CAP_PLUGIN_METHOD(setFlashMode, CAPPluginReturnPromise);
14
+ CAP_PLUGIN_METHOD(startRecordVideo, CAPPluginReturnPromise);
15
+ CAP_PLUGIN_METHOD(stopRecordVideo, CAPPluginReturnPromise);
13
16
  )