SLProject  4.3.020
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SENSiOSCameraDelegate Class Reference

#import <SENSiOSCameraDelegate.h>

Inherits NSObject, and <AVCaptureVideoDataOutputSampleBufferDelegate>.

Instance Methods

(BOOL) - startCamera:withWidth:andHeight:autoFocusState:videoStabilizationState:intrinsicsState:
 
(BOOL) - stopCamera
 
(SENSCaptureProps- retrieveCaptureProperties
 
(id) - init [implementation]
 
(void- captureOutput:didOutputSampleBuffer:fromConnection: [implementation]
 
(void- videoCameraStarted: [implementation]
 
(void- printActiveFormat [implementation]
 
(void- checkPermission [implementation]
 

Properties

std::function< void(unsigned char *, int, int, matrix_float3x3 *)> updateCB
 
std::function< void(bool)> permissionCB
 

Private Attributes

AVCaptureSession * _captureSession
 
AVCaptureDevice * _camera
 
AVCaptureDeviceInput * _cameraInput
 
AVCaptureVideoDataOutput * _videoOutput
 
BOOL _cameraIntrinsicsDelivery
 

Detailed Description

Definition at line 11 of file SENSiOSCameraDelegate.h.

Method Documentation

◆ captureOutput:didOutputSampleBuffer:fromConnection:

- (void) captureOutput: (AVCaptureOutput*)  captureOutput
didOutputSampleBuffer: (CMSampleBufferRef)  sampleBuffer
fromConnection: (AVCaptureConnection*)  connection 
implementation

Definition at line 19 of file SENSiOSCameraDelegate.mm.

47  :(AVCaptureOutput*)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection*)connection
48 {
49  // Check if this is the output we are expecting:
50  if (captureOutput == _videoOutput)
51  {
52  // If it's a video frame, copy and process it
53  CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
54 
55  CVReturn ret = CVPixelBufferLockBaseAddress(pixelBuffer, 0);
56  if (ret != kCVReturnSuccess)
57  return;
58 
59  int imgWidth = (int)CVPixelBufferGetWidth(pixelBuffer);
60  int imgHeight = (int)CVPixelBufferGetHeight(pixelBuffer);
61  unsigned char* data = (unsigned char*)CVPixelBufferGetBaseAddress(pixelBuffer);
62 
63  if (!data)
64  {
65  NSLog(@"No pixel buffer data");
66  return;
67  }
68 
69  matrix_float3x3* camMatrix = nil;
71  {
72  CFTypeRef cameraIntrinsicData = CMGetAttachment(sampleBuffer, kCMSampleBufferAttachmentKey_CameraIntrinsicMatrix, nil);
73  if (cameraIntrinsicData != nil)
74  {
75  CFDataRef cfdr = (CFDataRef)(cameraIntrinsicData);
76  (CFDataGetBytePtr(cfdr));
77  camMatrix = (matrix_float3x3*)(CFDataGetBytePtr(cfdr));
78  }
79  }
80 
81  if (_updateCB)
82  {
83  _updateCB(data, imgWidth, imgHeight, camMatrix);
84  }
85 
86  CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
87  }
88 }
AVCaptureVideoDataOutput * _videoOutput

◆ checkPermission

- (void) checkPermission
implementation

Definition at line 19 of file SENSiOSCameraDelegate.mm.

354 {
355  NSString* mediaType = AVMediaTypeVideo;
356  AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
357  if (authStatus == AVAuthorizationStatusAuthorized)
358  {
359  if (_permissionCB)
360  _permissionCB(true);
361  }
362  else if (authStatus == AVAuthorizationStatusDenied)
363  {
364  if (_permissionCB)
365  _permissionCB(false);
366  }
367  else if (authStatus == AVAuthorizationStatusRestricted)
368  {
369  // restricted, normally won't happen
370  }
371  else if (authStatus == AVAuthorizationStatusNotDetermined)
372  {
373  // not determined?!
374  [AVCaptureDevice requestAccessForMediaType:mediaType
375  completionHandler:^(BOOL granted) {
376  if (granted)
377  {
378  NSLog(@"Granted access to %@", mediaType);
379  if (_permissionCB)
380  _permissionCB(true);
381  }
382  else
383  {
384  NSLog(@"Not granted access to %@", mediaType);
385  if (_permissionCB)
386  _permissionCB(false);
387  }
388  }];
389  }
390 }

◆ init

- (id) init
implementation

Definition at line 19 of file SENSiOSCameraDelegate.mm.

27 {
28  //Initialize the parent class(es) up the hierarchy and create self:
29  self = [super init];
30 
31  //Initialize members (not necessary with ARC)
32  _captureSession = nil;
33  _camera = nil;
34  _cameraInput = nil;
35  _videoOutput = nil;
36 
38 
39  if (self)
40  {
41  [self checkPermission];
42  }
43 
44  return self;
45 }
AVCaptureDeviceInput * _cameraInput
AVCaptureSession * _captureSession

◆ printActiveFormat

- (void) printActiveFormat
implementation

Definition at line 19 of file SENSiOSCameraDelegate.mm.

100 {
101  if (_camera == nil)
102  return;
103 
104  AVCaptureDeviceFormat* currFormat = [_camera activeFormat];
105  CMFormatDescriptionRef formatDesc = [currFormat formatDescription];
106  if (formatDesc)
107  {
108  CMVideoDimensions dims = CMVideoFormatDescriptionGetDimensions(formatDesc);
109  printf("active format: w %d h %d", dims.width, dims.height);
110  }
111 }

◆ retrieveCaptureProperties

- (SENSCaptureProps) retrieveCaptureProperties

Definition at line 19 of file SENSiOSCameraDelegate.mm.

304 {
305  SENSCaptureProps characsVec;
306 
307  // specifying AVMediaTypeVideo will ensure we only get a list of cameras, no microphones
308  NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
309 
310  for (AVCaptureDevice* device in devices)
311  {
312  //device id
313  std::string deviceId = [[device uniqueID] UTF8String];
314  SENSCameraFacing facing;
315  //facing
316  if (AVCaptureDevicePositionFront == [device position])
317  facing = SENSCameraFacing::FRONT;
318  else if (AVCaptureDevicePositionBack == [device position])
319  facing = SENSCameraFacing::BACK;
320  else
321  facing = SENSCameraFacing::UNKNOWN;
322 
323  SENSCameraDeviceProps characs(deviceId, facing);
324 
325  NSArray<AVCaptureDeviceFormat*>* deviceFormats = [device formats];
326  for (AVCaptureDeviceFormat* format in deviceFormats)
327  {
328  CMFormatDescriptionRef formatDesc = [format formatDescription];
329  if (formatDesc)
330  {
331  //todo: for all formats setup a video output and check for intrinsics and
332 
333  CMVideoDimensions dims = CMVideoFormatDescriptionGetDimensions(formatDesc);
334  int w = dims.width;
335  int h = dims.height;
336  //printf("dims: w %d h %d\n", w, h);
337  if (!characs.contains({w, h}))
338  {
339  //calculate focal length in pixel from horizontal field of view
340  float horizFovDeg = [format videoFieldOfView];
341  float focalLengthPix = SENS::calcFocalLengthPixFromFOVDeg(horizFovDeg, w);
342 
343  characs.add(w, h, focalLengthPix);
344  }
345  }
346  }
347 
348  characsVec.push_back(characs);
349  }
350  return characsVec;
351 }
SENSCameraFacing
Definition of camera facing.
Definition: SENSCamera.h:28
float calcFocalLengthPixFromFOVDeg(const float fovDeg, const int imgLength)
Definition: SENSUtils.cpp:199

◆ startCamera:withWidth:andHeight:autoFocusState:videoStabilizationState:intrinsicsState:

- (BOOL) startCamera: (NSString*)  deviceId
withWidth: (int)  width
andHeight: (int)  height
autoFocusState: (BOOL)  autoFocusEnabled
videoStabilizationState: (BOOL)  videoStabilizationEnabled
intrinsicsState: (BOOL)  provideIntrinsics 

Definition at line 19 of file SENSiOSCameraDelegate.mm.

113  :(NSString*)deviceId
114  withWidth:(int)width
115  andHeight:(int)height
116  autoFocusState:(BOOL)autoFocusEnabled
117  videoStabilizationState:(BOOL)videoStabilizationEnabled
118  intrinsicsState:(BOOL)provideIntrinsics
119 {
120  // Make sure we initialize our camera pointer:
121  _camera = nil;
122 
123  // specifying AVMediaTypeVideo will ensure we only get a list of cameras, no microphones
124  NSArray* devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
125 
126  for (AVCaptureDevice* device in devices)
127  {
128  if ([device uniqueID] == deviceId)
129  {
130  _camera = device;
131  break;
132  }
133  }
134 
135  if (_camera == nil)
136  return NO;
137 
138  //We set the format directly on the device to get all available configurations (not all are available on AVCaptureSession)
139  //see: https://developer.apple.com/documentation/avfoundation/avcapturedevice?language=objc
140  //see: https://stackoverflow.com/questions/36689578/avfoundation-capturing-video-with-custom-resolution/40097057
141  //find best corresponding format
142  AVCaptureDeviceFormat* bestFormat = nil;
143  AVFrameRateRange* bestRange = nil;
144 
145  for (AVCaptureDeviceFormat* format in [_camera formats])
146  {
147  CMFormatDescriptionRef formatDesc = [format formatDescription];
148  if (formatDesc)
149  {
150  CMVideoDimensions dims = CMVideoFormatDescriptionGetDimensions(formatDesc);
151  if (dims.width == width && dims.height == height)
152  {
153  //std::cout << "w " << dims.width << " h " << dims.height << std::endl;
154  for (AVFrameRateRange* range in [format videoSupportedFrameRateRanges])
155  {
156  //std::cout << "min fps " << range.minFrameRate << " max fps " << range.maxFrameRate << std::endl;
157  if (bestRange == nil || bestRange.maxFrameRate < range.maxFrameRate)
158  {
159  bestFormat = format;
160  bestRange = range;
161  }
162  }
163  }
164  }
165  }
166 
167  // Set a frame rate for the camera:
168  // We first need to lock the camera, so no one else can mess with its configuration:
169  if ([_camera lockForConfiguration:nil])
170  {
171  // Set the device's active format.
172  [_camera setActiveFormat:bestFormat];
173  //[self printActiveFormat];
174 
175  // Set the device's min/max frame duration.
176  CMTime duration = [bestRange minFrameDuration];
177  [_camera setActiveVideoMinFrameDuration:duration];
178  [_camera setActiveVideoMaxFrameDuration:duration];
179 
180  //parameterize focus mode
181  if (autoFocusEnabled)
182  [_camera setFocusMode:AVCaptureFocusModeContinuousAutoFocus];
183  else
184  [_camera setFocusModeLockedWithLensPosition:1.0 completionHandler:nil];
185 
186  //we set geometric distortion correction to no for now because we dont know how it influences the camera intrinsics
187  if (@available(iOS 13.0, *))
188  {
189  if ([_camera isGeometricDistortionCorrectionSupported])
190  {
191  [_camera setGeometricDistortionCorrectionEnabled:NO];
192  }
193  }
194 
195  //Make sure we have a capture session
196  if (nil == _captureSession)
197  {
198  _captureSession = [[AVCaptureSession alloc] init];
199  }
200 
201  //disable that video device active format is overwritten
202  [_captureSession setAutomaticallyConfiguresCaptureDeviceForWideColor:NO];
203  //again: setting session present to AVCaptureSessionPresetInputPriority enabled that the previously set format on the video device is not overwritten
204  if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetInputPriority])
205  [_captureSession setSessionPreset:AVCaptureSessionPresetInputPriority];
206 
207  // Plug camera and capture sesiossion together:
208  {
209  // Request a camera input from the camera
210  NSError* error = nil;
211  _cameraInput = [AVCaptureDeviceInput deviceInputWithDevice:_camera
212  error:&error];
213  // Check if we've got any errors
214  if (nil != error)
215  return NO;
216 
217  // We've got the input from the camera, now attach it to the capture session:
218  if ([_captureSession canAddInput:_cameraInput])
219  [_captureSession addInput:_cameraInput];
220  else
221  return NO;
222  }
223 
224  // Add the video output:
225  {
226  // Create the video data output
227  _videoOutput = [[AVCaptureVideoDataOutput alloc] init];
228 
229  // Create a queue for capturing video frames
230  dispatch_queue_t captureQueue = dispatch_queue_create("captureQueue", DISPATCH_QUEUE_SERIAL);
231 
232  // Use the AVCaptureVideoDataOutputSampleBufferDelegate capabilities of CameraDelegate
233  [_videoOutput setSampleBufferDelegate:self queue:captureQueue];
234 
235  // Set up the video output:
236  // Do we care about missing frames?
237  [_videoOutput setAlwaysDiscardsLateVideoFrames:YES];
238 
239  // We want the frames in some BGR format
240  NSNumber* framePixelFormat = [NSNumber numberWithInt:kCVPixelFormatType_32BGRA];
241  _videoOutput.videoSettings = [NSDictionary dictionaryWithObject:framePixelFormat
242  forKey:(id)kCVPixelBufferPixelFormatTypeKey];
243 
244  // Add the video data output to the capture session
245  if ([_captureSession canAddOutput:_videoOutput])
246  [_captureSession addOutput:_videoOutput];
247  else
248  return NO;
249 
250  //parameterize video stabilization: if available and should be disabled we disable software video stabilization
251  AVCaptureConnection* capCon = [_videoOutput connectionWithMediaType:AVMediaTypeVideo];
252  if (capCon != nil)
253  {
254  //we have to turn video stabilization mode off if we want intrinsics!!
255  if ([capCon isVideoStabilizationSupported])
256  {
257  if (videoStabilizationEnabled)
258  [capCon setPreferredVideoStabilizationMode:AVCaptureVideoStabilizationModeAuto];
259  else
260  [capCon setPreferredVideoStabilizationMode:AVCaptureVideoStabilizationModeOff];
261  }
262 
263  if (provideIntrinsics && [capCon isCameraIntrinsicMatrixDeliverySupported])
264  {
265  [capCon setCameraIntrinsicMatrixDeliveryEnabled:YES];
267  }
268  }
269  }
270 
271  // Set up a callback, so we are notified when the camera actually starts
272  [[NSNotificationCenter defaultCenter] addObserver:self
273  selector:@selector(videoCameraStarted:)
274  name:AVCaptureSessionDidStartRunningNotification
275  object:_captureSession];
276 
277  // Start the captureing
278  [_captureSession startRunning];
279  //[self printActiveFormat];
280 
281  [_camera unlockForConfiguration];
282  }
283 
284  // Note: Returning true from this function only means that setting up went OK.
285  // It doesn't mean that the camera has started yet.
286  // We get notified about the camera having started in the videoCameraStarted() callback.
287  return YES;
288 }

◆ stopCamera

- (BOOL) stopCamera

Definition at line 19 of file SENSiOSCameraDelegate.mm.

291 {
292  if (nil != _captureSession)
293  {
294  [_captureSession stopRunning];
295  _captureSession = nil;
296  _camera = nil;
297  _cameraInput = nil;
298  _videoOutput = nil;
299  }
300  return true;
301 }

◆ videoCameraStarted:

- (void) videoCameraStarted: (NSNotification*)  note
implementation

Definition at line 19 of file SENSiOSCameraDelegate.mm.

90  :(NSNotification*)note
91 {
92  //Note: not used at the moment
93  // This callback has done its job, now disconnect it
94  [[NSNotificationCenter defaultCenter] removeObserver:self
95  name:AVCaptureSessionDidStartRunningNotification
96  object:_captureSession];
97 }

Member Data Documentation

◆ _camera

- (AVCaptureDevice*) _camera
private

Definition at line 15 of file SENSiOSCameraDelegate.mm.

◆ _cameraInput

- (AVCaptureDeviceInput*) _cameraInput
private

Definition at line 16 of file SENSiOSCameraDelegate.mm.

◆ _cameraIntrinsicsDelivery

- (BOOL) _cameraIntrinsicsDelivery
private

Definition at line 19 of file SENSiOSCameraDelegate.mm.

◆ _captureSession

- (AVCaptureSession*) _captureSession
private

Definition at line 14 of file SENSiOSCameraDelegate.mm.

◆ _videoOutput

- (AVCaptureVideoDataOutput*) _videoOutput
private

Definition at line 17 of file SENSiOSCameraDelegate.mm.

Property Documentation

◆ permissionCB

- (function<void(bool)>) SENSiOSCameraDelegate:
readwritenonatomicassign

Definition at line 24 of file SENSiOSCameraDelegate.h.

◆ updateCB

- (function<void(unsigned char*, int, int, matrix_float3x3*)>) SENSiOSCameraDelegate:
readwritenonatomicassign

Definition at line 23 of file SENSiOSCameraDelegate.h.


The documentation for this class was generated from the following files: