Расширения камеры

Производители устройств могут предоставлять сторонним разработчикам такие расширения, как боке, ночной режим и HDR, через интерфейс Camera Extensions, предоставляемый библиотекой OEM-поставщика. Разработчики могут использовать API Camera2 Extensions и API CameraX Extensions для доступа к расширениям, реализованным в библиотеке OEM-поставщика.

Список поддерживаемых расширений, одинаковый для Camera2 и CameraX, можно найти на странице CameraX Extensions API . Если вы хотите добавить расширение, сообщите об ошибке в Issue Tracker .

На этой странице описывается, как реализовать и включить библиотеку поставщика OEM на устройствах.

Архитектура

На следующей диаграмме описана архитектура интерфейса расширений камеры или extensions-interface : Архитектура

Рисунок 1. Архитектурная схема расширений камеры

Как показано на схеме, для поддержки расширений камеры необходимо реализовать extensions-interface , предоставляемый библиотекой поставщика OEM. Библиотека поставщика OEM поддерживает два API: CameraX Extensions API и Camera2 Extensions API , которые используются приложениями CameraX и Camera2 соответственно для доступа к расширениям поставщика.

Реализовать библиотеку поставщиков OEM

Для реализации библиотеки OEM-поставщика скопируйте файлы camera-extensions-stub в проект системной библиотеки. Эти файлы определяют интерфейс Camera Extensions.

Файлы camera-extensions-stub делятся на следующие категории:

Необходимые файлы интерфейса (не изменять)

  • PreviewExtenderImpl.java
  • ImageCaptureExtenderImpl.java
  • ExtenderStateListener.java
  • ProcessorImpl.java
  • PreviewImageProcessorImpl.java
  • CaptureProcessorImpl.java
  • CaptureStageImpl.java
  • RequestUpdateProcessorImpl.java
  • ProcessResultImpl.java
  • advanced/AdvancedExtenderImpl.java
  • advanced/Camera2OutputConfigImpl.java
  • advanced/Camera2SessionConfigImpl.java
  • advanced/ImageProcessorImpl.java
  • advanced/ImageReaderOutputConfigImpl.java
  • advanced/ImageReferenceImpl.java
  • advanced/MultiResolutionImageReaderOutputConfigImpl.java
  • advanced/OutputSurfaceImpl.java
  • advanced/RequestProcessorImpl.java
  • advanced/SessionProcessorImpl.java
  • advanced/SurfaceOutputConfigImpl.java

Обязательные реализации (добавьте свою реализацию)

  • ExtensionVersionImpl.java
  • InitializerImpl.java

Классы-расширители Bokeh (реализуйте их, если расширение Bokeh поддерживается)

  • BokehImageCaptureExtenderImpl.java
  • BokehPreviewExtenderImpl.java
  • advanced/BokehAdvancedExtenderImpl.java

Классы расширения Night (реализуйте их, если поддерживается расширение Night)

  • NightImageCaptureExtenderImpl.java
  • NightPreviewExtenderImpl.java
  • advanced/NightAdvancedExtenderImpl.java

Классы автоматического расширения (реализуйте их, если поддерживается автоматическое расширение)

  • AutoImageCaptureExtenderImpl.java
  • AutoPreviewExtenderImpl.java
  • advanced/AutoAdvancedExtenderImpl.java

Классы расширения HDR (реализуйте их, если поддерживается расширение HDR)

  • HdrImageCaptureExtenderImpl.java
  • HdrPreviewExtenderImpl.java
  • advanced/HdrAdvancedExtenderImpl.java

Классы расширителя Face Retouch (реализуйте его, если расширение Face Retouch поддерживается)

  • BeautyImageCaptureExtenderImpl.java
  • BeautyPreviewExtenderImpl.java
  • advanced/BeautyAdvancedExtenderImpl.java

Утилиты (необязательно, могут быть удалены)

  • advanced/Camera2OutputConfigImplBuilder.java
  • advanced/Camera2SessionConfigImplBuilder.java

Вам не обязательно предоставлять реализацию для каждого расширения. Если вы не реализуете расширение, установите для isExtensionAvailable() значение false или удалите соответствующие классы Extender. API расширений Camera2 и CameraX сообщают приложению, что расширение недоступно.

Давайте рассмотрим, как API расширений Camera2 и CameraX взаимодействуют с библиотекой поставщика для включения расширения. На следующей диаграмме показан весь процесс на примере расширения Night:

Основной поток

Рисунок 2. Реализация ночного расширения

  1. Проверка версии:

    Camera2/X вызывает ExtensionVersionImpl.checkApiVersion() , чтобы убедиться, что версия extensions-interface реализованная OEM, совместима с поддерживаемыми версиями Camera2/X.

  2. Инициализация библиотеки поставщика:

    У InitializerImpl есть метод init() , который инициализирует библиотеку поставщика. Camera2/X завершает инициализацию перед доступом к классам Extender.

  3. Классы Instantiate Extender:

    Создаёт экземпляры классов Extender для расширения. Существует два типа Extender: Basic Extender и Advanced Extender. Для всех расширений необходимо реализовать один тип Extender. Подробнее см. в разделе Сравнение Basic Extender и Advanced Extender .

    Camera2/X создаёт экземпляры классов Extender и взаимодействует с ними для получения информации и включения расширения. Для одного расширения Camera2/X может создавать экземпляры классов Extender несколько раз. Поэтому не следует выполнять сложную инициализацию в конструкторе или вызове init() . Выполняйте сложную работу только перед началом сеанса камеры, например, при вызове onInit() в базовом Extender или initSession() в расширенном Extender.

    Для расширения Night создаются следующие классы Extender для типа Basic Extender:

    • NightImageCaptureExtenderImpl.java
    • NightPreviewExtenderImpl.java

    А для типа Advanced Extender:

    • NightAdvancedExtenderImpl.java
  4. Проверить наличие расширения:

    Перед включением расширения isExtensionAvailable() проверяет, доступно ли расширение для указанного идентификатора камеры через экземпляр Extender.

  5. Инициализируйте Extender с информацией о камере:

    Camera2/X вызывает init() для экземпляра Extender и передает ему идентификатор камеры и CameraCharacteristics .

  6. Запрос информации:

    Вызывает класс Extender для извлечения такой информации, как поддерживаемые разрешения, по-прежнему фиксирует предполагаемую задержку и захватывает ключи запроса от Extender для подготовки к включению расширения.

  7. Включить расширение на Extender:

    Класс Extender предоставляет все интерфейсы, необходимые для работы класса. Он предоставляет механизм для подключения OEM-реализации к конвейеру Camera2, например, для внедрения параметров запроса захвата или включения постпроцессора.

    Для типа Advanced Extender Camera2/X взаимодействует с SessionProcessorImpl для включения расширения. Camera2/X извлекает экземпляр SessionProcessorImpl , вызывая createSessionProcessor() в Extender.

В следующих разделах поток расширения описывается более подробно.

Проверка версии

При загрузке библиотеки OEM-поставщика с устройства во время выполнения Camera2/X проверяет совместимость библиотеки с версией extensions-interface . extensions-interface использует семантическое версионирование, или MAJOR.MINOR.PATCH, например, 1.1.0 или 1.2.0. Однако при проверке версий используются только основная и дополнительная версии.

Для проверки версии Camera2/X вызывает ExtensionVersionImpl.checkApiVersion() с поддерживаемой версией extensions-interface . Затем Camera2/X использует версию, предоставленную OEM-библиотекой, чтобы определить, можно ли включить расширение и какие возможности оно должно использовать.

Совместимость с основными версиями

Если основные версии интерфейса расширения Camera2/X и библиотеки поставщика различаются, то они считаются несовместимыми и расширение отключается.

Обратная совместимость

При условии идентичности основной версии Camera2/X обеспечивает обратную совместимость с библиотеками OEM-поставщиков, созданными с использованием предыдущих версий extensions-interface . Например, если Camera2/X поддерживает extensions-interface 1.3.0, библиотеки OEM-поставщиков, реализовавшие версии 1.0.0, 1.1.0 и 1.2.0, по-прежнему совместимы. Это также означает, что после реализации определённой версии библиотеки поставщика Camera2/X обеспечивает обратную совместимость библиотеки с будущими версиями extension-interface .

Совместимость с предыдущими версиями

Прямая совместимость с библиотеками новых extensions-interface других производителей зависит от вас, производителя оборудования. Если вам требуются некоторые функции для реализации расширений, вы можете включить расширения, начиная с определённой версии. В этом случае вы можете вернуть поддерживаемую версию extensions-interface если версия библиотеки Camera2/X соответствует требованиям. Если версии Camera2/X не поддерживаются, вы можете вернуть несовместимую версию, например, 99.0.0, чтобы отключить расширения.

Инициализация библиотеки поставщика

После проверки версии extensions-interface реализованного OEM-библиотекой, Camera2/X запускает процесс инициализации. Метод InitializerImpl.init() сигнализирует OEM-библиотеке о том, что приложение пытается использовать расширения.

Camera2/X не выполняет никаких других вызовов в библиотеку OEM (кроме проверки версии) до тех пор, пока библиотека поставщика OEM не вызовет OnExtensionsInitializedCallback.onSuccess() для уведомления о завершении инициализации.

Необходимо реализовать InitializerImpl , начиная с extensions-interface 1.1.0. Camera2/X пропускает этап инициализации библиотеки, если библиотека поставщика OEM реализует extensions-interface 1.0.0.

Базовый расширитель против расширенного расширителя

Существует два типа реализации extensions-interface : базовый расширитель и расширенный расширитель. Расширенный расширитель поддерживается начиная с extensions-interface 1.2.0.

Реализуйте Basic Extender для расширений, которые обрабатывают изображения в HAL камеры или используют постпроцессор, способный обрабатывать потоки YUV.

Реализуйте расширенный расширитель для расширений, которым необходимо настраивать конфигурацию потока Camera2 и отправлять запросы на захват по мере необходимости.

Для сравнения смотрите следующую таблицу:

Базовый расширитель Расширенный расширитель
Конфигурации потока Зафиксированный
Предварительный просмотр: PRIVATE или YUV_420_888 (если есть процессор)
Фотоснимок: JPEG или YUV_420_888 (при наличии процессора)
Возможность настройки OEM-производителем.
Отправка запроса на захват Только камера Camera2/X может отправлять запросы на захват изображения. Вы можете задать параметры этих запросов. Если процессор предназначен для захвата изображений, камера Camera2/X может отправлять несколько запросов на захват изображения и передавать все изображения и результаты захвата процессору. Экземпляр RequestProcessorImpl предоставляется вам для выполнения запроса на захват камеры2 и получения результатов и изображения.

Camera2/X вызывает startRepeating и startCapture на SessionProcessorImpl , чтобы подать OEM-сигнал о необходимости начать повторяющийся запрос на предварительный просмотр и начать последовательность снимков соответственно.

Крючки в трубопроводе камеры
  • onPresetSession предоставляет параметры сеанса.
  • onEnableSession отправляет один запрос сразу после настройки CameraCaptureSession .
  • onDisableSession отправляет один запрос перед закрытием CameraCaptureSession .
  • initSession инициализирует и возвращает настроенную конфигурацию сеанса camera2 для создания сеанса захвата.
  • onCaptureSessionStart вызывается сразу после настройки CameraCaptureSession .
  • onCaptureSessionEnd вызывается перед закрытием CameraCaptureSession .
Подходит для Расширения, реализованные в HAL камеры или в процессоре, обрабатывающем изображения YUV.
  • Имеет реализации расширений на базе Camera2.
  • Требуется индивидуальная конфигурация потока, например поток RAW.
  • Требуется интерактивная последовательность захвата.
Поддерживаемая версия API Расширения Camera2: Android 13 или выше
Расширения CameraX: camera-extensions 1.1.0 или выше
Расширения Camera2: Android 12L или выше
Расширения CameraX: camera-extensions 1.2.0-alpha03 или выше

Потоки приложений

В следующей таблице показаны три типа потоков приложения и соответствующие им вызовы API расширений камеры. Хотя Camera2/X предоставляет эти API, для поддержки этих потоков необходимо правильно реализовать библиотеку поставщика, что будет подробно описано в следующем разделе.

Расширения Camera2 Расширения CameraX
Доступность расширения запроса CameraExtensionCharacteristics . getSupportedExtensions ExtensionsManager. isExtensionAvailable
Запрос информации CameraExtensionCharacteristics. getExtensionSupportedSizes CameraExtensionCharacteristics. getEstimatedCaptureLatencyRangeMillis CameraExtensionCharacteristics. getAvailableCaptureRequestKeys CameraExtensionCharacteristics. getAvailableCaptureResultKeys ExtensionsManager. getEstimatedCaptureLatencyRange

CameraX обрабатывает остальную информацию в библиотеке.

Предварительный просмотр и снимок экрана с включенным расширением CameraDevice. createExtensionSession

cameraExtensionsSession. setRepeatingRequest

cameraExtensionsSession. capture

val cameraSelector = ExtensionsManager. getExtensionEnabledCameraSelector bindToLifecycle(lifecycleOwner, cameraSelector, preview, ...)

Базовый расширитель

Интерфейс Basic Extender обеспечивает связь с несколькими точками конвейера камеры. Для каждого типа расширения существуют соответствующие классы Extender, которые OEM-производителям необходимо реализовать.

В следующей таблице перечислены классы расширителей, которые OEM-производителям необходимо реализовать для каждого расширения:

Классы-расширители для реализации
Ночь NightPreviewExtenderImpl.java

NightImageCaptureExtenderImpl.java

HDR HdrPreviewExtenderImpl.java HdrImageCaptureExtenderImpl.java
Авто AutoPreviewExtenderImpl.java AutoImageCaptureExtenderImpl.java
Боке BokehPreviewExtenderImpl.java BokehImageCaptureExtenderImpl.java
Ретушь лица BeautyPreviewExtenderImpl.java BeautyImageCaptureExtenderImpl.java

В следующем примере мы используем PreviewExtenderImpl и ImageCaptureExtenderImpl в качестве заполнителей. Замените их именами файлов, которые вы реализуете.

Basic Extender имеет следующие возможности:

  • Внедрить параметры сеанса при настройке CameraCaptureSession ( onPresetSession ).
  • Уведомлять вас о событиях начала и закрытия сеанса захвата и отправлять один запрос на уведомление HAL с возвращаемыми параметрами ( onEnableSession , onDisableSession ).
  • Внедрить параметры захвата для запроса ( PreviewExtenderImpl.getCaptureStage , ImageCaptureExtenderImpl.getCaptureStages ).
  • Добавьте процессоры для предварительного просмотра и захвата фотографий, способные обрабатывать поток YUV_420_888 .

Давайте посмотрим, как Camera2/X вызывает extensions-interface для реализации трех потоков приложений, упомянутых выше.

Поток приложения 1: проверка доступности расширения

BasicExtenderAppFlow1

Рисунок 3. Поток приложения 1 на базовом расширителе

В этом потоке Camera2/X напрямую вызывает метод isExtensionAvailable() как PreviewExtenderImpl , так и ImageCaptureExtenderImpl не вызывая init() . Для включения расширений оба класса Extender должны возвращать true .

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

Поток приложения 2: Запрос информации

BasicExtenderAppFlow2

Рисунок 4. Поток приложения 2 на базовом расширителе

Определив, доступно ли расширение, приложения должны запросить следующую информацию, прежде чем включить расширение.

  • Диапазон задержки захвата неподвижного изображения: ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange возвращает диапазон задержки захвата, чтобы приложение могло оценить, целесообразно ли включать расширение для текущего сценария.

  • Поддерживаемые размеры для предварительного просмотра и захвата поверхности: ImageCaptureExtenderImpl.getSupportedResolutions и PreviewExtenderImpl.getSupportedResolutions возвращают список форматов изображений и размеров, поддерживаемых для формата и размера поверхности.

  • Поддерживаемые ключи запроса и результата: Camera2/X вызывает следующие методы для извлечения поддерживаемых ключей запроса захвата и ключей результата из вашей реализации:

    • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
    • ImageCaptureExtenderImpl.getAvailableCapturetResultKeys

Camera2/X всегда сначала вызывает init() для этих классов Extender, прежде чем запрашивать дополнительную информацию.

Поток приложения 3: Предварительный просмотр/захват неподвижного изображения с включенным расширением (реализация HAL)

BasicExtenderAppFlow3

Рисунок 5. Поток приложения 3 на базовом расширителе

На схеме выше показан основной процесс включения предварительного просмотра и съёмки фотографий с помощью расширения без процессора. Это означает, что HAL камеры обрабатывает расширение.

В этом потоке Camera2/X сначала вызывает init() , а затем onInit , что уведомляет о скором запуске сеанса камеры с указанными расширениями. В onInit() можно выполнить сложную инициализацию.

При настройке CameraCaptureSession камера Camera2/X вызывает onPresetSession для получения параметров сеанса. После успешной настройки сеанса захвата камера Camera2/X вызывает onEnableSession возвращая экземпляр CaptureStageImpl , содержащий параметры захвата. Камера Camera2/X немедленно отправляет один запрос с этими параметрами захвата, чтобы уведомить HAL. Аналогично, перед закрытием сеанса захвата камера Camera2/X вызывает onDisableSession , а затем отправляет один запрос с возвращенными параметрами захвата.

Повторяющийся запрос, инициированный Camera2/X, содержит параметры запроса, возвращаемые функцией PreviewExtenderImpl.getCaptureStage() . Кроме того, запрос на захват неподвижного изображения содержит параметры, возвращаемые функцией ImageCaptureExtenderImpl.getCaptureStages() .

Наконец, Camera2/X вызывает onDeInit() после завершения сеанса работы с камерой. Вы можете освободить ресурсы в onDeinit() .

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

Помимо HAL камеры, можно также реализовать расширения в процессоре.

Реализуйте PreviewExtenderImpl.getProcessorType для указания типа процессора, как описано ниже:

  • PROCESSOR_TYPE_NONE : процессор отсутствует. Изображения обрабатываются в HAL камеры.

  • PROCESSOR_TYPE_REQUEST_UPDATE_ONLY : тип процессора позволяет обновлять повторяющийся запрос новыми параметрами запроса захвата на основе последнего TotalCaptureResult .

    PreviewExtenderImpl.getProcessor должен возвращать экземпляр RequestUpdateProcessorImpl , который обрабатывает экземпляр TotalCaptureResult и возвращает экземпляр CaptureStageImpl для обновления повторяющегося запроса. PreviewExtenderImpl.getCaptureStage() также должен отражать результат обработки и возвращать последний CaptureStageImpl .

  • PROCESSOR_TYPE_IMAGE_PROCESSOR : Этот тип позволяет реализовать процессор для обработки изображений YUV_420_888 и записать вывод на PRIVATE поверхность.

    Необходимо реализовать и вернуть экземпляр PreviewImageProcessorImpl в PreviewExtenderImpl.getProcessor . Процессор отвечает за обработку входных изображений YUV_420_888 . Он должен записывать выходные данные в формат PRIVATE для предварительного просмотра. Camera2/X использует поверхность YUV_420_888 вместо PRIVATE для настройки CameraCaptureSession для предварительного просмотра.

    Смотрите следующую иллюстрацию для наглядности:

PreviewProcessor

Рисунок 6. Предварительный просмотр с помощью PreviewImageProcessorImpl

Интерфейс PreviewImageProcessorImpl расширяет ProcessImpl и имеет три важных метода:

  • onOutputSurface(Surface surface, int imageFormat) задаёт выходную поверхность для процессора. Для PreviewImageProcessorImpl imageFormat — это формат пикселей, например, PixelFormat.RGBA_8888 .

  • onResolutionUpdate(Size size) задает размер входного изображения.

  • onImageFormatUpdate(int imageFormat) задаёт формат входного изображения. В настоящее время поддерживается только формат YUV_420_888 .

Процессор захвата изображений

Для захвата неподвижных изображений можно реализовать процессор, возвращая экземпляр CaptureProcessorImpl с помощью ImageCaptureExtenderImpl.getCaptureProcessor . Процессор отвечает за обработку списка захваченных изображений YUV_420_888 и экземпляров TotalCaptureResult , а также за запись вывода на поверхность YUV_420_888 .

Вы можете с уверенностью предположить, что предварительный просмотр включен и запущен, прежде чем отправлять запрос на захват неподвижного изображения.

Смотрите поток на диаграмме ниже:

CaptureProcessor

Рисунок 7. Поток захвата с помощью CaptureProcessorImpl

  1. Camera2/X использует формат поверхности YUV_420_888 для настройки сеанса съёмки неподвижных изображений. Camera2/X подготавливает CaptureProcessorImpl , вызывая:

    • CaptureProcessorImpl.onImageFormatUpdate() с YUV_420_888 .
    • CaptureProcessorImpl.onResolutionUpdate() с размером входного изображения.
    • CaptureProcessorImpl.onOutputSurface() с выходной поверхностью YUV_420_888 .
  2. ImageCaptureExtenderImpl.getCaptureStages возвращает список CaptureStageImpl , где каждый элемент соответствует экземпляру CaptureRequest с параметрами захвата, отправленными Camera2/X. Например, если возвращается список из трёх экземпляров CaptureStageImpl , Camera2/X отправляет три запроса на захват с соответствующими параметрами захвата, используя API captureBurst .

  3. Полученные изображения и экземпляры TotalCaptureResult объединяются и отправляются в CaptureProcessorImpl для обработки.

  4. CaptureProcessorImpl записывает результирующее изображение (формат YUV_420_888 ) на выходную поверхность, указанную вызовом onOutputSurface() . Camera2/X при необходимости преобразует его в изображения JPEG.

Поддержка ключей и результатов запроса на захват

Помимо предварительного просмотра и съёмки с камеры, приложения могут настраивать зум, параметры вспышки и активировать фокусировку касанием. Эти параметры могут быть несовместимы с вашей реализацией расширения.

В extensions-interface 1.3.0 были добавлены следующие методы, позволяющие вам раскрывать параметры, поддерживаемые вашей реализацией:

  • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys() возвращает ключи запроса захвата, поддерживаемые вашей реализацией.
  • ImageCaptureExtenderImpl.getAvailableCaptureResultKeys() возвращает ключи результата захвата, содержащиеся в результате захвата.

Если HAL камеры обрабатывает расширение, Camera2/X извлекает результаты захвата в CameraCaptureSession.CaptureCallback . Однако, если процессор реализован, Camera2/X извлекает результаты захвата в ProcessResultImpl , который передаётся методу process() в PreviewImageProcessorImpl и CaptureProcessorImpl . Вы отвечаете за передачу результата захвата через ProcessResultImpl в Camera2/X.

См. определение интерфейса CaptureProcessorImpl ниже в качестве примера. В extensions-interface версии 1.3.0 и выше выполняется второй вызов process() :

Interface CaptureProcessorImpl extends ProcessorImpl {
    // invoked when extensions-interface version < 1.3.0
    void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
    // invoked when extensions-interface version >= 1.3.0
    void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
            ProcessResultImpl resultCallback, Executor executor);
}

Для обычных операций с камерой, таких как масштабирование, фокусировка касанием, вспышка и компенсация экспозиции, мы рекомендуем поддерживать следующие клавиши как для запроса на захват, так и для результата захвата:

  • Масштаб:
    • CaptureRequest#CONTROL_ZOOM_RATIO
    • CaptureRequest#SCALER_CROP_REGION
  • Фокусировка касанием:
    • CaptureRequest#CONTROL_AF_MODE
    • CaptureRequest#CONTROL_AF_TRIGGER
    • CaptureRequest#CONTROL_AF_REGIONS
    • CaptureRequest#CONTROL_AE_REGIONS
    • CaptureRequest#CONTROL_AWB_REGIONS
  • Вспышка:
    • CaptureRequest#CONTROL_AE_MODE
    • CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
    • CaptureRequest#FLASH_MODE
  • Компенсация экспозиции:
    • CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION

Для базовых расширителей, реализующих версию 1.2.0 или более ранние, API расширений CameraX явно поддерживает все вышеперечисленные ключи. Для extensions-interface 1.3.0 и CameraX, и Camera2 учитывают возвращаемый список и поддерживают только содержащиеся в нём ключи. Например, если вы решите возвращать только CaptureRequest#CONTROL_ZOOM_RATIO и CaptureRequest#SCALER_CROP_REGION в реализации 1.3.0, это означает, что приложение будет поддерживать только зум, а фокусировка касанием, вспышка и компенсация экспозиции не поддерживаются.

Расширенный расширитель

Расширенный расширитель — это тип реализации, основанный на API Camera2. Этот тип расширителя был добавлен в extensions-interface версии 1.2.0. В зависимости от производителя устройства, расширения могут быть реализованы на уровне приложения, что обусловлено следующими факторами:

  • Пользовательская конфигурация потока: настройте пользовательские потоки, например поток RAW, или используйте несколько потоков для разных идентификаторов физических камер.

  • Возможность отправки запросов Camera2: поддержка сложной логики взаимодействия, которая может отправлять запросы на захват с параметрами, основанными на результатах предыдущих запросов.

Advanced Extender предоставляет оболочку или промежуточный уровень, чтобы вы могли настраивать конфигурацию потока и отправлять запросы на захват по требованию.

Файлы для реализации

Для перехода к реализации Advanced Extender метод isAdvancedExtenderImplemented() в ExtensionVersionImpl должен возвращать true . Для каждого типа расширения OEM-производители должны реализовать соответствующие классы Extender. Файлы реализации Advanced Extender находятся в пакете advanced .

Классы-расширители для реализации
Ночь advanced/NightAdvancedExtenderImpl.java
HDR advanced/HdrAdvancedExtenderImpl.java
Авто advanced/AutoAdvancedExtenderImpl.java
Боке advanced/BokehAdvancedExtenderImpl.java
Ретушь лица advanced/BeautyAdvancedExtenderImpl.java

В следующем примере мы используем AdvancedExtenderImpl в качестве заполнителя. Замените его именем файла расширения для реализуемого вами расширения.

Давайте посмотрим, как Camera2/X вызывает extensions-interface для реализации трех потоков приложения.

Поток приложения 1: проверка доступности расширений

AdvancedAppFlow1

Рисунок 8. Поток приложения 1 на Advanced Extender

Сначала приложение проверяет, поддерживается ли заданное расширение.

Поток приложения 2: Запрос информации

AdvancedAppFlow2

Рисунок 9. Поток приложения 2 на Advanced Extender

После вызова AdvancedExtenderImpl.init() приложение может запросить следующую информацию о AdvancedExtenderImpl :

  • Расчетная задержка захвата неподвижного изображения: AdvancedExtenderImpl.getEstimatedCaptureLatencyRange() возвращает диапазон задержки захвата, чтобы приложение могло оценить, целесообразно ли включать расширение для текущего сценария.

  • Поддерживаемые разрешения для предварительного просмотра и съемки фотографий:

    • AdvancedExtenderImpl.getSupportedPreviewOutputResolutions() возвращает сопоставление формата изображения со списком поддерживаемых размеров для формата и размера поверхности предварительного просмотра. Производители оригинального оборудования (OEM) должны поддерживать как минимум формат PRIVATE .

    • AdvancedExtenderImpl.getSupportedCaptureOutputResolutions() возвращает поддерживаемый формат и размеры поверхности захвата неподвижных изображений. Производители оригинального оборудования (OEM) должны поддерживать форматы вывода JPEG и YUV_420_888 .

    • AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions() возвращает поддерживаемые размеры для дополнительного потока YUV_420_888 для анализа изображений. Если поверхность анализа изображений YUV не поддерживается, getSupportedYuvAnalysisResolutions() должен возвращать null или пустой список.

  • Доступные ключи/результаты запроса захвата (добавлены в extensions-interface 1.3.0): Camera2/X вызывает следующие методы для извлечения поддерживаемых ключей запроса захвата и ключей результатов из вашей реализации:

    • AdvancedExtenderImpl.getAvailableCaptureRequestKeys
    • AdvancedExtenderImpl.getAvailableCaptureResultKeys

Для получения дополнительной информации см. раздел Ключи и результаты запроса на захват поддержки .

Поток приложения 3: Предварительный просмотр/захват неподвижного изображения с включенным расширением

AdvancedAppFlow3

Рисунок 10. Поток приложения 3 на Advanced Extender

На схеме выше показан основной процесс запуска предварительного просмотра и захвата стоп-кадра для типа Advanced Extender. Давайте рассмотрим каждый этап.

  1. Экземпляр SessionProcessorImpl

    Основная реализация Advanced Extender находится в SessionProcessorImpl , который отвечает за настройку сеанса и отправку запросов на захват для инициирования предварительного просмотра и захвата неподвижных изображений. Вызывается AdvancedExtenderImpl.createSessionProcessor() , возвращающий экземпляр SessionProcessorImpl .

  2. initSession

    SessionProcessorImpl.initSession() инициализирует сеанс для расширения. Здесь вы выделяете ресурсы и возвращаете конфигурацию сеанса для подготовки CameraCaptureSession .

    В качестве входных параметров Camera2/X задаёт конфигурации выходной поверхности для предварительного просмотра, съёмки фотографий и опционального анализа изображений YUV. Эта конфигурация выходной поверхности ( OutputSurfaceImpl ) содержит данные о поверхности, размере и формате изображения, которые извлекаются следующими методами в AdvancedExtenderImpl :

    • getSupportedPreviewOutputResolutions()
    • getSupportedCaptureOutputResolutions()
    • getSupportedYuvAnalysisResolutions()

    Необходимо вернуть экземпляр Camera2SessionConfigImpl , состоящий из списка экземпляров Camera2OutputConfigImpl и параметров сеанса, используемых для настройки CameraCaptureSession . Вы отвечаете за вывод корректных изображений с камеры на выходные поверхности, переданные Camera2/X. Вот несколько параметров для включения вывода:

    • Обработка в HAL камеры: выходные поверхности можно напрямую добавить в CameraCaptureSession с помощью реализации SurfaceOutputConfigImpl . Это настраивает предоставленную выходную поверхность для конвейера камеры и позволяет HAL камеры обрабатывать изображение.
    • Обработка промежуточной поверхности ImageReader (RAW, YUV и т. д.): добавьте промежуточные поверхности ImageReader в CameraCaptureSession с экземпляром ImageReaderOutputConfigImpl .

      Вам необходимо обработать промежуточные изображения и записать результирующее изображение на выходную поверхность.

    • Использовать общий доступ к поверхности Camera2: используйте общий доступ к поверхности с другой поверхностью, добавив любой экземпляр Camera2OutputConfigImpl к методу getSurfaceSharingOutputConfigs() другого экземпляра Camera2OutputConfigImpl . Формат и размер поверхности должны быть идентичны.

    Все Camera2OutputConfigImpl , включая SurfaceOutputConfigImpl и ImageReaderOutputConfigImpl должны иметь уникальный идентификатор ( getId() ), который используется для указания целевой поверхности и извлечения изображения из ImageReaderOutputConfigImpl .

  3. onCaptureSessionStart и RequestProcessorImpl

    Когда запускается CameraCaptureSession и фреймворк Camera вызывает onConfigured() , то Camera2/X вызывает SessionProcessorImpl.onCaptureSessionStart() с оболочкой запроса Camera2 RequestProcessImpl . Camera2/X реализует RequestProcessImpl , что позволяет выполнять запросы на захват и извлекать изображения , если используется ImageReaderOutputConfigImpl .

    API RequestProcessImpl аналогичны API Camera2 CameraCaptureSession с точки зрения выполнения запросов. Различия заключаются в следующем:

    • Целевая поверхность указывается идентификатором экземпляра Camera2OutputConfigImpl .
    • Возможность извлечения изображения из ImageReader .

    Вы можете вызвать RequestProcessorImpl.setImageProcessor() с указанным идентификатором Camera2OutputConfigImpl , чтобы зарегистрировать экземпляр ImageProcessorImpl для получения изображений.

    Экземпляр RequestProcessImpl становится недействительным после того, как Camera2/X вызывает SessionProcessorImpl.onCaptureSessionEnd() .

  4. Запустите предварительный просмотр и сделайте снимок

    В реализации Advanced Extender запросы на захват можно отправлять через интерфейс RequestProcessorImpl . Camera2/X уведомляет о необходимости запуска повторяющегося запроса на предварительный просмотр или последовательность захвата стоп-кадров, вызывая SessionProcessorImpl#startRepeating и SessionProcessorImpl#startCapture соответственно. Для удовлетворения этих запросов на предварительный просмотр и захват стоп-кадров необходимо отправлять запросы на захват.

    Camera2/X также задаёт параметры запроса на захват через SessionProcessorImpl#setParameters . Эти параметры запроса (если они поддерживаются) необходимо задать как для повторяющихся, так и для одиночных запросов.

    Необходимо поддерживать как минимум CaptureRequest.JPEG_ORIENTATION и CaptureRequest.JPEG_QUALITY . extensions-interface 1.3.0 поддерживает ключи запроса и результата, которые предоставляются следующими методами:

    • AdvancedExtenderImpl.getAvailableCaptureRequestKeys()
    • AdvancedExtenderImpl.getAvailableCaptureResultKeys()

    Когда разработчики задают ключи в списке getAvailableCaptureRequestKeys , необходимо включить параметры и убедиться, что результат захвата содержит ключи из списка getAvailableCaptureResultKeys .

  5. startTrigger

    SessionProcessorImpl.startTrigger() вызывается для запуска триггера, например CaptureRequest.CONTROL_AF_TRIGGER и CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER . Вы можете игнорировать любые ключи запроса захвата, которые не были объявлены в AdvancedExtenderImpl.getAvailableCaptureRequestKeys() .

    startTrigger() поддерживается начиная с версии extensions-interface 1.3.0. Она позволяет приложениям реализовывать фокусировку по касанию и вспышку с помощью расширений.

  6. Уборка

    При завершении сеанса захвата перед закрытием CameraCaptureSession вызывается SessionProcessorImpl.onCaptureSessionEnd() . После закрытия сеанса захвата deInitSession() выполняет очистку.

Поддержка предварительного просмотра, захвата фотографий и анализа изображений

Расширение следует применять как для предварительного просмотра, так и для захвата стоп-кадра. Однако, если задержка слишком велика для плавного отображения предварительного просмотра, расширение можно применять только для захвата стоп-кадра.

For the Basic Extender type, regardless of enabling the extension for preview, you must implement both ImageCaptureExtenderImpl and PreviewExtenderImpl for a given extension. Often, an app also uses a YUV stream to analyze the image content such as finding QR codes or text. To better support this use case , you should support the stream combination of preview, still capture, and a YUV_420_888 stream for configuring CameraCaptureSession . This means that if you implement a processor, then you have to support the stream combination of three YUV_420_888 streams.

For Advanced Extender, Camera2/X passes three output surfaces to the SessionProcessorImpl.initSession() call. These output surfaces are for preview , still capture, and image analysis, respectively. You must ensure that preview and still capture output surfaces show the valid output. However, for the image analysis output surface, ensure it's working only when it's non-null. If your implementation can't support the image analysis stream, you can return an empty list in AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions() . This ensures the image analysis output surface is always null in SessionProcessorImpl.initSession() .

Support video capture

The current Camera Extension architecture supports only the preview and still capture use cases. We don't support enabling the extension on the MediaCodec or MediaRecorder surfaces for recording the video. However, it's possible for apps to record the preview output.

Supporting MediaCodec and MediaRecorder surfaces is under investigation.

Extension-specific metadata

For Android 14 and higher, extension-specific metadata lets camera extension clients set and receive extension specific capture request settings and results. Specifically, camera extension clients can use the EXTENSION_STRENGTH capture request parameter to control the extension strength and the EXTENSION_CURRENT_TYPE capture result to indicate the enabled extension type.

Capture requests

The EXTENSION_STRENGTH capture request parameter controls the strength of the extension post-processing effect. The corresponding capture result includes the default strength value if this parameter isn't set explicitly by the client. This parameter can be applied as follows for these extension types:

  • BOKEH : Controls the amount of blur.
  • HDR and NIGHT : Controls the amount of images fused and the brightness of the final image.
  • FACE_RETOUCH : Controls the amount of cosmetic enhancement and skin smoothing.

The supported range for the EXTENSION_STRENGTH parameter is between 0 and 100 , with 0 indicating no extension processing or simple passthrough and 100 indicating the maximum extension strength of the processing effect.

To add support for EXTENSION_STRENGTH , use the vendor specific parameter APIs introduced in version 1.3.0 of the extension library interface. For more information, see getAvailableCaptureRequestKeys() .

Capture results

The EXTENSION_CURRENT_TYPE capture result lets extension implementations notify clients about the active extension type.

Because extensions using the AUTO type dynamically switch between extension types such as HDR and NIGHT depending on the scene conditions, camera extensions apps can use EXTENSION_CURRENT_TYPE to display information about the current extension selected by the AUTO extension.

Real-time still capture latency estimate

For Android 14 and higher, camera extension clients can query real-time still capture latency estimates based on the scene and environment conditions using getRealtimeStillCaptureLatency() . This method provides more accurate estimates than the static getEstimatedCaptureLatencyRangeMillis() method. Based on the latency estimate, apps can decide to skip extension processing or to display an indication to notify users about a long running operation.

CameraExtensionSession.StillCaptureLatency latency;

latency = extensionSession.getRealtimeStillCaptureLatency();

// The capture latency from ExtensionCaptureCallback#onCaptureStarted() until ExtensionCaptureCallback#onCaptureProcessStarted().

latency.getCaptureLatency();

// The processing latency from  ExtensionCaptureCallback#onCaptureProcessStarted() until  the processed frame returns to the client.

latency.getProcessingLatency();

To support real-time still capture latency estimates, implement the following:

Capture processing progress callbacks

For Android 14 and higher, camera extension clients can receive callbacks for the progress of long running still capture processing operations. Apps can display the current progress to users to improve the overall user experience.

Apps can use the following code to integrate this feature:

import android.hardware.camera2.CameraExtensionSession.
ExtensionCaptureCallback;

{

  class AppCallbackImpl extends ExtensionCaptureCallback {

    @Override
    public void onCaptureProcessProgressed(
      @NonNull CameraExtensionSession session,
      @NonNull CaptureRequest request,
      @IntRange(from = 0, to = 100) int progress) {
      // Update app UI with current progress
    }
  }

}

To support capture processing progress callbacks, your extension vendor implementation must call the following callbacks with the current progress value:

Postview still capture

For Android 14 and higher, camera extensions can supply a postview (preview image) using setPostviewOutputConfiguration . To improve the user experience, apps can display a postview image as a placeholder when an extension is experiencing increased processing latency, and replace the image when the final image is available. Apps can configure and issue postview capture requests using the following reference code:

{

if (!CameraExtensionCharacteristics.isPostviewAvailable()) {
    continue;
}

ExtensionSessionConfiguration extensionConfiguration = new
        ExtensionSessionConfiguration(
                CameraExtensionCharacteristics.EXTENSION_NIGHT,
                outputConfig,
                backgroundExecutor,
                extensionSessionStateCallback
    );

extensionConfiguration.setPostviewOutputConfiguration(
    postviewImageOutput);

CaptureRequest.Builder captureRequestBuilder =
    cameraDevice.createCaptureRequest(
        CameraDevice.TEMPLATE_STILL_CAPTURE);
captureRequestBuilder.addTarget(stillImageReader.getSurface());
captureRequestBuilder.addTarget(postviewImageSurface);

CaptureRequest captureRequest = captureRequestBuilder.build();

}

To support postview still capture, your vendor implementation must implement the following:

Support SurfaceView output

For Android 14 and higher, camera extension clients can use power and performance optimized preview render paths by registering a SurfaceView instance for preview output for repeating requests.

To support SurfaceView output, your vendor extension implementation must be capable of streaming and outputting preview to SurfaceView instances. To verify that this is supported, run the SurfaceViewExtensionPreviewTest.java CTS module.

Vendor specific session types

The feature enables vendor extension implementations to select a vendor specific session type that will be set in the internal camera capture session instead of the default value.

The feature works entirely within the framework and vendor stack and has no client/public visible API impact.

To select a vendor-specific session type, implement the following for your extension libraries: * ExtenderStateListener.onSessionType() for basic extensions * Camera2SessionConfigImpl.getSessionType() for advanced extensions

Extensions interface version history

The following table shows the Camera Extension interface version history. You should always implement the vendor library with the latest version.

Версия Added features
1.0.0
  • Version verification
    • ExtensionVersionImpl
  • Basic Extender
    • PreviewExtenderImpl
    • ImageCaptureExtenderImpl
    • Processor
      • PreviewImageProcessorImpl
      • CaptureProcessorImpl
      • RequestUpdateProcessorImpl
1.1.0
  • Library initialization
    • InitializerImpl
  • Expose supported resolutions
    • PreviewExtenderImpl.getSupportedResolutions
    • ImageCaptureExtenderImpl.getSupportedResolutions
1.2.0
  • AdvancedExtender
    • AdvancedExtenderImpl
    • SessionProcessorImpl
  • Get estimated capture latency
    • ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
1.3.0
  • Expose supported capture request keys/results keys
    • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys and getAvailableCaptureResultKeys
    • AdvancedExtenderImpl.getAvailableCaptureRequestKeys and getAvailableCaptureResultKeys
    • New process() call that takes ProcessResultImpl in PreviewImageProcessorImpl and CaptureProcessorImpl
    • Support trigger type request
      • AdvancedExtenderImpl.startTrigger
1.4.0
  • Extension-specific metadata
  • Dynamic still capture latency estimates
  • Capture processing progress callbacks
  • Postview still capture
  • Support for SurfaceView output
  • Vendor specific session types

Reference implementation

The following reference OEM vendor library implementations are available in frameworks/ex .

  • advancedSample : A basic implementation of Advanced Extender.

  • sample : A basic implementation of Basic Extender.

  • service_based_sample : An implementation that demonstrates how to host Camera Extensions in a Service . This implementation contains the following components:

    • oem_library : A Camera Extensions OEM library for Camera2 and CameraX Extensions APIs that implements Extensions-Interface . This acts as a passthrough that forwards calls from Extensions-Interface to the service. This library also provides AIDL files and wrapper classes to communicate with the service.

      Advanced Extender is enabled by default. To enable the Basic Extender, change ExtensionsVersionImpl#isAdvancedExtenderImplemented to return false .

    • extensions_service : A sample implementation of the Extensions Service. Add your implementation here. The interface to implement in the service is similar to the Extensions-Interface . For example, implementing the IAdvancedExtenderImpl.Stub performs the same operations as AdvancedExtenderImpl . ImageWrapper and TotalCaptureResultWrapper are required to make Image and TotalCaptureResult parcelable.

Set up the vendor library on a device

The OEM vendor library isn't built into an app; it's loaded from the device at runtime by Camera2/X. In CameraX, the <uses-library> tag declares that the androidx.camera.extensions.impl library, which is defined in the AndroidManifest.xml file of the camera-extensions library, is a dependency of CameraX and must be loaded at runtime. In Camera2, the framework loads an extensions service that also declares that the <uses-library> loads the same androidx.camera.extensions.impl library at runtime.

This allows third-party apps using extensions to automatically load the OEM vendor library. The OEM library is marked as optional so apps can run on devices that don't have the library on the device. Camera2/X handles this behavior automatically when an app tries to use a camera extension as long as the device manufacturer places the OEM library on the device so that it can be discovered by the app.

To set up the OEM library on a device, do the following:

  1. Add a permission file, which is required by the <uses-library> tag, using the following format: /etc/permissions/ ANY_FILENAME .xml . For example, /etc/permissions/camera_extensions.xml . The files in this directory provide a mapping of the library named in <uses-library> to the actual file path on the device.
  2. Use the example below to add the required information to the file.

    • name must be androidx.camera.extensions.impl as that's the library that CameraX searches for.
    • file is the absolute path of the file that contains the extensions implementation (for example, /system/framework/androidx.camera.extensions.impl.jar ).
    <?xml version="1.0" encoding="utf-8"?>
    <permissions>
        <library name="androidx.camera.extensions.impl"
                 file="OEM_IMPLEMENTED_JAR" />
    </permissions>

In Android 12 or higher, devices supporting CameraX extensions must have the ro.camerax.extensions.enabled property set to true , which allows for querying whether a device supports extensions. To do this, add the following line in the device make file:

PRODUCT_VENDOR_PROPERTIES += \
    ro.camerax.extensions.enabled=true \

Проверка

To test your implementation of the OEM vendor library during the development stage, use the example app at androidx-main/camera/integration-tests/extensionstestapp/ , which runs through various vendor extensions.

After you complete your implementation, use the camera extensions validation tool to run automated and manual tests to verify that the vendor library is implemented correctly.

Extended scene mode versus camera extensions

For the bokeh extension, in addition to exposing it using camera extensions, you can expose the extension using the extended scene mode, which is enabled through the CONTROL_EXTENDED_SCENE_MODE key. For more implementation details, see Camera bokeh .

Extended scene mode has fewer restrictions compared to camera extensions for camera2 apps. For example, you can enable extended scene mode in a regular CameraCaptureSession instance that supports flexible stream combinations and capture request parameters. In contrast, camera extensions support only a fixed set of stream types and have limited support for capture request parameters.

A downside of extended scene mode is that you can only implement it in the camera HAL, which means that it must be verified to work across all orthogonal controls available to app developers.

We recommend exposing bokeh using both the extended scene mode and Camera Extensions because apps might prefer to use a particular API to enable bokeh. We recommend first using the extended scene mode because this is the most flexible way for apps to enable the bokeh extension. Then you can implement the camera extensions interface based on the extended scene mode. If implementing bokeh in the camera HAL is difficult, for example, because it requires a post processor running in the app layer to process images, we recommend implementing the bokeh extension using the Camera Extensions interface.

Часто задаваемые вопросы (FAQ)

Are there any restrictions on API levels?

Yes. This depends on the Android API feature set that's required by the OEM vendor library implementation. For example, ExtenderStateListener.onPresetSession() uses the SessionConfiguration.setSessionParameters() call to set a baseline set of tags. This call is available only on API level 28 and higher. For details on specific interface methods, see the API reference documentation .