android - Android 一个 NDK 方法存在重入问题
问题描述
这是我的 NDK 方法:
void FrameReceived(int width, int height, const char *rawImageBytes, int size, jboolean remote)
{
//LOGE(".... **** ....FrameReceived Begin = %d", size);
if(size == 0)
return;
jboolean isAttached;
JNIEnv *env;
jint jParticipant;
jint jWidth;
jint jHeight;
jbyteArray jRawImageBytes;
env = getJniEnv(&isAttached);
if (env == NULL)
goto FAIL0;
//LOGE(".... **** ....TRYING TO FIND CALLBACK");
LOGI("FrameReceived will reach here 1");
char *modifiedRawImageBytes = malloc(size);
memcpy(modifiedRawImageBytes, rawImageBytes, size);
jint sizeWH = width * height;
jint quarter = sizeWH/4;
jint v0 = sizeWH + quarter;
for (int u = sizeWH, v = v0, o = sizeWH; u < v0; u++, v++, o += 2) {
modifiedRawImageBytes[o] = rawImageBytes[v]; // For NV21, V first
modifiedRawImageBytes[o + 1] = rawImageBytes[u]; // For NV21, U second
}
if(remote)
{
if(frameReceivedRemoteMethod == NULL)
frameReceivedRemoteMethod = getApplicationJniMethodId(env, applicationJniObj, "vidyoConferenceFrameReceivedRemoteCallback", "(III[B)V");
if (frameReceivedRemoteMethod == NULL) {
//LOGE(".... **** ....CALLBACK NOT FOUND");
goto FAIL1;
}
}
else
{
if(frameReceivedMethod == NULL)
frameReceivedMethod = getApplicationJniMethodId(env, applicationJniObj, "vidyoConferenceFrameReceivedCallback", "(III[B)V");
if (frameReceivedMethod == NULL) {
//LOGE(".... **** ....CALLBACK NOT FOUND");
goto FAIL1;
}
}
jWidth = width;
jHeight = height;
jRawImageBytes = (*env)->NewByteArray(env, size);
(*env)->SetByteArrayRegion(env, jRawImageBytes, 0, size, modifiedRawImageBytes);
//LOGE(".... **** ....CALLBACK BEING CALLED");
if(remote)
{
(*env)->CallVoidMethod(env, applicationJniObj, frameReceivedRemoteMethod, 0, jWidth, jHeight, jRawImageBytes);
}
else
{
(*env)->CallVoidMethod(env, applicationJniObj, frameReceivedMethod, 0, jWidth, jHeight, jRawImageBytes);
}
//LOGE(".... **** ....CALLBACK CALLED");
(*env)->DeleteLocalRef(env, jRawImageBytes);
free(modifiedRawImageBytes);
if (isAttached)
{
(*global_vm)->DetachCurrentThread(global_vm);
}
//LOGE("FrameReceived End");
return;
FAIL1:
if (isAttached)
{
(*global_vm)->DetachCurrentThread(global_vm);
}
FAIL0:
//LOGE("FrameReceived FAILED");
return;
}
根据 jboolean 远程调用这 2 个函数中的 1 个:
public void vidyoConferenceFrameReceivedCallback(final int participantId, final int width, final int height, final byte[] rawImageBytes) {
if (selfView == null || selfView.getVisibility() == View.GONE)
return;
try {
selfBitmap = Nv21Image.nv21ToBitmap(rs, rawImageBytes, width, height);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
selfView.setImageBitmap(selfBitmap);
}
});
} catch (Exception e) {
Logger.error("Error on vidyoConferenceFrameReceivedCallback: " + e.getMessage());
}
}
和这个:
public void vidyoConferenceFrameReceivedRemoteCallback(final int participantId, final int width, final int height, final byte[] rawImageBytes) {
if (remoteView == null || remoteView.getVisibility() == View.GONE)
return;
try {
remoteResolution = width + "x" + height;
remoteBitmap = Nv21Image.nv21ToBitmap(rs, rawImageBytes, width, height);
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
remoteView.setImageBitmap(remoteBitmap);
}
});
} catch (Exception e) {
Logger.error("Error on vidyoConferenceFrameReceivedRemoteCallback: " + e.getMessage());
}
}
如您所见,这两个函数看起来相同,只是图像视图和我保存数据的位图不同。但如果我分析我的应用程序。
第一种方法调用时,它的线程如下所示: https ://s3.amazonaws.com/uploads.hipchat.com/39260/829560/A3lm3QTz4gZN0VK/upload.png 它的平均时间是 4 秒,持续 15 秒分析。
但是第二种方法,远程方法,这样做: https ://s3.amazonaws.com/uploads.hipchat.com/39260/829560/wHp7NtKgKYTTEG7/upload.png 时间是 15 秒中的 15 秒。
在这里你可以清楚地看到,它以某种方式被冗余召回: https ://s3.amazonaws.com/uploads.hipchat.com/39260/829560/wCmS5CH21zbyMBr/upload.png
为什么会这样?
编辑:
我修改了远程功能来简单地做到这一点:
public void vidyoConferenceFrameReceivedRemoteCallback(final int participantId, final int width, final int height, final byte[] rawImageBytes) {
Log.i("", "vidyoConferenceFrameReceivedRemoteCallback RECEIVED FRAME ");
}
通过分析该线程,我得到了这个: https ://s3.amazonaws.com/uploads.hipchat.com/39260/829560/ZfylnBheyA6GjTe/upload.png
我认为 NDK 中的某些内容导致该函数以某种方式被多次调用
解决方案
推荐阅读
- c# - polling server after POST 201 CREATED c#
- scala - Future and Option in for comprehension in slick
- python - 重新分配在 __init__ 函数中声明的类实例属性的正确方法是什么?
- javascript - 如何在 Typescript 中更新数组列表的对象?
- assembly - 使用 ASCII 值作为名称的 MIPS 汇编语言代码
- ruby-on-rails - Cryptic Error when using firebase in rails
- python - pip 安装失败:cl.exe 失败,退出状态为 2
- php - 我应该将访问密钥放在 AWS SDK for PHP 中的什么位置?
- reactjs - Meteor React tutorial interacting with mongo not working
- c++ - Passing std::vector of std::shared_ptr, not updating the objects