BitmapToolkit Scol plugin
CameraInputAndroid.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
25#include "ArManager.h"
26#include "ICameraInput.h"
27#include "CameraInputAndroid.h"
28
29#include <stdexcept>
30#include <opencv2/opencv.hpp>
31
32#ifdef BT_USE_LIBUVC
33
34#include "libusb/libusb.h"
35
39
40// Construction
41CameraUvcAndroid::CameraUvcAndroid()
42{
43 mUpdated = false;
44 mIsOpen = false;
45 mIndex = 0;
46 mFrameConv = 0;
47 mUvcCtx = 0;
48 mUvcDevh = 0;
49
50 initJava();
51
52 uvc_error_t res;
53 res = uvc_init(&mUvcCtx, NULL);
54 if (res < 0)
55 {
56 uvc_perror(res, "uvc_init");
57 mUvcCtx = 0;
58 }
59}
60
61void CameraUvcAndroid::initJava()
62{
63 mApp = (struct android_app*)SCgetExtra("this_inst");
64 JNIEnv* env = 0;
65 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
66 mApp->activity->vm->AttachCurrentThread(&env, NULL);
67
68 libusb_set_option(0, LIBUSB_OPTION_ANDROID_JAVAVM, mApp->activity->vm, 0);
69}
70
71CameraUvcAndroid::~CameraUvcAndroid()
72{
73 mApp->activity->vm->DetachCurrentThread();
74
75 if (mUvcDevh)
76 uvc_close(mUvcDevh);
77
78 if (mFrameConv)
79 uvc_free_frame(mFrameConv);
80
81 if (mUvcCtx)
82 uvc_exit(mUvcCtx);
83
84 mFrameRGB.release();
85 mFrameBuffer.release();
86}
87
88bool CameraUvcAndroid::isValid()
89{
90 return (mUvcCtx) ? true : false;
91}
92
93bool CameraUvcAndroid::checkCameraPermission()
94{
95 JNIEnv* env = 0;
96 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
97 mApp->activity->vm->AttachCurrentThread(&env, NULL);
98
99 //wait for default authorization
100 jobject oActivity = mApp->activity->clazz;
101 jclass cActivity = env->GetObjectClass(oActivity);
102
103 if (cActivity)
104 {
105 bool authPassed = false;
106 while (!authPassed)
107 {
108 jfieldID reqBoolean = env->GetFieldID(cActivity, "mMinAuthPassed", "Z");
109 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
110 if (!authPassed)
111 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
112 }
113
114 //check camera permission
115 jmethodID camera_permission = env->GetMethodID(cActivity, "RequestCameraPermission", "()V");
116 if (camera_permission)
117 env->CallVoidMethod(oActivity, camera_permission);
118
119 if (env->ExceptionCheck())
120 {
121 env->ExceptionClear();
122 MMechostr(MSKRUNTIME, "Android camera exception : Check android.permission.CAMERA\n");
123 }
124
125 authPassed = false;
126 while (!authPassed)
127 {
128 jfieldID reqBoolean = env->GetFieldID(cActivity, "mCameraAuthPassed", "Z");
129 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
130 if (!authPassed)
131 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
132 }
133 env->DeleteLocalRef(cActivity);
134
135 return authPassed;
136 }
137 else
138 return false;
139}
140
141void CameraUvcAndroid::startPreview(int width, int height, int index)
142{
143 uvc_error_t res;
144 uvc_device_t* uvcDev;
145
146 mIndex = index;
147 mIsOpen = false;
148
149 if (!mUvcCtx)
150 {
151 res = uvc_init(&mUvcCtx, NULL);
152 if (res < 0)
153 {
154 uvc_perror(res, "uvc_init");
155 mUvcCtx = 0;
156 return;
157 }
158 }
159
160 if (checkCameraPermission())
161 {
162 /*
163 uvc_device_t** device_list;
164 uvc_device_t* dev;
165 uvc_device_descriptor_t *device_desc;
166 res = uvc_get_device_list(mUvcCtx, &device_list);
167
168 if (res < 0)
169 {
170 uvc_perror(res, "uvc_get_device_list");
171 return;
172 }
173
174 int i = 0;
175 // iterate over all devices.
176 while (device_list[i] != NULL)
177 {
178 // get the internal device object so we can use the libusb handle.
179 dev = device_list[i];
180
181 // get device descriptor.
182 res = uvc_get_device_descriptor((uvc_device_t *)dev, &device_desc);
183 if (res < 0)
184 {
185 uvc_free_device_list(device_list, 0);
186 return;
187 }
188
189 uvc_free_device_descriptor(device_desc);
190 i++;
191 }
192 uvc_free_device_list(device_list, 0);
193 */
194
195 // filter devices: vendor_id, product_id, "serial_num"
196 res = uvc_find_device(mUvcCtx, &uvcDev, 0, 0, NULL);
197
198 if (res < 0)
199 {
200 // no devices found
201 uvc_perror(res, "uvc_find_device");
202 mSize = cv::Size(0, 0);
203 return;
204 }
205 else
206 {
207 // Try to open the device: requires exclusive access
208 res = uvc_open(uvcDev, &mUvcDevh);
209
210 if (res < 0)
211 {
212 // unable to open device
213 uvc_perror(res, "uvc_open");
214 mSize = cv::Size(0, 0);
215 return;
216 }
217 else
218 {
219 // Print out a message containing all the information that libuvc knows about the device
220 //uvc_print_diag(mUvcDevh, stderr);
221
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);
226 int fps = 30;
227
228 switch (format_desc->bDescriptorSubtype)
229 {
230 case UVC_VS_FORMAT_MJPEG:
231 frame_format = UVC_FRAME_FORMAT_MJPEG;
232 break;
233 case UVC_VS_FORMAT_FRAME_BASED:
234 frame_format = UVC_FRAME_FORMAT_H264;
235 break;
236 default:
237 frame_format = UVC_FRAME_FORMAT_YUYV;
238 break;
239 }
240
241 if (frame_desc)
242 fps = 10000000 / frame_desc->dwDefaultFrameInterval;
243
244 //printf("\nFirst format: (%4s) %dx%d %dfps\n", format_desc->fourccFormat, width, height, fps);
245
246 // Try to negotiate first stream profile
247 uvc_stream_ctrl_t uvcCtrl;
248 res = uvc_get_stream_ctrl_format_size(mUvcDevh, &uvcCtrl, frame_format, width, height, fps);
249
250 if (res < 0)
251 {
252 if (frame_desc)
253 {
254 // try with frame size
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);
257 }
258 else
259 {
260 res = uvc_get_stream_ctrl_format_size(mUvcDevh, &uvcCtrl, frame_format, 640, 480, fps);
261 mSize = cv::Size(640, 480);
262 }
263 }
264
265 // Print out the result
266 //uvc_print_stream_ctrl(&uvcCtrl, stderr);
267
268 if (res < 0)
269 {
270 // device doesn't provide a matching stream
271 uvc_perror(res, "get_mode");
272 mSize = cv::Size(0, 0);
273 return;
274 }
275 else
276 {
277 if (mFrameConv)
278 uvc_free_frame(mFrameConv);
279
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);
283
284 // enable auto exposure - see uvc_set_ae_mode documentation
285 const uint8_t UVC_AUTO_EXPOSURE_MODE_AUTO = 2;
286 res = uvc_set_ae_mode(mUvcDevh, UVC_AUTO_EXPOSURE_MODE_AUTO);
287
288 if (res == UVC_ERROR_PIPE)
289 {
290 // this error indicates that the camera does not support the full AE mode;
291 // try again, using aperture priority mode (fixed aperture, variable exposure time)
292 const uint8_t UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY = 8;
293 res = uvc_set_ae_mode(mUvcDevh, UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY);
294
295 if (res < 0)
296 uvc_perror(res, " ... uvc_set_ae_mode failed to enable aperture priority mode");
297 else
298 uvc_perror(res, " ... uvc_set_ae_mode failed to enable auto exposure mode");
299 }
300
301 // Start the video stream. The library will call user function cb
302 res = uvc_start_streaming(mUvcDevh, &uvcCtrl, CameraUvcAndroid::streamCb, (void *) this, 0);
303
304 if (res < 0)
305 {
306 // unable to start stream
307 uvc_perror(res, "start_streaming");
308 mSize = cv::Size(0, 0);
309 return;
310 }
311
312 mIsOpen = true;
313 }
314 }
315 }
316 }
317
318 if (!mIsOpen)
319 mSize = cv::Size(0, 0);
320}
321
322void CameraUvcAndroid::stopPreview()
323{
324 if (mUvcDevh)
325 {
326 uvc_close(mUvcDevh);
327 mUvcDevh = 0;
328 }
329
330 if (mFrameConv)
331 {
332 uvc_free_frame(mFrameConv);
333 mFrameConv = 0;
334 }
335
336 // also close context otherwise usb messages are stuck
337 if (mUvcCtx)
338 {
339 uvc_exit(mUvcCtx);
340 mUvcCtx = 0;
341 }
342
343 mIsOpen = false;
344}
345
346bool CameraUvcAndroid::isOpen()
347{
348 return mIsOpen;
349}
350
351void CameraUvcAndroid::streamCb(uvc_frame_t *frame, void *ptr)
352{
353 CameraUvcAndroid* uvc = static_cast<CameraUvcAndroid*>(ptr);
354 uvc_error_t ret;
355
356 if (!uvc->mFrameConv)
357 return;
358
359 ret = uvc_any2bgr(frame, uvc->mFrameConv);
360 if (ret)
361 {
362 ret = uvc_any2rgb(frame, uvc->mFrameConv);
363
364 if (ret)
365 {
366 uvc_perror(ret, "uvc_any2rgb");
367 return;
368 }
369 else
370 {
371 uvc->mFrameBuffer.data = (uchar*)uvc->mFrameConv->data;
372 cv::cvtColor(uvc->mFrameBuffer, uvc->mFrameRGB, cv::COLOR_RGB2BGR);
373 }
374 }
375 else
376 {
377 uvc->mFrameBuffer.data = (uchar*)uvc->mFrameConv->data;
378 uvc->mFrameBuffer.copyTo(uvc->mFrameRGB);
379 }
380
381 uvc->mUpdated = true;
382}
383
384cv::Mat CameraUvcAndroid::grabFrame()
385{
386 mUpdated = false;
387 return mFrameRGB;
388}
389
390cv::Size CameraUvcAndroid::getSize()
391{
392 return mSize;
393}
394
395#endif //BT_USE_LIBUVC
396
400
401// Constants
404const std::string CameraBackendAndroid::android_package = "org/imaginer/scol/CameraBackend";
405
406// Construction
408{
409 mUpdated = false;
410 mIsOpen = false;
411 mIndex = 0;
412 initJava();
413}
414
416{
417 mApp = (struct android_app*)SCgetExtra("this_inst");
418 JNIEnv* env = 0;
419 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
420 mApp->activity->vm->AttachCurrentThread(&env, NULL);
421}
422
423CameraBackendAndroid::jmethodbox CameraBackendAndroid::grabMethod(JNIEnv* env, const char* name, const char* signature)
424{
426 result.clazz = 0;
427 result.instance = 0;
428 result.method = 0;
429
430 // Get class
431 jobject oActivity = mApp->activity->clazz;
432 jclass cActivity = env->GetObjectClass(oActivity);
433 if (cActivity)
434 {
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);
438 if (result.instance)
439 result.clazz = env->GetObjectClass(result.instance);
440 if (result.clazz)
441 result.method = env->GetMethodID(result.clazz, name, signature);
442
443 env->DeleteLocalRef(cActivity);
444 }
445 return result;
446}
447
449{
450 mApp->activity->vm->DetachCurrentThread();
451 mFrameBuffer.release();
452 mFrameRGB.release();
453}
454
455// Java methods
456void CameraBackendAndroid::startPreview(int width, int height, int index)
457{
458 mIndex = index;
459
460 JNIEnv* env = 0;
461 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
462 mApp->activity->vm->AttachCurrentThread(&env, NULL);
463
464 //wait for default authorization
465 jobject oActivity = mApp->activity->clazz;
466 jclass cActivity = env->GetObjectClass(oActivity);
467
468 if (cActivity)
469 {
470 bool authPassed = false;
471 while (!authPassed)
472 {
473 jfieldID reqBoolean = env->GetFieldID(cActivity, "mMinAuthPassed", "Z");
474 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
475 if (!authPassed)
476 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
477 }
478
479 //check camera permission
480 jmethodID camera_permission = env->GetMethodID(cActivity, "RequestCameraPermission", "()V");
481 if (camera_permission)
482 env->CallVoidMethod(oActivity, camera_permission);
483
484 if (env->ExceptionCheck())
485 {
486 env->ExceptionClear();
487 MMechostr(MSKRUNTIME, "Android camera exception : Check android.permission.CAMERA\n");
488 }
489
490 authPassed = false;
491 while (!authPassed)
492 {
493 jfieldID reqBoolean = env->GetFieldID(cActivity, "mCameraAuthPassed", "Z");
494 authPassed = (bool) env->GetBooleanField(oActivity, reqBoolean);
495 if (!authPassed)
496 boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
497 }
498 env->DeleteLocalRef(cActivity);
499 }
500
501 LOGI(">>>>>>> JgrabMethod look for 'openCamera'");
502 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "openCamera", "(III)V");
503 if (!method_box.instance)
504 {
505 LOGI(">>>>>>> JgrabMethod failed for 'openCamera'");
506 return;
507 }
508
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);
513
514 if (env->ExceptionCheck())
515 {
516 env->ExceptionDescribe();
517 env->ExceptionClear();
518 LOGI(">>>>>>> 'openCamera' error");
519 return;
520 }
521
522 if (isCameraOpened())
523 {
524 mSize = getPreviewSize();
525 mFrameBuffer = cv::Mat(mSize.height + mSize.height / 2, mSize.width, CV_8UC1);
526 mFrameRGB = cv::Mat(mSize.height, mSize.width, CV_8UC3);
527
528 mIsOpen = true;
529 }
530 else
531 {
532 mSize = cv::Size(0, 0);
533 }
534}
535
537{
538 if (mIsOpen)
539 {
540 mIsOpen = false;
541
542 JNIEnv* env = 0;
543 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
544 mApp->activity->vm->AttachCurrentThread(&env, NULL);
545
546 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "closeCamera", "()V");
547 if (!method_box.instance)
548 {
549 LOGI(">>>>>>> JgrabMethod failed for 'closeCamera'");
550 return;
551 }
552
553 env->CallVoidMethod(method_box.instance, method_box.method);
554 env->DeleteLocalRef(method_box.instance);
555 env->DeleteLocalRef(method_box.clazz);
556
557 if (env->ExceptionCheck())
558 {
559 env->ExceptionClear();
560 LOGI(">>>>>>> JgrabMethod failed for 'closeCamera'");
561 }
562 }
563}
564
566{
567 JNIEnv* env = 0;
568 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
569 mApp->activity->vm->AttachCurrentThread(&env, NULL);
570
571 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "torchOn", "()V");
572 if (!method_box.instance)
573 {
574 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
575 return;
576 }
577
578 env->CallVoidMethod(method_box.instance, method_box.method);
579 env->DeleteLocalRef(method_box.instance);
580 env->DeleteLocalRef(method_box.clazz);
581
582 if (env->ExceptionCheck())
583 {
584 env->ExceptionClear();
585 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
586 }
587}
588
590{
591 JNIEnv* env = 0;
592 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
593 mApp->activity->vm->AttachCurrentThread(&env, NULL);
594
595 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "torchOff", "()V");
596 if (!method_box.instance)
597 {
598 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
599 return;
600 }
601
602 env->CallVoidMethod(method_box.instance, method_box.method);
603 env->DeleteLocalRef(method_box.instance);
604 env->DeleteLocalRef(method_box.clazz);
605
606 if (env->ExceptionCheck())
607 {
608 env->ExceptionClear();
609 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
610 }
611}
612
614{
615 int ret = 0;
616 JNIEnv* env = 0;
617 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
618 mApp->activity->vm->AttachCurrentThread(&env, NULL);
619
620 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "getDeviceOrientation", "()I");
621 if (!method_box.instance)
622 {
623 LOGI(">>>>>>> JgrabMethod failed for 'getDeviceOrientation'");
624 return false;
625 }
626
627 ret = (int)env->CallIntMethod(method_box.instance, method_box.method);
628 env->DeleteLocalRef(method_box.instance);
629 env->DeleteLocalRef(method_box.clazz);
630
631 if (env->ExceptionCheck())
632 env->ExceptionClear();
633
634 //LOGI(">>>>>>> getDeviceOrientation: %d", ret);
635 return ret;
636}
637
638
640{
641 int degree = getDeviceOrientation();
642 if (degree == 90 || degree == 270)
643 return true;
644
645 return false;
646}
647
649{
650 bool ret = false;
651 JNIEnv* env = 0;
652 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
653 mApp->activity->vm->AttachCurrentThread(&env, NULL);
654
655 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "isCameraOpened", "()Z");
656 if (!method_box.instance)
657 {
658 LOGI(">>>>>>> JgrabMethod failed for 'isCameraOpened'");
659 return false;
660 }
661
662 ret = (bool)env->CallBooleanMethod(method_box.instance, method_box.method);
663 env->DeleteLocalRef(method_box.instance);
664 env->DeleteLocalRef(method_box.clazz);
665
666 if (env->ExceptionCheck())
667 env->ExceptionClear();
668
669 return ret;
670}
671
673{
674 return mIsOpen;
675}
676
678{
679 cv::Size nSize(0, 0);
680 JNIEnv* env = 0;
681 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
682 mApp->activity->vm->AttachCurrentThread(&env, NULL);
683
684 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "getPreviewSize", "()Landroid/graphics/Point;");
685 if (!method_box.instance)
686 {
687 LOGI(">>>>>>> JgrabMethod failed for 'getPreviewSize'");
688 return nSize;
689 }
690
691 jobject previewSize_object = env->CallObjectMethod(method_box.instance, method_box.method);
692
693 if (env->ExceptionCheck())
694 {
695 env->ExceptionClear();
696 return nSize;
697 }
698
699 if (previewSize_object == 0)
700 return nSize;
701
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");
705
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);
709
710 env->DeleteLocalRef(cameraSize_class);
711 env->DeleteLocalRef(previewSize_object);
712 env->DeleteLocalRef(method_box.instance);
713 env->DeleteLocalRef(method_box.clazz);
714 return nSize;
715}
716
718{
719 mUpdated = false;
720
721 JNIEnv* env = 0;
722 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
723 mApp->activity->vm->AttachCurrentThread(&env, NULL);
724
725 // get camera facing
726 CameraBackendAndroid::jmethodbox facing_method_box = grabMethod(env, "isCameraFacing", "()Z");
727 if (!facing_method_box.instance)
728 {
729 LOGI(">>>>>>> JgrabMethod failed for 'isCameraFacing'");
730 return cv::Mat();
731 }
732
733 bool camIsFacing = (bool)env->CallBooleanMethod(facing_method_box.instance, facing_method_box.method);
734
735 if (env->ExceptionCheck())
736 env->ExceptionClear();
737
738 env->DeleteLocalRef(facing_method_box.instance);
739 env->DeleteLocalRef(facing_method_box.clazz);
740
741 // get image buffer
742 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "grabFrame", "()[B");
743 if (!method_box.instance)
744 {
745 LOGI(">>>>>>> JgrabMethod failed for 'grabFrame'");
746 return cv::Mat();
747 }
748
749 jbyteArray frame_buffer_object = (jbyteArray)env->CallObjectMethod(method_box.instance, method_box.method);
750 if (!frame_buffer_object || env->ExceptionCheck())
751 {
752 // read exception
753 env->ExceptionClear();
754 env->DeleteLocalRef(method_box.instance);
755 env->DeleteLocalRef(method_box.clazz);
756 return cv::Mat();
757 }
758
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);
764
765 if (mFrameBuffer.data == NULL || env->ExceptionCheck())
766 {
767 // read exception
768 env->ExceptionClear();
769 MMechostr(MSKRUNTIME, "Could not get camera frame");
770 return cv::Mat();
771 }
772
773 if (mFrameBuffer.data)
774 {
775 cv::Mat rgbmat;
776 cv::cvtColor(mFrameBuffer, rgbmat, cv::COLOR_YUV2BGR_NV21, 3);
777
778 if (!rgbmat.empty())
779 {
780 //rotate picture
781
782 int rotation = getDeviceOrientation();
783 //image mirror for front view is managed by user
784 if (rotation == 180)
785 {
786 cv::flip(rgbmat, mFrameRGB, camIsFacing ? 1 : -1);
787 }
788 else if (rotation == 90)
789 {
790 cv::transpose(rgbmat, mFrameRGB);
791 cv::flip(mFrameRGB, mFrameRGB, camIsFacing ? 0 : 1);
792 }
793 else if (rotation == 270)
794 {
795 cv::transpose(rgbmat, mFrameRGB);
796 if (mIndex != 1)
797 cv::flip(mFrameRGB, mFrameRGB, 0);
798 }
799 /*else if(camIsFacing)
800 {
801 cv::flip(rgbmat, mFrameRGB, -1);
802 }*/
803 else
804 {
805 rgbmat.copyTo(mFrameRGB);
806 }
807
808 /*cv::Point center(rgbmat.cols / 2, rgbmat.rows / 2);
809 cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, rotation + 90, 1.0);
810 cv::warpAffine(rgbmat, mFrameRGB, rotationMatrix, (rotation == 0 || rotation == 180) ? cv::Size(rgbmat.cols, rgbmat.rows) : cv::Size(rgbmat.rows, rgbmat.cols));
811 */
812
813 mUpdated = true;
814 }
815
816 if (!mUpdated || mFrameRGB.empty())
817 return cv::Mat();
818 }
819 return mFrameRGB;
820}
821
823{
824 int w = (int)ANativeWindow_getWidth(mApp->window);
825 int h = (int)ANativeWindow_getHeight(mApp->window);
826
827 JNIEnv* env = 0;
828 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
829 mApp->activity->vm->AttachCurrentThread(&env, NULL);
830
831 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "doTouchFocus", "(IIII)V");
832 if (!method_box.instance)
833 {
834 LOGI(">>>>>>> JgrabMethod failed for 'setFocusPoint'");
835 return false;
836 }
837
838 env->CallVoidMethod(method_box.instance, method_box.method, (jint)x, (jint)y, (jint)w, (jint)h);
839
840 if (env->ExceptionCheck())
841 env->ExceptionClear();
842
843 // Release references
844 env->DeleteLocalRef(method_box.instance);
845 env->DeleteLocalRef(method_box.clazz);
846 return true;
847}
848
850{
851 return mSize;
852}
853
857
859 : ICameraInput(index)
860{
861
862#ifdef BT_USE_LIBUVC
863 //Try to initialise usb cam first, otherwise fallback on android camera
864 mUsbMode = false;
865
866 mVI = 0;
867
868 mUVC = new CameraUvcAndroid();
869 if (mUVC->isValid())
870 {
871 if (index == 0)
872 mUsbMode = true;
873 else
874 mIndex = index - 1;
875 }
876
877 if (!mUsbMode)
878 {
879 SAFE_DELETE(mUVC);
880 mVI = new CameraBackendAndroid();
881 }
882#else
883 mVI = new CameraBackendAndroid();
884#endif
885
886 mBufferSize = cv::Size(640, 480);
887 mInitializing = false;
888
889 MMechostr(MSKDEBUG, "CameraInputAndroid : Created CameraInputAndroid with size %d:%d", mBufferSize.width, mBufferSize.height);
890}
891
893{
894 if (!mInitializing)
895 {
896 mInitializing = true;
897
898 MMechostr(MSKDEBUG, "CameraInputAndroid::Initialize : Initializing camera backend with size %d:%d", mBufferSize.width, mBufferSize.height);
899 cv::Size nSize;
900#ifdef BT_USE_LIBUVC
901 if (mUsbMode)
902 {
903 mUVC->startPreview(mBufferSize.width, mBufferSize.height, mIndex);
904 if (mUVC->isOpen())
905 {
906 nSize = mUVC->getSize();
907 }
908 else
909 {
910 SAFE_DELETE(mUVC);
911 mUsbMode = false;
912 mVI = new CameraBackendAndroid();
913 }
914 }
915
916 if (!mUsbMode)
917 {
918 mVI->startPreview(mBufferSize.width, mBufferSize.height, mIndex);
919 nSize = mVI->getSize();
920 }
921#else
922 mVI->startPreview(mBufferSize.width, mBufferSize.height, mIndex);
923 nSize = mVI->getSize();
924#endif
925
926 mInitializing = false;
927 if (nSize.width == 0 || nSize.height == 0)
928 return false;
929
930 mBufferSize = nSize;
931 }
932 return true;
933}
934
936{
937#ifdef BT_USE_LIBUVC
938 if (mUsbMode)
939 {
940 if (!mInitializing && mUVC->isOpen())
941 mUVC->stopPreview();
942 }
943 else
944 {
945 if (!mInitializing && mVI->isOpen())
946 mVI->stopPreview();
947 }
948#else
949 if (!mInitializing && mVI->isOpen())
950 mVI->stopPreview();
951#endif
952}
953
955{
956 Close();
957 mFrameCached.release();
958
959#ifdef BT_USE_LIBUVC
960 SAFE_DELETE(mUVC);
961 SAFE_DELETE(mVI);
962#else
963 SAFE_DELETE(mVI);
964#endif
965}
966
968{
969#ifdef BT_USE_LIBUVC
970 if (mUsbMode)
971 {
972 return mUVC->isOpen();
973 }
974 else
975 {
976 return mVI->isOpen();
977 }
978#else
979 return mVI->isOpen();
980#endif
981}
982
984{
985 if (!IsOpened())
986 throw std::logic_error("CameraInputAndroid::UpdateImage : Device not initialised");
987
988#ifdef BT_USE_LIBUVC
989 if (mUsbMode)
990 {
991 mUVC->grabFrame().copyTo(mFrameCached);
992 }
993 else
994 {
995 mVI->grabFrame().copyTo(mFrameCached);
996 }
997#else
998 mVI->grabFrame().copyTo(mFrameCached);
999#endif
1000
1001 if (mFrameCached.empty())
1002 throw std::logic_error("CameraInputAndroid::UpdateImage : Frame is empty");
1003
1004 return mFrameCached;
1005}
1006
1008{
1009#ifdef BT_USE_LIBUVC
1010 if (mUsbMode)
1011 {
1012 return mBufferSize.width;
1013 }
1014 else
1015 {
1016 return mVI->isPortrait() ? mBufferSize.height : mBufferSize.width;
1017 }
1018#else
1019 return mVI->isPortrait() ? mBufferSize.height : mBufferSize.width;
1020#endif
1021}
1022
1024{
1025#ifdef BT_USE_LIBUVC
1026 if (mUsbMode)
1027 {
1028 return mBufferSize.height;
1029 }
1030 else
1031 {
1032 return mVI->isPortrait() ? mBufferSize.width : mBufferSize.height;
1033 }
1034#else
1035 return mVI->isPortrait() ? mBufferSize.width : mBufferSize.height;
1036#endif
1037}
1038
1039void CameraInputAndroid::SetSize(int width, int height)
1040{
1041 if (IsOpened())
1042 {
1043 cv::Size cur;
1044
1045 //MMechostr(MSKDEBUG, "CameraInputAndroid::SetSize : IsOpened : %d x %d\n", width, height);
1046 if (width < height)
1047 {
1048 int pw = height;
1049 height = width;
1050 width = pw;
1051 }
1052
1053 cv::Size nSize;
1054
1055#ifdef BT_USE_LIBUVC
1056 if (mUsbMode)
1057 {
1058 cur = mUVC->getSize();
1059 if (cur.width == width && cur.height == height)
1060 return;
1061
1062 mUVC->stopPreview();
1063 mUVC->startPreview(width, height, mIndex);
1064 nSize = mUVC->getSize();
1065
1066 MMechostr(MSKDEBUG, "CameraInputAndroid::SetSize : Camera set size : %ix%i\n", mBufferSize.width, mBufferSize.height);
1067 }
1068 else
1069 {
1070 cur = mVI->getSize();
1071 if (cur.width == width && cur.height == height)
1072 return;
1073
1074 mVI->stopPreview();
1075 mVI->startPreview(width / 2, height / 2, mIndex);
1076 nSize = mVI->getSize();
1077
1078 MMechostr(MSKDEBUG, "CameraInputAndroid::SetSize : Camera set size : %ix%i orientation : %i\n", mBufferSize.width, mBufferSize.height, mVI->getDeviceOrientation());
1079 }
1080#else
1081 cur = mVI->getSize();
1082 if (cur.width == width && cur.height == height)
1083 return;
1084
1085 mVI->stopPreview();
1086 mVI->startPreview(width / 2, height / 2, mIndex);
1087 nSize = mVI->getSize();
1088
1089 MMechostr(MSKDEBUG, "CameraInputAndroid::SetSize : Camera set size : %ix%i orientation : %i\n", mBufferSize.width, mBufferSize.height, mVI->getDeviceOrientation());
1090#endif
1091
1092 mBufferSize = nSize;
1093 }
1094 else
1095 {
1096 mBufferSize = cv::Size(width, height);
1097 }
1098
1099}
1100
1101bool CameraInputAndroid::TakeSnapshot(std::string path)
1102{
1103 std::cout << "CameraInputAndroid::TakeSnapshot : taking a snapshot of camera" << mIndex << "... ";
1104 if (!IsOpened())
1105 {
1106 std::cout << "CameraInputAndroid::TakeSnapshot : failed. camera not opened yet." << std::endl;
1107 return false;
1108 }
1109
1110 cv::Mat frame = UpdateImage();
1111 if (frame.empty())
1112 {
1113 std::cout << "CameraInputAndroid::TakeSnapshot : failed. Frame is empty." << std::endl;
1114 return false;
1115 }
1116
1117 if (!cv::imwrite(path, frame))
1118 {
1119 std::cout << "CameraInputAndroid::TakeSnapshot : failed. Couldn't write to " << path << "." << std::endl;
1120 return false;
1121 }
1122
1123 std::cout << "CameraInputAndroid::TakeSnapshot : success. Frame written to " << path << "." << std::endl;
1124 return true;
1125}
1126
1128{
1129 cv::Mat frame;
1130 try
1131 {
1132 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : updating frame");
1133 frame = UpdateImage();
1134 }
1135 catch (std::exception e)
1136 {
1137 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : %s", e.what());
1138 return;
1139 }
1140
1141 if (frame.empty())
1142 {
1143 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : frame empty!");
1144 return;
1145 }
1146
1147 ANativeWindow* window = (ANativeWindow*)SCgetExtra("hscol");
1148 if (!window)
1149 {
1150 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : error: window empty !");
1151 return;
1152 }
1153 ANativeWindow_Buffer buffer;
1154
1155 // Try lock buffer
1156 if (ANativeWindow_lock(window, &buffer, 0) < 0)
1157 return;
1158
1159 //MMechostr(MSKDEBUG, "buffer info :: width = %d height = %d stride = %d format = %d", buffer.width, buffer.height, buffer.stride, buffer.format);
1160
1161 cv::resize(frame, frame, cv::Size(buffer.width, buffer.height), 0, 0, cv::INTER_CUBIC);
1162
1163 for (unsigned int y = 0; y < frame.rows; y++)
1164 {
1165 for (unsigned int x = 0; x < frame.cols; x++)
1166 {
1167 unsigned long srcByte = (x * 3) + (frame.cols * 3 * y);
1168 unsigned long destByte = (x * 4) + (buffer.width * 4 * y);
1169
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;
1174 }
1175 }
1176
1177 // Unlock buffer
1178 ANativeWindow_unlockAndPost(window);
1179}
1180
1181bool CameraInputAndroid::SetFocusPoint(int x, int y)
1182{
1183#ifdef BT_USE_LIBUVC
1184 if (mUsbMode)
1185 {
1186 return false;
1187 }
1188 else
1189 {
1190 return mVI->setFocusPoint(x, y);
1191 }
1192#else
1193 return mVI->setFocusPoint(x, y);
1194#endif
1195}
1196
1197void CameraInputAndroid::SetTorchState(bool state)
1198{
1199#ifdef BT_USE_LIBUVC
1200 if (mUsbMode)
1201 {
1202 return;
1203 }
1204 else
1205 {
1206 if (state)
1207 mVI->torchOn();
1208 else
1209 mVI->torchOff();
1210 }
1211#else
1212 if (state)
1213 mVI->torchOn();
1214 else
1215 mVI->torchOff();
1216#endif
1217}
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
virtual bool TakeSnapshot(std::string path)
virtual void SetSize(int width, int height)
virtual void SetTorchState(bool state)
virtual bool SetFocusPoint(int x, int y)
Interface for camera management. Concrete classes are written for Windows, Android and OpenCV native ...