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