mirror of https://github.com/opencv/opencv.git
parent
5cae924a3d
commit
206aa50f86
14 changed files with 973 additions and 23 deletions
Binary file not shown.
Binary file not shown.
@ -0,0 +1,48 @@ |
||||
IF(NOT ANDROID) |
||||
MESSAGE( FATAL_ERROR "This project is for ANDROID only" ) |
||||
ENDIF() |
||||
|
||||
if (BUILD_ANDROID_CAMERA_WRAPPER) |
||||
add_subdirectory(camera_wrapper) |
||||
endif() |
||||
|
||||
project(opencv_androidcamera) |
||||
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/camera_wrapper ) |
||||
SET( LIBRARY_DEPS ${LIBRARY_DEPS} log dl ) |
||||
|
||||
SET( the_target opencv_androidcamera ) |
||||
|
||||
ADD_LIBRARY( ${the_target} STATIC src/camera_activity.cpp ) |
||||
|
||||
if (BUILD_SHARED_LIBS) |
||||
add_definitions(-DCVAPI_EXPORTS) |
||||
endif() |
||||
|
||||
TARGET_LINK_LIBRARIES( ${the_target} ${LIBRARY_DEPS} ) |
||||
|
||||
SET_TARGET_PROPERTIES(${the_target} PROPERTIES |
||||
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" |
||||
OUTPUT_NAME "${the_target}${OPENCV_DLLVERSION}" |
||||
DEFINE_SYMBOL "CVAPI_EXPORTS" |
||||
ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} |
||||
RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} |
||||
) |
||||
|
||||
IF (NOT BUILD_SHARED_LIBS) |
||||
install(TARGETS ${the_target} |
||||
RUNTIME DESTINATION bin COMPONENT main |
||||
ARCHIVE DESTINATION lib COMPONENT main |
||||
LIBRARY DESTINATION lib COMPONENT main |
||||
) |
||||
ENDIF() |
||||
|
||||
file(GLOB camera_wrappers "${CMAKE_CURRENT_SOURCE_DIR}/../../3rdparty/lib/libnative_camera_r*.so") |
||||
|
||||
foreach(wrapper ${camera_wrappers}) |
||||
ADD_CUSTOM_COMMAND( |
||||
TARGET ${the_target} |
||||
POST_BUILD |
||||
COMMAND ${CMAKE_COMMAND} -E copy "${wrapper}" "${LIBRARY_OUTPUT_PATH}" |
||||
) |
||||
endforeach() |
@ -0,0 +1,398 @@ |
||||
#define USE_RECORDING_INSTEAD_PREVIEW 0 |
||||
|
||||
#if !defined(ANDROID_r2_2_2) && !defined(ANDROID_r2_3_3) && !defined(ANDROID_r3_0_1) |
||||
#error unsupported version of Android |
||||
#endif |
||||
|
||||
#include <camera/CameraHardwareInterface.h> |
||||
#include "camera_wrapper.h" |
||||
#include "../camera_wrapper_connector/camera_properties.h" |
||||
#include <string> |
||||
|
||||
using namespace android; |
||||
|
||||
void debugShowFPS() |
||||
{ |
||||
static int mFrameCount = 0; |
||||
static int mLastFrameCount = 0; |
||||
static nsecs_t mLastFpsTime = systemTime();; |
||||
static float mFps = 0; |
||||
|
||||
mFrameCount++; |
||||
|
||||
if ( ( mFrameCount % 30 ) == 0 ) { |
||||
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("####### [%d] Frames, %f FPS", mFrameCount, mFps); |
||||
} |
||||
} |
||||
|
||||
class CameraHandler: public CameraListener |
||||
{ |
||||
protected: |
||||
sp<Camera> camera; |
||||
CameraCallback cameraCallback; |
||||
CameraParameters params; |
||||
void* userData; |
||||
int cameraId; |
||||
|
||||
bool isEmptyCameraCallbackReported; |
||||
virtual void doCall(void* buffer, size_t bufferSize) |
||||
{ |
||||
if (cameraCallback == 0) |
||||
{ |
||||
if (!isEmptyCameraCallbackReported) |
||||
LOGE("Camera callback is empty!"); |
||||
|
||||
isEmptyCameraCallbackReported = true; |
||||
return; |
||||
} |
||||
|
||||
bool res = (*cameraCallback)(buffer, bufferSize, userData); |
||||
|
||||
if(!res) closeCameraConnect(); |
||||
} |
||||
|
||||
virtual void doCall(const sp<IMemory>& dataPtr) |
||||
{ |
||||
LOGI("doCall started"); |
||||
|
||||
if (dataPtr == NULL) |
||||
{ |
||||
LOGE("CameraBuffer: dataPtr==NULL"); |
||||
return; |
||||
} |
||||
|
||||
size_t size = dataPtr->size(); |
||||
if (size <= 0) |
||||
{ |
||||
LOGE("CameraBuffer: IMemory object is of zero size"); |
||||
return; |
||||
} |
||||
|
||||
unsigned char* buffer = (unsigned char *)dataPtr->pointer(); |
||||
if (!buffer) |
||||
{ |
||||
LOGE("CameraBuffer: Buffer pointer is invalid"); |
||||
return; |
||||
} |
||||
|
||||
doCall(buffer, size); |
||||
} |
||||
|
||||
public: |
||||
CameraHandler(CameraCallback callback = 0, void* _userData = 0):cameraCallback(callback), userData(_userData), cameraId(0), isEmptyCameraCallbackReported(false) {} |
||||
virtual ~CameraHandler() |
||||
{ |
||||
LOGW("CameraHandler destructor is called!"); |
||||
} |
||||
|
||||
virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) |
||||
{ |
||||
LOGE("Notify cb: %d %d %d\n", msgType, ext1, ext2); |
||||
#if 0 |
||||
if ( msgType & CAMERA_MSG_FOCUS ) |
||||
LOGE("AutoFocus %s in %llu us\n", (ext1) ? "OK" : "FAIL", timevalDelay(&autofocus_start)); |
||||
|
||||
if ( msgType & CAMERA_MSG_SHUTTER ) |
||||
LOGE("Shutter done in %llu us\n", timeval_delay(&picture_start)); |
||||
#endif |
||||
} |
||||
|
||||
virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) |
||||
{ |
||||
debugShowFPS(); |
||||
|
||||
if ( msgType & CAMERA_MSG_PREVIEW_FRAME ) |
||||
{ |
||||
doCall(dataPtr); |
||||
return; |
||||
} |
||||
|
||||
if (msgType != CAMERA_MSG_PREVIEW_FRAME) |
||||
LOGE("Recieved not CAMERA_MSG_PREVIEW_FRAME message %d", (int) msgType); |
||||
|
||||
if ( msgType & CAMERA_MSG_RAW_IMAGE ) |
||||
LOGE("Unexpected data format: RAW\n"); |
||||
|
||||
if (msgType & CAMERA_MSG_POSTVIEW_FRAME) |
||||
LOGE("Unexpected data format: Postview frame\n"); |
||||
|
||||
if (msgType & CAMERA_MSG_COMPRESSED_IMAGE ) |
||||
LOGE("Unexpected data format: JPEG"); |
||||
} |
||||
|
||||
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); |
||||
} |
||||
|
||||
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; |
||||
}; |
||||
|
||||
|
||||
CameraHandler* CameraHandler::initCameraConnect(const CameraCallback& callback, int cameraId, void* userData, CameraParameters* prevCameraParameters) |
||||
{ |
||||
// if (camera != NULL)
|
||||
// {
|
||||
// LOGE("initCameraConnect: camera have been connected already");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
sp<Camera> camera = 0; |
||||
|
||||
#ifdef ANDROID_r2_2_2 |
||||
camera = Camera::connect(); |
||||
#endif |
||||
#ifdef ANDROID_r2_3_3 |
||||
camera = Camera::connect(cameraId); |
||||
#endif |
||||
|
||||
if ( NULL == 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=cameraId; |
||||
#if 1 |
||||
//setting paramers from previous camera handler
|
||||
if (prevCameraParameters != NULL) { |
||||
camera->setParameters(prevCameraParameters->flatten()); |
||||
} |
||||
#endif |
||||
handler->params.unflatten(camera->getParameters()); |
||||
|
||||
|
||||
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)); |
||||
|
||||
|
||||
//TODO: check if yuv420i format available. Set this format as preview format.
|
||||
|
||||
#if USE_RECORDING_INSTEAD_PREVIEW |
||||
status_t err = camera->setPreviewDisplay(sp<ISurface>(NULL /*new DummySurface1*/)); |
||||
#endif |
||||
|
||||
////ATTENTION: switching between two versions: with and without copying memory inside Android OS
|
||||
//// see the method CameraService::Client::copyFrameAndPostCopiedFrame and where it is used
|
||||
#if 1 |
||||
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 |
||||
|
||||
#if USE_RECORDING_INSTEAD_PREVIEW |
||||
status_t resStart = camera->startRecording(); |
||||
#else |
||||
status_t resStart = camera->startPreview(); |
||||
#endif |
||||
|
||||
if (resStart != 0) |
||||
{ |
||||
handler->closeCameraConnect(); |
||||
handler = 0; |
||||
} |
||||
return handler; |
||||
} |
||||
|
||||
void CameraHandler::closeCameraConnect() |
||||
{ |
||||
if (camera == NULL) |
||||
{ |
||||
LOGI("... camera is NULL"); |
||||
return; |
||||
} |
||||
|
||||
//TODO: ATTENTION! should we do it ALWAYS???
|
||||
#if USE_RECORDING_INSTEAD_PREVIEW |
||||
camera->stopRecording(); |
||||
#else |
||||
camera->stopPreview(); |
||||
#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) |
||||
{ |
||||
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); |
||||
double res; |
||||
memset(&res, 0, sizeof(res)); |
||||
(*( (void**)&res ))= (void*)( cameraPropertySupportedPreviewSizesString.c_str() ); |
||||
|
||||
return res; |
||||
} |
||||
|
||||
}; |
||||
return -1; |
||||
} |
||||
|
||||
void CameraHandler::setProperty(int propIdx, double 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; |
||||
}; |
||||
} |
||||
|
||||
void CameraHandler::applyProperties(CameraHandler** ppcameraHandler) |
||||
{ |
||||
LOGD("CameraHandler::applyProperties()"); |
||||
CameraHandler* previousCameraHandler=*ppcameraHandler; |
||||
CameraParameters curCameraParameters(previousCameraHandler->params.flatten()); |
||||
|
||||
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; |
||||
} |
||||
|
||||
|
||||
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); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,24 @@ |
||||
enum CameraWrapperErrorCode { |
||||
ERROR_NATIVE_CAMERA_WRAPPER_NOERROR = 0, |
||||
ERROR_NATIVE_CAMERA_WRAPPER_CANNOT_FIND_CLASS = 1, |
||||
ERROR_NATIVE_CAMERA_WRAPPER_CANNOT_FIND_FIELD = 2, |
||||
ERROR_NATIVE_CAMERA_WRAPPER_CANNOT_SET_PREVIEW_DISPLAY = 3 |
||||
}; |
||||
|
||||
typedef bool (*CameraCallback)(void* buffer, size_t bufferSize, void* userData); |
||||
|
||||
typedef void* (*InitCameraConnectC)(void* cameraCallback, int cameraId, void* userData); |
||||
typedef void (*CloseCameraConnectC)(void**); |
||||
typedef double (*GetCameraPropertyC)(void* camera, int propIdx); |
||||
typedef void (*SetCameraPropertyC)(void* camera, int propIdx, double value); |
||||
typedef void (*ApplyCameraPropertiesC)(void** camera); |
||||
|
||||
extern "C"
|
||||
{ |
||||
void* initCameraConnectC(void* cameraCallback, int cameraId, void* userData); |
||||
void closeCameraConnectC(void**); |
||||
double getCameraPropertyC(void* camera, int propIdx); |
||||
void setCameraPropertyC(void* camera, int propIdx, double value); |
||||
void applyCameraPropertiesC(void** camera); |
||||
} |
||||
|
@ -0,0 +1,48 @@ |
||||
#ifndef _CAMERAACTIVITY_H_ |
||||
#define _CAMERAACTIVITY_H_ |
||||
|
||||
#include <camera_properties.h> |
||||
//#include <opencv2/core/core.hpp>
|
||||
|
||||
class CameraActivity |
||||
{ |
||||
public: |
||||
enum ErrorCode { |
||||
NO_ERROR=0, |
||||
ERROR_WRONG_FRAME_SIZE, |
||||
ERROR_WRONG_POINTER_CAMERA_WRAPPER, |
||||
ERROR_CAMERA_CONNECTED, |
||||
ERROR_CANNOT_OPEN_CAMERA_WRAPPER_LIB, |
||||
ERROR_CANNOT_GET_FUNCTION_FROM_CAMERA_WRAPPER_LIB, |
||||
ERROR_CANNOT_INITIALIZE_CONNECTION, |
||||
ERROR_ISNT_CONNECTED, |
||||
ERROR_JAVA_VM_CANNOT_GET_CLASS, |
||||
ERROR_JAVA_VM_CANNOT_GET_FIELD, |
||||
ERROR_CANNOT_SET_PREVIEW_DISPLAY, |
||||
|
||||
ERROR_UNKNOWN=255 |
||||
}; |
||||
|
||||
CameraActivity(); |
||||
virtual ~CameraActivity(); |
||||
virtual bool onFrameBuffer(void* buffer, int bufferSize); |
||||
|
||||
ErrorCode connect(int cameraId = 0); |
||||
void disconnect(); |
||||
bool isConnected() const; |
||||
|
||||
double getProperty(int propIdx); |
||||
void setProperty(int propIdx, double value); |
||||
void applyProperties(); |
||||
|
||||
int getFrameWidth(); |
||||
int getFrameHeight(); |
||||
|
||||
static void setPathLibFolder(const char* path); |
||||
private: |
||||
void* camera; |
||||
int frameWidth; |
||||
int frameHeight; |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,10 @@ |
||||
#ifndef CAMERA_PROPERTIES_H |
||||
#define CAMERA_PROPERTIES_H |
||||
|
||||
enum { |
||||
ANDROID_CAMERA_PROPERTY_FRAMEWIDTH = 0, |
||||
ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT = 1, |
||||
ANDROID_CAMERA_PROPERTY_SUPPORTED_PREVIEW_SIZES_STRING = 2 |
||||
}; |
||||
|
||||
#endif // CAMERA_PROPERTIES_H
|
@ -0,0 +1,405 @@ |
||||
#include <dlfcn.h> |
||||
#include <android/log.h> |
||||
#include <string> |
||||
#include <vector> |
||||
#include "camera_activity.hpp" |
||||
#include "camera_wrapper.h" |
||||
|
||||
#define LOG_TAG "CAMERA_ACTIVITY" |
||||
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) |
||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) |
||||
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) |
||||
|
||||
///////
|
||||
// Debug
|
||||
#include <stdio.h> |
||||
#include <sys/types.h> |
||||
#include <dirent.h> |
||||
|
||||
|
||||
using namespace std; |
||||
|
||||
class CameraWrapperConnector |
||||
{ |
||||
public: |
||||
static CameraActivity::ErrorCode connect(int cameraId, CameraActivity* pCameraActivity, void** camera); |
||||
static CameraActivity::ErrorCode disconnect(void** camera); |
||||
static CameraActivity::ErrorCode setProperty(void* camera, int propIdx, double value); |
||||
static CameraActivity::ErrorCode getProperty(void* camera, int propIdx, double* value); |
||||
static CameraActivity::ErrorCode applyProperties(void** ppcamera); |
||||
|
||||
static void setPathLibFolder(const std::string& path); |
||||
|
||||
private: |
||||
static std::string pathLibFolder; |
||||
static bool isConnectedToLib; |
||||
|
||||
static std::string getPathLibFolder(); |
||||
static CameraActivity::ErrorCode connectToLib(); |
||||
static CameraActivity::ErrorCode getSymbolFromLib(void * libHandle, const char* symbolName, void** ppSymbol); |
||||
static void fillListWrapperLibs(const string& folderPath, vector<string>& listLibs); |
||||
|
||||
static InitCameraConnectC pInitCameraC; |
||||
static CloseCameraConnectC pCloseCameraC; |
||||
static GetCameraPropertyC pGetPropertyC; |
||||
static SetCameraPropertyC pSetPropertyC; |
||||
static ApplyCameraPropertiesC pApplyPropertiesC; |
||||
|
||||
friend bool nextFrame(void* buffer, size_t bufferSize, void* userData); |
||||
}; |
||||
|
||||
std::string CameraWrapperConnector::pathLibFolder; |
||||
#define DEFAULT_WRAPPER_PACKAGE_NAME "com.NativeCamera" |
||||
#define DEFAULT_PATH_LIB_FOLDER "/data/data/" DEFAULT_WRAPPER_PACKAGE_NAME "/lib/" |
||||
|
||||
bool CameraWrapperConnector::isConnectedToLib=false; |
||||
InitCameraConnectC CameraWrapperConnector::pInitCameraC = 0; |
||||
CloseCameraConnectC CameraWrapperConnector::pCloseCameraC = 0; |
||||
GetCameraPropertyC CameraWrapperConnector::pGetPropertyC = 0; |
||||
SetCameraPropertyC CameraWrapperConnector::pSetPropertyC = 0; |
||||
ApplyCameraPropertiesC CameraWrapperConnector::pApplyPropertiesC = 0; |
||||
|
||||
#define INIT_CAMERA_SYMBOL_NAME "initCameraConnectC" |
||||
#define CLOSE_CAMERA_SYMBOL_NAME "closeCameraConnectC" |
||||
#define SET_CAMERA_PROPERTY_SYMBOL_NAME "setCameraPropertyC" |
||||
#define GET_CAMERA_PROPERTY_SYMBOL_NAME "getCameraPropertyC" |
||||
#define APPLY_CAMERA_PROPERTIES_SYMBOL_NAME "applyCameraPropertiesC" |
||||
#define PREFIX_CAMERA_WRAPPER_LIB "libnative_camera" |
||||
|
||||
|
||||
bool nextFrame(void* buffer, size_t bufferSize, void* userData) |
||||
{ |
||||
if (userData == NULL) |
||||
return true; |
||||
|
||||
return ((CameraActivity*)userData)->onFrameBuffer(buffer, bufferSize); |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraWrapperConnector::connect(int cameraId, CameraActivity* pCameraActivity, void** camera) |
||||
{ |
||||
if (pCameraActivity == NULL) |
||||
{ |
||||
LOGE("CameraWrapperConnector::connect error: wrong pointer to CameraActivity object"); |
||||
return CameraActivity::ERROR_WRONG_POINTER_CAMERA_WRAPPER; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode errcode=connectToLib(); |
||||
if (errcode) return errcode; |
||||
|
||||
void* cmr = (*pInitCameraC)((void*)nextFrame, cameraId, (void*)pCameraActivity); |
||||
if (!cmr) |
||||
{ |
||||
LOGE("CameraWrapperConnector::connectWrapper ERROR: the initializing function returned false"); |
||||
return CameraActivity::ERROR_CANNOT_INITIALIZE_CONNECTION; |
||||
} |
||||
|
||||
*camera = cmr; |
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraWrapperConnector::disconnect(void** camera) |
||||
{ |
||||
if (camera == NULL || *camera == NULL) |
||||
{ |
||||
LOGE("CameraWrapperConnector::disconnect error: wrong pointer to camera object"); |
||||
return CameraActivity::ERROR_WRONG_POINTER_CAMERA_WRAPPER; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode errcode=connectToLib(); |
||||
if (errcode) return errcode; |
||||
|
||||
(*pCloseCameraC)(camera); |
||||
|
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraWrapperConnector::setProperty(void* camera, int propIdx, double value) |
||||
{ |
||||
if (camera == NULL) |
||||
{ |
||||
LOGE("CameraWrapperConnector::setProperty error: wrong pointer to camera object"); |
||||
return CameraActivity::ERROR_WRONG_POINTER_CAMERA_WRAPPER; |
||||
} |
||||
|
||||
(*pSetPropertyC)(camera, propIdx, value); |
||||
|
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraWrapperConnector::getProperty(void* camera, int propIdx, double* value) |
||||
{ |
||||
if (camera == NULL) |
||||
{ |
||||
LOGE("CameraWrapperConnector::getProperty error: wrong pointer to camera object"); |
||||
return CameraActivity::ERROR_WRONG_POINTER_CAMERA_WRAPPER; |
||||
} |
||||
|
||||
*value = (*pGetPropertyC)(camera, propIdx); |
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraWrapperConnector::applyProperties(void** ppcamera) |
||||
{ |
||||
if ((ppcamera == NULL) || (*ppcamera == NULL)) |
||||
{ |
||||
LOGE("CameraWrapperConnector::applyProperties error: wrong pointer to camera object"); |
||||
return CameraActivity::ERROR_WRONG_POINTER_CAMERA_WRAPPER; |
||||
} |
||||
|
||||
(*pApplyPropertiesC)(ppcamera); |
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraWrapperConnector::connectToLib() |
||||
{ |
||||
if (isConnectedToLib) { |
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
dlerror(); |
||||
string folderPath=getPathLibFolder(); |
||||
LOGD("CameraWrapperConnector::connectToLib: folderPath=%s", folderPath.c_str()); |
||||
|
||||
vector<string> listLibs; |
||||
fillListWrapperLibs(folderPath, listLibs); |
||||
|
||||
void * libHandle=0; |
||||
string cur_path; |
||||
for(size_t i=0; i < listLibs.size(); i++) { |
||||
cur_path=folderPath + listLibs[i]; |
||||
LOGD("try to load library '%s'", listLibs[i].c_str()); |
||||
libHandle=dlopen(cur_path.c_str(), RTLD_LAZY); |
||||
if (libHandle) { |
||||
LOGD("Loaded library '%s'", cur_path.c_str()); |
||||
break; |
||||
} else { |
||||
LOGD("CameraWrapperConnector::connectToLib ERROR: cannot dlopen camera wrapper library %s, dlerror=\"%s\"", |
||||
cur_path.c_str(), dlerror()); |
||||
} |
||||
} |
||||
|
||||
if (!libHandle) { |
||||
LOGE("CameraWrapperConnector::connectToLib ERROR: cannot dlopen camera wrapper library"); |
||||
return CameraActivity::ERROR_CANNOT_OPEN_CAMERA_WRAPPER_LIB; |
||||
} |
||||
|
||||
InitCameraConnectC pInit_C; |
||||
CloseCameraConnectC pClose_C; |
||||
GetCameraPropertyC pGetProp_C; |
||||
SetCameraPropertyC pSetProp_C; |
||||
ApplyCameraPropertiesC pApplyProp_C; |
||||
|
||||
CameraActivity::ErrorCode res; |
||||
|
||||
res = getSymbolFromLib(libHandle, (const char*)INIT_CAMERA_SYMBOL_NAME, (void**)(&pInit_C)); |
||||
if (res) return res; |
||||
|
||||
res = getSymbolFromLib(libHandle, CLOSE_CAMERA_SYMBOL_NAME, (void**)(&pClose_C)); |
||||
if (res) return res; |
||||
|
||||
res = getSymbolFromLib(libHandle, GET_CAMERA_PROPERTY_SYMBOL_NAME, (void**)(&pGetProp_C)); |
||||
if (res) return res; |
||||
|
||||
res = getSymbolFromLib(libHandle, SET_CAMERA_PROPERTY_SYMBOL_NAME, (void**)(&pSetProp_C)); |
||||
if (res) return res; |
||||
\
|
||||
res = getSymbolFromLib(libHandle, APPLY_CAMERA_PROPERTIES_SYMBOL_NAME, (void**)(&pApplyProp_C)); |
||||
if (res) return res; |
||||
|
||||
pInitCameraC = pInit_C; |
||||
pCloseCameraC = pClose_C; |
||||
pGetPropertyC = pGetProp_C; |
||||
pSetPropertyC = pSetProp_C; |
||||
pApplyPropertiesC = pApplyProp_C; |
||||
isConnectedToLib=true; |
||||
|
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraWrapperConnector::getSymbolFromLib(void* libHandle, const char* symbolName, void** ppSymbol) |
||||
{ |
||||
dlerror(); |
||||
*(void **) (ppSymbol)=dlsym(libHandle, symbolName); |
||||
|
||||
const char* error_dlsym_init=dlerror(); |
||||
if (error_dlsym_init) { |
||||
LOGE("CameraWrapperConnector::getSymbolFromLib ERROR: cannot get symbol of the function '%s' from the camera wrapper library, dlerror=\"%s\"", |
||||
symbolName, error_dlsym_init); |
||||
return CameraActivity::ERROR_CANNOT_GET_FUNCTION_FROM_CAMERA_WRAPPER_LIB; |
||||
} |
||||
return CameraActivity::NO_ERROR; |
||||
} |
||||
|
||||
void CameraWrapperConnector::fillListWrapperLibs(const string& folderPath, vector<string>& listLibs) |
||||
{ |
||||
DIR *dp; |
||||
struct dirent *ep; |
||||
|
||||
dp = opendir (folderPath.c_str()); |
||||
if (dp != NULL) |
||||
{ |
||||
while (ep = readdir (dp)) { |
||||
const char* cur_name=ep->d_name; |
||||
if (strstr(cur_name, PREFIX_CAMERA_WRAPPER_LIB)) { |
||||
listLibs.push_back(cur_name); |
||||
LOGE("||%s", cur_name); |
||||
} |
||||
} |
||||
(void) closedir (dp); |
||||
} |
||||
} |
||||
|
||||
std::string CameraWrapperConnector::getPathLibFolder() |
||||
{ |
||||
if (!pathLibFolder.empty()) |
||||
return pathLibFolder; |
||||
|
||||
Dl_info dl_info; |
||||
if(0 != dladdr((void *)nextFrame, &dl_info)) |
||||
{ |
||||
LOGD("Library name: %s", dl_info.dli_fname); |
||||
LOGD("Library base address: %p", dl_info.dli_fbase); |
||||
|
||||
char addrBuf[18]; |
||||
sprintf(addrBuf, "%x-", dl_info.dli_fbase); |
||||
int addrLength = strlen(addrBuf); |
||||
|
||||
char lineBuf[2048]; |
||||
FILE* file = fopen("/proc/self/smaps", "rt"); |
||||
|
||||
if(file) |
||||
{ |
||||
while (fgets(lineBuf, sizeof lineBuf, file) != NULL) |
||||
{ |
||||
if(0 == strncmp(lineBuf, addrBuf, addrLength)) |
||||
{ |
||||
//verify that line ends with library name
|
||||
int lineLength = strlen(lineBuf); |
||||
int libNameLength = strlen(dl_info.dli_fname); |
||||
|
||||
//trim end
|
||||
for(int i = lineLength - 1; i >= 0 && isspace(lineBuf[i]); --i) |
||||
{ |
||||
lineBuf[i] = 0; |
||||
--lineLength; |
||||
} |
||||
|
||||
if (0 != strncmp(lineBuf + lineLength - libNameLength, dl_info.dli_fname, libNameLength)) |
||||
{ |
||||
LOGE("Strange error: line \"%s\" does not ends with library name %s", lineBuf, dl_info.dli_fname); |
||||
continue; |
||||
} |
||||
|
||||
//extract path from smaps line
|
||||
char* pathBegin = strchr(lineBuf, '/'); |
||||
if (0 == pathBegin) |
||||
{ |
||||
LOGE("Strange error: could not find path beginning in lin \"%s\"", lineBuf); |
||||
continue; |
||||
} |
||||
|
||||
char* pathEnd = strrchr(pathBegin, '/'); |
||||
pathEnd[1] = 0; |
||||
|
||||
LOGD("Libraries folder found: %s", pathBegin); |
||||
|
||||
fclose(file); |
||||
return pathBegin; |
||||
} |
||||
} |
||||
fclose(file); |
||||
LOGE("Could not find library path."); |
||||
} |
||||
else |
||||
{ |
||||
LOGE("Could not read /proc/self/smaps"); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
LOGE("Could not get library name and base address."); |
||||
} |
||||
|
||||
return DEFAULT_PATH_LIB_FOLDER ; |
||||
} |
||||
|
||||
void CameraWrapperConnector::setPathLibFolder(const string& path) |
||||
{ |
||||
pathLibFolder=path; |
||||
} |
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CameraActivity::CameraActivity() : camera(0), frameWidth(-1), frameHeight(-1) |
||||
{ |
||||
} |
||||
|
||||
CameraActivity::~CameraActivity() |
||||
{ |
||||
if (camera != 0) |
||||
disconnect(); |
||||
} |
||||
|
||||
bool CameraActivity::onFrameBuffer(void* buffer, int bufferSize) |
||||
{ |
||||
LOGD("CameraActivity::onFrameBuffer - empty callback"); |
||||
return true; |
||||
} |
||||
|
||||
void CameraActivity::disconnect() |
||||
{ |
||||
CameraWrapperConnector::disconnect(&camera); |
||||
} |
||||
|
||||
bool CameraActivity::isConnected() const |
||||
{ |
||||
return camera != 0; |
||||
} |
||||
|
||||
CameraActivity::ErrorCode CameraActivity::connect(int cameraId) |
||||
{ |
||||
ErrorCode rescode = CameraWrapperConnector::connect(cameraId, this, &camera); |
||||
if (rescode) return rescode; |
||||
|
||||
return NO_ERROR; |
||||
} |
||||
|
||||
double CameraActivity::getProperty(int propIdx) |
||||
{ |
||||
double propVal; |
||||
ErrorCode rescode = CameraWrapperConnector::getProperty(camera, propIdx, &propVal); |
||||
if (rescode) return -1; |
||||
return propVal; |
||||
} |
||||
|
||||
void CameraActivity::setProperty(int propIdx, double value) |
||||
{ |
||||
CameraWrapperConnector::setProperty(camera, propIdx, value); |
||||
} |
||||
|
||||
void CameraActivity::applyProperties() |
||||
{ |
||||
frameWidth = -1; |
||||
frameHeight = -1; |
||||
CameraWrapperConnector::applyProperties(&camera); |
||||
} |
||||
|
||||
int CameraActivity::getFrameWidth() |
||||
{ |
||||
if (frameWidth < 0) |
||||
frameWidth = getProperty(ANDROID_CAMERA_PROPERTY_FRAMEWIDTH); |
||||
return frameWidth; |
||||
} |
||||
|
||||
int CameraActivity::getFrameHeight() |
||||
{ |
||||
if (frameHeight < 0) |
||||
frameHeight = getProperty(ANDROID_CAMERA_PROPERTY_FRAMEHEIGHT); |
||||
return frameHeight; |
||||
} |
||||
|
||||
void CameraActivity::setPathLibFolder(const char* path) |
||||
{ |
||||
CameraWrapperConnector::setPathLibFolder(path); |
||||
} |
Loading…
Reference in new issue