TL;DR;我在通过线程将我的FFMPEG原始数据从C++代码传递到JAVA代码以进行显示时遇到了问题。
设置了一个服务器,用于向客户端发送编码帧。这些编码帧是用一些FFMPEG魔术进行编码的。当在客户端接收时,前面提到的帧被解码为原始RGB数据(作为无符号字符*(。现在的问题是,帧是在一个"信道"中被接收的;听众";在某种程度上。只是一个在后台运行的线程轮询服务器,并在新帧可用时运行特定的onFrame
函数。
当前以视频格式显示帧的解决方案是将每一帧保存到C++中的内部存储中,然后在java端有一个FileObserver
,它可以在图像写入内存后立即显示图像。遗憾的是,这种方法在手机上产生了6 FPS的视频,而在服务器上产生了10 FPS的视频。
我需要一种方法将未签名的char*(jbytearray(传递到我的JAVA代码中,这样我就可以解码它并从RAM而不是磁盘中显示它。
值得一提的是,CCD_ 3函数不能有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 DETECTED ERROR IN APPLICATION: use of invalid jobject 0xc94f7f8c
错误。在调试模式下运行应用程序以捕捉错误后,我到达了jni.h
;触发错误的代码行是:m_env->CallVoidMethod(m_globalObject, testMethod, 5);
(5是我为了测试而试图通过的数字(。调试器高亮显示的jni.h中的代码行位于void CallVoidMethod(jobject obj, jmethodID methodID, ...)
中functions->CallVoidMethodV(this, obj, methodID, args);
,在第228行定义:void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);
我发现代码存在两个潜在问题:
1.跨线程共享JNIEnv*
每个本机线程都应该通过将自己连接到JVM,然后在某个时刻分离自己来获得自己的JNIEnv*
。有关更多详细信息和可能的解决方案,请参阅此答案。
2.缓存本地引用
作为本机函数的第二个参数接收的thiz
引用是本地引用,调用JNI函数返回的大多数jobject
也是本地引用
本地引用只能从最初交给它的线程"em>"中使用,并且在显式调用DeleteLocalRef((之前有效,或者更常见的情况是,在您从本机方法"返回之前有效
如果你想从另一个线程使用该对象,你需要从本地引用创建一个全局引用:
m_globalObject = NewGlobalRef(thiz);
当您不再需要在本机代码中的任何位置使用该对象时,请记住删除全局引用(DeleteGlobalRef(m_globalObject)
(。否则可能会导致内存泄漏。