Ответ 1
"встроенная функция JNI для Android" - это вид оксюморона. Это технически правильно, что многие классы Java Framework Java используют JNI где-то в цепочке, чтобы вызвать родные библиотеки.
Но есть три оговорки относительно этого утверждения.
-
Это "детали реализации" и могут быть изменены без уведомления в любой следующей версии Android или любой вилки (например, Kindle) или даже версии OEM, которая не считается "fork" (например, построено компанией Samsung или для Quallcom SOC).
-
Способ, которым встроенные методы реализуются в основных классах Java, отличается от "классического" JNI. Эти методы предварительно загружаются и кэшируются JVM и поэтому не страдают от большей части служебных данных, типичных для вызовов JNI.
-
Нет ничего, что может сделать ваш Java или собственный код для непосредственного взаимодействия с методами JNI других классов, особенно с классами, которые составляют системную инфраструктуру.
Все это говорит о том, что вы можете изучить исходный код Android, чтобы найти родные библиотеки, которые возвращают определенные классы и методы ( например, распознавание лиц) и использовать эти библиотеки в своем собственном коде или создать собственный JNI-слой, чтобы использовать эти библиотеки из вашего кода Java.
Чтобы дать конкретный пример, обнаружение лица в Android реализовано с помощью класса android.media.FaceDetector, который загружает libFFTEm.so
. Вы можете посмотреть собственный код и использовать его по своему усмотрению. Вы не должны предполагать, что libFFTEm.so
будет присутствовать на устройстве или что библиотека на устройстве будет иметь тот же API.
Но в этом конкретном случае это не проблема, потому что вся работа neven
полностью основана на программном обеспечении. Поэтому вы можете скопировать этот код целиком или только соответствующие его части и сделать его частью вашей родной библиотеки. Обратите внимание, что для многих устройств вы можете просто загружать и использовать /system/lib/libFFTEm.so
и никогда не чувствовать дискомфорта, пока не столкнетесь с системой, которая будет плохо себя вести.
Один замечательный вывод, который вы можете сделать, прочитав собственный код, заключается в том, что основные алгоритмы игнорируют информацию о цвете. Поэтому, если изображение, для которого вы хотите найти координаты лица, поступает из источника YUV, вы можете избежать множества накладных расходов, если вы вызываете
// run detection
btk_DCR_assignGrayByteImage(hdcr, bwbuffer, width, height);
int numberOfFaces = 0;
if (btk_FaceFinder_putDCR(hfd, hdcr) == btk_STATUS_OK) {
numberOfFaces = btk_FaceFinder_faces(hfd);
} else {
ALOGE("ERROR: Return 0 faces because error exists in btk_FaceFinder_putDCR.\n");
}
непосредственно с вашим массивом байтов YUV (или Y) вместо преобразования его в RGB и обратно в YUV в android.media.FaceDetector.findFaces(). Если ваш буфер YUV поступает из Java, вы можете создать собственный класс YuvFaceDetector
, который будет копией android.media.FaceDetector с помощью только разница, что YuvFaceDetector.findFaces()
будет принимать значения Y (яркости) только вместо растрового изображения и избегать преобразования RGB в Y.
Некоторые другие ситуации не так просты. Например, видеокодеки тесно связаны с аппаратной платформой, и вы не можете просто скопировать код из libstagefright.so в свой проект. Jpeg-кодек - специальный зверь. В современных системах (IIRC, начиная с версии 2.2) вы можете ожидать, что /system/lib/libjpeg.so
будет присутствовать. Но многие платформы также имеют намного более эффективные HW-реализации Jpeg-кодеков через libstagefright.so
или OpenMAX, и часто они используются в android.graphics.Bitmap.compress( ) и android.graphics.BitmapFactory.decode ***() методы.
И также есть оптимизированный libjpeg-turbo, который имеет свои преимущества перед /system/lib/libjpeg.so
.