30#include <opencv2/opencv.hpp>
34#include "libusb/libusb.h"
41CameraUvcAndroid::CameraUvcAndroid()
53 res = uvc_init(&mUvcCtx, NULL);
56 uvc_perror(res,
"uvc_init");
61void CameraUvcAndroid::initJava()
63 mApp = (
struct android_app*)SCgetExtra(
"this_inst");
65 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
66 mApp->activity->vm->AttachCurrentThread(&env, NULL);
68 libusb_set_option(0, LIBUSB_OPTION_ANDROID_JAVAVM, mApp->activity->vm, 0);
71CameraUvcAndroid::~CameraUvcAndroid()
73 mApp->activity->vm->DetachCurrentThread();
79 uvc_free_frame(mFrameConv);
85 mFrameBuffer.release();
88bool CameraUvcAndroid::isValid()
90 return (mUvcCtx) ? true :
false;
93bool CameraUvcAndroid::checkCameraPermission()
96 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
97 mApp->activity->vm->AttachCurrentThread(&env, NULL);
100 jobject oActivity = mApp->activity->clazz;
101 jclass cActivity = env->GetObjectClass(oActivity);
105 bool authPassed =
false;
108 jfieldID reqBoolean = env->GetFieldID(cActivity,
"mMinAuthPassed",
"Z");
109 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
111 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
115 jmethodID camera_permission = env->GetMethodID(cActivity,
"RequestCameraPermission",
"()V");
116 if (camera_permission)
117 env->CallVoidMethod(oActivity, camera_permission);
119 if (env->ExceptionCheck())
121 env->ExceptionClear();
122 MMechostr(MSKRUNTIME,
"Android camera exception : Check android.permission.CAMERA\n");
128 jfieldID reqBoolean = env->GetFieldID(cActivity,
"mCameraAuthPassed",
"Z");
129 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
131 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
133 env->DeleteLocalRef(cActivity);
141void CameraUvcAndroid::startPreview(
int width,
int height,
int index)
144 uvc_device_t* uvcDev;
151 res = uvc_init(&mUvcCtx, NULL);
154 uvc_perror(res,
"uvc_init");
160 if (checkCameraPermission())
196 res = uvc_find_device(mUvcCtx, &uvcDev, 0, 0, NULL);
201 uvc_perror(res,
"uvc_find_device");
202 mSize = cv::Size(0, 0);
208 res = uvc_open(uvcDev, &mUvcDevh);
213 uvc_perror(res,
"uvc_open");
214 mSize = cv::Size(0, 0);
222 const uvc_format_desc_t *format_desc = uvc_get_format_descs(mUvcDevh);
223 const uvc_frame_desc_t *frame_desc = format_desc->frame_descs;
224 enum uvc_frame_format frame_format;
225 mSize = cv::Size(width, height);
228 switch (format_desc->bDescriptorSubtype)
230 case UVC_VS_FORMAT_MJPEG:
231 frame_format = UVC_FRAME_FORMAT_MJPEG;
233 case UVC_VS_FORMAT_FRAME_BASED:
234 frame_format = UVC_FRAME_FORMAT_H264;
237 frame_format = UVC_FRAME_FORMAT_YUYV;
242 fps = 10000000 / frame_desc->dwDefaultFrameInterval;
247 uvc_stream_ctrl_t uvcCtrl;
248 res = uvc_get_stream_ctrl_format_size(mUvcDevh, &uvcCtrl, frame_format, width, height, fps);
255 res = uvc_get_stream_ctrl_format_size(mUvcDevh, &uvcCtrl, frame_format, frame_desc->wWidth, frame_desc->wHeight, fps);
256 mSize = cv::Size(frame_desc->wWidth, frame_desc->wHeight);
260 res = uvc_get_stream_ctrl_format_size(mUvcDevh, &uvcCtrl, frame_format, 640, 480, fps);
261 mSize = cv::Size(640, 480);
271 uvc_perror(res,
"get_mode");
272 mSize = cv::Size(0, 0);
278 uvc_free_frame(mFrameConv);
280 mFrameConv = uvc_allocate_frame(mSize.width * mSize.height * 3);
281 mFrameBuffer = cv::Mat(mSize.height, mSize.width, CV_8UC3);
282 mFrameRGB = cv::Mat(mSize.height, mSize.width, CV_8UC3);
285 const uint8_t UVC_AUTO_EXPOSURE_MODE_AUTO = 2;
286 res = uvc_set_ae_mode(mUvcDevh, UVC_AUTO_EXPOSURE_MODE_AUTO);
288 if (res == UVC_ERROR_PIPE)
292 const uint8_t UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY = 8;
293 res = uvc_set_ae_mode(mUvcDevh, UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY);
296 uvc_perror(res,
" ... uvc_set_ae_mode failed to enable aperture priority mode");
298 uvc_perror(res,
" ... uvc_set_ae_mode failed to enable auto exposure mode");
302 res = uvc_start_streaming(mUvcDevh, &uvcCtrl, CameraUvcAndroid::streamCb, (
void *)
this, 0);
307 uvc_perror(res,
"start_streaming");
308 mSize = cv::Size(0, 0);
319 mSize = cv::Size(0, 0);
322void CameraUvcAndroid::stopPreview()
332 uvc_free_frame(mFrameConv);
346bool CameraUvcAndroid::isOpen()
351void CameraUvcAndroid::streamCb(uvc_frame_t *frame,
void *ptr)
353 CameraUvcAndroid* uvc =
static_cast<CameraUvcAndroid*
>(ptr);
356 if (!uvc->mFrameConv)
359 ret = uvc_any2bgr(frame, uvc->mFrameConv);
362 ret = uvc_any2rgb(frame, uvc->mFrameConv);
366 uvc_perror(ret,
"uvc_any2rgb");
371 uvc->mFrameBuffer.data = (uchar*)uvc->mFrameConv->data;
372 cv::cvtColor(uvc->mFrameBuffer, uvc->mFrameRGB, cv::COLOR_RGB2BGR);
377 uvc->mFrameBuffer.data = (uchar*)uvc->mFrameConv->data;
378 uvc->mFrameBuffer.copyTo(uvc->mFrameRGB);
381 uvc->mUpdated =
true;
384cv::Mat CameraUvcAndroid::grabFrame()
390cv::Size CameraUvcAndroid::getSize()
417 mApp = (
struct android_app*)SCgetExtra(
"this_inst");
419 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
420 mApp->activity->vm->AttachCurrentThread(&env, NULL);
431 jobject oActivity = mApp->activity->clazz;
432 jclass cActivity = env->GetObjectClass(oActivity);
435 jfieldID camera_backend_fieldID = env->GetFieldID(cActivity,
"mCameraBackend",
"Lorg/imaginer/scol/CameraBackend;");
436 if (camera_backend_fieldID)
437 result.
instance = env->GetObjectField(oActivity, camera_backend_fieldID);
441 result.
method = env->GetMethodID(result.
clazz, name, signature);
443 env->DeleteLocalRef(cActivity);
450 mApp->activity->vm->DetachCurrentThread();
461 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
462 mApp->activity->vm->AttachCurrentThread(&env, NULL);
465 jobject oActivity = mApp->activity->clazz;
466 jclass cActivity = env->GetObjectClass(oActivity);
470 bool authPassed =
false;
473 jfieldID reqBoolean = env->GetFieldID(cActivity,
"mMinAuthPassed",
"Z");
474 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
476 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
480 jmethodID camera_permission = env->GetMethodID(cActivity,
"RequestCameraPermission",
"()V");
481 if (camera_permission)
482 env->CallVoidMethod(oActivity, camera_permission);
484 if (env->ExceptionCheck())
486 env->ExceptionClear();
487 MMechostr(MSKRUNTIME,
"Android camera exception : Check android.permission.CAMERA\n");
493 jfieldID reqBoolean = env->GetFieldID(cActivity,
"mCameraAuthPassed",
"Z");
494 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
496 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
498 env->DeleteLocalRef(cActivity);
501 LOGI(
">>>>>>> JgrabMethod look for 'openCamera'");
505 LOGI(
">>>>>>> JgrabMethod failed for 'openCamera'");
509 LOGI(
">>>>>>> JgrabMethod call method");
510 env->CallVoidMethod(method_box.
instance, method_box.
method, (jint)width, (jint)height, (jint)index);
511 env->DeleteLocalRef(method_box.
instance);
512 env->DeleteLocalRef(method_box.
clazz);
514 if (env->ExceptionCheck())
516 env->ExceptionDescribe();
517 env->ExceptionClear();
518 LOGI(
">>>>>>> 'openCamera' error");
525 mFrameBuffer = cv::Mat(mSize.height + mSize.height / 2, mSize.width, CV_8UC1);
526 mFrameRGB = cv::Mat(mSize.height, mSize.width, CV_8UC3);
532 mSize = cv::Size(0, 0);
543 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
544 mApp->activity->vm->AttachCurrentThread(&env, NULL);
549 LOGI(
">>>>>>> JgrabMethod failed for 'closeCamera'");
554 env->DeleteLocalRef(method_box.
instance);
555 env->DeleteLocalRef(method_box.
clazz);
557 if (env->ExceptionCheck())
559 env->ExceptionClear();
560 LOGI(
">>>>>>> JgrabMethod failed for 'closeCamera'");
568 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
569 mApp->activity->vm->AttachCurrentThread(&env, NULL);
574 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
579 env->DeleteLocalRef(method_box.
instance);
580 env->DeleteLocalRef(method_box.
clazz);
582 if (env->ExceptionCheck())
584 env->ExceptionClear();
585 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
592 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
593 mApp->activity->vm->AttachCurrentThread(&env, NULL);
598 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
603 env->DeleteLocalRef(method_box.
instance);
604 env->DeleteLocalRef(method_box.
clazz);
606 if (env->ExceptionCheck())
608 env->ExceptionClear();
609 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
617 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
618 mApp->activity->vm->AttachCurrentThread(&env, NULL);
623 LOGI(
">>>>>>> JgrabMethod failed for 'getDeviceOrientation'");
627 ret = (int)env->CallIntMethod(method_box.
instance, method_box.
method);
628 env->DeleteLocalRef(method_box.
instance);
629 env->DeleteLocalRef(method_box.
clazz);
631 if (env->ExceptionCheck())
632 env->ExceptionClear();
642 if (degree == 90 || degree == 270)
652 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
653 mApp->activity->vm->AttachCurrentThread(&env, NULL);
658 LOGI(
">>>>>>> JgrabMethod failed for 'isCameraOpened'");
662 ret = (bool)env->CallBooleanMethod(method_box.
instance, method_box.
method);
663 env->DeleteLocalRef(method_box.
instance);
664 env->DeleteLocalRef(method_box.
clazz);
666 if (env->ExceptionCheck())
667 env->ExceptionClear();
679 cv::Size nSize(0, 0);
681 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
682 mApp->activity->vm->AttachCurrentThread(&env, NULL);
687 LOGI(
">>>>>>> JgrabMethod failed for 'getPreviewSize'");
691 jobject previewSize_object = env->CallObjectMethod(method_box.
instance, method_box.
method);
693 if (env->ExceptionCheck())
695 env->ExceptionClear();
699 if (previewSize_object == 0)
702 jclass cameraSize_class = env->GetObjectClass(previewSize_object);
703 jfieldID size_width_field = env->GetFieldID(cameraSize_class,
"x",
"I");
704 jfieldID size_height_field = env->GetFieldID(cameraSize_class,
"y",
"I");
706 int width = env->GetIntField(previewSize_object, size_width_field);
707 int height = env->GetIntField(previewSize_object, size_height_field);
708 nSize = cv::Size(width, height);
710 env->DeleteLocalRef(cameraSize_class);
711 env->DeleteLocalRef(previewSize_object);
712 env->DeleteLocalRef(method_box.
instance);
713 env->DeleteLocalRef(method_box.
clazz);
722 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
723 mApp->activity->vm->AttachCurrentThread(&env, NULL);
729 LOGI(
">>>>>>> JgrabMethod failed for 'isCameraFacing'");
733 bool camIsFacing = (bool)env->CallBooleanMethod(facing_method_box.
instance, facing_method_box.
method);
735 if (env->ExceptionCheck())
736 env->ExceptionClear();
738 env->DeleteLocalRef(facing_method_box.
instance);
739 env->DeleteLocalRef(facing_method_box.
clazz);
745 LOGI(
">>>>>>> JgrabMethod failed for 'grabFrame'");
749 jbyteArray frame_buffer_object = (jbyteArray)env->CallObjectMethod(method_box.
instance, method_box.
method);
750 if (!frame_buffer_object || env->ExceptionCheck())
753 env->ExceptionClear();
754 env->DeleteLocalRef(method_box.
instance);
755 env->DeleteLocalRef(method_box.
clazz);
759 int length = env->GetArrayLength((jarray)frame_buffer_object);
760 env->GetByteArrayRegion(frame_buffer_object, 0, length, (jbyte*)
mFrameBuffer.data);
761 env->DeleteLocalRef(frame_buffer_object);
762 env->DeleteLocalRef(method_box.
instance);
763 env->DeleteLocalRef(method_box.
clazz);
768 env->ExceptionClear();
769 MMechostr(MSKRUNTIME,
"Could not get camera frame");
776 cv::cvtColor(
mFrameBuffer, rgbmat, cv::COLOR_YUV2BGR_NV21, 3);
786 cv::flip(rgbmat,
mFrameRGB, camIsFacing ? 1 : -1);
788 else if (rotation == 90)
793 else if (rotation == 270)
824 int w = (int)ANativeWindow_getWidth(mApp->window);
825 int h = (int)ANativeWindow_getHeight(mApp->window);
828 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
829 mApp->activity->vm->AttachCurrentThread(&env, NULL);
834 LOGI(
">>>>>>> JgrabMethod failed for 'setFocusPoint'");
838 env->CallVoidMethod(method_box.
instance, method_box.
method, (jint)x, (jint)y, (jint)w, (jint)h);
840 if (env->ExceptionCheck())
841 env->ExceptionClear();
844 env->DeleteLocalRef(method_box.
instance);
845 env->DeleteLocalRef(method_box.
clazz);
868 mUVC =
new CameraUvcAndroid();
886 mBufferSize = cv::Size(640, 480);
887 mInitializing =
false;
889 MMechostr(MSKDEBUG,
"CameraInputAndroid : Created CameraInputAndroid with size %d:%d", mBufferSize.width, mBufferSize.height);
896 mInitializing =
true;
898 MMechostr(MSKDEBUG,
"CameraInputAndroid::Initialize : Initializing camera backend with size %d:%d", mBufferSize.width, mBufferSize.height);
903 mUVC->startPreview(mBufferSize.width, mBufferSize.height,
mIndex);
906 nSize = mUVC->getSize();
926 mInitializing =
false;
927 if (nSize.width == 0 || nSize.height == 0)
940 if (!mInitializing && mUVC->isOpen())
945 if (!mInitializing && mVI->
isOpen())
949 if (!mInitializing && mVI->
isOpen())
957 mFrameCached.release();
972 return mUVC->isOpen();
986 throw std::logic_error(
"CameraInputAndroid::UpdateImage : Device not initialised");
991 mUVC->grabFrame().copyTo(mFrameCached);
1001 if (mFrameCached.empty())
1002 throw std::logic_error(
"CameraInputAndroid::UpdateImage : Frame is empty");
1004 return mFrameCached;
1012 return mBufferSize.width;
1016 return mVI->
isPortrait() ? mBufferSize.height : mBufferSize.width;
1019 return mVI->
isPortrait() ? mBufferSize.height : mBufferSize.width;
1028 return mBufferSize.height;
1032 return mVI->
isPortrait() ? mBufferSize.width : mBufferSize.height;
1035 return mVI->
isPortrait() ? mBufferSize.width : mBufferSize.height;
1058 cur = mUVC->getSize();
1059 if (cur.width == width && cur.height == height)
1062 mUVC->stopPreview();
1063 mUVC->startPreview(width, height,
mIndex);
1064 nSize = mUVC->getSize();
1066 MMechostr(MSKDEBUG,
"CameraInputAndroid::SetSize : Camera set size : %ix%i\n", mBufferSize.width, mBufferSize.height);
1071 if (cur.width == width && cur.height == height)
1078 MMechostr(MSKDEBUG,
"CameraInputAndroid::SetSize : Camera set size : %ix%i orientation : %i\n", mBufferSize.width, mBufferSize.height, mVI->
getDeviceOrientation());
1082 if (cur.width == width && cur.height == height)
1089 MMechostr(MSKDEBUG,
"CameraInputAndroid::SetSize : Camera set size : %ix%i orientation : %i\n", mBufferSize.width, mBufferSize.height, mVI->
getDeviceOrientation());
1092 mBufferSize = nSize;
1096 mBufferSize = cv::Size(width, height);
1103 std::cout <<
"CameraInputAndroid::TakeSnapshot : taking a snapshot of camera" <<
mIndex <<
"... ";
1106 std::cout <<
"CameraInputAndroid::TakeSnapshot : failed. camera not opened yet." << std::endl;
1113 std::cout <<
"CameraInputAndroid::TakeSnapshot : failed. Frame is empty." << std::endl;
1117 if (!cv::imwrite(path, frame))
1119 std::cout <<
"CameraInputAndroid::TakeSnapshot : failed. Couldn't write to " << path <<
"." << std::endl;
1123 std::cout <<
"CameraInputAndroid::TakeSnapshot : success. Frame written to " << path <<
"." << std::endl;
1132 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : updating frame");
1135 catch (std::exception e)
1137 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : %s", e.what());
1143 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : frame empty!");
1147 ANativeWindow* window = (ANativeWindow*)SCgetExtra(
"hscol");
1150 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : error: window empty !");
1153 ANativeWindow_Buffer buffer;
1156 if (ANativeWindow_lock(window, &buffer, 0) < 0)
1161 cv::resize(frame, frame, cv::Size(buffer.width, buffer.height), 0, 0, cv::INTER_CUBIC);
1163 for (
unsigned int y = 0; y < frame.rows; y++)
1165 for (
unsigned int x = 0; x < frame.cols; x++)
1167 unsigned long srcByte = (x * 3) + (frame.cols * 3 * y);
1168 unsigned long destByte = (x * 4) + (buffer.width * 4 * y);
1170 ((
unsigned char*)buffer.bits)[destByte + 2] = frame.data[srcByte];
1171 ((
unsigned char*)buffer.bits)[destByte + 1] = frame.data[srcByte + 1];
1172 ((
unsigned char*)buffer.bits)[destByte + 0] = frame.data[srcByte + 2];
1173 ((
unsigned char*)buffer.bits)[destByte + 3] = 255;
1178 ANativeWindow_unlockAndPost(window);
bool setFocusPoint(int x, int y)
void startPreview(int width, int height, int index, bool recordingHint)
static const int CAMERA_FACING_FRONT
static const int CAMERA_FACING_BACK
jmethodbox grabMethod(JNIEnv *env, const char *name, const char *signature)
static const std::string android_package
cv::Size getPreviewSize()
int getDeviceOrientation()