I have compiled FFmpeg library using NDK and use it to trim videos and get thumbnails from a video in my app, so basically I have ffmpeg.so and video-trimmer.so libraries up and running.
The problem however is strange, the trim or getThumbnail operations are successful but just one time i.e. the first time and the operations fail the second time. However it is successful the third time, I googled it and got two similar posts on SO related to my problem
POST 1:
POST 2:
Interestingly they suggest the same solution and I am unable to solve the issue being a naive in C programming language.
Here is what I have done
void Java_com_example_demo_natives_LibraryLoader_loadTrimmerLibrary(JNIEnv* env, jclass class, jstring libffmpeg_path, jstring inputFile, jstring outFile,
jstring startTime, jstring length)
{
const char* path;
void* handle;
int *(*Java_com_example_demo_natives_VideoTrimmer_trim)(JNIEnv *, jclass, jstring, jstring, jstring, jstring);
path = (*env)->GetStringUTFChars(env, libffmpeg_path, 0);
handle = dlopen(path, RTLD_LAZY);
Java_com_example_demo_natives_VideoTrimmer_trim = dlsym(handle, "Java_com_example_demo_natives_VideoTrimmer_trim");
(*Java_com_example_demo_natives_VideoTrimmer_trim)(env, class, inputFile, outFile, startTime, length);
(*env)->ReleaseStringUTFChars(env, libffmpeg_path, path);
dlclose(handle);
}
Despite of calling dlclose the library instance still exists in memory, what I am doing wrong here?
I come to know that library instance still exists because when I load the libraries again in some other activity the error message says library already exists in CL.
I want to get rid of the instance of that library from memory, please help...
try moving the position of the 'ReleaseString...'
it should be after the 'dlopen'
it should be before the call into the other shared lib...
(*env)->GetStringUTFChars
dlopen
(*env)->ReleaseStringUTFChars
make the main call
dlclose
Related
One of the ways to register native functions in JNI is by using the function RegisterNatives(). An example (although seemingly with some errors) can be found in the Android documentation here. Here's a code example demonstrating this technique:
#include <jni.h>
void JNICALL test(JNIEnv* const environment, jobject const objectOrClass) {
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* const vm, void* const reserved) {
JNIEnv* environment;
vm->GetEnv(reinterpret_cast<void**>(&environment), JNI_VERSION_1_6);
auto const classRef = environment->FindClass("com/example/test/MainActivity");
JNINativeMethod method;
method.name = "test";
method.signature = "()V";
method.fnPtr = reinterpret_cast<void*>(test);
environment->RegisterNatives(classRef, &method, 1);
return JNI_VERSION_1_6;
}
Using RegisterNatives() requires casting (non-member) function pointers to type void*, as shown above. According to this documentation, this isn't necessarily portable in C++. It may be guaranteed to work in some environments (such as POSIX), but the behavior is otherwise implementation-dependent.
I wouldn't expect this functionality to be exposed this way if it wasn't reliable, but does either JNI or Android offer any guarantees that this can be counted on to work? Is it just assumed that JNI and/or Android will always be running in environments where casting between function pointers and void* is supported?
EDIT:
After further consideration, it seems JNI would almost have to do something non-portable with respect to native functions, irrespective of the cast issue. The only information about the function JNI has (other than the address) is a string describing the argument and return types, so it seems unlikely that the void* will ever be cast back to a valid function pointer and used in the conventional way. Presumably the calls are instead made via low-level platform-specific code.
It still seems like a requirement that function-pointer-to-void* casts be well-behaved, so if anyone knows if or how JNI guarantees that, I'd still be interested to know.
I have the following setup - a MainActivity with button which starts SDLActivity (SDL2). On the C++ side of my SDL project I have a main.cpp with declared native function:
extern "C" void Java_org_libdsl_app_SDLActivity_nativeSetAcc (JNIEnv* env, jclass clazz, jint Acc);
void Java_org_libdsl_app_SDLActivity_nativeSetAcc (JNIEnv* env, jclass clazz, jint Acc)
{
SDL_Log ("set acc");
// does something with the Acc value
}
I've put the following in the SDLActivity.java:
public static native void nativeSetAcc (int Acc);
but I'm getting unsatisified link error (java.lang.UnsatisfiedLinkError: Native method not found: org.libsdl.app.SDLActivity.nativeSetAcc:(I)V)
The C/SDL side compiles OK ("jni.h" is included as well). The android part runs fine until I want to use nativeSetAcc;
The strange part is that other JNI functions from SDL library do indeed work (nativeQuit, nativeResume, etc). And I'm sure that I do LoadLibrary ("main") - the code inside main's main() is working (looping SDL events, etc).
Looking at the hexdump of libmain.so I do see the Java_org_libdsl_app_SDLActivity_nativeSetAcc string.
Please help! Surely I'm missing something small, but I can't see.
OK Guys, I'm stupid. Instead of libsdl I was using libdsl in the code. A little sleep at sunday is very recommended
In the jni layer of the android code that I have written, am returning an array from the jni layer to the java layer. I am using DeleteLocalRef() to free the local reference before passing the result. i just wanted to make sure that the code i have written is proper. Please find the code below.Any help is appreciated.
extern "C"
{
JNIEXPORT jbyteArray JNICALL Java_com_jni_btRead(JNIEnv* env, jobject)
{
unsigned char* reply = btRead();
jbyteArray jba;
if(reply)
{
jba = env->NewByteArray(2048);
env->SetByteArrayRegion(jba, 0, 2048, reinterpret_cast<jbyte*>(reply));
}
else
{
jba = env->NewByteArray(0);
}
env->DeleteLocalRef(jba);
return jba;
}
}
Local variables are always created in stack segment and hence destroyed after returning from function. This diagram may help.
A quote from here:
A local reference is valid only within the dynamic context of the
native method that creates it, and only within that one invocation of
the native method. All local references created during the execution
of a native method will be freed once the native method returns.
So you may not free your local reference as it gets freed automatically.
I'm writing an Android app using the NDK and NativeActivity. My app depends on a few bits of third party code that are shipped as assets. Currently I'm working on trying to extract those assets while keeping the folder structure intact.
I've tried using the AssetManager, but to keep the folder structure intact it seemed like there would a huge amount of code involved, for a simple task such as what I've mentioned. I've since switched focus to try to implement treating the APK as a ZIP file and extract its contents that way. But that requires I find the exact path to the APK.
In a normal Android app one would use getPackageCodePath, but this is an abstract method attached to the Context class. My question is how do I obtain the exact path to the APK when not using a normal Activity?
Also I tried calling getPackageCodePath via JNI, but that crashed the app on account of not being able to find the method.
EDIT:
Is this even possible?
I was actually able to call getPackageCodePath via JNI and get it to work. The following code put at the top of android_main in the native-activity sample in NDK r7 logs the correct path and doesn't crash:
void android_main(struct android_app* state) {
struct engine engine;
ANativeActivity* activity = state->activity;
JNIEnv* env = activity->env;
jclass clazz = (*env)->GetObjectClass(env, activity->clazz);
jmethodID methodID = (*env)->GetMethodID(env, clazz, "getPackageCodePath", "()Ljava/lang/String;");
jobject result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
const char* str;
jboolean isCopy;
str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
LOGI("Looked up package code path: %s", str);
...
}
I feel like this might not be a great solution, though. There are two things that worry me:
Thread safety - there's an ugly warning about only using the env member of ANativeActivity in the main Java thread, and if I understand things correctly, this code is going to get run in the native activity's thread.
ANativeActivity's clazz member appears to be misnamed and is actually the instance of the Java NativeActivity instead of the class object. Otherwise this code wouldn't work. I really hate relying on something that is obviously misnamed like this.
Aside from that, it works, and I'm actually about to use it myself to try to extract the assets out of the .apk using libzip and into the data directory.
Since I just had to search for exactly how to do the attach/detach calls I'll paste the updated version here.
The following seems to get the right location without crashing (after minimal testing)
ANativeActivity* activity = state->activity;
JNIEnv* env=0;
(*activity->vm)->AttachCurrentThread(activity->vm, &env, 0);
jclass clazz = (*env)->GetObjectClass(env, activity->clazz);
jmethodID methodID = (*env)->GetMethodID(env, clazz, "getPackageCodePath", "()Ljava/lang/String;");
jobject result = (*env)->CallObjectMethod(env, activity->clazz, methodID);
const char* str;
jboolean isCopy;
str = (*env)->GetStringUTFChars(env, (jstring)result, &isCopy);
LOGI("Looked up package code path: %s", str);
(*activity->vm)->DetachCurrentThread(activity->vm);
Had to modify it to this in the year 2014.
ANativeActivity* activity = state->activity;
JNIEnv* env=0;
activity->vm->AttachCurrentThread(&env, NULL);
jclass clazz = env->GetObjectClass(activity->clazz);
jmethodID methodID = env->GetMethodID(clazz, "getPackageCodePath", "()Ljava/lang/String;");
jobject result = env->CallObjectMethod(activity->clazz, methodID);
jboolean isCopy;
std::string res = env->GetStringUTFChars((jstring)result, &isCopy);
LOG_DEBUG("Looked up package code path: %s", res.c_str());
activity->vm->DetachCurrentThread();
Did you try to read /proc/self/cmdline from your application?
You should be able to open it as a normal (as far as proc files are normal :-) so you can read from the file until EOF, but not seek) c FILE and read from it.
As an example for the phone app, I can see from ps in android that the name of the applications is the expected app name:
# ps | grep phone
radio 1588 839 1467420 103740 SyS_epoll_ 7f7de374ac S com.android.phone
And checking the cmdline for that pid returns a good app name:
# cat /proc/1588/cmdline
com.android.phone
Call getPackageCodePath() in Java and pass jstring to your C++ app via native method
I want to use the OpenCV Android porting, that you can find HERE, to make some image transformations for an Augmented Reality application. I've found no problem configuring and building the library, I receive no error and I succed put it within my Android application throght JNI process: the library libopencv.so is in the correct directory "\libs\armeabi\" under my project's directory.
And now the problems:
1) First I want to understand what version of the original openCV library this porting derive from. Is important for me know if it derive from version 1.5, 2.0 or 2.1 because same functions are very different and others are absent.
2) Before starting with real time video manipulation, I'd try make some simple operations on a single image or saved video:
JNIEXPORT
jstring
JNICALL
Java_org_examples_testOpenCV_OpenCV_LoadImage(JNIEnv* env, jobject thiz)
{
IplImage* imgIn = cvLoadImage("/sdcard/testimage.jpg", -1);
if (!imgIn) return env->NewStringUTF("Error");
cvReleaseImage( &imgIn );
return env->NewStringUTF("Ok");
}
JNIEXPORT
jstring
JNICALL
Java_balmas_examples_testOpenCV_OpenCV_manageVideo(JNIEnv* env, jobject thiz)
{
CvCapture* capture = cvCaptureFromFile("/sdcard/video_galaxyspica_352x288_15fps.3gp");
if (!capture) return env->NewStringUTF("Error");
return env->NewStringUTF("Ok");
}
In both cases I receive "Error". There are no problems with files on the sdcard becouse I try to make this:
FILE* file = fopen("/sdcard/video_galaxyspica_352x288_15fps.3gp","w+");
//FILE* file = fopen("/sdcard/testimage.jpg","w+");
if (!file) return env->NewStringUTF("Error");
else {
fflush(file);
fclose(file);
return env->NewStringUTF("OK");
}
and I receive "OK".
I realize that there is some problem within highgui library but I don't understand what and wath I should make to avoid the problem.
Some suggestions!!!
Thank you everyone
guys- you may want to try this link, it ports the C++ 'modern' interface to opencv. The IplImage stuff is deprecated, but new versions leave wrappers if you need to support legacy code.
http://code.google.com/p/android-opencv/
There's a sample camera-calibration app, you click snap a few times and it will solve for the K matrix.
Note: you'll need the crystax ndk for STL classes, http://www.crystax.net/android/ndk-r4.php