Added Android native camera module
authorAndrey Kamaev <no@email>
Thu, 16 Jun 2011 18:00:41 +0000 (18:00 +0000)
committerAndrey Kamaev <no@email>
Thu, 16 Jun 2011 18:00:41 +0000 (18:00 +0000)
14 files changed:
3rdparty/lib/libnative_camera_r2.2.2.so [new file with mode: 0644]
3rdparty/lib/libnative_camera_r2.3.3.so [new file with mode: 0644]
CMakeLists.txt
OpenCVConfig.cmake.in
android/android.toolchain.cmake
modules/CMakeLists.txt
modules/androidcamera/CMakeLists.txt [new file with mode: 0644]
modules/androidcamera/camera_wrapper/camera_wrapper.cpp [new file with mode: 0644]
modules/androidcamera/camera_wrapper/camera_wrapper.h [new file with mode: 0644]
modules/androidcamera/include/camera_activity.hpp [new file with mode: 0644]
modules/androidcamera/include/camera_properties.h [new file with mode: 0644]
modules/androidcamera/src/camera_activity.cpp [new file with mode: 0644]
modules/highgui/CMakeLists.txt
modules/highgui/src/cap_android.cpp

diff --git a/3rdparty/lib/libnative_camera_r2.2.2.so b/3rdparty/lib/libnative_camera_r2.2.2.so
new file mode 100644 (file)
index 0000000..0866e43
Binary files /dev/null and b/3rdparty/lib/libnative_camera_r2.2.2.so differ
diff --git a/3rdparty/lib/libnative_camera_r2.3.3.so b/3rdparty/lib/libnative_camera_r2.3.3.so
new file mode 100644 (file)
index 0000000..54e6c09
Binary files /dev/null and b/3rdparty/lib/libnative_camera_r2.3.3.so differ
index 7b2647b..282ece7 100644 (file)
@@ -553,19 +553,6 @@ if(WITH_JASPER AND NOT JASPER_FOUND)
     set(JASPER_LIBRARIES libjasper)
 endif()
 
-if (ANDROID)
-  #android camera support
-  set(NativeCamera_DIR "${OpenCV_SOURCE_DIR}/android/native-camera/build")
-  FIND_PACKAGE(NativeCamera QUIET)
-  if(NativeCamera_FOUND)
-    set(HAVE_ANDROID_NATIVE_CAMERA TRUE)
-    set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${NativeCamera_LIBS})
-  else()
-    set(HAVE_ANDROID_NATIVE_CAMERA FALSE)
-    message(STATUS "Could NOT find NativeCamera for Android")
-  endif()
-endif()
-
 #message(STATUS "Graphic libraries: ${PNG_LIBRARIES} ${JPEG_LIBRARIES} ${TIFF_LIBRARIES} ${JASPER_LIBRARIES}")
 
 if(WITH_OPENEXR)
@@ -667,7 +654,7 @@ endif()
 ############################### TBB ################################
 
 if (WITH_TBB)
-    if (UNIX AND NOT APPLE)
+    if (UNIX AND NOT APPLE AND NOT ANDROID)
         PKG_CHECK_MODULES(TBB tbb)
         message(STATUS "TBB detected: ${TBBLIB_FOUND}")
 
@@ -682,7 +669,7 @@ if (WITH_TBB)
     endif()    
     
     if (NOT HAVE_TBB)
-        set(TBB_DEFAULT_INCLUDE_DIRS "/opt/intel/tbb" "/usr/local/include" "/usr/include" "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB" "C:/Program Files (x86)/TBB")
+        set(TBB_DEFAULT_INCLUDE_DIRS "/opt/intel/tbb" "/usr/local/include" "/usr/include" "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB" "C:/Program Files (x86)/TBB" "${CMAKE_INSTALL_PREFIX}/include")
         
         find_path(TBB_INCLUDE_DIR "tbb/tbb.h" PATHS ${TBB_DEFAULT_INCLUDE_DIRS} DOC "The path to TBB headers")
         if (TBB_INCLUDE_DIR)
@@ -692,6 +679,9 @@ if (WITH_TBB)
             endif()
             if (APPLE)
                 set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} libtbb.dylib)
+            elseif (ANDROID)
+                set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} tbbmalloc tbb)
+                add_definitions(-DTBB_USE_GCC_BUILTINS)
             elseif (UNIX)
                 set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} tbb)
             elseif (WIN32)
@@ -1170,10 +1160,6 @@ set(CMAKE_BASE_INCLUDE_DIRS_CONFIGCMAKE "\"${CMAKE_CURRENT_SOURCE_DIR}\"")
 
 set(CMAKE_LIB_DIRS_CONFIGCMAKE "${LIBRARY_OUTPUT_PATH}")
 
-if( HAVE_ANDROID_NATIVE_CAMERA )
-    set(CMAKE_LIB_DIRS_CONFIGCMAKE ${CMAKE_LIB_DIRS_CONFIGCMAKE} ${NativeCamera_LIB_DIR})
-endif()
-
 configure_file("${CMAKE_CURRENT_SOURCE_DIR}/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig.cmake" IMMEDIATE @ONLY)
 
 # --------------------------------------------------------------------------------------------
@@ -1467,7 +1453,7 @@ message(STATUS "    V4L/V4L2:                   ${HAVE_CAMV4L}/${HAVE_CAMV4L2}")
 endif()
 message(STATUS "    Xine:                       ${HAVE_XINE}")
 if(ANDROID)
-message(STATUS "    AndroidNativeCamera:        ${HAVE_ANDROID_NATIVE_CAMERA}")
+message(STATUS "    AndroidNativeCamera:        build")
 endif()
 endif() #if(UNIX AND NOT APPLE)
 
index 5864419..cac601b 100644 (file)
@@ -58,6 +58,9 @@ if(NOT ANDROID)
 else()\r
     #libraries order is very important because linker from Android NDK is one-pass linker\r
     set(OPENCV_LIB_COMPONENTS opencv_contrib opencv_calib3d opencv_objdetect opencv_features2d opencv_imgproc opencv_video  opencv_highgui opencv_ml opencv_legacy  opencv_flann opencv_core )\r
+    IF (NOT @BUILD_SHARED_LIBS@)\r
+        set(OPENCV_LIB_COMPONENTS opencv_androidcamera ${OPENCV_LIB_COMPONENTS})\r
+    ENDIF()\r
 endif()\r
 \r
 SET(OpenCV_LIBS "")\r
@@ -114,6 +117,23 @@ IF (NOT @BUILD_SHARED_LIBS@)
 \r
 ENDIF(NOT @BUILD_SHARED_LIBS@)\r
 \r
+# ======================================================\r
+#  Android camera helper macro\r
+# ======================================================\r
+IF (ANDROID)\r
+  macro( COPY_NATIVE_CAMERA_LIBS target )\r
+    get_target_property(target_location ${target} LOCATION)\r
+    get_filename_component(target_location "${target_location}" PATH)\r
+    file(GLOB camera_wrappers "${OpenCV_LIB_DIR}/libnative_camera_r*.so")\r
+    foreach(wrapper ${camera_wrappers})\r
+        ADD_CUSTOM_COMMAND(\r
+          TARGET ${target}\r
+          POST_BUILD\r
+          COMMAND ${CMAKE_COMMAND} -E copy "${wrapper}" "${target_location}"\r
+          )\r
+    endforeach()\r
+  endmacro()\r
+ENDIF(ANDROID)\r
 \r
 # ======================================================\r
 #  Version variables:\r
index ba540e1..912c1bf 100644 (file)
@@ -321,7 +321,7 @@ set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "c flags" )
 #-L${LIBCPP_LINK_DIR} -lstdc++ -lsupc++
 #Also, this is *required* to use the following linker flags that routes around
 #a CPU bug in some Cortex-A8 implementations:
-set( LINKER_FLAGS "-Wl,--fix-cortex-a8 -L${STL_LIBRARIES_PATH} -lstdc++ -lsupc++ " )
+set( LINKER_FLAGS "-Wl,--fix-cortex-a8 -L${STL_LIBRARIES_PATH} -L${CMAKE_INSTALL_PREFIX}/lib -lstdc++ -lsupc++ " )
 
 set( NO_UNDEFINED ON CACHE BOOL "Don't all undefined symbols" )
 if( NO_UNDEFINED )
index 87bd901..77bb7d1 100644 (file)
@@ -3,6 +3,8 @@ if(ANDROID)
   if(ANDROID_API_LEVEL LESS 8)
     ADD_DEFINITIONS(-DGTEST_HAS_CLONE=0)
   endif()
+
+  add_subdirectory(androidcamera)
 endif()
 
 add_subdirectory(calib3d)
diff --git a/modules/androidcamera/CMakeLists.txt b/modules/androidcamera/CMakeLists.txt
new file mode 100644 (file)
index 0000000..751bbec
--- /dev/null
@@ -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()
\ No newline at end of file
diff --git a/modules/androidcamera/camera_wrapper/camera_wrapper.cpp b/modules/androidcamera/camera_wrapper/camera_wrapper.cpp
new file mode 100644 (file)
index 0000000..2071d6e
--- /dev/null
@@ -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);
+}
+
+}
diff --git a/modules/androidcamera/camera_wrapper/camera_wrapper.h b/modules/androidcamera/camera_wrapper/camera_wrapper.h
new file mode 100644 (file)
index 0000000..f1ae6bd
--- /dev/null
@@ -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);
+}
+
diff --git a/modules/androidcamera/include/camera_activity.hpp b/modules/androidcamera/include/camera_activity.hpp
new file mode 100644 (file)
index 0000000..76a63b0
--- /dev/null
@@ -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
\ No newline at end of file
diff --git a/modules/androidcamera/include/camera_properties.h b/modules/androidcamera/include/camera_properties.h
new file mode 100644 (file)
index 0000000..42202e3
--- /dev/null
@@ -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
diff --git a/modules/androidcamera/src/camera_activity.cpp b/modules/androidcamera/src/camera_activity.cpp
new file mode 100644 (file)
index 0000000..ca612b3
--- /dev/null
@@ -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);
+}
index cf65495..a1469aa 100644 (file)
@@ -211,9 +211,11 @@ if(APPLE)
     endif()
 endif(APPLE)
 
-if(HAVE_ANDROID_NATIVE_CAMERA)
+if(ANDROID)
+  include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../androidcamera/include")
   set(highgui_srcs ${highgui_srcs} src/cap_android.cpp)
   add_definitions(-DHAVE_ANDROID_NATIVE_CAMERA)
+  set(HIGHGUI_LIBRARIES ${HIGHGUI_LIBRARIES} opencv_androidcamera)
 endif()
 
 if(COMMAND get_module_external_sources)
@@ -331,6 +333,10 @@ if(NOT ZLIB_FOUND)
     add_dependencies(${the_target} zlib)
 endif()
 
+if(ANDROID)
+    add_dependencies(${the_target} opencv_androidcamera)
+endif()
+
 #message(STATUS "GRFMT: ${GRFMT_LIBS}")
 #message(STATUS "HIGHGUI_LIBS: ${HIGHGUI_LIBRARIES}")
 #message(STATUS "OPENCV_LIBS: ${OPENCV_LINKER_LIBS}")
@@ -371,6 +377,9 @@ if(BUILD_TESTS)
                       "${CMAKE_CURRENT_BINARY_DIR}")
 
   set(test_deps opencv_ts opencv_highgui opencv_imgproc)
+  if(ANDROID)
+    set(test_deps ${test_deps} opencv_androidcamera)
+  endif()
 
   foreach(d ${test_deps})
       if(${d} MATCHES "opencv_")
index 26fe28e..8aabf67 100644 (file)
@@ -46,7 +46,7 @@
 #include <opencv2/imgproc/imgproc.hpp>
 #include <pthread.h>
 #include <android/log.h>
-#include "camera_activity.h"
+#include <camera_activity.hpp>
 
 #if !defined(LOGD) && !defined(LOGI) && !defined(LOGE)
 #define LOG_TAG "CV_CAP"