Подтвердить что ты не робот

Как получить необработанный буфер камеры Android в C с помощью JNI?

Я искал Google и StackOverflow исчерпывающе и не могу найти это. Может быть, мне не хватает чего-то очевидного. Спасибо!

(Это связано с тем, что реализация Java в режиме предварительного просмотра [даже с буфером] слишком неэффективна.)

4b9b3361

Ответ 1

Я провел небольшое исследование по теме. Это презентация (от стр .277, китайский) очень помогло.

Цепочка вызова предварительного просмотра камеры

Как уже упоминалось, вы можете получить буфер с помощью метода Camera.setPreviewCallback.
Вот как это происходит (подробная версия):

  • Пользователь вызывает Camera.startPreview(), который является нативной функцией.
  • android_hardware_Camera_startPreview вызывает метод startPreview класса С++ Camera.
  • Camera вызывает метод startPreview интерфейса ICamera
  • ICamera вызывает вызов IPC для удаленного клиента.
  • Он вызывает метод setCameraMode класса CameraService.
  • CameraService устанавливает окно для отображения предварительного просмотра и вызывает метод startPreview класса CameraHardwareInterface.
  • Последний пытается вызвать метод start_preview на конкретном устройстве camera_device_t. Я больше не искал, но он должен выполнить вызов драйвера.
  • При поступлении изображения вызывается dataCallback of CameraService.
  • Он передает данные в метод handlePreviewData клиента.
  • Клиент либо копирует буфер, либо отправляет его непосредственно в ICameraClient.
  • ICameraClient отправляет его через IPC в Camera.
  • Camera вызывает зарегистрированный прослушиватель и передает буфер на JNI.
  • Он вызывает обратный вызов в классе Java. Если пользователь предоставил буфер с Camera.addCallbackBuffer, он сначала копирует его в буфер.
  • Наконец, класс Java Camera обрабатывает сообщение и вызывает метод onPreviewFrame Camera.PreviewCallback.

Как вы можете видеть, вызовы 2 IPC были вызваны, и буфер был скопирован по меньшей мере дважды на шагах 10, 11. Первый экземпляр необработанного буфера, который возвращается camera_device_t, размещен в другом процессе, и вы не можете получить доступ к нему из-за для проверок безопасности в CameraService.

поверхность предварительного просмотра

Однако, когда вы устанавливаете поверхность предварительного просмотра, используя либо Camera.setPreviewTexture, либо Camera.setPreviewDisplay, он передается непосредственно на устройство камеры и обновляется в реальном времени без участия всей вышеперечисленной цепи. Как говорится в документации:

Обработайте необработанный буфер, который управляется компоновщиком экрана.

Java class Surface имеет способ извлечения содержимого:

public static native Bitmap screenshot(int width, int height, int minLayer, int maxLayer);

Но этот API скрыт. См., Например, этот вопрос, чтобы использовать его.

Ответ 2

Нет никакого общедоступного API, чтобы делать то, что вы хотите; единственным официальным (то есть гарантированным для работы) методом является обратный вызов предварительного просмотра на уровне Java, настроенный посредством вызова Camera.setPreviewCallback(). В Android > 3.0 вы также можете использовать Camera.setPreviewTexture() для маршрутизации данных предварительного просмотра на графический процессор и обрабатывать его там, используя GLES (или считывать его обратно в CPU). Путь GPU - это то, что использует приложение камеры ICS AOSP для своих видеоэффектов.

Предположительно, OpenCV и другие просмотрели собственный код платформы Android и обошли API Java Camera API, напрямую связавшись с услугами ниже.

Это довольно опасно, потому что нет абсолютно никакой гарантии, что эти интерфейсы не изменятся между версиями Android, поскольку они не являются частью публичного API. Теперь их использование может быть прекрасным, а затем, когда пользователь обновит свое устройство, ваше приложение перестанет работать.