mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1018 lines
35 KiB
1018 lines
35 KiB
#if !defined(ANDROID_r2_2_0) && !defined(ANDROID_r2_3_3) && !defined(ANDROID_r3_0_1) && \ |
|
!defined(ANDROID_r4_0_0) && !defined(ANDROID_r4_0_3) && !defined(ANDROID_r4_1_1) && \ |
|
!defined(ANDROID_r4_2_0) && !defined(ANDROID_r4_3_0) |
|
# error Building camera wrapper for your version of Android is not supported by OpenCV.\ |
|
You need to modify OpenCV sources in order to compile camera wrapper for your version of Android. |
|
#endif |
|
|
|
#include <camera/Camera.h> |
|
#include <camera/CameraParameters.h> |
|
|
|
#if defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) |
|
# include <system/camera.h> |
|
#endif //defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) |
|
|
|
#include "camera_wrapper.h" |
|
#include "../include/camera_properties.h" |
|
|
|
#if defined(ANDROID_r3_0_1) || defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) || defined(ANDROID_r4_1_1) |
|
//Include SurfaceTexture.h file with the SurfaceTexture class |
|
# include <gui/SurfaceTexture.h> |
|
# define MAGIC_OPENCV_TEXTURE_ID (0x10) |
|
#elif defined(ANDROID_r4_1_1) || defined(ANDROID_r4_2_0) |
|
# include <gui/ISurface.h> |
|
# include <gui/BufferQueue.h> |
|
#elif defined(ANDROID_r4_3_0) |
|
# include <gui/IGraphicBufferProducer.h> |
|
# include <gui/BufferQueue.h> |
|
#else |
|
# include <surfaceflinger/ISurface.h> |
|
#endif |
|
|
|
#include <string> |
|
#include <fstream> |
|
|
|
//undef logging macro from /system/core/libcutils/loghack.h |
|
#ifdef LOGD |
|
# undef LOGD |
|
#endif |
|
|
|
#ifdef LOGI |
|
# undef LOGI |
|
#endif |
|
|
|
#ifdef LOGW |
|
# undef LOGW |
|
#endif |
|
|
|
#ifdef LOGE |
|
# undef LOGE |
|
#endif |
|
|
|
// LOGGING |
|
#include <android/log.h> |
|
#define CAMERA_LOG_TAG "OpenCV_NativeCamera" |
|
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, CAMERA_LOG_TAG, __VA_ARGS__)) |
|
|
|
#include <dlfcn.h> |
|
|
|
using namespace android; |
|
|
|
void debugShowFPS(); |
|
|
|
#if defined(ANDROID_r4_1_1) || defined(ANDROID_r4_2_0) || defined(ANDROID_r4_3_0) |
|
class ConsumerListenerStub: public BufferQueue::ConsumerListener |
|
{ |
|
public: |
|
virtual void onFrameAvailable() |
|
{ |
|
} |
|
virtual void onBuffersReleased() |
|
{ |
|
} |
|
}; |
|
#endif |
|
|
|
std::string getProcessName() |
|
{ |
|
std::string result; |
|
std::ifstream f; |
|
|
|
f.open("/proc/self/cmdline"); |
|
if (f.is_open()) |
|
{ |
|
std::string fullPath; |
|
std::getline(f, fullPath, '\0'); |
|
if (!fullPath.empty()) |
|
{ |
|
int i = fullPath.size()-1; |
|
while ((i >= 0) && (fullPath[i] != '/')) i--; |
|
result = fullPath.substr(i+1, std::string::npos); |
|
} |
|
} |
|
|
|
f.close(); |
|
|
|
return result; |
|
} |
|
|
|
void debugShowFPS() |
|
{ |
|
static int mFrameCount = 0; |
|
static int mLastFrameCount = 0; |
|
static nsecs_t mLastFpsTime = systemTime(); |
|
static float mFps = 0; |
|
|
|
mFrameCount++; |
|
|
|
if (( mFrameCount % 30 ) != 0) |
|
return; |
|
|
|
nsecs_t now = systemTime(); |
|
nsecs_t diff = now - mLastFpsTime; |
|
|
|
if (diff==0) |
|
return; |
|
|
|
mFps = ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff; |
|
mLastFpsTime = now; |
|
mLastFrameCount = mFrameCount; |
|
LOGI("### Camera FPS ### [%d] Frames, %.2f FPS", mFrameCount, mFps); |
|
} |
|
|
|
class CameraHandler: public CameraListener |
|
{ |
|
protected: |
|
int cameraId; |
|
sp<Camera> camera; |
|
CameraParameters params; |
|
CameraCallback cameraCallback; |
|
void* userData; |
|
|
|
int emptyCameraCallbackReported; |
|
|
|
static const char* flashModesNames[ANDROID_CAMERA_FLASH_MODES_NUM]; |
|
static const char* focusModesNames[ANDROID_CAMERA_FOCUS_MODES_NUM]; |
|
static const char* whiteBalanceModesNames[ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM]; |
|
static const char* antibandingModesNames[ANDROID_CAMERA_ANTIBANDING_MODES_NUM]; |
|
|
|
void doCall(void* buffer, size_t bufferSize) |
|
{ |
|
if (cameraCallback == 0) |
|
{ |
|
if (!emptyCameraCallbackReported) |
|
LOGE("CameraHandler::doCall(void*, size_t): Camera callback is empty!"); |
|
|
|
emptyCameraCallbackReported++; |
|
} |
|
else |
|
{ |
|
bool res = (*cameraCallback)(buffer, bufferSize, userData); |
|
|
|
if(!res) |
|
{ |
|
LOGE("CameraHandler::doCall(void*, size_t): cameraCallback returns false (camera connection will be closed)"); |
|
closeCameraConnect(); |
|
} |
|
} |
|
} |
|
|
|
void doCall(const sp<IMemory>& dataPtr) |
|
{ |
|
if (dataPtr == NULL) |
|
{ |
|
LOGE("CameraHandler::doCall(const sp<IMemory>&): dataPtr==NULL (no frame to handle)"); |
|
return; |
|
} |
|
|
|
size_t size = dataPtr->size(); |
|
if (size <= 0) |
|
{ |
|
LOGE("CameraHandler::doCall(const sp<IMemory>&): IMemory object is of zero size"); |
|
return; |
|
} |
|
|
|
void* buffer = (void *)dataPtr->pointer(); |
|
if (!buffer) |
|
{ |
|
LOGE("CameraHandler::doCall(const sp<IMemory>&): Buffer pointer is NULL"); |
|
return; |
|
} |
|
|
|
doCall(buffer, size); |
|
} |
|
|
|
virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) |
|
{ |
|
static uint32_t count = 0; |
|
count++; |
|
|
|
LOGE("Recording cb: %d %lld %%p Offset:%%d Stride:%%d\n", msgType, timestamp); |
|
|
|
if (dataPtr == NULL) |
|
{ |
|
LOGE("postDataTimestamp: dataPtr IS ZERO -- returning"); |
|
camera->releaseRecordingFrame(dataPtr); |
|
LOGE("postDataTimestamp: camera->releaseRecordingFrame(dataPtr) is done"); |
|
return; |
|
} |
|
|
|
uint8_t *ptr = (uint8_t*) dataPtr->pointer(); |
|
if (ptr) |
|
LOGE("VID_CB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9]); |
|
else |
|
LOGE("postDataTimestamp: Ptr is zero"); |
|
|
|
camera->releaseRecordingFrame(dataPtr); |
|
} |
|
|
|
// Split list of floats, returns number of floats found |
|
static int split_float(const char *str, float* out, char delim, int max_elem_num, |
|
char **endptr = NULL) |
|
{ |
|
// Find the first float. |
|
char *end = const_cast<char*>(str); |
|
int elem_num = 0; |
|
for(; elem_num < max_elem_num; elem_num++ ){ |
|
char* curr_end; |
|
out[elem_num] = (float)strtof(end, &curr_end); |
|
// No other numbers found, finish the loop |
|
if(end == curr_end){ |
|
break; |
|
} |
|
if (*curr_end != delim) { |
|
// When end of string, finish the loop |
|
if (*curr_end == 0){ |
|
elem_num++; |
|
break; |
|
} |
|
else { |
|
LOGE("Cannot find delimeter (%c) in str=%s", delim, str); |
|
return -1; |
|
} |
|
} |
|
// Skip the delimiter character |
|
end = curr_end + 1; |
|
} |
|
if (endptr) |
|
*endptr = end; |
|
return elem_num; |
|
} |
|
|
|
int is_supported(const char* supp_modes_key, const char* mode) |
|
{ |
|
const char* supported_modes = params.get(supp_modes_key); |
|
return (supported_modes && mode && (strstr(supported_modes, mode) > 0)); |
|
} |
|
|
|
float getFocusDistance(int focus_distance_type) |
|
{ |
|
#if !defined(ANDROID_r2_2_0) |
|
if (focus_distance_type >= 0 && focus_distance_type < 3) |
|
{ |
|
float focus_distances[3]; |
|
const char* output = params.get(CameraParameters::KEY_FOCUS_DISTANCES); |
|
int val_num = CameraHandler::split_float(output, focus_distances, ',', 3); |
|
if(val_num == 3) |
|
{ |
|
return focus_distances[focus_distance_type]; |
|
} |
|
else |
|
{ |
|
LOGE("Invalid focus distances."); |
|
} |
|
} |
|
#endif |
|
return -1; |
|
} |
|
|
|
static int getModeNum(const char** modes, const int modes_num, const char* mode_name) |
|
{ |
|
for (int i = 0; i < modes_num; i++){ |
|
if(!strcmp(modes[i],mode_name)) |
|
return i; |
|
} |
|
return -1; |
|
} |
|
|
|
public: |
|
CameraHandler(CameraCallback callback = 0, void* _userData = 0): |
|
cameraId(0), |
|
cameraCallback(callback), |
|
userData(_userData), |
|
emptyCameraCallbackReported(0) |
|
{ |
|
LOGD("Instantiated new CameraHandler (%p, %p)", callback, _userData); |
|
} |
|
|
|
virtual ~CameraHandler() |
|
{ |
|
LOGD("CameraHandler destructor is called"); |
|
} |
|
|
|
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) |
|
{ |
|
LOGE("CameraHandler::Notify: msgType=%d ext1=%d ext2=%d\n", msgType, ext1, ext2); |
|
#if 0 |
|
if ( msgType & CAMERA_MSG_FOCUS ) |
|
LOGE("CameraHandler::Notify AutoFocus %s in %llu us\n", (ext1) ? "OK" : "FAIL", timevalDelay(&autofocus_start)); |
|
|
|
if ( msgType & CAMERA_MSG_SHUTTER ) |
|
LOGE("CameraHandler::Notify Shutter done in %llu us\n", timeval_delay(&picture_start)); |
|
#endif |
|
} |
|
|
|
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr |
|
#if defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) || defined(ANDROID_r4_1_1) || defined(ANDROID_r4_2_0) || defined(ANDROID_r4_3_0) |
|
,camera_frame_metadata_t* |
|
#endif |
|
) |
|
{ |
|
debugShowFPS(); |
|
|
|
if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) |
|
{ |
|
doCall(dataPtr); |
|
return; |
|
} |
|
|
|
//if (msgType != CAMERA_MSG_PREVIEW_FRAME) |
|
//LOGE("CameraHandler::postData Recieved message %d is not equal to CAMERA_MSG_PREVIEW_FRAME (%d)", (int) msgType, CAMERA_MSG_PREVIEW_FRAME); |
|
|
|
if ( msgType & CAMERA_MSG_RAW_IMAGE ) |
|
LOGE("CameraHandler::postData Unexpected data format: RAW\n"); |
|
|
|
if (msgType & CAMERA_MSG_POSTVIEW_FRAME) |
|
LOGE("CameraHandler::postData Unexpected data format: Postview frame\n"); |
|
|
|
if (msgType & CAMERA_MSG_COMPRESSED_IMAGE ) |
|
LOGE("CameraHandler::postData Unexpected data format: JPEG"); |
|
} |
|
|
|
static CameraHandler* initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters); |
|
void closeCameraConnect(); |
|
double getProperty(int propIdx); |
|
void setProperty(int propIdx, double value); |
|
static void applyProperties(CameraHandler** ppcameraHandler); |
|
|
|
std::string cameraPropertySupportedPreviewSizesString; |
|
std::string cameraPropertyPreviewFormatString; |
|
}; |
|
|
|
const char* CameraHandler::flashModesNames[ANDROID_CAMERA_FLASH_MODES_NUM] = |
|
{ |
|
CameraParameters::FLASH_MODE_AUTO, |
|
CameraParameters::FLASH_MODE_OFF, |
|
CameraParameters::FLASH_MODE_ON, |
|
CameraParameters::FLASH_MODE_RED_EYE, |
|
CameraParameters::FLASH_MODE_TORCH |
|
}; |
|
|
|
const char* CameraHandler::focusModesNames[ANDROID_CAMERA_FOCUS_MODES_NUM] = |
|
{ |
|
CameraParameters::FOCUS_MODE_AUTO, |
|
#if !defined(ANDROID_r2_2_0) |
|
CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO, |
|
#endif |
|
CameraParameters::FOCUS_MODE_EDOF, |
|
CameraParameters::FOCUS_MODE_FIXED, |
|
CameraParameters::FOCUS_MODE_INFINITY |
|
}; |
|
|
|
const char* CameraHandler::whiteBalanceModesNames[ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM] = |
|
{ |
|
CameraParameters::WHITE_BALANCE_AUTO, |
|
CameraParameters::WHITE_BALANCE_CLOUDY_DAYLIGHT, |
|
CameraParameters::WHITE_BALANCE_DAYLIGHT, |
|
CameraParameters::WHITE_BALANCE_FLUORESCENT, |
|
CameraParameters::WHITE_BALANCE_INCANDESCENT, |
|
CameraParameters::WHITE_BALANCE_SHADE, |
|
CameraParameters::WHITE_BALANCE_TWILIGHT |
|
}; |
|
|
|
const char* CameraHandler::antibandingModesNames[ANDROID_CAMERA_ANTIBANDING_MODES_NUM] = |
|
{ |
|
CameraParameters::ANTIBANDING_50HZ, |
|
CameraParameters::ANTIBANDING_60HZ, |
|
CameraParameters::ANTIBANDING_AUTO |
|
}; |
|
|
|
|
|
CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters) |
|
{ |
|
|
|
typedef sp<Camera> (*Android22ConnectFuncType)(); |
|
typedef sp<Camera> (*Android23ConnectFuncType)(int); |
|
typedef sp<Camera> (*Android3DConnectFuncType)(int, int); |
|
typedef sp<Camera> (*Android43ConnectFuncType)(int, const String16&, int); |
|
|
|
const int ANY_CAMERA_INDEX = -1; |
|
const int BACK_CAMERA_INDEX = 99; |
|
const int FRONT_CAMERA_INDEX = 98; |
|
|
|
enum { |
|
CAMERA_SUPPORT_MODE_2D = 0x01, /* Camera Sensor supports 2D mode. */ |
|
CAMERA_SUPPORT_MODE_3D = 0x02, /* Camera Sensor supports 3D mode. */ |
|
CAMERA_SUPPORT_MODE_NONZSL = 0x04, /* Camera Sensor in NON-ZSL mode. */ |
|
CAMERA_SUPPORT_MODE_ZSL = 0x08 /* Camera Sensor supports ZSL mode. */ |
|
}; |
|
|
|
// used for Android 4.3 |
|
enum { |
|
USE_CALLING_UID = -1 |
|
}; |
|
|
|
const char Android22ConnectName[] = "_ZN7android6Camera7connectEv"; |
|
const char Android23ConnectName[] = "_ZN7android6Camera7connectEi"; |
|
const char Android3DConnectName[] = "_ZN7android6Camera7connectEii"; |
|
const char Android43ConnectName[] = "_ZN7android6Camera7connectEiRKNS_8String16Ei"; |
|
|
|
int localCameraIndex = cameraId; |
|
|
|
if (cameraId == ANY_CAMERA_INDEX) |
|
{ |
|
localCameraIndex = 0; |
|
} |
|
#if !defined(ANDROID_r2_2_0) |
|
else if (cameraId == BACK_CAMERA_INDEX) |
|
{ |
|
LOGD("Back camera selected"); |
|
for (int i = 0; i < Camera::getNumberOfCameras(); i++) |
|
{ |
|
CameraInfo info; |
|
Camera::getCameraInfo(i, &info); |
|
if (info.facing == CAMERA_FACING_BACK) |
|
{ |
|
localCameraIndex = i; |
|
break; |
|
} |
|
} |
|
} |
|
else if (cameraId == FRONT_CAMERA_INDEX) |
|
{ |
|
LOGD("Front camera selected"); |
|
for (int i = 0; i < Camera::getNumberOfCameras(); i++) |
|
{ |
|
CameraInfo info; |
|
Camera::getCameraInfo(i, &info); |
|
if (info.facing == CAMERA_FACING_FRONT) |
|
{ |
|
localCameraIndex = i; |
|
break; |
|
} |
|
} |
|
} |
|
|
|
if (localCameraIndex == BACK_CAMERA_INDEX) |
|
{ |
|
LOGE("Back camera not found!"); |
|
return NULL; |
|
} |
|
else if (localCameraIndex == FRONT_CAMERA_INDEX) |
|
{ |
|
LOGE("Front camera not found!"); |
|
return NULL; |
|
} |
|
#endif |
|
|
|
LOGD("CameraHandler::initCameraConnect(%p, %d, %p, %p)", callback, localCameraIndex, userData, prevCameraParameters); |
|
|
|
sp<Camera> camera = 0; |
|
|
|
void* CameraHALHandle = dlopen("libcamera_client.so", RTLD_LAZY); |
|
|
|
if (!CameraHALHandle) |
|
{ |
|
LOGE("Cannot link to \"libcamera_client.so\""); |
|
return NULL; |
|
} |
|
|
|
// reset errors |
|
dlerror(); |
|
|
|
if (Android22ConnectFuncType Android22Connect = (Android22ConnectFuncType)dlsym(CameraHALHandle, Android22ConnectName)) |
|
{ |
|
LOGD("Connecting to CameraService v 2.2"); |
|
camera = Android22Connect(); |
|
} |
|
else if (Android23ConnectFuncType Android23Connect = (Android23ConnectFuncType)dlsym(CameraHALHandle, Android23ConnectName)) |
|
{ |
|
LOGD("Connecting to CameraService v 2.3"); |
|
camera = Android23Connect(localCameraIndex); |
|
} |
|
else if (Android3DConnectFuncType Android3DConnect = (Android3DConnectFuncType)dlsym(CameraHALHandle, Android3DConnectName)) |
|
{ |
|
LOGD("Connecting to CameraService v 3D"); |
|
camera = Android3DConnect(localCameraIndex, CAMERA_SUPPORT_MODE_2D); |
|
} |
|
else if (Android43ConnectFuncType Android43Connect = (Android43ConnectFuncType)dlsym(CameraHALHandle, Android43ConnectName)) |
|
{ |
|
std::string currentProcName = getProcessName(); |
|
LOGD("Current process name for camera init: %s", currentProcName.c_str()); |
|
camera = Android43Connect(localCameraIndex, String16(currentProcName.c_str()), USE_CALLING_UID); |
|
} |
|
else |
|
{ |
|
dlclose(CameraHALHandle); |
|
LOGE("Cannot connect to CameraService. Connect method was not found!"); |
|
return NULL; |
|
} |
|
|
|
dlclose(CameraHALHandle); |
|
|
|
if ( 0 == camera.get() ) |
|
{ |
|
LOGE("initCameraConnect: Unable to connect to CameraService\n"); |
|
return 0; |
|
} |
|
|
|
CameraHandler* handler = new CameraHandler(callback, userData); |
|
camera->setListener(handler); |
|
|
|
handler->camera = camera; |
|
handler->cameraId = localCameraIndex; |
|
|
|
if (prevCameraParameters != NULL) |
|
{ |
|
LOGI("initCameraConnect: Setting paramers from previous camera handler"); |
|
camera->setParameters(prevCameraParameters->flatten()); |
|
handler->params.unflatten(prevCameraParameters->flatten()); |
|
} |
|
else |
|
{ |
|
android::String8 params_str = camera->getParameters(); |
|
LOGI("initCameraConnect: [%s]", params_str.string()); |
|
|
|
handler->params.unflatten(params_str); |
|
|
|
LOGD("Supported Cameras: %s", handler->params.get("camera-indexes")); |
|
LOGD("Supported Picture Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES)); |
|
LOGD("Supported Picture Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PICTURE_FORMATS)); |
|
LOGD("Supported Preview Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES)); |
|
LOGD("Supported Preview Formats: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS)); |
|
LOGD("Supported Preview Frame Rates: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FRAME_RATES)); |
|
LOGD("Supported Thumbnail Sizes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_JPEG_THUMBNAIL_SIZES)); |
|
LOGD("Supported Whitebalance Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE)); |
|
LOGD("Supported Effects: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_EFFECTS)); |
|
LOGD("Supported Scene Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_SCENE_MODES)); |
|
LOGD("Supported Focus Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES)); |
|
LOGD("Supported Antibanding Options: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_ANTIBANDING)); |
|
LOGD("Supported Flash Modes: %s", handler->params.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES)); |
|
|
|
#if !defined(ANDROID_r2_2_0) |
|
// Set focus mode to continuous-video if supported |
|
const char* available_focus_modes = handler->params.get(CameraParameters::KEY_SUPPORTED_FOCUS_MODES); |
|
if (available_focus_modes != 0) |
|
{ |
|
if (strstr(available_focus_modes, "continuous-video") != NULL) |
|
{ |
|
handler->params.set(CameraParameters::KEY_FOCUS_MODE, CameraParameters::FOCUS_MODE_CONTINUOUS_VIDEO); |
|
|
|
status_t resParams = handler->camera->setParameters(handler->params.flatten()); |
|
|
|
if (resParams != 0) |
|
{ |
|
LOGE("initCameraConnect: failed to set autofocus mode to \"continuous-video\""); |
|
} |
|
else |
|
{ |
|
LOGD("initCameraConnect: autofocus is set to mode \"continuous-video\""); |
|
} |
|
} |
|
} |
|
#endif |
|
|
|
//check if yuv420sp format available. Set this format as preview format. |
|
const char* available_formats = handler->params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS); |
|
if (available_formats != 0) |
|
{ |
|
const char* format_to_set = 0; |
|
const char* pos = available_formats; |
|
const char* ptr = pos; |
|
while(true) |
|
{ |
|
while(*ptr != 0 && *ptr != ',') ++ptr; |
|
if (ptr != pos) |
|
{ |
|
if (0 == strncmp(pos, "yuv420sp", ptr - pos)) |
|
{ |
|
format_to_set = "yuv420sp"; |
|
break; |
|
} |
|
if (0 == strncmp(pos, "yvu420sp", ptr - pos)) |
|
format_to_set = "yvu420sp"; |
|
} |
|
if (*ptr == 0) |
|
break; |
|
pos = ++ptr; |
|
} |
|
|
|
if (0 != format_to_set) |
|
{ |
|
handler->params.setPreviewFormat(format_to_set); |
|
|
|
status_t resParams = handler->camera->setParameters(handler->params.flatten()); |
|
|
|
if (resParams != 0) |
|
LOGE("initCameraConnect: failed to set preview format to %s", format_to_set); |
|
else |
|
LOGD("initCameraConnect: preview format is set to %s", format_to_set); |
|
} |
|
} |
|
} |
|
|
|
status_t bufferStatus; |
|
#if defined(ANDROID_r2_2_0) |
|
bufferStatus = camera->setPreviewDisplay(sp<ISurface>(0 /*new DummySurface*/)); |
|
if (bufferStatus != 0) |
|
LOGE("initCameraConnect: failed setPreviewDisplay(0) call (status %d); camera might not work correctly on some devices", bufferStatus); |
|
#elif defined(ANDROID_r2_3_3) |
|
/* Do nothing in case of 2.3 for now */ |
|
#elif defined(ANDROID_r3_0_1) || defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) |
|
sp<SurfaceTexture> surfaceTexture = new SurfaceTexture(MAGIC_OPENCV_TEXTURE_ID); |
|
bufferStatus = camera->setPreviewTexture(surfaceTexture); |
|
if (bufferStatus != 0) |
|
LOGE("initCameraConnect: failed setPreviewTexture call (status %d); camera might not work correctly", bufferStatus); |
|
#elif defined(ANDROID_r4_1_1) || defined(ANDROID_r4_2_0) || defined(ANDROID_r4_3_0) |
|
sp<BufferQueue> bufferQueue = new BufferQueue(); |
|
sp<BufferQueue::ConsumerListener> queueListener = new ConsumerListenerStub(); |
|
bufferQueue->consumerConnect(queueListener); |
|
bufferStatus = camera->setPreviewTexture(bufferQueue); |
|
if (bufferStatus != 0) |
|
LOGE("initCameraConnect: failed setPreviewTexture call; camera might not work correctly"); |
|
#endif |
|
|
|
#if (defined(ANDROID_r2_2_0) || defined(ANDROID_r2_3_3) || defined(ANDROID_r3_0_1)) |
|
# if 1 |
|
////ATTENTION: switching between two versions: with and without copying memory inside Android OS |
|
//// see the method CameraService::Client::copyFrameAndPostCopiedFrame and where it is used |
|
camera->setPreviewCallbackFlags( FRAME_CALLBACK_FLAG_ENABLE_MASK | FRAME_CALLBACK_FLAG_COPY_OUT_MASK);//with copy |
|
# else |
|
camera->setPreviewCallbackFlags( FRAME_CALLBACK_FLAG_ENABLE_MASK );//without copy |
|
# endif |
|
#else |
|
camera->setPreviewCallbackFlags( CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK | CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK);//with copy |
|
#endif //!(defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3)) |
|
|
|
LOGD("Starting preview"); |
|
status_t previewStatus = camera->startPreview(); |
|
|
|
if (previewStatus != 0) |
|
{ |
|
LOGE("initCameraConnect: startPreview() fails. Closing camera connection..."); |
|
handler->closeCameraConnect(); |
|
handler = 0; |
|
} |
|
else |
|
{ |
|
LOGD("Preview started successfully"); |
|
} |
|
|
|
return handler; |
|
} |
|
|
|
void CameraHandler::closeCameraConnect() |
|
{ |
|
if (camera == NULL) |
|
{ |
|
LOGI("... camera is already NULL"); |
|
return; |
|
} |
|
|
|
camera->stopPreview(); |
|
#if defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) || defined(ANDROID_r4_1_1) || defined(ANDROID_r4_2_0) || defined(ANDROID_r4_3_0) |
|
camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP); |
|
#endif |
|
camera->disconnect(); |
|
camera.clear(); |
|
camera=NULL; |
|
// ATTENTION!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
// When we set |
|
// camera=NULL |
|
// above, the pointed instance of android::Camera object is destructed, |
|
// since this member `camera' has type android::sp<Camera> (android smart pointer template class), |
|
// and this is the only pointer to it. |
|
// |
|
// BUT this instance of CameraHandler is set as a listener for that android::Camera object |
|
// (see the function CameraHandler::initCameraConnect above), |
|
// so this instance of CameraHandler is pointed from that android::Camera object as |
|
// sp<CameraListener> mListener |
|
// and there is no other android smart pointers to this. |
|
// |
|
// It means, when that instance of the android::Camera object is destructed, |
|
// it calls destructor for this CameraHandler instance too. |
|
// |
|
// So, this line `camera=NULL' causes to the call `delete this' |
|
// (see destructor of the template class android::sp) |
|
// |
|
// So, we must not call `delete this' after the line, since it just has been called indeed |
|
} |
|
|
|
double CameraHandler::getProperty(int propIdx) |
|
{ |
|
LOGD("CameraHandler::getProperty(%d)", propIdx); |
|
|
|
switch (propIdx) |
|
{ |
|
case ANDROID_CAMERA_PROPERTY_FRAMEWIDTH: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
return w; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
return h; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING: |
|
{ |
|
cameraPropertySupportedPreviewSizesString = params.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES); |
|
union {const char* str;double res;} u; |
|
memset(&u.res, 0, sizeof(u.res)); |
|
u.str = cameraPropertySupportedPreviewSizesString.c_str(); |
|
return u.res; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_PREVIEW_FORMAT_STRING: |
|
{ |
|
const char* fmt = params.get(CameraParameters::KEY_PREVIEW_FORMAT); |
|
if (fmt == CameraParameters::PIXEL_FORMAT_YUV422SP) |
|
fmt = "yuv422sp"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_YUV420SP) |
|
fmt = "yuv420sp"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_YUV422I) |
|
fmt = "yuv422i"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_RGB565) |
|
fmt = "rgb565"; |
|
else if (fmt == CameraParameters::PIXEL_FORMAT_JPEG) |
|
fmt = "jpeg"; |
|
cameraPropertyPreviewFormatString = fmt; |
|
|
|
union {const char* str;double res;} u; |
|
memset(&u.res, 0, sizeof(u.res)); |
|
u.str = cameraPropertyPreviewFormatString.c_str(); |
|
return u.res; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_EXPOSURE: |
|
{ |
|
int exposure = params.getInt(CameraParameters::KEY_EXPOSURE_COMPENSATION); |
|
return exposure; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FPS: |
|
{ |
|
return params.getPreviewFrameRate(); |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FLASH_MODE: |
|
{ |
|
int flash_mode = getModeNum(CameraHandler::flashModesNames, |
|
ANDROID_CAMERA_FLASH_MODES_NUM, |
|
params.get(CameraParameters::KEY_FLASH_MODE)); |
|
return flash_mode; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FOCUS_MODE: |
|
{ |
|
int focus_mode = getModeNum(CameraHandler::focusModesNames, |
|
ANDROID_CAMERA_FOCUS_MODES_NUM, |
|
params.get(CameraParameters::KEY_FOCUS_MODE)); |
|
return focus_mode; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_WHITE_BALANCE: |
|
{ |
|
int white_balance = getModeNum(CameraHandler::whiteBalanceModesNames, |
|
ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM, |
|
params.get(CameraParameters::KEY_WHITE_BALANCE)); |
|
return white_balance; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_ANTIBANDING: |
|
{ |
|
int antibanding = getModeNum(CameraHandler::antibandingModesNames, |
|
ANDROID_CAMERA_ANTIBANDING_MODES_NUM, |
|
params.get(CameraParameters::KEY_ANTIBANDING)); |
|
return antibanding; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FOCAL_LENGTH: |
|
{ |
|
float focal_length = params.getFloat(CameraParameters::KEY_FOCAL_LENGTH); |
|
return focal_length; |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_NEAR: |
|
{ |
|
return getFocusDistance(ANDROID_CAMERA_FOCUS_DISTANCE_NEAR_INDEX); |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_OPTIMAL: |
|
{ |
|
return getFocusDistance(ANDROID_CAMERA_FOCUS_DISTANCE_OPTIMAL_INDEX); |
|
} |
|
case ANDROID_CAMERA_PROPERTY_FOCUS_DISTANCE_FAR: |
|
{ |
|
return getFocusDistance(ANDROID_CAMERA_FOCUS_DISTANCE_FAR_INDEX); |
|
} |
|
default: |
|
LOGW("CameraHandler::getProperty - Unsupported property."); |
|
}; |
|
return -1; |
|
} |
|
|
|
void CameraHandler::setProperty(int propIdx, double value) |
|
{ |
|
LOGD("CameraHandler::setProperty(%d, %f)", propIdx, value); |
|
|
|
switch (propIdx) |
|
{ |
|
case ANDROID_CAMERA_PROPERTY_FRAMEWIDTH: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
w = (int)value; |
|
params.setPreviewSize(w, h); |
|
} |
|
break; |
|
case ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT: |
|
{ |
|
int w,h; |
|
params.getPreviewSize(&w, &h); |
|
h = (int)value; |
|
params.setPreviewSize(w, h); |
|
} |
|
break; |
|
case ANDROID_CAMERA_PROPERTY_EXPOSURE: |
|
{ |
|
int max_exposure = params.getInt("max-exposure-compensation"); |
|
int min_exposure = params.getInt("min-exposure-compensation"); |
|
if(max_exposure && min_exposure){ |
|
int exposure = (int)value; |
|
if(exposure >= min_exposure && exposure <= max_exposure){ |
|
params.set("exposure-compensation", exposure); |
|
} else { |
|
LOGE("Exposure compensation not in valid range (%i,%i).", min_exposure, max_exposure); |
|
} |
|
} else { |
|
LOGE("Exposure compensation adjust is not supported."); |
|
} |
|
} |
|
break; |
|
case ANDROID_CAMERA_PROPERTY_FLASH_MODE: |
|
{ |
|
int new_val = (int)value; |
|
if(new_val >= 0 && new_val < ANDROID_CAMERA_FLASH_MODES_NUM){ |
|
const char* mode_name = flashModesNames[new_val]; |
|
if(is_supported(CameraParameters::KEY_SUPPORTED_FLASH_MODES, mode_name)) |
|
params.set(CameraParameters::KEY_FLASH_MODE, mode_name); |
|
else |
|
LOGE("Flash mode %s is not supported.", mode_name); |
|
} else { |
|
LOGE("Flash mode value not in valid range."); |
|
} |
|
} |
|
break; |
|
case ANDROID_CAMERA_PROPERTY_FOCUS_MODE: |
|
{ |
|
int new_val = (int)value; |
|
if(new_val >= 0 && new_val < ANDROID_CAMERA_FOCUS_MODES_NUM){ |
|
const char* mode_name = focusModesNames[new_val]; |
|
if(is_supported(CameraParameters::KEY_SUPPORTED_FOCUS_MODES, mode_name)) |
|
params.set(CameraParameters::KEY_FOCUS_MODE, mode_name); |
|
else |
|
LOGE("Focus mode %s is not supported.", mode_name); |
|
} else { |
|
LOGE("Focus mode value not in valid range."); |
|
} |
|
} |
|
break; |
|
case ANDROID_CAMERA_PROPERTY_WHITE_BALANCE: |
|
{ |
|
int new_val = (int)value; |
|
if(new_val >= 0 && new_val < ANDROID_CAMERA_WHITE_BALANCE_MODES_NUM){ |
|
const char* mode_name = whiteBalanceModesNames[new_val]; |
|
if(is_supported(CameraParameters::KEY_SUPPORTED_WHITE_BALANCE, mode_name)) |
|
params.set(CameraParameters::KEY_WHITE_BALANCE, mode_name); |
|
else |
|
LOGE("White balance mode %s is not supported.", mode_name); |
|
} else { |
|
LOGE("White balance mode value not in valid range."); |
|
} |
|
} |
|
break; |
|
case ANDROID_CAMERA_PROPERTY_ANTIBANDING: |
|
{ |
|
int new_val = (int)value; |
|
if(new_val >= 0 && new_val < ANDROID_CAMERA_ANTIBANDING_MODES_NUM){ |
|
const char* mode_name = antibandingModesNames[new_val]; |
|
if(is_supported(CameraParameters::KEY_SUPPORTED_ANTIBANDING, mode_name)) |
|
params.set(CameraParameters::KEY_ANTIBANDING, mode_name); |
|
else |
|
LOGE("Antibanding mode %s is not supported.", mode_name); |
|
} else { |
|
LOGE("Antibanding mode value not in valid range."); |
|
} |
|
} |
|
break; |
|
default: |
|
LOGW("CameraHandler::setProperty - Unsupported property."); |
|
}; |
|
} |
|
|
|
void CameraHandler::applyProperties(CameraHandler** ppcameraHandler) |
|
{ |
|
LOGD("CameraHandler::applyProperties()"); |
|
|
|
if (ppcameraHandler == 0) |
|
{ |
|
LOGE("applyProperties: Passed NULL ppcameraHandler"); |
|
return; |
|
} |
|
|
|
if (*ppcameraHandler == 0) |
|
{ |
|
LOGE("applyProperties: Passed NULL *ppcameraHandler"); |
|
return; |
|
} |
|
|
|
CameraParameters curCameraParameters((*ppcameraHandler)->params.flatten()); |
|
|
|
#if defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) || defined(ANDROID_r4_1_1) || defined(ANDROID_r4_2_0) || defined(ANDROID_r4_3_0) |
|
CameraHandler* handler=*ppcameraHandler; |
|
|
|
handler->camera->stopPreview(); |
|
handler->camera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP); |
|
|
|
status_t reconnectStatus = handler->camera->reconnect(); |
|
if (reconnectStatus != 0) |
|
{ |
|
LOGE("applyProperties: failed to reconnect camera (status %d)", reconnectStatus); |
|
return; |
|
} |
|
|
|
handler->camera->setParameters(curCameraParameters.flatten()); |
|
handler->params.unflatten(curCameraParameters.flatten()); |
|
|
|
status_t bufferStatus; |
|
# if defined(ANDROID_r4_0_0) || defined(ANDROID_r4_0_3) |
|
sp<SurfaceTexture> surfaceTexture = new SurfaceTexture(MAGIC_OPENCV_TEXTURE_ID); |
|
bufferStatus = handler->camera->setPreviewTexture(surfaceTexture); |
|
if (bufferStatus != 0) |
|
LOGE("applyProperties: failed setPreviewTexture call (status %d); camera might not work correctly", bufferStatus); |
|
# elif defined(ANDROID_r4_1_1) || defined(ANDROID_r4_2_0) || defined(ANDROID_r4_3_0) |
|
sp<BufferQueue> bufferQueue = new BufferQueue(); |
|
sp<BufferQueue::ConsumerListener> queueListener = new ConsumerListenerStub(); |
|
bufferQueue->consumerConnect(queueListener); |
|
bufferStatus = handler->camera->setPreviewTexture(bufferQueue); |
|
if (bufferStatus != 0) |
|
LOGE("applyProperties: failed setPreviewTexture call; camera might not work correctly"); |
|
# endif |
|
|
|
handler->camera->setPreviewCallbackFlags( CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK | CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK);//with copy |
|
|
|
LOGD("Starting preview"); |
|
status_t previewStatus = handler->camera->startPreview(); |
|
|
|
if (previewStatus != 0) |
|
{ |
|
LOGE("initCameraConnect: startPreview() fails. Closing camera connection..."); |
|
handler->closeCameraConnect(); |
|
handler = NULL; |
|
} |
|
else |
|
{ |
|
LOGD("Preview started successfully"); |
|
} |
|
#else |
|
CameraHandler* previousCameraHandler=*ppcameraHandler; |
|
CameraCallback cameraCallback=previousCameraHandler->cameraCallback; |
|
void* userData=previousCameraHandler->userData; |
|
int cameraId=previousCameraHandler->cameraId; |
|
|
|
LOGD("CameraHandler::applyProperties(): before previousCameraHandler->closeCameraConnect"); |
|
previousCameraHandler->closeCameraConnect(); |
|
LOGD("CameraHandler::applyProperties(): after previousCameraHandler->closeCameraConnect"); |
|
|
|
LOGD("CameraHandler::applyProperties(): before initCameraConnect"); |
|
CameraHandler* handler=initCameraConnect(cameraCallback, cameraId, userData, &curCameraParameters); |
|
LOGD("CameraHandler::applyProperties(): after initCameraConnect, handler=0x%x", (int)handler); |
|
if (handler == NULL) { |
|
LOGE("ERROR in applyProperties --- cannot reinit camera"); |
|
handler=initCameraConnect(cameraCallback, cameraId, userData, NULL); |
|
LOGD("CameraHandler::applyProperties(): repeate initCameraConnect after ERROR, handler=0x%x", (int)handler); |
|
if (handler == NULL) { |
|
LOGE("ERROR in applyProperties --- cannot reinit camera AGAIN --- cannot do anything else"); |
|
} |
|
} |
|
(*ppcameraHandler)=handler; |
|
#endif |
|
} |
|
|
|
|
|
extern "C" { |
|
|
|
void* initCameraConnectC(void* callback, int cameraId, void* userData) |
|
{ |
|
return CameraHandler::initCameraConnect((CameraCallback)callback, cameraId, userData, NULL); |
|
} |
|
|
|
void closeCameraConnectC(void** camera) |
|
{ |
|
CameraHandler** cc = (CameraHandler**)camera; |
|
(*cc)->closeCameraConnect(); |
|
*cc = 0; |
|
} |
|
|
|
double getCameraPropertyC(void* camera, int propIdx) |
|
{ |
|
return ((CameraHandler*)camera)->getProperty(propIdx); |
|
} |
|
|
|
void setCameraPropertyC(void* camera, int propIdx, double value) |
|
{ |
|
((CameraHandler*)camera)->setProperty(propIdx,value); |
|
} |
|
|
|
void applyCameraPropertiesC(void** camera) |
|
{ |
|
CameraHandler::applyProperties((CameraHandler**)camera); |
|
} |
|
|
|
}
|
|
|