I have compiled ffmpeg code and generated .so files,
Then I put these .so files in jniLibs/armeabi/ folder.
To use it below code :
Controller.java
public class Controller {
static {
System.loadLibrary("avutil");
System.loadLibrary("swresample");
System.loadLibrary("avcodec");
System.loadLibrary("avformat");
System.loadLibrary("swscale");
System.loadLibrary("avfilter");
System.loadLibrary("avdevice");
}
public static native void runffmpegCommand(String[] argv);
public static void testFFMPEG(String[] strings) {
runffmpegCommand(new String[]);
}
}
ffmpeg_controller.c
#include <android/log.h>
#include "ffmpeg_Controller.h"
#include <stdlib.h>
#include <stdbool.h>
int main(int argc, char **argv);
JavaVM *sVm = NULL;
jint JNI_OnLoad( JavaVM* vm, void* reserved )
{
sVm = vm;
return JNI_VERSION_1_6;
}
JNIEXPORT void JNICALL Java_com_test_Controller_runffmpegCommand(JNIEnv *env, jobject obj, jobjectArray args)
{
int i = 0;
int argc = 0;
char **argv = NULL;
jstring *strr = NULL;
if (args != NULL) {
argc = (*env)->GetArrayLength(env, args);
argv = (char **) malloc(sizeof(char *) * argc);
strr = (jstring *) malloc(sizeof(jstring) * argc);
for(i=0;i<argc;i++) { strr[i] = (jstring)(*env)->GetObjectArrayElement(env, args, i);
argv[i] = (char *)(*env)->GetStringUTFChars(env, strr[i], 0);
}
}
main(argc, argv);
for(i=0;i<argc;i++) {
(*env)->ReleaseStringUTFChars(env, strr[i], argv[i]);
}
free(argv);
free(strr);
}
ffmpeg_controller.h
#include <jni.h>
#ifndef _Included_com_test_Controller
#define _Included_com_test_Controller
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_android_com_test_Controller_runffmpegCommand(JNIEnv *, jobject, jobjectArray);
#ifdef __cplusplus
}
#endif
#endif
When I run this code it through error as below:
Logs:
2018-12-17 14:11:17.850 25598-25598/com.android.test E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.test, PID: 25598
java.lang.UnsatisfiedLinkError: dlopen failed: "/data/app/com.android.test-1/lib/arm/libavutil.so" is 64-bit instead of 32-bit
at java.lang.Runtime.loadLibrary0(Runtime.java:989)
at java.lang.System.loadLibrary(System.java:1530)
I think the problem her because you run application with targetSdkVersion 26 or more so the solution i think it's her look:
https://stackoverflow.com/a/52951886/7055487
The Exception is self-explain: "libavutil.so is 64-bit instead of 32-bit": you have copied a 64 bit library in a "jniLibs" subfolder that expects 32 bit libraries.
"jniLibs/armeabi" subfolder is for 32bit ONLY devices
Related
I'm gonna write a c program that loads a native android library (.so) this is my code:
#include <stdio.h>
#include <dlfcn.h>
#include <stdlib.h>
typedef void (*target_func)(JNIEnv* env, jobject obj, int x);
int main(int argc, char ** argv) {
char *lib = "/path/to/lib.so"
void *handle = dlopen(lib, RTLD_LAZY);
if (NULL == handle) {
printf("load library error\n");
return 1;
}
void *offset_func = dlsym(handle, "Java_com_example_test_MainActivity_myFunc");
if (NULL == offset_func) {
printf("getprocaddress error\n");
return 1;
}
target_func target = (target_func)((unsigned char *)offset_func);
target(nullptr, nullptr, 10); // Here i need to pass JNIEnv pointer
return 0;
}
The only thing that i need is to pass the JNIEnv (the first parameter), Is there any way ??
My program runs on android emulator and because of that i tried to resolve JNIEnv from libart.so but i wasn't success to disassemble libart.so in IDA Pro.
I know when we launch an apk in our device, the ART (or Dalvik) creates JNIEnv for the app but i don't know how can i emulate and create JNIEnv similar to ART.
I'd like to using some asset files of my app in native c++ code, so I have some testing code like follows:
Java
package com.example.andy.textureviewtest;
import ...
public class MainActivity extends AppCompatActivity {
private AssetManager assetManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.sample_text);
tv.setText(stringFromJNI());
assetManager = getAssets();
generateAssets(assetManager);
}
public native String stringFromJNI();
public native int generateAssets(AssetManager assetManager);
static {
System.loadLibrary("native-lib");
}
}
C++
#include <jni.h>
#include <string>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/log.h>
JNIEXPORT jstring JNICALL Java_com_example_andy_textureviewtest_MainActivity_stringFromJNI(
JNIEnv* env,
jobject /* this */) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
JNIEXPORT jint JNICALL Java_com_example_andy_textureviewtest_MainActivity_generateAssets(
JNIEnv* env,jobject thiz,jobject assetManager) {
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_UNKNOWN);
off_t bufferSize = AAsset_getLength(asset);
}
return 0;
}
but when my app runs, I only got this error:
java.lang.UnsatisfiedLinkError: No implementation found for int com.example.andy.textureviewtest.MainActivity.generateAssets(android.content.res.AssetManager) (tried Java_com_example_andy_textureviewtest_MainActivity_generateAssets and Java_com_example_andy_textureviewtest_MainActivity_generateAssets__Landroid_content_res_AssetManager_2)
Anything wrong here that I might have missed?
Your C++ functions probably are missing
extern "C"
prefix. Their exported names are mangled by the C++ compiler, and JNI fails to resolve them.
I am following a tutorial on NDK development using C++. The app is a basic fibonacci number printing app. I have the appropriate System.loadLibrary and the JNI_OnLoad call. I can see in the logcat that the library is getting loaded. However, post that, the system still looks for methods based on the package names. Heres the error from logcat .
No implementation found for long com.test.fib.FibLib.fibN(long) (tried Java_com_test_fib_FibLib_fibN and Java_com_test_fib_FibLib_fibN__J)
And here is the class where I have the cpp code and related stuff .
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <android/log.h>
#include <jni.h>
#define LOG_TAG "Fibonacci Stuff"
#define LOG_D(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
namespace com_test_fib {
static long fib(long n) {
if(n==0) return 0;
if(n==1) return 1;
return fib(n-1) + fib(n-2);
}
/* JNI wrapper */
static jlong fibN(JNIEnv* env, jclass clazz, jlong n) {
return fib(n);
}
static JNINativeMethod method_table[] = {
{"fibN", "(J)J", (void *) fibN }
};
}
using namespace com_test_fib;
extern "C" jint JNI_Onload(JavaVM* vm, void* reserved) {
LOG_D ("JNI_OnLoad");
JNIEnv* env;
if(vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) != JNI_OK ) {
LOG_D("Initial Get env error");
return JNI_ERR;
}
else {
jclass clazz = env->FindClass("com/test/fib/FibLib");
LOG_D ("Find the class");
if(clazz) {
LOG_D ("Class not found");
jint ret = env->RegisterNatives(clazz, method_table, sizeof(method_table)/sizeof(method_table[0]) );
env->DeleteLocalRef(clazz);
return ret ==0 ? JNI_VERSION_1_6 : JNI_ERR;
} else {
LOG_D("Some error it seems");
return JNI_ERR;
}
}
}
Here is the loadLibrary call
package com.test.fib;
import android.util.Log;
public class FibLib {
public static long fibJ(long n) {
if(n==0) {
return 0;
}
if(n==1) {
return 1;
}
return fibJ(n-1) + fibJ(n-2);
}
/* Wrapper to call the JNI code. This is called by the activity */
public static native long fibN(long n);
static {
Log.d("Sys library loading", "This should call the onLoad function");
System.loadLibrary("Fib");
}
}
I can see the above message in Logcat. After that i directly see the exceptions and no messages from the onLoad method. I am using eclipse, min version is 14 and compile version is 5.1.1. Device is nexus 7. The package names are matching com.test.fib) in the app and the namespace.
Can anyone please let me know whats wrong here. THis is driving me mad..
Thanks
I did an Opencv's application en windows and now I am using JNI to convert this code to Android but I am having some problems.
In concrete my native code not do nothing.
This is my Java class where I define my native methods:
package com.example.telo3;
import org.opencv.core.Mat;
public class Process {
static {
System.loadLibrary("nativo");
}
public Process(){
dir=inicializar_nativo();
}
public void Procesar(Mat framedetect, Mat framedraw){
procesar_nativo(dir,framedetect.getNativeObjAddr(),framedraw.getNativeObjAddr());
}
private long dir;
private static native long inicializar_nativo();
private static native void procesar_nativo(long thiz, long framedetect, long framedraw);
}
This is my JNI code:
#include "nativo.h"
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/video/tracking.hpp"
#include <iostream>
#include <stdio.h>
#include "FaceDetector.h"
#include "Draw.h"
#include "Almacena.h"
#include "Runnable.h"
using namespace std;
using namespace cv;
#include <android/log.h>
#define LOG_TAG "NATIVO"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
struct variables {
Almacena almacena;
Draw draw;
FaceDetector face_detector;
};
JNIEXPORT jlong JNICALL Java_com_example_telo3_Process_inicializar_1nativo(
JNIEnv *, jobject) {
long dir = (long) new variables();
return (dir);
}
JNIEXPORT void JNICALL Java_com_example_telo3_Process_procesar_1nativo(JNIEnv *,
jobject, jlong dir, jlong framedetect, jlong framedraw) {
Mat* telo =(Mat*)framedetect;
Mat* telo2= (Mat*)framedraw;
((variables*)dir)->almacena = ((variables*)dir)->face_detector.Detect(*telo);
//almacena = face_detector.Detect(frame_gray);
((variables*)dir)->draw.Dibujar(*telo2,((variables*)dir)->almacena);
//frame_capturado = draw.Dibujar(frame_capturado, almacena);
if( (((variables*)dir)->almacena.get_faces()).size() ==0){
LOGD("no detecto caras");
}
}
I think that I use the Jni correctly but the function Detect not works correctly because when I uses this if return 0.
Looks like a simple typo for me.
Your package is "com.example.telo3"
Your class is "Process"
Your function is "inicializar_nativo()"
So the c++ function has to be declared as
JNIEXPORT jlong JNICALL Java_com_example_telo3_Process_inicializar_nativo(...)
You have declared it as
JNIEXPORT jlong JNICALL Java_com_example_telo3_Process_inicializar_1nativo(...)
Did you get an unsatisfied link exception or such?
I am writing a plugin using android NDK.right now i have done the following:
1- wrote simple functions in C++ and made a .so(shared library) of it. code is as follows:
#include <jni.h>
#include <string.h>
#include <android/log.h>
#define DEBUG_TAG "NDK_AndroidNDK1SampleActivity"
extern "C" {
static JavaVM *gJavaVM;
static JNIEnv *env;
static jobject gInterfaceObject, gDataObject;
JNIEXPORT jstring JNICALL Java_com_gvs_tes_NdkTestActivity_getNumbr(JNIEnv * env,jobject obj);
JNIEXPORT void JNICALL Java_com_gvs_tes_NdkTestActivity_getActivity(JNIEnv * env, jobject obj);};
JNIEXPORT jstring JNICALL Java_com_gvs_tes_NdkTestActivity_getNumbr(JNIEnv * env,jobject obj)
{
jboolean isCopy;
jstring szLogThis =(jstring) "hellog";
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", szLogThis);
return szLogThis;
}
JNIEXPORT void JNICALL Java_com_gvs_tes_NdkTestActivity_getActivity(JNIEnv * env, jobject obj)
{
jstring logs =(jstring) "Function Started";
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", logs);
if(env)
{
jstring logs =(jstring) "env not null";
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", logs);
}
jclass interfaceClass = env->FindClass("com/gvs/tes/testClass");
if(!interfaceClass)
{
jstring logThis =(jstring) "Activity Class Could not be get";
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", logThis);
return;
}
jmethodID altmethod = env->GetMethodID(interfaceClass, "<init>","()V");
jobject objClas = env->NewGlobalRef(env->NewObject(interfaceClass, altmethod));
jmethodID method = env->GetMethodID(interfaceClass, "chekClas","(I)V");
if(!method)
{
jstring logThis =(jstring) "Function Could not be get";
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", logThis);
return;
}
jint val = 3;
env->CallVoidMethod(objClas, method, val);
logs =(jstring) "Function Ended";
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NDK:LC: [%s]", logs);
}
2- I copied .so file to [myUnityProject]/Assets/Plugins/Android folder.
3- then i wrote following Script to call function
using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;
public class myScript : MonoBehaviour {
//[DllImport ("ndktest")]
//private static extern string Java_com_gvs_tes_NdkTestActivity_getNumbr();
[DllImport ("ndktest")]
private static extern void Java_com_gvs_tes_NdkTestActivity_getActivity();
// Use this for initialization
void Start () {
print("hello start");
//print ("CHECKING return value : "+Java_com_gvs_tes_NdkTestActivity_getNumbr().ToString());
Java_com_gvs_tes_NdkTestActivity_getActivity(); // PROBLEM OCCURS HERE
print("after Function call inside script");
}
// Update is called once per frame
void Update () {
}
}
Now My Main problem is 'How to access Java files present in my Android Project'.Kindly point me into right direction if i am doing it stupidly wrong As my Only purpose is to be able to use an SDK(built for android in java) inside my Unity Application.Any Help is greatly appreciated.