java — JNI передает различные значения аргументов функции из того, что фактически было задано

У меня есть встроенная функция c ++, которая действует на объект cv :: Mat (opencv), передаваемый из Java через JNI (OpenCV4Android).

Это мое объявление функции:

extern "C" jboolean Java_com_test_JNIActivity_track(JNIEnv *env, jobject obj, jlong inMatGr, jlong inMatRgba, jint currFrame);

и это код, к которому я обращаюсь и печатаю переданные аргументы:

extern "C" jboolean Java_com_test_JNIActivity_track(JNIEnv *env, jobject obj, jlong inMatGr, jlong inMatRgba, jint currFrame)
{
ALOG("Native: Rgba@%.8x, Gray@%.8x", inMatRgba, inMatGr);

cv::Mat& captured_image = *(cv::Mat *)inMatRgba;
cv::Mat_<uchar>& grayscale_image = *(cv::Mat_<uchar> *)inMatGr;
...
}

Часть объявления Java установлена ​​следующим образом:

private native boolean track(long grayAddr, long rgbaAddr, int currFrameNum);

и это реализация метода OnCameraFrame ():

public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba();
mGray = inputFrame.gray();
Log.d(TAG_LOG, "Java: Rgba@0x" + Long.toString(mRgba.getNativeObjAddr(),16) +
", Gray@0x" + Long.toString(mGray.getNativeObjAddr(),16));
track(mGray.getNativeObjAddr(), mRgba.getNativeObjAddr(), currFrameNum++);
//Log.d(TAG_LOG, "Java: Frame(" + currFrameNum + ')');
return inputFrame.rgba();
}

Тем не менее, я получаю разные значения (когда внутри нативной функции) для двух аргументов из того, что я установил в части Java (Mat.getNatvieObjAddr ()).

Это значения в обеих сторонах интерфейса JNI:

In Java: 1st argument = 0x405ab288, 2nd argument = 0x557ab9d8
In Native: 1st argument = 0x00000000, 2nd argument = 0x405ab288

Последний аргумент является jint и дает правильное значение, может ли эта проблема быть связана с jlong, имеющим разные размеры на разных архитектурах (код запускается на процессоре armv7a).

Я ценю любую помощь. Благодарю.

0

Решение

Я понял это сам и делюсь тем, кто в моей ситуации.

private native boolean track(long grayAddr, long rgbaAddr, int currFrameNum);

Длинный тип Java имеет размер 8 байт, так же как и jlong ​​(typedef как _int64_t на c ++ или long long на C, проверьте jni.h).

cv::Mat& captured_image = *(cv::Mat *)inMatRgba;

inMatRgba это указатель на резюме :: Mat объект. На 64-битных машинах указатель составляет 8 байт (так же, как jlong), поэтому он должен работать хорошо; однако на 32-битных машинах указатель составляет 4 байта, и только младшие 4 байта inMatRgba считаются адресом объекта cv :: Mat. Это проблема, если 32-битный компьютер имеет старший порядок байтов (младшие 4 байта содержат значение 0 в этом случае).

Решение:

Я должен был определить различные назначения для каждого случая:

int *ptrRgba = NULL;
int *ptrGr = NULL;

if (4 == sizeof(int *) && is_big_endian()) {
ptrRgba = (int *)&inMatRgba;
ptrGr = (int *)&inMatGr;
}

cv::Mat& captured_image = ptrRgba ? *(cv::Mat *)(*(ptrRgba+1)) : *(cv::Mat *)inMatRgba;
cv::Mat_<uchar>& grayscale_image = ptrGr ? *(cv::Mat_<uchar> *)(*(ptrGr+1)) : *(cv::Mat_<uchar> *)inMatGr;
1

Другие решения

Других решений пока нет …