I am developing an Android Player App, use SDL2.0.8 + ffplay(base on ffmpeg4.1).
There is a Intent from MainActivity to SDLActivity(both two in the same process).
When i press backButton in SDLActivity, SDLActivity will be destoryed suddenly(looks like System.exit(0)). The main process seem to be recreated, i can see the pid changed.
This is not the UE I want.
What can i do to make SDLActivity back Smoothly, just like normal backpress .
SDLActivity:
if (id == android.R.id.home) {
if (mMediaPlayer != null) {
try {
mMediaPlayer.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
finish();
return true;
}
MediaPlayer:
@Override
public void stop() throws Exception {
Log.v(TAG, "stop()");
mNextNativeState = NativeState.PAUSED;
handleNativeState();
// Send a quit message to the application
mExitCalledFromJava = true;
nativeQuit();
// Now wait for the SDL thread to quit
if (mSDLThread != null) {
try {
mSDLThread.join();
} catch (Exception e) {
Log.v(TAG, "Problem stopping thread: " + e);
}
mSDLThread = null;
Log.v(TAG, "Finished waiting for SDL thread");
}
// Reset everything in case the user re opens the app
initialize();
mIsPrepared = false;
}
ffplay (catch SDL quit event):
if (exit_on_keydown || event.key.keysym.sym == SDLK_ESCAPE ||
event.key.keysym.sym == SDLK_q || event.key.keysym.sym == SDLK_AC_BACK) {
do_exit(cur_stream);
break;
}
...
case SDL_QUIT:
case FF_QUIT_EVENT:
do_exit(cur_stream);
break;
ffplay(do_exit):
if (is) {
stream_close(is);
}
if (renderer)
SDL_DestroyRenderer(renderer);
if (window)
SDL_DestroyWindow(window);
uninit_opts();
#if CONFIG_AVFILTER
av_freep(&vfilters_list);
#endif
avformat_network_deinit();
if (show_status)
printf("\n");
SDL_Quit();
exit(0);
int main(int argc, char **argv) {
...
event_loop(is);//Infinite
/* never returns */
return 0;
}
but i got another question, when i add JNI_OnLoad (add this for tell java some information about play progress)in ffplay, I got some error about libc( seem to the app hang at libc error)
pthread_key_t mThreadKey;
JavaVM *mJavaVM;
//get JNIEnv
JNIEnv *Android_JNI_GetEnv(void) {
JNIEnv *env;
int status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
if (status < 0) {
LOGE("failed to attach current thread");
return 0;
}
return env;
}
void Android_JNI_ThreadDestroyed(void *value) {
JNIEnv *env = (JNIEnv *) value;
if (env != NULL) {
(*mJavaVM)->DetachCurrentThread(mJavaVM);
pthread_setspecific(mThreadKey, NULL);
}
}
//entrance
//JNIEXPORT jint
JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
JNIEnv *env;
mJavaVM = vm;
LOGI("JNI_OnLoad called");
if ((*mJavaVM)->GetEnv(mJavaVM, (void **) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE("Failed to get the environment using GetEnv()");
return -1;
}
// Get jclass with env->FindClass.
// Register methods with env->RegisterNatives.
Android_JNI_GetEnv();
return JNI_VERSION_1_4;
}
//start play
void Android_JNI_OnPrepared(void) {
JNIEnv *mEnv = Android_JNI_GetEnv();
jclass cls = (*mEnv)->FindClass(mEnv, "com/gmyboy/player/MediaPlayer");
if (cls == NULL) {
LOGE("FindClass Error");
}
jmethodID midOnPrepared = (*mEnv)->GetStaticMethodID(mEnv, cls, "onPrepared", "()V");
(*mEnv)->CallStaticVoidMethod(mEnv, cls, midOnPrepared);
(*mEnv)->DeleteLocalRef(mEnv, cls);
}
any thing error about JNI_Onload ? what is the best practice of tell something to java code?
JNIEnv *Android_JNI_GetEnv(void) {
/* From http://developer.android.com/guide/practices/jni.html
* All threads are Linux threads, scheduled by the kernel.
* They're usually started from managed code (using Thread.start), but they can also be created elsewhere and then
* attached to the JavaVM. For example, a thread started with pthread_create can be attached with the
* JNI AttachCurrentThread or AttachCurrentThreadAsDaemon functions. Until a thread is attached, it has no JNIEnv,
* and cannot make JNI calls.
* Attaching a natively-created thread causes a java.lang.Thread object to be constructed and added to the "main"
* ThreadGroup, making it visible to the debugger. Calling AttachCurrentThread on an already-attached thread
* is a no-op.
* Note: You can call this function any number of times for the same thread, there's no harm in it
*/
JNIEnv *env;
int status = (*mJavaVM)->AttachCurrentThread(mJavaVM, &env, NULL);
if (status < 0) {
LOGE("failed to attach current thread");
return 0;
}
/* From http://developer.android.com/guide/practices/jni.html
* Threads attached through JNI must call DetachCurrentThread before they exit. If coding this directly is awkward,
* in Android 2.0 (Eclair) and higher you can use pthread_key_create to define a destructor function that will be
* called before the thread exits, and call DetachCurrentThread from there. (Use that key with pthread_setspecific
* to store the JNIEnv in thread-local-storage; that way it'll be passed into your destructor as the argument.)
* Note: The destructor is not called unless the stored value is != NULL
* Note: You can call this function any number of times for the same thread, there's no harm in it
* (except for some lost CPU cycles)
*/
pthread_setspecific(mThreadKey, (void *) env);
return env;
}