7613


失礼いたします。

現在、趣味でOpenCVのAndroid版を使ったアプリを作っております。  
しかし、アプリを実行すると、LogCatに題目のエラーが発生した後、強制終了してしまいます。

ソースは以下の通りです。  
以下の通り、画像処理の部分についてはAndroidNDKの機能を使用しております。

MainActivity.java

[code]

    package com.example.foo;
    
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
    import org.opencv.android.OpenCVLoader;
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;
    import org.opencv.android.CameraBridgeViewBase;
    import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.WindowManager;
    
    public class MainActivity extends Activity implements CvCameraViewListener2 {
        private static final String    TAG = "MainActivity";
    
        private Mat                    mMatCamera;
        private Mat                    mMatView;
    
        private CameraBridgeViewBase   mOpenCvCameraView;
    
        static {
            if (!OpenCVLoader.initDebug()) {
                // Handle initialization error
            } else {
                System.loadLibrary("foo");
            }
        }
    
        public MainActivity() {
        }
    
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    
            setContentView(R.layout.foo);
    
            mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.foo_activity_surface_view);
            mOpenCvCameraView.setCvCameraViewListener(this);
        }
    
        @Override
        public void onPause()
        {
            super.onPause();
            if (mOpenCvCameraView != null)
                mOpenCvCameraView.disableView();
        }
    
        @Override
        public void onResume()
        {
            super.onResume();
            mOpenCvCameraView.enableView();
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            if (mOpenCvCameraView != null)
                mOpenCvCameraView.disableView();
        }
    
        public void onCameraViewStarted(int width, int height) {
            mMatView = new Mat(height, width, CvType.CV_8UC4);
        }
    
        public void onCameraViewStopped() {
            if (mMatCamera != null)
                mMatCamera.release();
            if (mMatView != null)
                mMatView.release();
        }
    
        public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
            mMatCamera = inputFrame.rgba();
    
            foo(mMatCamera.getNativeObjAddr(), mMatView.getNativeObjAddr());
    
            return mMatView;
        }
    
        private native void foo(long matCameraAddr, long matViewAddr);
    }
    
[/code]

jni_part.cpp

[code]

    #include <jni.h>
    #include <opencv2/core/core.hpp>
    
    JNIEXPORT void JNICALL Java_com_example_foo_MainActivity_foo(JNIEnv*, jobject, jlong matCameraAddr, jlong matViewAddr)
    {
        // 何か処理
    }
    
[/code]

Android.mk

[code]

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    
    OPENCV_CAMERA_MODULES:=on
    OPENCV_INSTALL_MODULES:=on
    include ../../sdk/native/jni/OpenCV.mk
    
    LOCAL_MODULE    := foo
    LOCAL_SRC_FILES := jni_part.cpp
    LOCAL_LDLIBS +=  -llog -ldl
    
    include $(BUILD_SHARED_LIBRARY)
    
[/code]

  
エラーの内容は以下の通りです。

[code]

    03-08 10:58:42.984: E/AndroidRuntime(26065): FATAL EXCEPTION: Thread-157860
    03-08 10:58:42.984: E/AndroidRuntime(26065): Process: com.example.foo, PID: 26065
    03-08 10:58:42.984: E/AndroidRuntime(26065): java.lang.UnsatisfiedLinkError: Native method not found: com.example.foo.MainActivity.foo:(JJ)V
    03-08 10:58:42.984: E/AndroidRuntime(26065):    at com.example.foo.MainActivity.foo(Native Method)
    03-08 10:58:42.984: E/AndroidRuntime(26065):    at com.example.foo.MainActivity.onCameraFrame(MainActivity.java:81)
    03-08 10:58:42.984: E/AndroidRuntime(26065):    at org.opencv.android.CameraBridgeViewBase.deliverAndDrawFrame(CameraBridgeViewBase.java:387)
    03-08 10:58:42.984: E/AndroidRuntime(26065):    at org.opencv.android.JavaCameraView$CameraWorker.run(JavaCameraView.java:328)
    03-08 10:58:42.984: E/AndroidRuntime(26065):    at java.lang.Thread.run(Thread.java:841)
    
[/code]

以上、よろしくお願いいたします。


CC BY-SA 3.0
2015-03-08T05:56:17.213
7601
2015-03-09T04:51:55.353
8741
question
android opencv
java.lang.UnsatisfiedLinkError: Native method not foundが発生してしまう


JNIからネイティブメソッド実体を見つけられないようです。C++としてコンパイルしていますから、soファイルのエクスポート名がズレたようです。

以下のような jni_part.h を作って、jni_part.c の先頭で `#include "jni_part.h"` すると直りますか？

[code]

    #ifdef __cplusplus
    extern "C" {
    #endif
    
    JNIEXPORT void JNICALL Java_com_example_foo_MainActivity_foo(JNIEnv*,
      jobject, jlong, jlong);
    
    #ifdef __cplusplus
    }
    #endif
    
[/code]

* * *

追記：本質的には、Java/nativeメソッド宣言に対応するC++/関数宣言にて`extern "C"`指定が必要となります。

C++では関数オーバーロード等を実現するため、名前マングリング(name
mangling)とよばれる変形処理が行われており、ビルドされたSOファイルにはこの変形された名前が出力されます。一方、JNIでは「関数の名前」に頼ってネイティブ関数を探そうとしますので、質問文中にあるような`UnsatisfiedLinkError`例外になります。

`extern "C"`指定により名前マングリングを抑止し、ソースコード上の関数名そのままをSOファイルに出力させます。なお、手抜きをするなら
jni_part.h を作らずに、ネイティブ関数定義を全部囲う`extern "C" {`～`}`を書けばOKです。

[code]

    extern "C" {
    
    JNIEXPORT void JNICALL Java_com_example_foo_MainActivity_foo(JNIEnv*,
      jobject, jlong matCameraAddr, jlong matViewAddr)
    {
      // 何か処理
    }
    
    // さらに他ネイティブメソッドの実装...
    }
    
[/code]


CC BY-SA 3.0
2015-03-08T12:13:33.610
7613
2015-03-09T04:51:55.353
2015-03-09T04:51:55.353
49
49
7601
answer