Я хочу использовать изображения, полученные из повторяющегося запроса, в методе с использованием JNI. Изображения имеют максимальный выходной размер.
Метод Image.Plane
getBuffer
гласит:
Получить прямой ByteBuffer, содержащий данные кадра.
В частности, возвращаемый буфер всегда будет возвращать значение isDirect true, поэтому базовые данные могут быть отображены как указатель в JNI без каких-либо копий с помощью GetDirectBufferAddress.
Замечательно, копирование не требуется !! Мне нужна только яркость изображения YUV, поэтому я выбрал метод испытания.
Java сторона:
...
// within a method
test(image.getPlanes()[0].getBuffer(), imWidth, imHeight, image.getPlanes()[0].getPixelStride(), mOutputImage);
...
private native boolean test(ByteBuffer inputBuffer, int width, int height, int stride, byte[] outputBytes);
static {
try {
System.loadLibrary("native-lib");
} catch (final UnsatisfiedLinkError e) {
//Log.e(TAG, "loadLibrary" + Log.getStackTraceString(e));
}
}
Сторона JNI:
JNIEXPORT jboolean JNICALL Java_com_my_package_test(JNIEnv* env, jclass thiz, jobject byteBuffer, jint width, jint height, jint stride, jbyteArray output) {
// Get the pointers to the arrays and deal with potential errors
jbyte * cInput = (jbyte*)env->GetDirectBufferAddress(byteBuffer);
if (cInput == NULL) {
LOGE("Failed to obtain the provided byte arrays");
return JNI_FALSE;
}
jbyte * cOutput = env->GetByteArrayElements(output, NULL);
if (cOutput == NULL) {
LOGE("Failed to obtain the provided byte arrays");
return JNI_FALSE;
}
int yTimesW, yTimesS;
jbyte val1, val2;
for (y = 0; y < height; y++) {
yTimesW = y * stride;
yTimesS = y * width;
for (x = 0; x < width; x++) {
val1 = cInput[yTimesS + x];
// Something is done with val1 before populating the output...
val2 = val1;
cOutput[yTimesW + X] = val2;
}
}
// Release the pointer
env->ReleaseByteArrayElements(output, cOutput, 0);
return JNI_TRUE;
}
У меня была Java-версия моего метода, в которой использовался метод ByteBuffer.get(byte[] dst)
(который копирует память), поэтому я предполагал, что версия JNI будет быстрее, но я был шокирован, обнаружив, что на моем Samsung Galaxy S8, это было на самом деле в пять раз медленнее ...
Короче говоря, я написал много разных версий метода JNI и несколько раз ударил головой об стену, прежде чем обнаружил, что на S9 результаты были такими, как я ожидал. Я обнаружил, что трудоемкой частью моего кода был доступ к памяти (cInput[yTimesS + x]
), на S8 это занимает много времени, тогда как на S9 это очень быстро.
Итак, мои вопросы:
- Я что-то упустил и что-то не так делаю?
- Может ли это быть из-за проблемы с выделением памяти на S8? (стек против кучи и т. д.)
- Если проблема действительно исходит от S8, есть ли способ ее исправить (взломать или что-то)?
- Если это происходит на S8, то это может также произойти и на других телефонах, поэтому кто-нибудь уже испытывал это на других телефонах и, возможно, самое главное, кто-нибудь знает, как это обнаружить, не тестируя каждый телефон на рынке?