Ответ 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
ofCameraService
. - Он передает данные в метод
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 скрыт. См., Например, этот вопрос, чтобы использовать его.