簡體   English   中英

如何從 JNI 中的線程內部調用 JAVA 方法

[英]How To Call JAVA Methods from inside of a Thread in JNI

TL;博士; 我在將我的 FFMPEG 原始數據從 C++ 代碼傳遞到 JAVA 代碼以通過線程顯示時遇到問題。

有一個服務器設置向其客戶端發送編碼幀。 這些編碼幀是用一些 FFMPEG 魔法編碼的。 在客戶端收到時,上述幀將被解碼為原始 RGB 數據(作為無符號字符 *)。 現在的問題是幀是在某種“偵聽器”中接收的。 只是一個在后台運行的線程輪詢服務器並在新幀可用時運行特定的onFrame function。

當前以視頻格式顯示幀的解決方案是將每個幀保存到 C++ 的內部存儲中,然后在 java 端有一個FileObserver ,一旦它寫入 ZCD69B4957F06CD8198D7 就顯示圖像可悲的是,這種方法在手機上產生了 6 FPS 的視頻,而來自服務器的視頻則為 10 FPS。

我需要一種將 unsigned char * (jbytearray) 傳遞給我的 JAVA 代碼的方法,這樣我就可以對其進行解碼並從 RAM 而不是磁盤顯示它。

值得一提的是, onFrame function 的 arguments 列表中不能有JNIEnv* && jobject (庫要求)。

到目前為止,我嘗試的是在我的MainActivity中創建一個本機方法,通過該方法我傳遞JNIEnvjobject並將它們分配給全局變量

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

在嘗試了邁克爾解決方案中的代碼后,我得到了
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.緩存本地引用
您作為本機 function 的第二個參數收到的thiz引用是本地引用,調用 JNI 函數返回的大多數jobject也是本地引用。
本地引用只能“從它最初交給的線程中使用,並且在顯式調用 DeleteLocalRef() 或更常見的情況下,直到您從本機方法返回之前有效”

如果你想從另一個線程使用 object,你需要從本地引用創建一個全局引用:

m_globalObject = NewGlobalRef(thiz);

當您不再需要在本機代碼中的任何位置使用 object 時,請記住刪除全局引用 ( DeleteGlobalRef(m_globalObject) )。 否則可能會導致 memory 泄漏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM