Base for Native Activity example added.

pull/662/head
Alexander Smorkalov 12 years ago
parent 819ac111a2
commit 436d9bbcbb
  1. 10
      cmake/OpenCVDetectAndroidSDK.cmake
  2. 4
      samples/android/CMakeLists.txt
  3. 28
      samples/android/native-activity/AndroidManifest.xml
  4. 12
      samples/android/native-activity/jni/Android.mk
  5. 2
      samples/android/native-activity/jni/Application.mk
  6. 222
      samples/android/native-activity/jni/native.cpp
  7. BIN
      samples/android/native-activity/res/drawable/icon.png
  8. 4
      samples/android/native-activity/res/values/strings.xml

@ -264,13 +264,23 @@ macro(add_android_project target path)
ocv_list_filterout(android_proj_jni_files "\\\\.svn")
if(android_proj_jni_files AND EXISTS ${path}/jni/Android.mk AND NOT DEFINED JNI_LIB_NAME)
# find local module name in Android.mk file to build native lib
file(STRINGS "${path}/jni/Android.mk" JNI_LIB_NAME REGEX "LOCAL_MODULE[ ]*:=[ ]*.*" )
string(REGEX REPLACE "LOCAL_MODULE[ ]*:=[ ]*([a-zA-Z_][a-zA-Z_0-9]*)[ ]*" "\\1" JNI_LIB_NAME "${JNI_LIB_NAME}")
# find using of native app glue to determine native activity
file(STRINGS "${path}/jni/Android.mk" NATIVE_APP_GLUE REGEX ".*(call import-module,android/native_app_glue)" )
if(JNI_LIB_NAME)
ocv_include_modules_recurse(${android_proj_NATIVE_DEPS})
ocv_include_directories("${path}/jni")
if (NATIVE_APP_GLUE)
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
list(APPEND android_proj_jni_files ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
set(android_proj_NATIVE_DEPS ${android_proj_NATIVE_DEPS} android)
endif()
add_library(${JNI_LIB_NAME} MODULE ${android_proj_jni_files})
target_link_libraries(${JNI_LIB_NAME} ${OPENCV_LINKER_LIBS} ${android_proj_NATIVE_DEPS})

@ -11,6 +11,10 @@ add_subdirectory(face-detection)
add_subdirectory(image-manipulations)
add_subdirectory(color-blob-detection)
if (ANDROID_NATIVE_API_LEVEL GREATER 8)
add_subdirectory(native-activity)
endif()
add_subdirectory(tutorial-1-camerapreview)
add_subdirectory(tutorial-2-mixedprocessing)
add_subdirectory(tutorial-3-cameracontrol)

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.opencv.examples.native_activity"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />
<application android:label="@string/app_name"
android:icon="@drawable/icon"
android:hasCode="false" android:debuggable="true">
<activity android:name="android.app.NativeActivity"
android:label="@string/app_name">
<meta-data android:name="android.app.lib_name"
android:value="native_activity" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
</manifest>

@ -0,0 +1,12 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := native_activity
LOCAL_SRC_FILES := native.cpp
LOCAL_LDLIBS := -lm -llog -landroid
LOCAL_STATIC_LIBRARIES := android_native_app_glue
include $(BUILD_SHARED_LIBRARY)
$(call import-module,android/native_app_glue)

@ -0,0 +1,2 @@
APP_ABI := armeabi-v7a
APP_PLATFORM := android-9

@ -0,0 +1,222 @@
#include <android_native_app_glue.h>
#include <errno.h>
#include <jni.h>
#include <sys/time.h>
#include <time.h>
#include <android/log.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <queue>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#define LOG_TAG "OCV:libnative_activity"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
struct Engine
{
android_app* app;
cv::Ptr<cv::VideoCapture> capture;
};
cv::Size calcOptimalResolution(const char* supported, int width, int height)
{
int frameWidth = 0;
int frameHeight = 0;
size_t prev_idx = 0;
size_t idx = 0;
float minDiff = FLT_MAX;
do
{
int tmp_width;
int tmp_height;
prev_idx = idx;
while ((supported[idx] != '\0') && (supported[idx] != ','))
idx++;
sscanf(&supported[prev_idx], "%dx%d", &tmp_width, &tmp_height);
int w_diff = width - tmp_width;
int h_diff = height - tmp_height;
if ((h_diff >= 0) && (w_diff >= 0))
{
if ((h_diff <= minDiff) && (tmp_height <= 720))
{
frameWidth = tmp_width;
frameHeight = tmp_height;
minDiff = h_diff;
}
}
idx++; // to skip coma symbol
} while(supported[idx-1] != '\0');
return cv::Size(frameWidth, frameHeight);
}
static void engine_draw_frame(Engine* engine, const cv::Mat& frame)
{
if (engine->app->window == NULL)
{
return; // No window.
}
ANativeWindow_Buffer buffer;
if (ANativeWindow_lock(engine->app->window, &buffer, NULL) < 0)
{
LOGW("Unable to lock window buffer");
return;
}
void* pixels = buffer.bits;
for (int yy = 0; yy < std::min(frame.rows, buffer.height); yy++)
{
unsigned char* line = (unsigned char*)pixels;
memcpy(line, frame.ptr<unsigned char>(yy),
std::min(frame.cols, buffer.width)*4*sizeof(unsigned char));
// go to next line
pixels = (int32_t*)pixels + buffer.stride;
}
ANativeWindow_unlockAndPost(engine->app->window);
}
static void engine_handle_cmd(android_app* app, int32_t cmd)
{
Engine* engine = (Engine*)app->userData;
switch (cmd)
{
case APP_CMD_INIT_WINDOW:
if (app->window != NULL)
{
LOGI("APP_CMD_INIT_WINDOW");
engine->capture = new cv::VideoCapture(0);
union {double prop; const char* name;} u;
u.prop = engine->capture->get(CV_CAP_PROP_SUPPORTED_PREVIEW_SIZES_STRING);
cv::Size resolution;
if (u.name)
resolution = calcOptimalResolution(u.name,
ANativeWindow_getWidth(app->window),
ANativeWindow_getHeight(app->window));
else
{
LOGE("Cannot get supported camera resolutions");
resolution = cv::Size(ANativeWindow_getWidth(app->window),
ANativeWindow_getHeight(app->window));
}
if ((resolution.width != 0) && (resolution.height != 0))
{
engine->capture->set(CV_CAP_PROP_FRAME_WIDTH, resolution.width);
engine->capture->set(CV_CAP_PROP_FRAME_HEIGHT, resolution.height);
}
if (ANativeWindow_setBuffersGeometry(app->window, resolution.width,
resolution.height, WINDOW_FORMAT_RGBA_8888) < 0)
{
LOGE("Cannot set pixel format!");
return;
}
LOGI("Camera initialized at resoution %dx%d", resolution.width, resolution.height);
}
break;
case APP_CMD_TERM_WINDOW:
LOGI("APP_CMD_TERM_WINDOW");
engine->capture->release();
break;
}
}
void android_main(android_app* app)
{
Engine engine;
// Make sure glue isn't stripped.
app_dummy();
memset(&engine, 0, sizeof(engine));
app->userData = &engine;
app->onAppCmd = engine_handle_cmd;
engine.app = app;
float fps = 0;
cv::Mat drawingFrame;
bool firstFrame = true;
std::queue<int64> timeQueue;
// loop waiting for stuff to do.
while (1)
{
// Read all pending events.
int ident;
int events;
android_poll_source* source;
// Process system events
while ((ident=ALooper_pollAll(0, NULL, &events, (void**)&source)) >= 0)
{
// Process this event.
if (source != NULL)
{
source->process(app, source);
}
// Check if we are exiting.
if (app->destroyRequested != 0)
{
LOGI("Engine thread destroy requested!");
return;
}
}
int64 then;
int64 now = cv::getTickCount();
timeQueue.push(now);
// Capture frame from camera and draw it
if (!engine.capture.empty())
{
if (engine.capture->grab())
{
engine.capture->retrieve(drawingFrame, CV_CAP_ANDROID_COLOR_FRAME_RGBA);
// if (firstFrame)
// {
// firstFrame = false;
// engine.capture->set(CV_CAP_PROP_AUTOGRAB, 1);
// }
}
char buffer[256];
sprintf(buffer, "Display performance: %dx%d @ %.3f", drawingFrame.cols, drawingFrame.rows, fps);
cv::putText(drawingFrame, std::string(buffer), cv::Point(8,64), cv::FONT_HERSHEY_COMPLEX_SMALL, 1, cv::Scalar(0,255,0,255));
engine_draw_frame(&engine, drawingFrame);
}
if (timeQueue.size() >= 2)
then = timeQueue.front();
else
then = 0;
if (timeQueue.size() >= 25)
timeQueue.pop();
fps = 1.f*timeQueue.size()*(float)cv::getTickFrequency()/(float)(now-then);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">OCV Native Activity</string>
</resources>
Loading…
Cancel
Save