长话短说;我在通过线程将我的 FFMPEG 原始数据从 C++ 代码传递到 JAVA 代码以进行显示时遇到问题。
有一个服务器设置发送编码帧到它的客户端。这些编码帧是用一些 FFMPEG 魔法编码的。当在客户端接收时,上述帧被解码为原始 RGB 数据(作为 unsigned char *)。现在的问题是帧正在以某种“监听器”的形式接收。只是在后台运行的线程轮询服务器并在新帧可用时运行特定的 onFrame
函数。
当前以视频格式显示帧的解决方案是在 C++ 中将每个帧保存到内部存储器,然后在 java 端有一个 FileObserver
,它在写入图像后立即显示图像在内存中。遗憾的是,对于来自服务器的 10 FPS 视频,该方法在手机上产生 6 FPS 视频。
我需要一种将 unsigned char * (jbytearray) 传递到我的 JAVA 代码的方法,这样我就可以解码它并从 RAM 而不是磁盘显示它。
值得一提的是,onFrame
函数的参数列表中不能包含 JNIEnv*
&& jobject
(库要求)。
到目前为止我尝试的是在我的 MainActivity
中创建一个本地方法,我通过它传递 JNIEnv
和 jobject
并将它们分配给全局变量
JNIEnv* m_globalEnv = env;
jobject m_globalObject = thiz;
JavaVM m_jvm = 0;
jclass mainActivity = m_globalEnv->GetObjectClass(m_globalObject);
jmethodID testMethod = m_globalEnv->GetMethodID(mainClass, "testMethod", "(I)V");
m_globalEnv->GetJavaVM(&m_jvm);
之后,在我的 onFrame
中调用
jvm->AttachCurrentThread(&m_globalEnv, NULL);
然后我尝试从代码中的某处调用 JAVA 方法(这与我在 onFrame
中调用它的位置/时间无关)通过执行以下操作:
m_globalEnv->CallVoidMethod(m_globalObject, "testMethod", 5);
然后所有崩溃都发生在:
1- JNI DETECTED ERROR IN APPLICATION: use of invalid jobject 0xffe8ea7c
2- JNI DETECTED ERROR IN APPLICATION: Thread is making JNI calls without being attached
.
.
.
编辑 1
在尝试了 Michael 解决方案中的代码后,我得到了
java_vm_ext.cc:542] JNI 检测到应用程序错误:使用无效的 jobject 0xc94f7f8c
错误。
在 Debug模式下运行应用程序以捕获错误后,我到达了 jni.h
;触发错误的代码行是:
m_env->CallVoidMethod(m_globalObject, testMethod, 5);
(5 是我为测试目的而尝试传递的数字)。
调试器突出显示的 jni.h 中的代码行位于
void CallVoidMethod(jobject obj, jmethodID methodID, ...)
这是
函数->CallVoidMethodV(this, obj, methodID, args);
在第 228 行定义:
void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
最佳答案
我发现代码有两个潜在问题:
<强>1。跨线程共享JNIEnv*
每个 native 线程都应该通过将自身附加到 JVM 来获得自己的 JNIEnv*
,然后在某个时候分离自身。参见 this answer了解更多详情和可能的解决方案。
<强>2。缓存本地引用
作为 native 函数的第二个参数收到的 thiz
引用是本地引用,调用 JNI 函数返回的大多数 jobject
也是如此。
本地引用只能“从它最初传递给的线程中使用,并且在显式调用 DeleteLocalRef() 之前有效,或者更常见的是,直到您从本地方法返回之前”。< br/>
如果您想从另一个线程使用该对象,您需要从本地引用创建一个全局引用:
m_globalObject = NewGlobalRef(thiz);
当您不再需要在 native 代码中的任何位置使用该对象时,请记住删除全局引用 (DeleteGlobalRef(m_globalObject)
)。否则可能会导致内存泄漏。
关于java - 如何从 JNI 中的线程内部调用 JAVA 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58875780/