SLProject  4.3.020
A platform independent 3D computer graphics framework for desktop OS, Android, iOS and online in web browsers
SENSAndroidCamera.cpp
Go to the documentation of this file.
1 /**
2  * \file SENSAndroidCamera.cpp
3  * \authors Michael Goettlicher, Luc Girod, Marcus Hudritsch
4  * \date Winter 2016
5  * \remarks Please use clangformat to format the code. See more code style on
6  * https://github.com/cpvrlab/SLProject4/wiki/SLProject-Coding-Style
7  * \copyright http://opensource.org/licenses/GPL-3.0
8 */
9 
10 #include <iostream>
11 #include <string>
12 #include <utility>
13 #include <algorithm>
14 #include "SENSAndroidCamera.h"
15 #include "SENSException.h"
16 
17 #include <android/log.h>
18 #include <opencv2/opencv.hpp>
19 #include <Utils.h>
20 #include <HighResTimer.h>
21 #include "SENSAndroidCameraUtils.h"
22 #include "SENSUtils.h"
23 
24 #define LOG_NDKCAM_WARN(...) Utils::log("SENSAndroidCamera", __VA_ARGS__);
25 #define LOG_NDKCAM_INFO(...) Utils::log("SENSAndroidCamera", __VA_ARGS__);
26 #define LOG_NDKCAM_DEBUG(...) Utils::log("SENSAndroidCamera", __VA_ARGS__);
27 /*
28  * Camera Manager Listener object
29  */
30 void onCameraAvailable(void* ctx, const char* id)
31 {
32  reinterpret_cast<SENSAndroidCamera*>(ctx)->onCameraStatusChanged(id, true);
33 }
34 void onCameraUnavailable(void* ctx, const char* id)
35 {
36  reinterpret_cast<SENSAndroidCamera*>(ctx)->onCameraStatusChanged(id, false);
37 }
38 
39 /*
40  * CameraDevice callbacks
41  */
42 void onDeviceDisconnected(void* ctx, ACameraDevice* dev)
43 {
44  reinterpret_cast<SENSAndroidCamera*>(ctx)->onDeviceDisconnected(dev);
45 }
46 
47 void onDeviceErrorChanges(void* ctx, ACameraDevice* dev, int err)
48 {
49  reinterpret_cast<SENSAndroidCamera*>(ctx)->onDeviceError(dev, err);
50 }
51 
52 // CaptureSession state callbacks
53 void onSessionClosed(void* ctx, ACameraCaptureSession* ses)
54 {
55  LOG_NDKCAM_WARN("onSessionClosed: CaptureSession state: session %p closed", ses);
56  reinterpret_cast<SENSAndroidCamera*>(ctx)
57  ->onSessionState(ses, CaptureSessionState::CLOSED);
58 }
59 
60 void onSessionReady(void* ctx, ACameraCaptureSession* ses)
61 {
62  LOG_NDKCAM_WARN("onSessionReady: CaptureSession state: session %p ready", ses);
63  reinterpret_cast<SENSAndroidCamera*>(ctx)
64  ->onSessionState(ses, CaptureSessionState::READY);
65 }
66 
67 void onSessionActive(void* ctx, ACameraCaptureSession* ses)
68 {
69  LOG_NDKCAM_WARN("onSessionActive: CaptureSession state: session %p active", ses);
70  reinterpret_cast<SENSAndroidCamera*>(ctx)
71  ->onSessionState(ses, CaptureSessionState::ACTIVE);
72 }
73 
75  : _cameraDeviceOpened(false)
76 {
77  LOG_NDKCAM_INFO("Camera instantiated");
78 }
79 
81 {
82  //stop();
83  LOG_NDKCAM_INFO("~SENSAndroidCamera: Camera destructor finished");
84 }
85 
86 /**
87  * ImageReader listener: called by AImageReader for every frame captured
88  * We pass the event to ImageReader class, so it could do some housekeeping
89  * about
90  * the loaded queue. For example, we could keep a counter to track how many
91  * buffers are full and idle in the queue. If camera almost has no buffer to
92  * capture
93  * we could release ( skip ) some frames by AImageReader_getNextImage() and
94  * AImageReader_delete().
95  */
96 void onImageCallback(void* ctx, AImageReader* reader)
97 {
98  reinterpret_cast<SENSAndroidCamera*>(ctx)->imageCallback(reader);
99 }
100 
101 //start camera selected in initOptimalCamera as soon as it is available
103 {
104  //init camera manager
105  if (!_cameraManager)
106  {
107  //init availability
109  {
110  _cameraAvailability[c.deviceId()] = false;
111  }
112 
113  LOG_NDKCAM_DEBUG("openCamera: Creating camera manager ...");
114  _cameraManager = ACameraManager_create();
115  if (!_cameraManager)
116  throw SENSException(SENSType::CAM, "Could not instantiate camera manager!", __LINE__, __FILE__);
117 
118  //register callbacks
120  .context = this,
121  .onCameraAvailable = onCameraAvailable,
122  .onCameraUnavailable = onCameraUnavailable,
123  };
124  ACameraManager_registerAvailabilityCallback(_cameraManager,
126 
127  //Attention: if we never access the _cameraManager the onCameraStatusChanged never comes (seems to be an android bug)
128  {
129  ACameraIdList* cameraIds = nullptr;
130  camera_status_t status = ACameraManager_getCameraIdList(_cameraManager, &cameraIds);
131  ACameraManager_deleteCameraIdList(cameraIds);
132  //PrintCameras(_cameraManager);
133  }
134  LOG_NDKCAM_DEBUG("openCamera: Camera manager created!");
135  }
136 
137  //find current SENSCameraDeviceProps
139 
140  if (!_cameraDeviceOpened)
141  {
142  LOG_NDKCAM_DEBUG("openCamera: Camera device not open");
143  auto condition = [&]
144  {
145  LOG_NDKCAM_DEBUG("openCamera: checking condition");
146  return (_cameraAvailability[camProps->deviceId()]);
147  };
148  std::unique_lock<std::mutex> lock(_cameraAvailabilityMutex);
149  //wait here before opening the required camera device until it is available
150  _openCameraCV.wait(lock, condition);
151 
152  LOG_NDKCAM_DEBUG("openCamera: Opening camera ...");
153  //open the so found camera with _characteristics.cameraId
154  ACameraDevice_stateCallbacks cameraDeviceListener = {
155  .context = this,
156  .onDisconnected = ::onDeviceDisconnected,
157  .onError = ::onDeviceErrorChanges,
158  };
159 
160  camera_status_t cameraState;
161  int n = 0;
162  int nMax = 10;
163  while (n < nMax)
164  {
165  cameraState = ACameraManager_openCamera(_cameraManager,
166  camProps->deviceId().c_str(),
167  &cameraDeviceListener,
168  &_cameraDevice);
169 
170  if (cameraState == ACAMERA_OK)
171  break;
172  n++;
173  }
174 
175  if (cameraState != ACAMERA_OK)
176  {
177  throw SENSException(SENSType::CAM, "Could not camera camera!", __LINE__, __FILE__);
178  }
179  else
180  {
181  _cameraDeviceOpened = true;
182  LOG_NDKCAM_DEBUG("openCamera: Camera opened!");
183  }
184  }
185  else
186  {
187  LOG_NDKCAM_DEBUG("openCamera: Camera device is already open");
188  }
189 
190  const auto& streamConfig = _config.streamConfig;
191  LOG_NDKCAM_INFO("openCamera: CaptureSize (%d, %d)", streamConfig.widthPix, streamConfig.heightPix);
192 
193  if (_imageReader && _captureSize != cv::Size(streamConfig.widthPix, streamConfig.heightPix))
194  {
195  LOG_NDKCAM_INFO("openCamera: ImageReader valid and captureSize does not fit");
196  //stop repeating request and wait for stopped state
197  if (_captureSession)
198  {
199  LOG_NDKCAM_DEBUG("openCamera: Stopping repeating request...");
200  //if (_captureSessionState == CaptureSessionState::ACTIVE)
201  //{
202  ACameraCaptureSession_stopRepeating(_captureSession);
203 
204  auto condition = [&]
205  {
207  };
208  std::unique_lock<std::mutex> lock(_captureSessionStateMutex);
209  //wait here until capture session is stopped
210  _captureSessionStateCV.wait(lock, condition);
211  //}
212  //else
213  // LOG_NDKCAM_WARN("CaptureSessionState NOT ACTIVE");
214  LOG_NDKCAM_DEBUG("openCamera: Repeating request stopped!");
215 
216  //LOG_NDKCAM_DEBUG("stop: closing capture session...");
217  //todo: it is recommended not to close before creating a new session
218  //ACameraCaptureSession_close(_captureSession);
219  //_captureSession = nullptr;
220  }
221 
222  LOG_NDKCAM_DEBUG("openCamera: Free request stuff...");
223  if (_captureRequest)
224  {
225  ACaptureRequest_removeTarget(_captureRequest, _cameraOutputTarget);
226  ACaptureRequest_free(_captureRequest);
227  _captureRequest = nullptr;
228  }
229 
231  {
232  ACaptureSessionOutputContainer_remove(_captureSessionOutputContainer,
234  ACaptureSessionOutput_free(_captureSessionOutput);
235  _captureSessionOutput = nullptr;
236  }
237 
238  if (_surface)
239  {
240  ANativeWindow_release(_surface);
241  _surface = nullptr;
242  }
243 
245  {
246  ACaptureSessionOutputContainer_free(_captureSessionOutputContainer);
248  }
249 
250  if (_imageReader)
251  {
252  LOG_NDKCAM_DEBUG("openCamera: Deleting image reader...");
253  AImageReader_delete(_imageReader);
254  _imageReader = nullptr;
255  }
256  }
257 
259  {
260  if (!_imageReader)
261  {
262  LOG_NDKCAM_INFO("openCamera: Creating image reader...");
263 
264  _captureSize = cv::Size(streamConfig.widthPix, streamConfig.heightPix);
265 
266  //create image reader with 2 surfaces (a surface is the like a ring buffer for images)
267  if (AImageReader_new(streamConfig.widthPix, streamConfig.heightPix, AIMAGE_FORMAT_YUV_420_888, 2, &_imageReader) != AMEDIA_OK)
268  throw SENSException(SENSType::CAM, "Could not create image reader!", __LINE__, __FILE__);
269 
270  //register onImageAvailable listener
271  AImageReader_ImageListener listener{
272  .context = this,
273  .onImageAvailable = onImageCallback,
274  };
275  AImageReader_setImageListener(_imageReader, &listener);
276 
278  }
279  }
280  else
281  {
282  //todo: throw something
283  }
284 }
285 
286 const SENSCameraConfig& SENSAndroidCamera::start(std::string deviceId,
287  const SENSCameraStreamConfig& streamConfig,
288  bool provideIntrinsics)
289 {
290  if (_started)
291  {
292  Utils::warnMsg("SENSWebCamera", "Call to start was ignored. Camera is currently running!", __LINE__, __FILE__);
293  return _config;
294  }
295 
296  //retrieve all camera characteristics
297  if (_captureProperties.size() == 0)
299 
300  if (_captureProperties.size() == 0)
301  throw SENSException(SENSType::CAM, "Could not retrieve camera properties!", __LINE__, __FILE__);
302 
303  if (!_captureProperties.containsDeviceId(deviceId))
304  throw SENSException(SENSType::CAM, "DeviceId does not exist!", __LINE__, __FILE__);
305 
308  if (props)
309  facing = props->facing();
310 
311  //init config here
312  _config = SENSCameraConfig(deviceId,
313  streamConfig,
314  facing,
316  processStart();
317 
318  openCamera();
319 
320  _started = true;
321  return _config;
322 }
323 
325 {
326  //Get the pointer to a surface from the image reader (Surface from java is like nativeWindow in ndk)
327  AImageReader_getWindow(_imageReader, &_surface);
328 
329  // Avoid surface to be deleted
330  ANativeWindow_acquire(_surface);
331  //create a capture session and provide the surfaces to it
332  ACaptureSessionOutput_create(_surface, &_captureSessionOutput);
333  //create an output container for capture session and add it to the session
334  ACaptureSessionOutputContainer_create(&_captureSessionOutputContainer);
335  ACaptureSessionOutputContainer_add(_captureSessionOutputContainer, _captureSessionOutput);
336 
337  ACameraOutputTarget_create(_surface, &_cameraOutputTarget);
338  ACameraDevice_createCaptureRequest(_cameraDevice, TEMPLATE_PREVIEW, &_captureRequest);
339 
340  ACaptureRequest_addTarget(_captureRequest, _cameraOutputTarget);
341 
343 
344  ACameraCaptureSession_stateCallbacks captureSessionStateCallbacks = {
345  .context = this,
346  .onActive = ::onSessionActive,
347  .onReady = ::onSessionReady,
348  .onClosed = ::onSessionClosed};
349  camera_status_t captureSessionStatus = ACameraDevice_createCaptureSession(_cameraDevice,
351  &captureSessionStateCallbacks,
352  &_captureSession);
353  if (captureSessionStatus != AMEDIA_OK)
354  {
355  LOG_NDKCAM_WARN("Creating capture session failed!");
356  }
357  //throw SENSException(SENSType::CAM, "Could not create capture session!", __LINE__, __FILE__);
358 
359  //adjust capture request properties:
360 
361  //auto focus mode
363  {
364  uint8_t afMode = ACAMERA_CONTROL_AF_MODE_OFF;
365  ACaptureRequest_setEntry_u8(_captureRequest, ACAMERA_CONTROL_AF_MODE, 1, &afMode);
366  float focusDistance = 0.0f;
367  ACaptureRequest_setEntry_float(_captureRequest, ACAMERA_LENS_FOCUS_DISTANCE, 1, &focusDistance);
368  }
369  else
370  {
371  uint8_t afMode = ACAMERA_CONTROL_AF_MODE_CONTINUOUS_VIDEO;
372  ACaptureRequest_setEntry_u8(_captureRequest, ACAMERA_CONTROL_AF_MODE, 1, &afMode);
373  }
374 
375  //digital video stabilization (software) -> turn off by default (for now)
376  {
377  uint8_t mode = ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE_OFF;
378  ACaptureRequest_setEntry_u8(_captureRequest, ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE, 1, &mode);
379  }
380  //optical video stabilization (hardware)
381  {
382  uint8_t mode = ACAMERA_LENS_OPTICAL_STABILIZATION_MODE_OFF;
383  ACaptureRequest_setEntry_u8(_captureRequest, ACAMERA_LENS_OPTICAL_STABILIZATION_MODE, 1, &mode);
384  }
385 
386  //install repeating request
387  ACameraCaptureSession_setRepeatingRequest(_captureSession, nullptr, 1, &_captureRequest, nullptr);
388 }
389 
391 {
392  if (_started)
393  {
394  if (_captureSession)
395  {
396  LOG_NDKCAM_DEBUG("stop: stopping repeating request...");
398  {
399  ACameraCaptureSession_stopRepeating(_captureSession);
400  }
401  else
402  LOG_NDKCAM_WARN("stop: CaptureSessionState NOT ACTIVE");
403 
404  LOG_NDKCAM_DEBUG("stop: closing capture session...");
405  //todo: it is recommended not to close before creating a new session
406  ACameraCaptureSession_close(_captureSession);
407  _captureSession = nullptr;
408  }
409 
410  if (_captureRequest)
411  {
412  LOG_NDKCAM_DEBUG("stop: free request stuff...");
413  ACaptureRequest_removeTarget(_captureRequest, _cameraOutputTarget);
414  ACaptureRequest_free(_captureRequest);
415  _captureRequest = nullptr;
416  }
417 
419  {
420  ACaptureSessionOutputContainer_remove(_captureSessionOutputContainer,
422  ACaptureSessionOutput_free(_captureSessionOutput);
423  _captureSessionOutput = nullptr;
424  }
425 
426  if (_surface)
427  {
428  ANativeWindow_release(_surface);
429  _surface = nullptr;
430  }
431 
433  {
434  ACaptureSessionOutputContainer_free(_captureSessionOutputContainer);
436  }
437 
438  if (_cameraDevice)
439  {
440  LOG_NDKCAM_DEBUG("stop: closing camera...");
441  ACameraDevice_close(_cameraDevice);
442  _cameraDevice = nullptr;
443  _cameraDeviceOpened = false;
444  }
445 
446  if (_cameraManager)
447  {
448  LOG_NDKCAM_DEBUG("stop: deleting camera manager...");
449  ACameraManager_unregisterAvailabilityCallback(_cameraManager,
451  ACameraManager_delete(_cameraManager);
452  _cameraManager = nullptr;
453  }
454 
455  if (_imageReader)
456  {
457  LOG_NDKCAM_DEBUG("stop: free image reader...");
458  AImageReader_delete(_imageReader);
459  _imageReader = nullptr;
460  }
461  }
462 }
463 
464 cv::Mat SENSAndroidCamera::convertToYuv(AImage* image)
465 {
466  int32_t height, width, rowStrideY;
467  AImage_getHeight(image, &height);
468  AImage_getWidth(image, &width);
469  AImage_getPlaneRowStride(image, 0, &rowStrideY);
470 
471  //pointers to yuv data planes and length of yuv data planes in byte
472  uint8_t *yPixel, /* *uPixel,*/ *vPixel;
473  int32_t yLen, /*uLen,*/ vLen;
474  AImage_getPlaneData(image, 0, &yPixel, &yLen);
475  //AImage_getPlaneData(image, 1, &uPixel, &uLen);
476  AImage_getPlaneData(image, 2, &vPixel, &vLen);
477 
478  //Attention: There may be additional padding at the end of every line, in this case width is not equal to rowStrideY.
479  //As this padding is not contained at the end of the Y-block, yLen can be calculated as follows:
480  // yLen = rowStrideY * height - (rowStrideY - width)
481  //But when copying the UV-block we have to "insert" the additional padding at the end of the Y-block
482  //in the new yuv image!
483  //(https://stackoverflow.com/questions/40030533/android-camera2-preview-output-sizes)
484  //(https://stackoverflow.com/questions/52726002/camera2-captured-picture-conversion-from-yuv-420-888-to-nv21/52740776#52740776)
485 
486  //copy image data to yuv image: we use the rowStrideY to define the maximum data block width including potential padding
487  cv::Mat yuv(height + (height / 2), rowStrideY, CV_8UC1);
488  memcpy(yuv.data, yPixel, yLen);
489  //The interleaved uv data starts with v pixels, you can inspect this by comparing uPixel and vPixel adresses,
490  //which is one byte lower. So the order is V/U: NV12: YYYYUV NV21: YYYYVU
491  // This is also described like this in wikipedia in section https://en.wikipedia.org/wiki/YUV#Y%E2%80%B2UV420sp_(NV21)_to_RGB_conversion_(Android)
492  // U follows V in the interleaved block (in contradiction to what is shown in the drawing explaining yuv in wikipedia).
493  // As both planes have the same length, but one starts one byte lower, we have to copy one
494  //additional byte to get all the data (see vLen+1).
495  //We do not have to additionally copy the v plane. The u plane contains the interleaved u and v data!
496  memcpy(yuv.data + yLen + (rowStrideY - width), vPixel, vLen + 1);
497 
498  //If there is line padding we get rid of it now by defining a sub region of interest in the target image size
499  if (rowStrideY > width)
500  {
501  cv::Rect roi(0, 0, width, yuv.rows);
502  cv::Mat roiYuv = yuv(roi);
503  return roiYuv;
504  }
505  else
506  return yuv;
507 }
508 
509 void SENSAndroidCamera::imageCallback(AImageReader* reader)
510 {
511  AImage* image = nullptr;
512  media_status_t status = AImageReader_acquireLatestImage(reader, &image);
513  if (status == AMEDIA_OK && image)
514  {
515  cv::Mat yuv = convertToYuv(image);
516 
517  AImage_delete(image);
518 
519  cv::Mat bgr;
520  HighResTimer t;
521  cv::cvtColor(yuv, bgr, cv::COLOR_YUV2BGR_NV21, 3);
522  SENS_DEBUG("SENSAndroidCamera: time for yuv conversion: %f ms", t.elapsedTimeInMilliSec());
523 
524  updateFrame(bgr, cv::Mat(), false, bgr.cols, bgr.rows);
525  }
526 }
527 
528 /**
529  * Handle Camera DeviceStateChanges msg, notify device is disconnected
530  * simply close the camera
531  */
533 {
534  if (dev == _cameraDevice)
535  {
536  std::string id(ACameraDevice_getId(dev));
537  LOG_NDKCAM_WARN("device %s is disconnected", id.c_str());
538 
539  {
540  std::lock_guard<std::mutex> lock(_cameraAvailabilityMutex);
541  _cameraAvailability[id] = false;
542  }
543 
544  _cameraDeviceOpened = false;
545  ACameraDevice_close(_cameraDevice);
546  _cameraDevice = nullptr;
547  }
548 }
549 /**
550  * Handles Camera's deviceErrorChanges message, no action;
551  * mainly debugging purpose
552  *
553  *
554  */
555 void SENSAndroidCamera::onDeviceError(ACameraDevice* dev, int err)
556 {
557  if (dev == _cameraDevice)
558  {
559  std::string errStr;
560  switch (err)
561  {
562  case ERROR_CAMERA_IN_USE:
563  errStr = "ERROR_CAMERA_IN_USE";
564  break;
565  case ERROR_CAMERA_SERVICE:
566  errStr = "ERROR_CAMERA_SERVICE";
567  break;
568  case ERROR_CAMERA_DEVICE:
569  errStr = "ERROR_CAMERA_DEVICE";
570  break;
571  case ERROR_CAMERA_DISABLED:
572  errStr = "ERROR_CAMERA_DISABLED";
573  break;
574  case ERROR_MAX_CAMERAS_IN_USE:
575  errStr = "ERROR_MAX_CAMERAS_IN_USE";
576  break;
577  default:
578  errStr = "Unknown Error";
579  }
580 
581  std::string id(ACameraDevice_getId(dev));
582  {
583  std::lock_guard<std::mutex> lock(_cameraAvailabilityMutex);
584  _cameraAvailability[id] = false;
585  }
586  _cameraDeviceOpened = false;
587 
588  LOG_NDKCAM_INFO("CameraDevice %s is in error %s", id.c_str(), errStr.c_str());
589  }
590 }
591 
592 /**
593  * OnCameraStatusChanged()
594  * handles Callback from ACameraManager
595  */
596 void SENSAndroidCamera::onCameraStatusChanged(const char* id, bool available)
597 {
598  LOG_NDKCAM_INFO("onCameraStatusChanged: id: %s available: %s ", id, available ? "true" : "false");
599  {
600  std::lock_guard<std::mutex> lock(_cameraAvailabilityMutex);
601  _cameraAvailability[std::string(id)] = available;
602  }
603  _openCameraCV.notify_one();
604 }
605 
607 {
608  if (state == CaptureSessionState::READY) // session is ready
609  return "READY";
610  else if (state == CaptureSessionState::ACTIVE)
611  return "ACTIVE";
612  else if (state == CaptureSessionState::CLOSED)
613  return "CLOSED";
614  else if (state == CaptureSessionState::MAX_STATE)
615  return "MAX_STATE";
616  else
617  return "UNKNOWN";
618 }
619 /**
620  * Handles capture session state changes.
621  * Update into internal session state.
622  */
623 void SENSAndroidCamera::onSessionState(ACameraCaptureSession* ses,
624  CaptureSessionState state)
625 {
626  if (!_captureSession)
627  LOG_NDKCAM_WARN("onSessionState: CaptureSession is NULL");
628 
629  if (state >= CaptureSessionState::MAX_STATE)
630  {
631  throw SENSException(SENSType::CAM, "Wrong state " + std::to_string((int)state), __LINE__, __FILE__);
632  }
633 
634  LOG_NDKCAM_WARN("onSessionState: CaptureSession state: %s", getPrintableState(state).c_str());
635 
636  {
637  std::lock_guard<std::mutex> lock(_captureSessionStateMutex);
638  _captureSessionState = state;
639 
641  {
642  _started = true;
643  }
644  else
645  {
646  _started = false;
647  }
648  }
649  _captureSessionStateCV.notify_one();
650 }
651 
653 {
654  if (_captureProperties.size() == 0)
655  {
656  ACameraManager* cameraManager = ACameraManager_create();
657  if (!cameraManager)
658  throw SENSException(SENSType::CAM, "Could not instantiate camera manager!", __LINE__, __FILE__);
659 
660  ACameraIdList* cameraIds = nullptr;
661  if (ACameraManager_getCameraIdList(cameraManager, &cameraIds) != ACAMERA_OK)
662  throw SENSException(SENSType::CAM, "Could not retrieve camera list!", __LINE__, __FILE__);
663 
664  for (int i = 0; i < cameraIds->numCameras; ++i)
665  {
666  std::string cameraId = cameraIds->cameraIds[i];
667 
668  ACameraMetadata* camCharacteristics;
669  ACameraManager_getCameraCharacteristics(cameraManager, cameraId.c_str(), &camCharacteristics);
670 
671  int32_t numEntries = 0; //will be filled by getAllTags with number of entries
672  const uint32_t* tags = nullptr;
673  ACameraMetadata_getAllTags(camCharacteristics, &numEntries, &tags);
674 
675  std::vector<float> focalLengthsMM;
676  cv::Size2f physicalSensorSizeMM;
678 
679  //make a first loop to estimate physical sensor parameters
680  for (int tagIdx = 0; tagIdx < numEntries; ++tagIdx)
681  {
682  ACameraMetadata_const_entry lensInfo = {0};
683  //first check that ACAMERA_LENS_FACING is contained at all
684  if (tags[tagIdx] == ACAMERA_LENS_FACING)
685  {
686  ACameraMetadata_getConstEntry(camCharacteristics, tags[tagIdx], &lensInfo);
687  acamera_metadata_enum_android_lens_facing_t androidFacing = static_cast<acamera_metadata_enum_android_lens_facing_t>(lensInfo.data.u8[0]);
688  if (androidFacing == ACAMERA_LENS_FACING_BACK)
689  facing = SENSCameraFacing::BACK;
690  else if (androidFacing == ACAMERA_LENS_FACING_FRONT)
691  facing = SENSCameraFacing::FRONT;
692  else //if (androidFacing == ACAMERA_LENS_FACING_EXTERNAL)
694  }
695  else if (tags[tagIdx] == ACAMERA_LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
696  {
697  if (ACameraMetadata_getConstEntry(camCharacteristics, tags[tagIdx], &lensInfo) ==
698  ACAMERA_OK)
699  {
700  for (int i = 0; i < lensInfo.count; ++i)
701  {
702  //characteristics.focalLenghtsMM.push_back(lensInfo.data.f[i]);
703  focalLengthsMM.push_back(lensInfo.data.f[i]);
704  }
705  }
706  }
707  else if (tags[tagIdx] == ACAMERA_SENSOR_INFO_PHYSICAL_SIZE)
708  {
709  if (ACameraMetadata_getConstEntry(camCharacteristics, tags[tagIdx], &lensInfo) == ACAMERA_OK)
710  {
711  //characteristics.physicalSensorSizeMM.width = lensInfo.data.f[0];
712  //characteristics.physicalSensorSizeMM.height = lensInfo.data.f[1];
713 
714  physicalSensorSizeMM.width = lensInfo.data.f[0];
715  physicalSensorSizeMM.height = lensInfo.data.f[1];
716  }
717  }
718  }
719 
720  //todo: if we have more than one focal length, what do we do?
721  //if we have more than one focal length, we select the first one..
722 
723  SENSCameraDeviceProps characteristics(cameraId, facing);
724 
725  //in the second loop we use the physical sensor parameters to specify a focal length in pixel for every stream config
726  for (int tagIdx = 0; tagIdx < numEntries; ++tagIdx)
727  {
728  if (tags[tagIdx] == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS)
729  {
730  ACameraMetadata_const_entry lensInfo = {0};
731  if (ACameraMetadata_getConstEntry(camCharacteristics, tags[tagIdx], &lensInfo) == ACAMERA_OK)
732  {
733  if (lensInfo.count & 0x3)
735  "STREAM_CONFIGURATION (%d) should multiple of 4",
736  __LINE__,
737  __FILE__);
738 
739  if (lensInfo.type != ACAMERA_TYPE_INT32)
741  "STREAM_CONFIGURATION TYPE(%d) is not ACAMERA_TYPE_INT32(1)",
742  __LINE__,
743  __FILE__);
744 
745  int width = 0, height = 0;
746  for (uint32_t i = 0; i < lensInfo.count; i += 4)
747  {
748  //example for content interpretation:
749  //std::string direction = lensInfo.data.i32[i + 3] ? "INPUT" : "OUTPUT";
750  //std::string format = GetFormatStr(lensInfo.data.i32[i]);
751 
752  //OUTPUT format and AIMAGE_FORMAT_YUV_420_888 image format
753  if (!lensInfo.data.i32[i + 3] && lensInfo.data.i32[i] == AIMAGE_FORMAT_YUV_420_888)
754  {
755  width = lensInfo.data.i32[i + 1];
756  height = lensInfo.data.i32[i + 2];
757 
758  float focalLengthPix = -1.f;
759  if (focalLengthsMM.size() && physicalSensorSizeMM.width > 0 && physicalSensorSizeMM.height > 0)
760  {
761  //we assume the image is cropped at one side only. we compare the sensor aspect ratio
762  //with the image aspect ratio and use the uncropped length to estimate a focal length in pixel that fits to this stream configuration size
763  if ((float)physicalSensorSizeMM.width / (float)physicalSensorSizeMM.height > (float)width / (float)height)
764  focalLengthPix = focalLengthsMM.front() / physicalSensorSizeMM.height * (float)height;
765  else
766  focalLengthPix = focalLengthsMM.front() / physicalSensorSizeMM.width * (float)width;
767  }
768 
769  if (!characteristics.contains({width, height}))
770  characteristics.add(width, height, focalLengthPix);
771  }
772  }
773  }
774  }
775  }
776  ACameraMetadata_free(camCharacteristics);
777  _captureProperties.push_back(characteristics);
778  }
779 
780  ACameraManager_deleteCameraIdList(cameraIds);
781  ACameraManager_delete(cameraManager);
782  }
783 
784  return _captureProperties;
785 }
#define SENS_DEBUG(...)
Definition: SENS.h:60
void onSessionActive(void *ctx, ACameraCaptureSession *ses)
#define LOG_NDKCAM_INFO(...)
#define LOG_NDKCAM_WARN(...)
void onImageCallback(void *ctx, AImageReader *reader)
void onDeviceDisconnected(void *ctx, ACameraDevice *dev)
void onSessionClosed(void *ctx, ACameraCaptureSession *ses)
void onDeviceErrorChanges(void *ctx, ACameraDevice *dev, int err)
void onCameraAvailable(void *ctx, const char *id)
void onSessionReady(void *ctx, ACameraCaptureSession *ses)
std::string getPrintableState(CaptureSessionState state)
void onCameraUnavailable(void *ctx, const char *id)
#define LOG_NDKCAM_DEBUG(...)
CaptureSessionState
SENSCameraFacing
Definition of camera facing.
Definition: SENSCamera.h:28
static WAI::ModeOrbSlam2 * mode
Definition: WAIInterface.cpp:5
High Resolution Timer class using C++11.
Definition: HighResTimer.h:31
float elapsedTimeInMilliSec()
Definition: HighResTimer.h:38
ACaptureRequest * _captureRequest
void onDeviceError(ACameraDevice *dev, int err)
std::atomic< bool > _cameraDeviceOpened
AImageReader * _imageReader
void onSessionState(ACameraCaptureSession *ses, CaptureSessionState state)
ACaptureSessionOutput * _captureSessionOutput
static cv::Mat convertToYuv(AImage *image)
ACameraManager_AvailabilityCallbacks _cameraManagerAvailabilityCallbacks
ACameraOutputTarget * _cameraOutputTarget
std::condition_variable _openCameraCV
std::mutex _captureSessionStateMutex
CaptureSessionState _captureSessionState
void stop() override
Stop a started camera device.
ANativeWindow * _surface
const SENSCaptureProps & captureProperties() override
Get SENSCaptureProps which contains necessary information about all available camera devices and thei...
ACameraCaptureSession * _captureSession
ACameraManager * _cameraManager
void onDeviceDisconnected(ACameraDevice *dev)
void imageCallback(AImageReader *reader)
std::condition_variable _captureSessionStateCV
std::map< std::string, bool > _cameraAvailability
const SENSCameraConfig & start(std::string deviceId, const SENSCameraStreamConfig &streamConfig, bool provideIntrinsics=true) override
ACaptureSessionOutputContainer * _captureSessionOutputContainer
std::mutex _cameraAvailabilityMutex
ACameraDevice * _cameraDevice
void onCameraStatusChanged(const char *id, bool available)
SENSCameraConfig _config
indicates what is currently running
Definition: SENSCamera.h:218
SENSCaptureProps _captureProperties
Definition: SENSCamera.h:216
std::atomic< bool > _started
flags if camera was started
Definition: SENSCamera.h:217
void updateFrame(cv::Mat bgrImg, cv::Mat intrinsics, int width, int height, bool intrinsicsChanged)
Definition: SENSCamera.cpp:220
void processStart()
call from start function to do startup preprocessing
Definition: SENSCamera.cpp:294
const SENSCameraFacing & facing() const
Definition: SENSCamera.h:86
bool contains(cv::Size toFind)
Definition: SENSCamera.h:88
const std::string & deviceId() const
Definition: SENSCamera.h:85
void add(int widthPix, int heightPix, float focalLengthPix)
Definition: SENSCamera.h:97
bool containsDeviceId(const std::string &deviceId) const
Definition: SENSCamera.cpp:61
const SENSCameraDeviceProps * camPropsForDeviceId(const std::string &deviceId) const
Definition: SENSCamera.cpp:73
void warnMsg(const char *tag, const char *msg, const int line, const char *file)
Platform independent warn message output.
Definition: Utils.cpp:1142
SENSCameraStreamConfig streamConfig
currently selected stream config index (use it to look up original capture size)
Definition: SENSCamera.h:131
std::string deviceId
Definition: SENSCamera.h:130
SENSCameraFocusMode focusMode
autofocus mode
Definition: SENSCamera.h:132