BitmapToolkit Scol plugin
CameraInputAndroid-old.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"
28
29#include <stdexcept>
30#include <opencv2/opencv.hpp>
31
32static cv::Size calc_optimal_camera_resolution(CameraBackendAndroid::PreviewSizes supportedPreviewSizes, int width, int height, float target_ratio, float ratio_tolerance = 0.2f)
33{
34 LOGI("getting optimal resolution for %d:%d, with target ratio %f, with a ratio tolerance of %f", width, height, target_ratio, ratio_tolerance);
35
36 int nearest_width_low = 0;
37 int nearest_height_low = 0;
38 int nearest_width_high = 0;
39 int nearest_height_high = 0;
40
41 CameraBackendAndroid::PreviewSizes nearestRatioPreviewSizes;
42
43 float current_width = 0.0f;
44 float current_height = 0.0f;
45 for (unsigned i = 0; i < supportedPreviewSizes.size(); i++)
46 {
47 cv::Size tsize = supportedPreviewSizes[i];
48 current_width = (float)tsize.width;
49 current_height = (float)tsize.height;
50
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)
53 {
54 LOGI("supported preview size with ratio aroud %f : %d:%d", target_ratio, tsize.width, tsize.height);
55 nearestRatioPreviewSizes.push_back(tsize);
56 }
57
58 nearest_width_high = std::max(nearest_width_high, tsize.width);
59 nearest_height_high = std::max(nearest_height_high, tsize.height);
60 }
61
62 // If there's nothing near the target ratio, ignore and try to find nearest anyway
63 if (nearestRatioPreviewSizes.empty())
64 nearestRatioPreviewSizes = supportedPreviewSizes;
65
66 for (unsigned i = 0; i < nearestRatioPreviewSizes.size(); i++)
67 {
68 cv::Size tsize = nearestRatioPreviewSizes[i];
69 if ((tsize.width == width) && (tsize.height == height))
70 {
71 nearest_width_high = tsize.width;
72 nearest_height_high = tsize.height;
73 nearest_width_low = tsize.width;
74 nearest_height_low = tsize.height;
75 break;
76 }
77
78 if ((tsize.height >= height) && (tsize.height <= nearest_height_high))
79 {
80 nearest_width_high = tsize.width;
81 nearest_height_high = tsize.height;
82 }
83 if ((tsize.height <= height) && (tsize.height >= nearest_height_low))
84 {
85 nearest_width_low = tsize.width;
86 nearest_height_low = tsize.height;
87 }
88 }
89
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);
92
93 return size_found;
94}
95
99
100// Constants
103const std::string CameraBackendAndroid::android_package = "org/imaginer/scol/CameraBackend";
104
105// Construction
107{
108 mAutoUpdate = false;
109 mUpdated = false;
110 mIsOpen = false;
111 mNbEmptyFrames = 0;
112 mIndex = 0;
113 initJava();
114}
115
117{
118 mApp = (struct android_app*)SCgetExtra("this_inst");
119 JNIEnv* env = 0;
120 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
121 mApp->activity->vm->AttachCurrentThread(&env, NULL);
122}
123
124CameraBackendAndroid::jmethodbox CameraBackendAndroid::grabMethod(JNIEnv* env, const char* name, const char* signature)
125{
127 result.clazz = 0;
128 result.instance = 0;
129 result.method = 0;
130
131 // Get class
132 jobject oActivity = mApp->activity->clazz;
133 jclass cActivity = env->GetObjectClass(oActivity);
134 if (cActivity)
135 {
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);
139 if (result.instance)
140 result.clazz = env->GetObjectClass(result.instance);
141 if (result.clazz)
142 result.method = env->GetMethodID(result.clazz, name, signature);
143
144 env->DeleteLocalRef(cActivity);
145 }
146 return result;
147}
148
150{
151 mAutoUpdate = false;
152 mApp->activity->vm->DetachCurrentThread();
153}
154
155// Java methods
156void CameraBackendAndroid::startPreview(int width, int height, int index, bool recordingHint)
157{
158 mIndex = index;
159
160 JNIEnv* env = 0;
161 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
162 mApp->activity->vm->AttachCurrentThread(&env, NULL);
163
164 LOGI(">>>>>>> JgrabMethod look for 'openCamera'");
165 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "openCamera", "(IZ)V");
166 if (!method_box.instance)
167 {
168 LOGI(">>>>>>> JgrabMethod failed for 'openCamera'");
169 return;
170 }
171
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);
176
177 if (env->ExceptionCheck())
178 {
179 env->ExceptionDescribe();
180 env->ExceptionClear();
181 LOGI(">>>>>>> 'openCamera' error");
182 return;
183 }
184
185 method_box = grabMethod(env, "startPreview", "(II)V");
186 if (!method_box.instance)
187 {
188 LOGI(">>>>>>> JgrabMethod failed for 'startPreview'");
189 return;
190 }
191
192 if (isCameraOpened())
193 {
194 //check preview sizes
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;
199
200 mSize = cv::Size(0, 0);
201 if (!supportedPreviewSizes.empty())
202 {
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);
206 }
207 else
208 {
209 MMechostr(MSKRUNTIME, "CameraBackendAndroid::startPreview : Cannot get supported camera camera_resolutions\n");
210 mSize = cv::Size(width, height);
211 }
212
213 mFrameBuffer = cv::Mat(mSize.height * 3 / 2, mSize.width, CV_8UC1);
214 mFrameRGB = cv::Mat(mSize.height, mSize.width, CV_8UC3);
215 //mFrameCached = cv::Mat(mSize.height, mSize.width, CV_8UC3);
216
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);
221
222 if (env->ExceptionCheck())
223 {
224 env->ExceptionClear();
225 return;
226 }
227
228 mAutoUpdate = true;
229 mIsOpen = true;
230 mNbEmptyFrames = 0;
231 }
232}
233
235{
236 if (mIsOpen)
237 {
238 mIsOpen = false;
239 mAutoUpdate = false;
240
241 JNIEnv* env = 0;
242 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
243 mApp->activity->vm->AttachCurrentThread(&env, NULL);
244
245 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "closeCamera", "()V");
246 if (!method_box.instance)
247 {
248 LOGI(">>>>>>> JgrabMethod failed for 'closeCamera'");
249 return;
250 }
251
252 env->CallVoidMethod(method_box.instance, method_box.method);
253 env->DeleteLocalRef(method_box.instance);
254 env->DeleteLocalRef(method_box.clazz);
255
256 if (env->ExceptionCheck())
257 {
258 env->ExceptionClear();
259 LOGI(">>>>>>> JgrabMethod failed for 'closeCamera'");
260 }
261 }
262}
263
265{
266 JNIEnv* env = 0;
267 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
268 mApp->activity->vm->AttachCurrentThread(&env, NULL);
269
270 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "torchOn", "()V");
271 if (!method_box.instance)
272 {
273 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
274 return;
275 }
276
277 env->CallVoidMethod(method_box.instance, method_box.method);
278 env->DeleteLocalRef(method_box.instance);
279 env->DeleteLocalRef(method_box.clazz);
280
281 if (env->ExceptionCheck())
282 {
283 env->ExceptionClear();
284 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
285 }
286}
287
289{
290 JNIEnv* env = 0;
291 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
292 mApp->activity->vm->AttachCurrentThread(&env, NULL);
293
294 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "torchOff", "()V");
295 if (!method_box.instance)
296 {
297 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
298 return;
299 }
300
301 env->CallVoidMethod(method_box.instance, method_box.method);
302 env->DeleteLocalRef(method_box.instance);
303 env->DeleteLocalRef(method_box.clazz);
304
305 if (env->ExceptionCheck())
306 {
307 env->ExceptionClear();
308 LOGI(">>>>>>> JgrabMethod failed for 'torchOn'");
309 }
310}
311
313{
314 int ret = 0;
315 JNIEnv* env = 0;
316 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
317 mApp->activity->vm->AttachCurrentThread(&env, NULL);
318
319 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "getDeviceOrientation", "()I");
320 if (!method_box.instance)
321 {
322 LOGI(">>>>>>> JgrabMethod failed for 'getDeviceOrientation'");
323 return false;
324 }
325
326 ret = (int)env->CallIntMethod(method_box.instance, method_box.method);
327 env->DeleteLocalRef(method_box.instance);
328 env->DeleteLocalRef(method_box.clazz);
329
330 if (env->ExceptionCheck())
331 env->ExceptionClear();
332
333 //LOGI(">>>>>>> getDeviceOrientation: %d", ret);
334 return ret;
335}
336
337
339{
340 int degree = getDeviceOrientation();
341 if (degree == 90 || degree == 270)
342 return true;
343
344 return false;
345}
346
348{
349 bool ret = false;
350 JNIEnv* env = 0;
351 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
352 mApp->activity->vm->AttachCurrentThread(&env, NULL);
353
354 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "isCameraOpened", "()Z");
355 if (!method_box.instance)
356 {
357 LOGI(">>>>>>> JgrabMethod failed for 'isCameraOpened'");
358 return false;
359 }
360
361 ret = (bool)env->CallBooleanMethod(method_box.instance, method_box.method);
362 env->DeleteLocalRef(method_box.instance);
363 env->DeleteLocalRef(method_box.clazz);
364
365 if (env->ExceptionCheck())
366 env->ExceptionClear();
367
368 return ret;
369}
370
372{
373 return mIsOpen;
374}
375
376bool CameraBackendAndroid::setPreviewSize(int width, int height)
377{
378 if (mIsOpen)
379 {
380 mAutoUpdate = false;
381 }
382
383 bool result = false;
384 mFrameBuffer = cv::Mat(height * 3 / 2, width, CV_8UC1);
385 mFrameRGB = cv::Mat(height, width, CV_8UC3);
386 //mFrameCached = cv::Mat(height, width, CV_8UC3);
387
388 JNIEnv* env = 0;
389 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
390 mApp->activity->vm->AttachCurrentThread(&env, NULL);
391
392 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "setPreviewSize", "(II)Z");
393 if (!method_box.instance)
394 {
395 LOGI(">>>>>>> JgrabMethod failed for 'setPreviewSize'");
396 return false;
397 }
398
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);
402
403 if (env->ExceptionCheck())
404 env->ExceptionClear();
405
406 if (mIsOpen)
407 {
408 mAutoUpdate = true;
409 }
410
411 return result;
412}
413
415{
416 cv::Size nSize(0, 0);
417 JNIEnv* env = 0;
418 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
419 mApp->activity->vm->AttachCurrentThread(&env, NULL);
420
421 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "getPreviewSize", "()Landroid/hardware/Camera$Size;");
422 if (!method_box.instance)
423 {
424 LOGI(">>>>>>> JgrabMethod failed for 'getPreviewSize'");
425 return nSize;
426 }
427
428 jobject previewSize_object = env->CallObjectMethod(method_box.instance, method_box.method);
429
430 if (env->ExceptionCheck())
431 {
432 env->ExceptionClear();
433 return nSize;
434 }
435
436 if (previewSize_object == 0)
437 return nSize;
438
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");
442
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);
446
447 env->DeleteLocalRef(cameraSize_class);
448 env->DeleteLocalRef(previewSize_object);
449 env->DeleteLocalRef(method_box.instance);
450 env->DeleteLocalRef(method_box.clazz);
451 return nSize;
452}
453
455{
457 JNIEnv* env = 0;
458 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
459 mApp->activity->vm->AttachCurrentThread(&env, NULL);
460
461 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "getSupportedPreviewSizes", "()[Landroid/hardware/Camera$Size;");
462 if (!method_box.instance)
463 {
464 LOGI(">>>>>>> JgrabMethod failed for 'getSupportedPreviewSizes'");
465 return result;
466 }
467
468 jobjectArray supportedPreviewSizes_object = (jobjectArray)env->CallObjectMethod(method_box.instance, method_box.method);
469 if (env->ExceptionCheck())
470 env->ExceptionClear();
471
472 if (supportedPreviewSizes_object == 0)
473 return result;
474
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");
478
479
480 int length = env->GetArrayLength((jarray)supportedPreviewSizes_object);
481 for (int i = 0; i < length; i++)
482 {
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);
486
487 result.push_back(cv::Size(width, height));
488 env->DeleteLocalRef(previewSize_object);
489 }
490
491 env->DeleteLocalRef(supportedPreviewSizes_object);
492 env->DeleteLocalRef(cameraSize_class);
493 env->DeleteLocalRef(method_box.instance);
494 env->DeleteLocalRef(method_box.clazz);
495 return result;
496}
497
499{
500 mUpdated = false;
501
502 JNIEnv* env = 0;
503 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
504 mApp->activity->vm->AttachCurrentThread(&env, NULL);
505
506 CameraBackendAndroid::jmethodbox facing_method_box = grabMethod(env, "isCameraFacing", "()Z");
507 if (!facing_method_box.instance)
508 {
509 LOGI(">>>>>>> JgrabMethod failed for 'isCameraFacing'");
510 return cv::Mat();
511 }
512
513 bool camIsFacing = (bool)env->CallBooleanMethod(facing_method_box.instance, facing_method_box.method);
514
515 if (env->ExceptionCheck())
516 env->ExceptionClear();
517
518 env->DeleteLocalRef(facing_method_box.instance);
519 env->DeleteLocalRef(facing_method_box.clazz);
520
521 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "grabFrame", "()[B");
522 if (!method_box.instance)
523 {
524 LOGI(">>>>>>> JgrabMethod failed for 'grabFrame'");
525 return cv::Mat();
526 }
527
528 jbyteArray frame_buffer_object = (jbyteArray)env->CallObjectMethod(method_box.instance, method_box.method);
529 if (!frame_buffer_object || env->ExceptionCheck())
530 {
531 // read exception
532 env->ExceptionClear();
533 env->DeleteLocalRef(method_box.instance);
534 env->DeleteLocalRef(method_box.clazz);
535 return cv::Mat();
536 }
537
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);
543
544 if (mFrameBuffer.data == NULL || env->ExceptionCheck())
545 {
546 // read exception
547 env->ExceptionClear();
548 MMechostr(MSKRUNTIME, "Could not get camera frame");
549 return cv::Mat();
550 }
551
552 if (mFrameBuffer.data)
553 {
554 cv::Mat rgbmat;
555 cv::cvtColor(mFrameBuffer, rgbmat, cv::COLOR_YUV2BGR_NV21, 3);
556
557 if (!rgbmat.empty())
558 {
559 //mFrameCached = mFrameRGB;
560
561 //rotate picture
562 int rotation = getDeviceOrientation();
563 //image mirror for front view is managed by user
564 if (rotation == 180)
565 {
566 cv::flip(rgbmat, mFrameRGB, camIsFacing ? 1 : -1);
567 }
568 else if (rotation == 90)
569 {
570 cv::transpose(rgbmat, mFrameRGB);
571 cv::flip(mFrameRGB, mFrameRGB, camIsFacing ? 0 : 1);
572 }
573 else if (rotation == 270)
574 {
575 cv::transpose(rgbmat, mFrameRGB);
576 if (mIndex != 1)
577 cv::flip(mFrameRGB, mFrameRGB, 0);
578 }
579 /*else if(camIsFacing)
580 {
581 cv::flip(rgbmat, mFrameRGB, -1);
582 }*/
583 else
584 {
585 rgbmat.copyTo(mFrameRGB);
586 }
587 /*cv::Point center(rgbmat.cols / 2, rgbmat.rows / 2);
588 cv::Mat rotationMatrix = cv::getRotationMatrix2D(center, rotation + 90, 1.0);
589 cv::warpAffine(rgbmat, mFrameRGB, rotationMatrix, (rotation == 0 || rotation == 180) ? cv::Size(rgbmat.cols, rgbmat.rows) : cv::Size(rgbmat.rows, rgbmat.cols));
590 */
591
592 mUpdated = true;
593 }
594
595 if (!mUpdated || mFrameRGB.empty())
596 return cv::Mat();
597
598 if (mNbEmptyFrames <= 25)
599 {
600 //LOGI(">>>>>>> Check Camera frame state");
601 cv::Mat grey;
602 cv::cvtColor(mFrameRGB, grey, cv::COLOR_BGR2GRAY);
603
604 mNbEmptyFrames++;
605
606 /*
607 //crash with buffers (we send a bad cvmat format)
608 //get involved if the camera is just hidden
609 if (cv::countNonZero(grey) == 0 && mNbEmptyFrames == 25)
610 {
611 LOGI(">>>>>>> Black Camera detected restart without recording hint");
612 stopPreview();
613 startPreview(mSize.width, mSize.height, mIndex, false);
614 return cv::Mat();
615 }*/
616 }
617 }
618 return mFrameRGB;
619}
620
622{
623 int w = (int)ANativeWindow_getWidth(mApp->window);
624 int h = (int)ANativeWindow_getHeight(mApp->window);
625
626 JNIEnv* env = 0;
627 if (mApp->activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK)
628 mApp->activity->vm->AttachCurrentThread(&env, NULL);
629
630 CameraBackendAndroid::jmethodbox method_box = grabMethod(env, "doTouchFocus", "(IIII)V");
631 if (!method_box.instance)
632 {
633 LOGI(">>>>>>> JgrabMethod failed for 'setFocusPoint'");
634 return false;
635 }
636
637 env->CallVoidMethod(method_box.instance, method_box.method, (jint)x, (jint)y, (jint)w, (jint)h);
638
639 if (env->ExceptionCheck())
640 env->ExceptionClear();
641
642 // Release references
643 env->DeleteLocalRef(method_box.instance);
644 env->DeleteLocalRef(method_box.clazz);
645 return true;
646}
647
649{
650 return mSize;
651}
652
656
658 : ICameraInput(index)
659{
660 mVI = new CameraBackendAndroid();
661 mBufferSize = cv::Size(640, 480);
662 mInitializing = false;
663 MMechostr(MSKDEBUG, "CameraInputAndroid : Created CameraInputAndroid with size %d:%d", mBufferSize.width, mBufferSize.height);
664}
665
667{
668 if (!mInitializing)
669 {
670 mInitializing = true;
671 MMechostr(MSKDEBUG, "CameraInputAndroid::Initialize : Initializing camera backend with size %d:%d", mBufferSize.width, mBufferSize.height);
672 mVI->startPreview(mBufferSize.width, mBufferSize.height, mIndex, true);
673 cv::Size nSize = mVI->getSize();
674
675 mInitializing = false;
676 if (nSize.width == 0 || nSize.height == 0)
677 return true;
678
679 mBufferSize = nSize;
680 }
681 return true;
682}
683
685{
686 if (!mInitializing && mVI->isOpen())
687 mVI->stopPreview();
688}
689
691{
692 Close();
693 SAFE_DELETE(mVI);
694}
695
697{
698 return mVI->isOpen();
699}
700
702{
703 if (!IsOpened())
704 throw std::logic_error("CameraInputAndroid::UpdateImage : Device not initialised");
705
706 cv::Mat frame = mVI->grabFrame();
707
708 if (frame.empty())
709 throw std::logic_error("CameraInputAndroid::UpdateImage : Frame is empty");
710
711 return frame;
712}
713
715{
716 return mVI->isPortrait() ? mBufferSize.height : mBufferSize.width;
717}
718
720{
721 return mVI->isPortrait() ? mBufferSize.width : mBufferSize.height;
722}
723
724void CameraInputAndroid::SetSize(int width, int height)
725{
726 bool portrait = mVI->isPortrait();
727
728 if (IsOpened())
729 {
730 //MMechostr(MSKDEBUG, "CameraInputAndroid::SetSize : IsOpened : %d x %d\n", width, height);
731 if (width < height)
732 {
733 int pw = height;
734 height = width;
735 width = pw;
736 }
737
738 //MMechostr(MSKDEBUG, "CameraInputAndroid::SetSize : Size check : %d x %d\n", width, height);
739
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;
744
745 mBufferSize = cv::Size(0, 0);
746 if (!supportedPreviewSizes.empty())
747 {
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);
751 }
752 else
753 MMechostr(MSKRUNTIME, "CameraInputAndroid::SetSize : Cannot get supported camera camera_resolutions\n");
754
755 if ((mBufferSize.width == 0) && (mBufferSize.height == 0))
756 mBufferSize = cv::Size(640, 480);
757
758 mVI->setPreviewSize(mBufferSize.width, mBufferSize.height);
759 }
760 else
761 {
762 mBufferSize = cv::Size(width, height);
763 }
764
765 MMechostr(MSKDEBUG, "CameraInputAndroid::SetSize : Camera set size : %ix%i orientation : %i\n", mBufferSize.width, mBufferSize.height, mVI->getDeviceOrientation());
766}
767
768bool CameraInputAndroid::TakeSnapshot(std::string path)
769{
770 std::cout << "CameraInputAndroid::TakeSnapshot : taking a snapshot of camera" << mIndex << "... ";
771 if (!IsOpened())
772 {
773 std::cout << "CameraInputAndroid::TakeSnapshot : failed. camera not opened yet." << std::endl;
774 return false;
775 }
776
777 cv::Mat frame = UpdateImage();
778 if (frame.empty())
779 {
780 std::cout << "CameraInputAndroid::TakeSnapshot : failed. Frame is empty." << std::endl;
781 return false;
782 }
783
784 if (!cv::imwrite(path, frame))
785 {
786 std::cout << "CameraInputAndroid::TakeSnapshot : failed. Couldn't write to " << path << "." << std::endl;
787 return false;
788 }
789
790 std::cout << "CameraInputAndroid::TakeSnapshot : success. Frame written to " << path << "." << std::endl;
791 return true;
792}
793
795{
796 cv::Mat frame;
797 try
798 {
799 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : updating frame");
800 frame = UpdateImage();
801 }
802 catch (std::exception e)
803 {
804 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : %s", e.what());
805 return;
806 }
807
808 if (frame.empty())
809 {
810 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : frame empty!");
811 return;
812 }
813
814 ANativeWindow* window = (ANativeWindow*)SCgetExtra("hscol");
815 if (!window)
816 {
817 MMechostr(MSKDEBUG, "CameraInputAndroid::RenderToScreen : error: window empty !");
818 return;
819 }
820 ANativeWindow_Buffer buffer;
821
822 // Try lock buffer
823 if (ANativeWindow_lock(window, &buffer, 0) < 0)
824 return;
825
826 //MMechostr(MSKDEBUG, "buffer info :: width = %d height = %d stride = %d format = %d", buffer.width, buffer.height, buffer.stride, buffer.format);
827
828 cv::resize(frame, frame, cv::Size(buffer.width, buffer.height), 0, 0, cv::INTER_CUBIC);
829
830 for (unsigned int y = 0; y < frame.rows; y++)
831 {
832 for (unsigned int x = 0; x < frame.cols; x++)
833 {
834 unsigned long srcByte = (x * 3) + (frame.cols * 3 * y);
835 unsigned long destByte = (x * 4) + (buffer.width * 4 * y);
836
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;
841 }
842 }
843
844 // Unlock buffer
845 ANativeWindow_unlockAndPost(window);
846}
847
848bool CameraInputAndroid::SetFocusPoint(int x, int y)
849{
850 return mVI->setFocusPoint(x, y);
851}
852
854{
855 if (state)
856 mVI->torchOn();
857 else
858 mVI->torchOff();
859}
void startPreview(int width, int height, int index, bool recordingHint)
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
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 ...