30#include <opencv2/opencv.hpp>
32static cv::Size calc_optimal_camera_resolution(
CameraBackendAndroid::PreviewSizes supportedPreviewSizes,
int width,
int height,
float target_ratio,
float ratio_tolerance = 0.2f)
34 LOGI(
"getting optimal resolution for %d:%d, with target ratio %f, with a ratio tolerance of %f", width, height, target_ratio, ratio_tolerance);
36 int nearest_width_low = 0;
37 int nearest_height_low = 0;
38 int nearest_width_high = 0;
39 int nearest_height_high = 0;
43 float current_width = 0.0f;
44 float current_height = 0.0f;
45 for (
unsigned i = 0; i < supportedPreviewSizes.size(); i++)
47 cv::Size tsize = supportedPreviewSizes[i];
48 current_width = (float)tsize.width;
49 current_height = (float)tsize.height;
51 LOGI(
"testing ratio %d/%d = %f", tsize.width, tsize.height, (current_width / current_height));
52 if (fabs((current_width / current_height) - target_ratio) <= ratio_tolerance)
54 LOGI(
"supported preview size with ratio aroud %f : %d:%d", target_ratio, tsize.width, tsize.height);
55 nearestRatioPreviewSizes.push_back(tsize);
58 nearest_width_high = std::max(nearest_width_high, tsize.width);
59 nearest_height_high = std::max(nearest_height_high, tsize.height);
63 if (nearestRatioPreviewSizes.empty())
64 nearestRatioPreviewSizes = supportedPreviewSizes;
66 for (
unsigned i = 0; i < nearestRatioPreviewSizes.size(); i++)
68 cv::Size tsize = nearestRatioPreviewSizes[i];
69 if ((tsize.width == width) && (tsize.height == height))
71 nearest_width_high = tsize.width;
72 nearest_height_high = tsize.height;
73 nearest_width_low = tsize.width;
74 nearest_height_low = tsize.height;
78 if ((tsize.height >= height) && (tsize.height <= nearest_height_high))
80 nearest_width_high = tsize.width;
81 nearest_height_high = tsize.height;
83 if ((tsize.height <= height) && (tsize.height >= nearest_height_low))
85 nearest_width_low = tsize.width;
86 nearest_height_low = tsize.height;
90 cv::Size size_found = (std::abs(nearest_height_high - height) < std::abs(height - nearest_height_low)) ? cv::Size(nearest_width_high, nearest_height_high) : cv::Size(nearest_width_low, nearest_height_low);
91 LOGI(
"nearest preview size found : %d:%d", size_found.width, size_found.height);
118 mApp = (
struct android_app*)SCgetExtra(
"this_inst");
120 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
121 mApp->activity->vm->AttachCurrentThread(&env, NULL);
132 jobject oActivity = mApp->activity->clazz;
133 jclass cActivity = env->GetObjectClass(oActivity);
136 jfieldID camera_backend_fieldID = env->GetFieldID(cActivity,
"mCameraBackend",
"Lorg/imaginer/scol/CameraBackend;");
137 if (camera_backend_fieldID)
138 result.
instance = env->GetObjectField(oActivity, camera_backend_fieldID);
142 result.
method = env->GetMethodID(result.
clazz, name, signature);
144 env->DeleteLocalRef(cActivity);
152 mApp->activity->vm->DetachCurrentThread();
161 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
162 mApp->activity->vm->AttachCurrentThread(&env, NULL);
164 LOGI(
">>>>>>> JgrabMethod look for 'openCamera'");
168 LOGI(
">>>>>>> JgrabMethod failed for 'openCamera'");
172 LOGI(
">>>>>>> JgrabMethod call method");
173 env->CallVoidMethod(method_box.
instance, method_box.
method, (jint)index, (jboolean)recordingHint);
174 env->DeleteLocalRef(method_box.
instance);
175 env->DeleteLocalRef(method_box.
clazz);
177 if (env->ExceptionCheck())
179 env->ExceptionDescribe();
180 env->ExceptionClear();
181 LOGI(
">>>>>>> 'openCamera' error");
185 method_box =
grabMethod(env,
"startPreview",
"(II)V");
188 LOGI(
">>>>>>> JgrabMethod failed for 'startPreview'");
196 float native_width = (float)ANativeWindow_getWidth(mApp->window);
197 float native_height = (float)ANativeWindow_getHeight(mApp->window);
198 float native_ratio = (
isPortrait()) ? native_height / native_width : native_width / native_height;
200 mSize = cv::Size(0, 0);
201 if (!supportedPreviewSizes.empty())
203 mSize = calc_optimal_camera_resolution(supportedPreviewSizes, width, height, (
float)width / (
float)height);
204 if ((mSize.width == 0) && (mSize.height == 0))
205 mSize = calc_optimal_camera_resolution(supportedPreviewSizes, width, height, native_ratio);
209 MMechostr(MSKRUNTIME,
"CameraBackendAndroid::startPreview : Cannot get supported camera camera_resolutions\n");
210 mSize = cv::Size(width, height);
213 mFrameBuffer = cv::Mat(mSize.height * 3 / 2, mSize.width, CV_8UC1);
214 mFrameRGB = cv::Mat(mSize.height, mSize.width, CV_8UC3);
217 LOGI(
">>>>>>> JgrabMethod call method");
218 env->CallVoidMethod(method_box.
instance, method_box.
method, (jint)mSize.width, (jint)mSize.height);
219 env->DeleteLocalRef(method_box.
instance);
220 env->DeleteLocalRef(method_box.
clazz);
222 if (env->ExceptionCheck())
224 env->ExceptionClear();
242 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
243 mApp->activity->vm->AttachCurrentThread(&env, NULL);
248 LOGI(
">>>>>>> JgrabMethod failed for 'closeCamera'");
253 env->DeleteLocalRef(method_box.
instance);
254 env->DeleteLocalRef(method_box.
clazz);
256 if (env->ExceptionCheck())
258 env->ExceptionClear();
259 LOGI(
">>>>>>> JgrabMethod failed for 'closeCamera'");
267 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
268 mApp->activity->vm->AttachCurrentThread(&env, NULL);
273 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
278 env->DeleteLocalRef(method_box.
instance);
279 env->DeleteLocalRef(method_box.
clazz);
281 if (env->ExceptionCheck())
283 env->ExceptionClear();
284 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
291 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
292 mApp->activity->vm->AttachCurrentThread(&env, NULL);
297 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
302 env->DeleteLocalRef(method_box.
instance);
303 env->DeleteLocalRef(method_box.
clazz);
305 if (env->ExceptionCheck())
307 env->ExceptionClear();
308 LOGI(
">>>>>>> JgrabMethod failed for 'torchOn'");
316 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
317 mApp->activity->vm->AttachCurrentThread(&env, NULL);
322 LOGI(
">>>>>>> JgrabMethod failed for 'getDeviceOrientation'");
326 ret = (int)env->CallIntMethod(method_box.
instance, method_box.
method);
327 env->DeleteLocalRef(method_box.
instance);
328 env->DeleteLocalRef(method_box.
clazz);
330 if (env->ExceptionCheck())
331 env->ExceptionClear();
341 if (degree == 90 || degree == 270)
351 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
352 mApp->activity->vm->AttachCurrentThread(&env, NULL);
357 LOGI(
">>>>>>> JgrabMethod failed for 'isCameraOpened'");
361 ret = (bool)env->CallBooleanMethod(method_box.
instance, method_box.
method);
362 env->DeleteLocalRef(method_box.
instance);
363 env->DeleteLocalRef(method_box.
clazz);
365 if (env->ExceptionCheck())
366 env->ExceptionClear();
385 mFrameRGB = cv::Mat(height, width, CV_8UC3);
389 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
390 mApp->activity->vm->AttachCurrentThread(&env, NULL);
395 LOGI(
">>>>>>> JgrabMethod failed for 'setPreviewSize'");
399 result = env->CallBooleanMethod(method_box.
instance, method_box.
method, (jint)width, (jint)height);
400 env->DeleteLocalRef(method_box.
instance);
401 env->DeleteLocalRef(method_box.
clazz);
403 if (env->ExceptionCheck())
404 env->ExceptionClear();
416 cv::Size nSize(0, 0);
418 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
419 mApp->activity->vm->AttachCurrentThread(&env, NULL);
424 LOGI(
">>>>>>> JgrabMethod failed for 'getPreviewSize'");
428 jobject previewSize_object = env->CallObjectMethod(method_box.
instance, method_box.
method);
430 if (env->ExceptionCheck())
432 env->ExceptionClear();
436 if (previewSize_object == 0)
439 jclass cameraSize_class = env->GetObjectClass(previewSize_object);
440 jfieldID size_width_field = env->GetFieldID(cameraSize_class,
"width",
"I");
441 jfieldID size_height_field = env->GetFieldID(cameraSize_class,
"height",
"I");
443 int width = env->GetIntField(previewSize_object, size_width_field);
444 int height = env->GetIntField(previewSize_object, size_height_field);
445 nSize = cv::Size(width, height);
447 env->DeleteLocalRef(cameraSize_class);
448 env->DeleteLocalRef(previewSize_object);
449 env->DeleteLocalRef(method_box.
instance);
450 env->DeleteLocalRef(method_box.
clazz);
458 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
459 mApp->activity->vm->AttachCurrentThread(&env, NULL);
464 LOGI(
">>>>>>> JgrabMethod failed for 'getSupportedPreviewSizes'");
468 jobjectArray supportedPreviewSizes_object = (jobjectArray)env->CallObjectMethod(method_box.
instance, method_box.
method);
469 if (env->ExceptionCheck())
470 env->ExceptionClear();
472 if (supportedPreviewSizes_object == 0)
475 jclass cameraSize_class = env->FindClass(
"android/hardware/Camera$Size");
476 jfieldID size_width_field = env->GetFieldID(cameraSize_class,
"width",
"I");
477 jfieldID size_height_field = env->GetFieldID(cameraSize_class,
"height",
"I");
480 int length = env->GetArrayLength((jarray)supportedPreviewSizes_object);
481 for (
int i = 0; i < length; i++)
483 jobject previewSize_object = env->GetObjectArrayElement(supportedPreviewSizes_object, (jsize)i);
484 int width = env->GetIntField(previewSize_object, size_width_field);
485 int height = env->GetIntField(previewSize_object, size_height_field);
487 result.push_back(cv::Size(width, height));
488 env->DeleteLocalRef(previewSize_object);
491 env->DeleteLocalRef(supportedPreviewSizes_object);
492 env->DeleteLocalRef(cameraSize_class);
493 env->DeleteLocalRef(method_box.
instance);
494 env->DeleteLocalRef(method_box.
clazz);
503 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
504 mApp->activity->vm->AttachCurrentThread(&env, NULL);
509 LOGI(
">>>>>>> JgrabMethod failed for 'isCameraFacing'");
513 bool camIsFacing = (bool)env->CallBooleanMethod(facing_method_box.
instance, facing_method_box.
method);
515 if (env->ExceptionCheck())
516 env->ExceptionClear();
518 env->DeleteLocalRef(facing_method_box.
instance);
519 env->DeleteLocalRef(facing_method_box.
clazz);
524 LOGI(
">>>>>>> JgrabMethod failed for 'grabFrame'");
528 jbyteArray frame_buffer_object = (jbyteArray)env->CallObjectMethod(method_box.
instance, method_box.
method);
529 if (!frame_buffer_object || env->ExceptionCheck())
532 env->ExceptionClear();
533 env->DeleteLocalRef(method_box.
instance);
534 env->DeleteLocalRef(method_box.
clazz);
538 int length = env->GetArrayLength((jarray)frame_buffer_object);
539 env->GetByteArrayRegion(frame_buffer_object, 0, length, (jbyte*)
mFrameBuffer.data);
540 env->DeleteLocalRef(frame_buffer_object);
541 env->DeleteLocalRef(method_box.
instance);
542 env->DeleteLocalRef(method_box.
clazz);
547 env->ExceptionClear();
548 MMechostr(MSKRUNTIME,
"Could not get camera frame");
555 cv::cvtColor(
mFrameBuffer, rgbmat, cv::COLOR_YUV2BGR_NV21, 3);
566 cv::flip(rgbmat,
mFrameRGB, camIsFacing ? 1 : -1);
568 else if (rotation == 90)
573 else if (rotation == 270)
598 if (mNbEmptyFrames <= 25)
602 cv::cvtColor(
mFrameRGB, grey, cv::COLOR_BGR2GRAY);
623 int w = (int)ANativeWindow_getWidth(mApp->window);
624 int h = (int)ANativeWindow_getHeight(mApp->window);
627 if (mApp->activity->vm->GetEnv((
void**)&env, JNI_VERSION_1_6) != JNI_OK)
628 mApp->activity->vm->AttachCurrentThread(&env, NULL);
633 LOGI(
">>>>>>> JgrabMethod failed for 'setFocusPoint'");
637 env->CallVoidMethod(method_box.
instance, method_box.
method, (jint)x, (jint)y, (jint)w, (jint)h);
639 if (env->ExceptionCheck())
640 env->ExceptionClear();
643 env->DeleteLocalRef(method_box.
instance);
644 env->DeleteLocalRef(method_box.
clazz);
661 mBufferSize = cv::Size(640, 480);
662 mInitializing =
false;
663 MMechostr(MSKDEBUG,
"CameraInputAndroid : Created CameraInputAndroid with size %d:%d", mBufferSize.width, mBufferSize.height);
670 mInitializing =
true;
671 MMechostr(MSKDEBUG,
"CameraInputAndroid::Initialize : Initializing camera backend with size %d:%d", mBufferSize.width, mBufferSize.height);
673 cv::Size nSize = mVI->
getSize();
675 mInitializing =
false;
676 if (nSize.width == 0 || nSize.height == 0)
686 if (!mInitializing && mVI->
isOpen())
704 throw std::logic_error(
"CameraInputAndroid::UpdateImage : Device not initialised");
709 throw std::logic_error(
"CameraInputAndroid::UpdateImage : Frame is empty");
716 return mVI->
isPortrait() ? mBufferSize.height : mBufferSize.width;
721 return mVI->
isPortrait() ? mBufferSize.width : mBufferSize.height;
741 float native_width = (float)ANativeWindow_getWidth((ScolWindowHandle)SCgetExtra(
"hscol"));
742 float native_height = (float)ANativeWindow_getHeight((ScolWindowHandle)SCgetExtra(
"hscol"));
743 float native_ratio = (portrait) ? native_height / native_width : native_width / native_height;
745 mBufferSize = cv::Size(0, 0);
746 if (!supportedPreviewSizes.empty())
748 mBufferSize = calc_optimal_camera_resolution(supportedPreviewSizes, width, height, (
float)width / (
float)height);
749 if ((mBufferSize.width == 0) && (mBufferSize.height == 0))
750 mBufferSize = calc_optimal_camera_resolution(supportedPreviewSizes, width, height, native_ratio);
753 MMechostr(MSKRUNTIME,
"CameraInputAndroid::SetSize : Cannot get supported camera camera_resolutions\n");
755 if ((mBufferSize.width == 0) && (mBufferSize.height == 0))
756 mBufferSize = cv::Size(640, 480);
762 mBufferSize = cv::Size(width, height);
765 MMechostr(MSKDEBUG,
"CameraInputAndroid::SetSize : Camera set size : %ix%i orientation : %i\n", mBufferSize.width, mBufferSize.height, mVI->
getDeviceOrientation());
770 std::cout <<
"CameraInputAndroid::TakeSnapshot : taking a snapshot of camera" <<
mIndex <<
"... ";
773 std::cout <<
"CameraInputAndroid::TakeSnapshot : failed. camera not opened yet." << std::endl;
780 std::cout <<
"CameraInputAndroid::TakeSnapshot : failed. Frame is empty." << std::endl;
784 if (!cv::imwrite(path, frame))
786 std::cout <<
"CameraInputAndroid::TakeSnapshot : failed. Couldn't write to " << path <<
"." << std::endl;
790 std::cout <<
"CameraInputAndroid::TakeSnapshot : success. Frame written to " << path <<
"." << std::endl;
799 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : updating frame");
802 catch (std::exception e)
804 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : %s", e.what());
810 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : frame empty!");
814 ANativeWindow* window = (ANativeWindow*)SCgetExtra(
"hscol");
817 MMechostr(MSKDEBUG,
"CameraInputAndroid::RenderToScreen : error: window empty !");
820 ANativeWindow_Buffer buffer;
823 if (ANativeWindow_lock(window, &buffer, 0) < 0)
828 cv::resize(frame, frame, cv::Size(buffer.width, buffer.height), 0, 0, cv::INTER_CUBIC);
830 for (
unsigned int y = 0; y < frame.rows; y++)
832 for (
unsigned int x = 0; x < frame.cols; x++)
834 unsigned long srcByte = (x * 3) + (frame.cols * 3 * y);
835 unsigned long destByte = (x * 4) + (buffer.width * 4 * y);
837 ((
unsigned char*)buffer.bits)[destByte + 2] = frame.data[srcByte];
838 ((
unsigned char*)buffer.bits)[destByte + 1] = frame.data[srcByte + 1];
839 ((
unsigned char*)buffer.bits)[destByte + 0] = frame.data[srcByte + 2];
840 ((
unsigned char*)buffer.bits)[destByte + 3] = 255;
845 ANativeWindow_unlockAndPost(window);
bool setFocusPoint(int x, int y)
void startPreview(int width, int height, int index, bool recordingHint)
PreviewSizes getSupportedPreviewSizes()
static const int CAMERA_FACING_FRONT
static const int CAMERA_FACING_BACK
std::vector< cv::Size > PreviewSizes
bool setPreviewSize(int width, int height)
jmethodbox grabMethod(JNIEnv *env, const char *name, const char *signature)
static const std::string android_package
cv::Size getPreviewSize()
int getDeviceOrientation()