@@ -33,23 +33,27 @@ using namespace cv;
3333
3434#define FOURCC_BGR CV_FOURCC_MACRO (' B' ,' G' ,' R' ,' 3' )
3535#define FOURCC_RGB CV_FOURCC_MACRO (' R' ,' G' ,' B' ,' 3' )
36+ #define FOURCC_BGRA CV_FOURCC_MACRO (' B' ,' G' ,' R' ,' 4' )
37+ #define FOURCC_RGBA CV_FOURCC_MACRO (' R' ,' G' ,' B' ,' 4' )
3638#define FOURCC_GRAY CV_FOURCC_MACRO (' G' ,' R' ,' E' ,' Y' )
3739#define FOURCC_NV21 CV_FOURCC_MACRO (' N' ,' V' ,' 2' ,' 1' )
3840#define FOURCC_YV12 CV_FOURCC_MACRO (' Y' ,' V' ,' 1' ,' 2' )
3941#define FOURCC_UNKNOWN 0xFFFFFFFF
4042
41- template <typename T> class RangeValue {
42- public:
43+ template <typename T> struct RangeValue {
4344 T min, max;
4445 /* *
4546 * return absolute value from relative value
4647 * * value: in percent (50 for 50%)
4748 * */
4849 T value (int percent) {
49- return static_cast <T>(min + (max - min) * percent / 100 );
50+ return static_cast <T>(min + ((max - min) * percent) / 100 );
51+ }
52+ RangeValue (T minv = 0 , T maxv = 0 ) : min(minv), max(maxv) {}
53+ bool Supported () const { return (min != max); }
54+ T clamp ( T value ) const {
55+ return (value > max) ? max : ((value < min) ? min : value);
5056 }
51- RangeValue () { min = max = static_cast <T>(0 ); }
52- bool Supported (void ) const { return (min != max); }
5357};
5458
5559static inline void deleter_ACameraManager (ACameraManager *cameraManager) {
@@ -165,8 +169,7 @@ void OnCaptureFailed(void* context,
165169 * on camera. For this sample purpose, clamp to a range showing visible
166170 * video on preview: 100000ns ~ 250000000ns
167171 */
168- static const long kMinExposureTime = 1000000L ;
169- static const long kMaxExposureTime = 250000000L ;
172+ static const RangeValue<int64_t > exposureTimeLimits = { 1000000 , 250000000 };
170173
171174static double elapsedTimeFrom (std::chrono::time_point<std::chrono::system_clock> start) {
172175 return std::chrono::duration<double >(std::chrono::system_clock::now () - start).count ();
@@ -188,7 +191,7 @@ class AndroidCameraCapture : public IVideoCapture
188191 int32_t frameWidth = 0 ;
189192 int32_t frameStride = 0 ;
190193 int32_t frameHeight = 0 ;
191- int32_t colorFormat;
194+ int32_t colorFormat = COLOR_FormatUnknown ;
192195 std::vector<uint8_t > buffer;
193196 bool sessionOutputAdded = false ;
194197 bool targetAdded = false ;
@@ -198,8 +201,9 @@ class AndroidCameraCapture : public IVideoCapture
198201 bool settingHeight = false ;
199202 int desiredWidth = 640 ;
200203 int desiredHeight = 480 ;
201- bool autoExposure = true ;
202- int64_t exposureTime = 0L ;
204+ uint8_t flashMode = ACAMERA_FLASH_MODE_OFF;
205+ uint8_t aeMode = ACAMERA_CONTROL_AE_MODE_ON;
206+ int64_t exposureTime = 0 ;
203207 RangeValue<int64_t > exposureRange;
204208 int32_t sensitivity = 0 ;
205209 RangeValue<int32_t > sensitivityRange;
@@ -212,7 +216,24 @@ class AndroidCameraCapture : public IVideoCapture
212216 std::condition_variable condition;
213217
214218public:
215- AndroidCameraCapture () {}
219+ AndroidCameraCapture (const VideoCaptureParameters& params)
220+ {
221+ desiredWidth = params.get <int >(CAP_PROP_FRAME_WIDTH, desiredWidth);
222+ desiredHeight = params.get <int >(CAP_PROP_FRAME_HEIGHT, desiredHeight);
223+
224+ static const struct {
225+ int propId;
226+ uint32_t defaultValue;
227+ } items[] = {
228+ { CAP_PROP_AUTO_EXPOSURE, 1 },
229+ { CAP_PROP_FOURCC, FOURCC_UNKNOWN },
230+ { CAP_PROP_ANDROID_DEVICE_TORCH, 0 }
231+ };
232+
233+ for (auto it = std::begin (items); it != std::end (items); ++it) {
234+ setProperty (it->propId , params.get <double >(it->propId , it->defaultValue ));
235+ }
236+ }
216237
217238 ~AndroidCameraCapture () { cleanUp (); }
218239
@@ -357,14 +378,20 @@ class AndroidCameraCapture : public IVideoCapture
357378 if (colorFormat == COLOR_FormatYUV420Planar) {
358379 Mat yuv (frameHeight + frameHeight/2 , frameWidth, CV_8UC1, buffer.data ());
359380 switch (fourCC) {
381+ case FOURCC_BGRA:
382+ cvtColor (yuv, out, COLOR_YUV2BGRA_YV12);
383+ break ;
384+ case FOURCC_RGBA:
385+ cvtColor (yuv, out, COLOR_YUV2RGBA_YV12);
386+ break ;
360387 case FOURCC_BGR:
361- cv:: cvtColor (yuv, out, cv:: COLOR_YUV2BGR_YV12);
388+ cvtColor (yuv, out, COLOR_YUV2BGR_YV12);
362389 break ;
363390 case FOURCC_RGB:
364- cv:: cvtColor (yuv, out, cv:: COLOR_YUV2RGB_YV12);
391+ cvtColor (yuv, out, COLOR_YUV2RGB_YV12);
365392 break ;
366393 case FOURCC_GRAY:
367- cv:: cvtColor (yuv, out, cv:: COLOR_YUV2GRAY_YV12);
394+ cvtColor (yuv, out, COLOR_YUV2GRAY_YV12);
368395 break ;
369396 case FOURCC_YV12:
370397 yuv.copyTo (out);
@@ -377,14 +404,20 @@ class AndroidCameraCapture : public IVideoCapture
377404 Mat yuv (frameHeight + frameHeight/2 , frameStride, CV_8UC1, buffer.data ());
378405 Mat tmp = (frameWidth == frameStride) ? yuv : yuv (Rect (0 , 0 , frameWidth, frameHeight + frameHeight / 2 ));
379406 switch (fourCC) {
407+ case FOURCC_BGRA:
408+ cvtColor (tmp, out, COLOR_YUV2BGRA_NV21);
409+ break ;
410+ case FOURCC_RGBA:
411+ cvtColor (tmp, out, COLOR_YUV2RGBA_NV21);
412+ break ;
380413 case FOURCC_BGR:
381- cv:: cvtColor (tmp, out, cv:: COLOR_YUV2BGR_NV21);
414+ cvtColor (tmp, out, COLOR_YUV2BGR_NV21);
382415 break ;
383416 case FOURCC_RGB:
384- cv:: cvtColor (tmp, out, cv:: COLOR_YUV2RGB_NV21);
417+ cvtColor (tmp, out, COLOR_YUV2RGB_NV21);
385418 break ;
386419 case FOURCC_GRAY:
387- cv:: cvtColor (tmp, out, cv:: COLOR_YUV2GRAY_NV21);
420+ cvtColor (tmp, out, COLOR_YUV2GRAY_NV21);
388421 break ;
389422 case FOURCC_NV21:
390423 tmp.copyTo (out);
@@ -408,13 +441,15 @@ class AndroidCameraCapture : public IVideoCapture
408441 case CAP_PROP_FRAME_HEIGHT:
409442 return isOpened () ? frameHeight : desiredHeight;
410443 case CAP_PROP_AUTO_EXPOSURE:
411- return autoExposure ? 1 : 0 ;
444+ return (aeMode == ACAMERA_CONTROL_AE_MODE_ON) ? 1 : 0 ;
412445 case CAP_PROP_EXPOSURE:
413446 return exposureTime;
414447 case CAP_PROP_ISO_SPEED:
415448 return sensitivity;
416449 case CAP_PROP_FOURCC:
417450 return fourCC;
451+ case CAP_PROP_ANDROID_DEVICE_TORCH:
452+ return (flashMode == ACAMERA_FLASH_MODE_TORCH) ? 1 : 0 ;
418453 default :
419454 break ;
420455 }
@@ -452,6 +487,8 @@ class AndroidCameraCapture : public IVideoCapture
452487 switch (newFourCC) {
453488 case FOURCC_BGR:
454489 case FOURCC_RGB:
490+ case FOURCC_BGRA:
491+ case FOURCC_RGBA:
455492 case FOURCC_GRAY:
456493 fourCC = newFourCC;
457494 return true ;
@@ -478,29 +515,31 @@ class AndroidCameraCapture : public IVideoCapture
478515 }
479516 }
480517 case CAP_PROP_AUTO_EXPOSURE:
481- autoExposure = (value != 0 );
518+ aeMode = (value != 0 ) ? ACAMERA_CONTROL_AE_MODE_ON : ACAMERA_CONTROL_AE_MODE_OFF ;
482519 if (isOpened ()) {
483- uint8_t aeMode = autoExposure ? ACAMERA_CONTROL_AE_MODE_ON : ACAMERA_CONTROL_AE_MODE_OFF;
484- camera_status_t status = ACaptureRequest_setEntry_u8 (captureRequest.get (), ACAMERA_CONTROL_AE_MODE, 1 , &aeMode);
485- return status == ACAMERA_OK;
520+ return submitRequest (ACaptureRequest_setEntry_u8, ACAMERA_CONTROL_AE_MODE, aeMode);
486521 }
487522 return true ;
488523 case CAP_PROP_EXPOSURE:
489524 if (isOpened () && exposureRange.Supported ()) {
490- exposureTime = ( int64_t ) value;
525+ exposureTime = exposureRange. clamp ( static_cast < int64_t >( value)) ;
491526 LOGI (" Setting CAP_PROP_EXPOSURE will have no effect unless CAP_PROP_AUTO_EXPOSURE is off" );
492- camera_status_t status = ACaptureRequest_setEntry_i64 (captureRequest.get (), ACAMERA_SENSOR_EXPOSURE_TIME, 1 , &exposureTime);
493- return status == ACAMERA_OK;
527+ return submitRequest (ACaptureRequest_setEntry_i64, ACAMERA_SENSOR_EXPOSURE_TIME, exposureTime);
494528 }
495529 return false ;
496530 case CAP_PROP_ISO_SPEED:
497531 if (isOpened () && sensitivityRange.Supported ()) {
498- sensitivity = ( int32_t ) value;
532+ sensitivity = sensitivityRange. clamp ( static_cast < int32_t >( value)) ;
499533 LOGI (" Setting CAP_PROP_ISO_SPEED will have no effect unless CAP_PROP_AUTO_EXPOSURE is off" );
500- camera_status_t status = ACaptureRequest_setEntry_i32 (captureRequest.get (), ACAMERA_SENSOR_SENSITIVITY, 1 , &sensitivity);
501- return status == ACAMERA_OK;
534+ return submitRequest (ACaptureRequest_setEntry_i32, ACAMERA_SENSOR_SENSITIVITY, sensitivity);
502535 }
503536 return false ;
537+ case CAP_PROP_ANDROID_DEVICE_TORCH:
538+ flashMode = (value != 0 ) ? ACAMERA_FLASH_MODE_TORCH : ACAMERA_FLASH_MODE_OFF;
539+ if (isOpened ()) {
540+ return submitRequest (ACaptureRequest_setEntry_u8, ACAMERA_FLASH_MODE, flashMode);
541+ }
542+ return true ;
504543 default :
505544 break ;
506545 }
@@ -561,7 +600,7 @@ class AndroidCameraCapture : public IVideoCapture
561600 return false ;
562601 }
563602 std::shared_ptr<ACameraMetadata> cameraMetadata = std::shared_ptr<ACameraMetadata>(metadata, deleter_ACameraMetadata);
564- ACameraMetadata_const_entry entry;
603+ ACameraMetadata_const_entry entry = {} ;
565604 ACameraMetadata_getConstEntry (cameraMetadata.get (), ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry);
566605
567606 double bestScore = std::numeric_limits<double >::max ();
@@ -594,25 +633,19 @@ class AndroidCameraCapture : public IVideoCapture
594633 }
595634 LOGI (" Best resolution match: %dx%d" , bestMatchWidth, bestMatchHeight);
596635
597- ACameraMetadata_const_entry val = { 0 , };
598- camera_status_t status = ACameraMetadata_getConstEntry (cameraMetadata.get (), ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, &val);
599- if (status == ACAMERA_OK) {
600- exposureRange.min = val.data .i64 [0 ];
601- if (exposureRange.min < kMinExposureTime ) {
602- exposureRange.min = kMinExposureTime ;
603- }
604- exposureRange.max = val.data .i64 [1 ];
605- if (exposureRange.max > kMaxExposureTime ) {
606- exposureRange.max = kMaxExposureTime ;
607- }
636+ ACameraMetadata_const_entry val;
637+ cStatus = ACameraMetadata_getConstEntry (cameraMetadata.get (), ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, &val);
638+ if (cStatus == ACAMERA_OK) {
639+ exposureRange.min = exposureTimeLimits.clamp (val.data .i64 [0 ]);
640+ exposureRange.max = exposureTimeLimits.clamp (val.data .i64 [1 ]);
608641 exposureTime = exposureRange.value (2 );
609642 } else {
610643 LOGW (" Unsupported ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE" );
611- exposureRange.min = exposureRange.max = 0l ;
612- exposureTime = 0l ;
644+ exposureRange.min = exposureRange.max = 0 ;
645+ exposureTime = 0 ;
613646 }
614- status = ACameraMetadata_getConstEntry (cameraMetadata.get (), ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, &val);
615- if (status == ACAMERA_OK){
647+ cStatus = ACameraMetadata_getConstEntry (cameraMetadata.get (), ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, &val);
648+ if (cStatus == ACAMERA_OK){
616649 sensitivityRange.min = val.data .i32 [0 ];
617650 sensitivityRange.max = val.data .i32 [1 ];
618651 sensitivity = sensitivityRange.value (2 );
@@ -693,12 +726,13 @@ class AndroidCameraCapture : public IVideoCapture
693726 return false ;
694727 }
695728 captureSession = std::shared_ptr<ACameraCaptureSession>(session, deleter_ACameraCaptureSession);
696- uint8_t aeMode = autoExposure ? ACAMERA_CONTROL_AE_MODE_ON : ACAMERA_CONTROL_AE_MODE_OFF;
729+
697730 ACaptureRequest_setEntry_u8 (captureRequest.get (), ACAMERA_CONTROL_AE_MODE, 1 , &aeMode);
698731 ACaptureRequest_setEntry_i32 (captureRequest.get (), ACAMERA_SENSOR_SENSITIVITY, 1 , &sensitivity);
699- if (!autoExposure ) {
732+ if (aeMode != ACAMERA_CONTROL_AE_MODE_ON ) {
700733 ACaptureRequest_setEntry_i64 (captureRequest.get (), ACAMERA_SENSOR_EXPOSURE_TIME, 1 , &exposureTime);
701734 }
735+ ACaptureRequest_setEntry_u8 (captureRequest.get (), ACAMERA_FLASH_MODE, 1 , &flashMode);
702736
703737 cStatus = ACameraCaptureSession_setRepeatingRequest (captureSession.get (), GetCaptureCallback (), 1 , &request, nullptr );
704738 if (cStatus != ACAMERA_OK) {
@@ -732,6 +766,18 @@ class AndroidCameraCapture : public IVideoCapture
732766 cameraManager = nullptr ;
733767 imageReader = nullptr ;
734768 }
769+
770+ template <typename FuncT, typename T>
771+ bool submitRequest (FuncT setFn, uint32_t tag, const T &data)
772+ {
773+ ACaptureRequest *request = captureRequest.get ();
774+
775+ return request &&
776+ setFn (request, tag, 1 , &data) == ACAMERA_OK &&
777+ ACameraCaptureSession_setRepeatingRequest (captureSession.get (),
778+ GetCaptureCallback (),
779+ 1 , &request, nullptr ) == ACAMERA_OK;
780+ }
735781};
736782
737783/* ******************************* Session management *******************************/
@@ -788,8 +834,8 @@ void OnCaptureFailed(void* context,
788834
789835/* ***************** Implementation of interface functions ********************/
790836
791- Ptr<IVideoCapture> cv::createAndroidCapture_cam ( int index ) {
792- Ptr<AndroidCameraCapture> res = makePtr<AndroidCameraCapture>();
837+ Ptr<IVideoCapture> cv::createAndroidCapture_cam (int index, const VideoCaptureParameters& params ) {
838+ Ptr<AndroidCameraCapture> res = makePtr<AndroidCameraCapture>(params );
793839 if (res && res->initCapture (index))
794840 return res;
795841 return Ptr<IVideoCapture>();
0 commit comments