Skip to content

Commit d369cf6

Browse files
authored
Merge pull request opencv#26627 from warped-rudi:torch
Android camera feature enhancements opencv#26627 Closes opencv#24687 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [ ] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake
1 parent 1c28a98 commit d369cf6

File tree

4 files changed

+109
-51
lines changed

4 files changed

+109
-51
lines changed

modules/videoio/include/opencv2/videoio.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,18 @@ enum { CAP_PROP_ARAVIS_AUTOTRIGGER = 600 //!< Autom
580580

581581
//! @} ARAVIS
582582

583+
584+
/** @name Android
585+
@{
586+
*/
587+
588+
//! Properties of cameras available through NDK Camera API backend
589+
enum { CAP_PROP_ANDROID_DEVICE_TORCH = 8001,
590+
};
591+
592+
//! @} Android
593+
594+
583595
/** @name AVFoundation framework for iOS
584596
@{
585597
*/

modules/videoio/src/cap_android_camera.cpp

Lines changed: 94 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -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

5559
static 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

171174
static 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

214218
public:
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>();

modules/videoio/src/cap_android_mediandk.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ const AndroidMediaNdkVideoWriter::FourCCInfo AndroidMediaNdkVideoWriter::FOURCC_
668668

669669
/****************** Implementation of interface functions ********************/
670670

671-
Ptr<IVideoCapture> cv::createAndroidCapture_file(const std::string &filename) {
671+
Ptr<IVideoCapture> cv::createAndroidCapture_file(const std::string &filename, const VideoCaptureParameters& ) {
672672
Ptr<AndroidMediaNdkCapture> res = makePtr<AndroidMediaNdkCapture>();
673673
if (res && res->initCapture(filename.c_str()))
674674
return res;

modules/videoio/src/cap_interface.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,8 +391,8 @@ Ptr<IVideoCapture> createGPhoto2Capture(const std::string& deviceName);
391391

392392
Ptr<IVideoCapture> createXINECapture(const std::string &filename);
393393

394-
Ptr<IVideoCapture> createAndroidCapture_cam( int index );
395-
Ptr<IVideoCapture> createAndroidCapture_file(const std::string &filename);
394+
Ptr<IVideoCapture> createAndroidCapture_cam(int index, const VideoCaptureParameters& params);
395+
Ptr<IVideoCapture> createAndroidCapture_file(const std::string &filename, const VideoCaptureParameters& params);
396396
Ptr<IVideoWriter> createAndroidVideoWriter(const std::string& filename, int fourcc,
397397
double fps, const Size& frameSize,
398398
const VideoWriterParameters& params);

0 commit comments

Comments
 (0)