Extensões de câmera

Os fabricantes de dispositivos podem expor extensões como bokeh, modo noturno e HDR para desenvolvedores terceirizados por meio da interface de extensões de câmera fornecida pela biblioteca do fornecedor OEM. Os desenvolvedores podem usar a API Camera2 Extensions e a API CameraX Extensions para acessar as extensões implementadas na biblioteca do fornecedor OEM.

Para obter uma lista de extensões suportadas, que é a mesma em Camera2 e CameraX, consulte API de extensões CameraX . Se você quiser adicionar uma extensão, registre um bug no Issue Tracker .

Esta página descreve como implementar e ativar a biblioteca do fornecedor OEM em dispositivos.

Arquitetura

O diagrama a seguir descreve a arquitetura da interface Camera Extensions ou extensions-interface : Arquitetura

Figura 1. Diagrama de arquitetura de extensões de câmera

Conforme mostrado no diagrama, para oferecer suporte a extensões de câmera, você precisa implementar a extensions-interface fornecida pela biblioteca do fornecedor OEM. Sua biblioteca de fornecedores OEM permite duas APIs: CameraX Extensions API e Camera2 Extensions API , que são usadas pelos aplicativos CameraX e Camera2, respectivamente, para acessar extensões de fornecedores.

Implementar a biblioteca de fornecedores OEM

Para implementar a biblioteca do fornecedor OEM, copie os arquivos camera-extensions-stub em um projeto de biblioteca do sistema. Esses arquivos definem a interface das extensões da câmera.

Os arquivos camera-extensions-stub são divididos nas seguintes categorias:

Arquivos de interface essenciais (não modifique)

  • 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

Implementações obrigatórias (adicione sua implementação)

  • ExtensionVersionImpl.java
  • InitializerImpl.java

Classes extensoras de Bokeh (implemente-as se a extensão Bokeh for suportada)

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

Classes extensoras noturnas (implemente-as se a extensão noturna for suportada)

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

Classes de extensão automática (implemente-as se a extensão automática for suportada)

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

Classes de extensor HDR (implemente-as se a extensão HDR for suportada)

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

Classes extensoras de Retoque Facial (implemente-as se a extensão Retoque Facial for suportada)

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

Utilitários (opcional, pode ser excluído)

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

Você não é obrigado a fornecer uma implementação para cada extensão. Se você não implementar uma extensão, configure isExtensionAvailable() para retornar false ou remova as classes Extender correspondentes. As APIs de extensões Camera2 e CameraX informam ao aplicativo que a extensão não está disponível.

Vejamos como as APIs de extensões Camera2 e CameraX interagem com a biblioteca do fornecedor para habilitar uma extensão. O diagrama a seguir ilustra o fluxo ponta a ponta usando a extensão Night como exemplo:

Fluxo principal

Figura 2. Implementação da extensão noturna

  1. Verificação de versão:

    Camera2/X chama ExtensionVersionImpl.checkApiVersion() para garantir que a versão extensions-interface implementada pelo OEM seja compatível com as versões suportadas por Camera2/X.

  2. Inicialização da biblioteca do fornecedor:

    InitializerImpl possui um método init() que inicializa a biblioteca do fornecedor. Camera2/X conclui a inicialização antes de acessar as classes do Extender.

  3. Instanciar classes do Extender:

    Instancia as classes Extender para a extensão. Existem dois tipos de Extender: Extender Básico e Extender Avançado. Você deve implementar um tipo de extensor para todas as extensões. Para obter mais informações, consulte Extender Básico versus Extender Avançado .

    Camera2/X instancia e interage com as classes Extender para recuperar informações e ativar a extensão. Para uma determinada extensão, Camera2/X pode instanciar as classes Extender várias vezes. Como resultado, não faça inicialização pesada no construtor ou na chamada init() . Faça o trabalho pesado somente quando a sessão da câmera estiver prestes a começar, como quando onInit() é chamado no Basic Extender ou initSession() é chamado no Advanced Extender.

    Para a extensão Night, as seguintes classes Extender são instanciadas para o tipo Basic Extender:

    • NightImageCaptureExtenderImpl.java
    • NightPreviewExtenderImpl.java

    E para o tipo Advanced Extender:

    • NightAdvancedExtenderImpl.java
  4. Verifique a disponibilidade da extensão:

    Antes de habilitar a extensão, isExtensionAvailable() verifica se a extensão está disponível no ID da câmera especificada por meio da instância do Extender.

  5. Inicialize o Extender com informações da câmera:

    Camera2/X chama init() na instância do Extender e passa a ela o ID da câmera e CameraCharacteristics .

  6. Informações de consulta:

    Invoca a classe Extender para recuperar informações como resoluções suportadas, ainda capturar a latência estimada e capturar chaves de solicitação do Extender em preparação para habilitar a extensão.

  7. Habilite a extensão no Extender:

    A classe Extender fornece todas as interfaces necessárias para habilitar a classe. Ele oferece um mecanismo para conectar a implementação OEM ao pipeline Camera2, como injetar parâmetros de solicitação de captura ou ativar um pós-processador.

    Para o tipo Advanced Extender, Camera2/X interage com SessionProcessorImpl para ativar a extensão. Camera2/X recupera a instância SessionProcessorImpl chamando createSessionProcessor() no Extender.

As seções a seguir descrevem o fluxo de extensão com mais detalhes.

Verificação de versão

Ao carregar a biblioteca do fornecedor OEM do dispositivo em tempo de execução, Camera2/X verifica se a biblioteca é compatível com a versão extensions-interface . A extensions-interface usa controle de versão semântico, ou MAJOR.MINOR.PATCH, por exemplo, 1.1.0 ou 1.2.0. No entanto, apenas as versões principais e secundárias são usadas durante a verificação de versão.

Para verificar a versão, Camera2/X chama ExtensionVersionImpl.checkApiVersion() com a versão extensions-interface suportada. Camera2/X então usa a versão relatada pela biblioteca OEM para determinar se a extensão pode ser habilitada e quais recursos ela deve invocar.

Compatibilidade de versão principal

Se as versões principais da interface de extensão forem diferentes entre Camera2/X e a biblioteca do fornecedor, ela será considerada incompatível e a extensão será desativada.

Compatibilidade com versões anteriores

Contanto que a versão principal seja idêntica, o Camera2/X garante compatibilidade retroativa com bibliotecas de fornecedores OEM construídas com versões anteriores extensions-interface . Por exemplo, se Camera2/X suportar extensions-interface 1.3.0, as bibliotecas do fornecedor OEM que implementaram 1.0.0, 1.1.0 e 1.2.0 ainda serão compatíveis. Isso também significa que depois de implementar uma versão específica da biblioteca do fornecedor, o Camera2/X garante que a biblioteca seja compatível com versões anteriores extension-interface futura.

Compatibilidade futura

A compatibilidade futura com bibliotecas de fornecedores de extensions-interface mais recentes depende de você, o OEM. Se precisar de alguns recursos para implementar as extensões, você pode querer habilitá-las a partir de uma determinada versão. Nesse caso, você pode retornar a versão extensions-interface suportada quando a versão da biblioteca Camera2/X atender aos requisitos. Se as versões Camera2/X não forem suportadas, você poderá retornar uma versão incompatível, como 99.0.0, para desativar as extensões.

Inicialização da biblioteca do fornecedor

Após verificar a versão extensions-interface implementada pela biblioteca OEM, Camera2/X inicia o processo de inicialização. O método InitializerImpl.init() sinaliza à biblioteca OEM que um aplicativo está tentando usar extensões.

Camera2/X não faz outras chamadas para a biblioteca OEM (além da verificação de versão) até que a biblioteca do fornecedor OEM chame OnExtensionsInitializedCallback.onSuccess() para notificar a conclusão da inicialização.

Você deve implementar InitializerImpl a partir da extensions-interface 1.1.0. Camera2/X ignora a etapa de inicialização da biblioteca se a biblioteca do fornecedor OEM implementar extensions-interface 1.0.0.

Extensor Básico versus Extensor Avançado

Existem dois tipos de implementação extensions-interface : Basic Extender e Advanced Extender. Advanced Extender é suportado desde extensions-interface 1.2.0.

Implemente o Basic Extender para extensões que processam imagens no HAL da câmera ou use um pós-processador capaz de processar fluxos YUV.

Implemente o Advanced Extender para extensões que precisam personalizar a configuração do stream Camera2 e enviar solicitações de captura conforme necessário.

Veja a tabela a seguir para comparação:

Extensor Básico Extensor Avançado
Configurações de fluxo Fixo
Pré-visualização: PRIVATE ou YUV_420_888 (se existir processador)
Captura de imagem: JPEG ou YUV_420_888 (se existir processador)
Customizável pelo OEM.
Enviando solicitação de captura Somente Camera2/X pode enviar solicitações de captura. Você pode definir os parâmetros para essas solicitações. Quando o processador é fornecido para captura de imagem, Camera2/X pode enviar múltiplas solicitações de captura e enviar todas as imagens e resultados de captura para o processador. Uma instância RequestProcessorImpl é fornecida a você para executar a solicitação de captura camera2 e obter resultados e imagem.

Camera2/X invoca startRepeating e startCapture em SessionProcessorImpl para sinalizar ao OEM para iniciar a solicitação repetida de visualização e iniciar a sequência de captura estática, respectivamente.

Ganchos no pipeline da câmera
  • onPresetSession fornece parâmetros de sessão.
  • onEnableSession envia uma única solicitação logo após a configuração CameraCaptureSession .
  • onDisableSession envia uma única solicitação antes que CameraCaptureSession seja fechado.
  • initSession inicializa e retorna uma configuração de sessão camera2 personalizada para criar a sessão de captura.
  • onCaptureSessionStart é invocado logo após a configuração CameraCaptureSession .
  • onCaptureSessionEnd é invocado antes que CameraCaptureSession seja fechado.
Adequado para Extensões implementadas no HAL da câmera ou em um processador que processa imagens YUV.
  • Possui implementações baseadas em Camera2 para as extensões.
  • Precisa de configuração de fluxo personalizada, como fluxo RAW.
  • Precisa de sequência de captura interativa.
Versão da API suportada Extensões Camera2: Android 13 ou superior
Extensões CameraX: camera-extensions 1.1.0 ou superior
Extensões Camera2: Android 12L ou superior
Extensões CameraX: camera-extensions 1.2.0-alpha03 ou superior

Fluxos de aplicativos

A tabela a seguir mostra três tipos de fluxos de aplicativos e suas chamadas de API de extensões de câmera correspondentes. Embora Camera2/X forneça essas APIs, você deve implementar adequadamente a biblioteca do fornecedor para dar suporte a esses fluxos, que descreveremos com mais detalhes em uma seção posterior.

Extensões da câmera2 Extensões CameraX
Disponibilidade da extensão de consulta CameraExtensionCharacteristics . getSupportedExtensions ExtensionsManager. isExtensionAvailable
Consultar informações CameraExtensionCharacteristics. getExtensionSupportedSizes CameraExtensionCharacteristics. getEstimatedCaptureLatencyRangeMillis CameraExtensionCharacteristics. getAvailableCaptureRequestKeys CameraExtensionCharacteristics. getAvailableCaptureResultKeys ExtensionsManager. getEstimatedCaptureLatencyRange

CameraX lida com o restante das informações da biblioteca.

Visualizar e capturar imagens com extensão habilitada CameraDevice. createExtensionSession

cameraExtensionsSession. setRepeatingRequest

cameraExtensionsSession. capture

val cameraSelector = ExtensionsManager. getExtensionEnabledCameraSelector bindToLifecycle(lifecycleOwner, cameraSelector, visualização, ...)

Extensor Básico

A interface do Basic Extender fornece ganchos em vários locais do pipeline da câmera. Cada tipo de extensão possui classes Extender correspondentes que os OEMs precisam implementar.

A tabela a seguir lista as classes Extender que os OEMS precisam implementar para cada extensão:

Classes extensoras para implementar
Noite NightPreviewExtenderImpl.java

NightImageCaptureExtenderImpl.java

HDR HdrPreviewExtenderImpl.java HdrImageCaptureExtenderImpl.java
Auto AutoPreviewExtenderImpl.java AutoImageCaptureExtenderImpl.java
Bokeh BokehPreviewExtenderImpl.java BokehImageCaptureExtenderImpl.java
Retoque facial BeautyPreviewExtenderImpl.java BeautyImageCaptureExtenderImpl.java

Usamos PreviewExtenderImpl e ImageCaptureExtenderImpl como espaços reservados no exemplo a seguir. Substitua-os pelos nomes dos arquivos reais que você está implementando.

O Extender Básico possui os seguintes recursos:

  • Injete parâmetros de sessão ao configurar CameraCaptureSession ( onPresetSession ).
  • Notificá-lo sobre os eventos de início e fechamento da sessão de captura e enviar uma única solicitação para notificar o HAL com os parâmetros retornados ( onEnableSession , onDisableSession ).
  • Injete parâmetros de captura para a solicitação ( PreviewExtenderImpl.getCaptureStage , ImageCaptureExtenderImpl.getCaptureStages ).
  • Adicione processadores para visualização e captura que sejam capazes de processar o fluxo YUV_420_888 .

Vamos ver como Camera2/X invoca a extensions-interface para atingir os três fluxos de aplicativos mencionados acima.

Fluxo de aplicativo 1: verificar a disponibilidade da extensão

BasicExtenderAppFlow1

Figura 3. Fluxo de aplicativo 1 no Basic Extender

Neste fluxo, Camera2/X chama diretamente o método isExtensionAvailable() de PreviewExtenderImpl e ImageCaptureExtenderImpl sem chamar init() . Ambas as classes Extender devem retornar true para ativar as extensões.

Geralmente, essa é a primeira etapa para os aplicativos verificarem se o tipo de extensão fornecido é compatível com um determinado ID de câmera antes de ativar a extensão. Isso ocorre porque algumas extensões são suportadas apenas em determinados IDs de câmera.

Fluxo de aplicativo 2: consultar informações

BasicExtenderAppFlow2

Figura 4. Fluxo de aplicativo 2 no Basic Extender

Depois de determinar se a extensão está disponível, os aplicativos devem consultar as informações a seguir antes de ativar a extensão.

  • Ainda intervalo de latência de captura: ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange retorna o intervalo de latência de captura para o aplicativo avaliar se é apropriado habilitar a extensão para o cenário atual.

  • Tamanhos suportados para a superfície de visualização e captura: ImageCaptureExtenderImpl.getSupportedResolutions e PreviewExtenderImpl.getSupportedResolutions retornam uma lista de formatos de imagem e os tamanhos que são suportados para formato e tamanho de superfície.

  • Chaves de solicitação e resultado suportadas: Camera2/X invoca os seguintes métodos para recuperar as chaves de solicitação de captura e chaves de resultado suportadas de sua implementação:

    • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
    • ImageCaptureExtenderImpl.getAvailableCapturetResultKeys

Camera2/X sempre chama init() primeiro nessas classes do Extender antes de consultar mais informações.

Fluxo de aplicativo 3: visualização/captura estática com extensão habilitada (implementação HAL)

BasicExtenderAppFlow3

Figura 5. Fluxo de aplicativo 3 no Basic Extender

O diagrama acima ilustra o fluxo principal de ativação da visualização e ainda da captura com uma extensão sem qualquer processador. Isso significa que a câmera HAL processa a extensão.

Nesse fluxo, Camera2/X primeiro chama init() e depois onInit , que notifica que uma sessão de câmera está prestes a começar com as extensões especificadas. Você pode fazer uma inicialização pesada em onInit() .

Ao configurar CameraCaptureSession , Camera2/X invoca onPresetSession para obter os parâmetros da sessão. Depois que a sessão de captura for configurada com sucesso, Camera2/X invoca onEnableSession retornando uma instância CaptureStageImpl que contém os parâmetros de captura. Camera2/X envia imediatamente uma única solicitação com esses parâmetros de captura para notificar o HAL. Da mesma forma, antes que a sessão de captura seja fechada, Camera2/X invoca onDisableSession e envia uma única solicitação com os parâmetros de captura retornados.

A solicitação repetida acionada por Camera2/X contém os parâmetros de solicitação retornados por PreviewExtenderImpl.getCaptureStage() . Além disso, a solicitação de captura estática contém os parâmetros retornados por ImageCaptureExtenderImpl.getCaptureStages() .

Finalmente, Camera2/X invoca onDeInit() após o término da sessão da câmera. Você pode liberar recursos em onDeinit() .

Processador de visualização

Além do HAL da câmera, você também pode implementar extensões em um processador.

Implemente PreviewExtenderImpl.getProcessorType para especificar o tipo de processador conforme explicado abaixo:

  • PROCESSOR_TYPE_NONE : Sem processador. As imagens são processadas na câmera HAL.

  • PROCESSOR_TYPE_REQUEST_UPDATE_ONLY : o tipo de processador permite atualizar a solicitação repetida com novos parâmetros de solicitação de captura com base no TotalCaptureResult mais recente.

    PreviewExtenderImpl.getProcessor deve retornar uma instância RequestUpdateProcessorImpl que processa a instância TotalCaptureResult e retorna uma instância CaptureStageImpl para atualizar a solicitação repetida. PreviewExtenderImpl.getCaptureStage() também deve refletir o resultado do processamento e retornar o CaptureStageImpl mais recente.

  • PROCESSOR_TYPE_IMAGE_PROCESSOR : Este tipo permite implementar um processador para processar imagens YUV_420_888 e gravar a saída em uma superfície PRIVATE .

    Você precisa implementar e retornar uma instância PreviewImageProcessorImpl em PreviewExtenderImpl.getProcessor . O processador é responsável pelo processamento das imagens de entrada YUV_420_888 . Deve gravar a saída no formato PRIVATE de visualização. Camera2/X usa uma superfície YUV_420_888 em vez de PRIVATE para configurar CameraCaptureSession para visualização.

    Veja a ilustração a seguir para o fluxo:

Processador de visualização

Figura 6. Fluxo de visualização com PreviewImageProcessorImpl

A interface PreviewImageProcessorImpl estende ProcessImpl e possui três métodos importantes:

  • onOutputSurface(Surface surface, int imageFormat) define a superfície de saída para o processador. Para PreviewImageProcessorImpl , imageFormat é um formato de pixel como PixelFormat.RGBA_8888 .

  • onResolutionUpdate(Size size) define o tamanho da imagem de entrada.

  • onImageFormatUpdate(int imageFormat) define o formato da imagem de entrada. Atualmente, só pode ser YUV_420_888 .

Processador de captura de imagem

Para captura estática, você pode implementar um processador retornando uma instância CaptureProcessorImpl usando ImageCaptureExtenderImpl.getCaptureProcessor . O processador é responsável por processar uma lista de imagens YUV_420_888 capturadas e instâncias TotalCaptureResult e gravar a saída em uma superfície YUV_420_888 .

Você pode assumir com segurança que a visualização está habilitada e em execução antes de enviar a solicitação de captura estática.

Veja o fluxo no diagrama abaixo:

Processador de Captura

Figura 7. Fluxo de captura contínua com CaptureProcessorImpl

  1. Camera2/X usa uma superfície de formato YUV_420_888 para captura estática para configurar a sessão de captura. Camera2/X prepara CaptureProcessorImpl chamando:

    • CaptureProcessorImpl.onImageFormatUpdate() com YUV_420_888 .
    • CaptureProcessorImpl.onResolutionUpdate() pelo tamanho da imagem de entrada.
    • CaptureProcessorImpl.onOutputSurface() com uma superfície de saída YUV_420_888 .
  2. ImageCaptureExtenderImpl.getCaptureStages retorna uma lista de CaptureStageImpl , onde cada elemento é mapeado para uma instância CaptureRequest com parâmetros de captura que são enviados por Camera2/X. Por exemplo, se retornar uma lista de três instâncias CaptureStageImpl , Camera2/X enviará três solicitações de captura com parâmetros de captura correspondentes usando a API captureBurst .

  3. As imagens recebidas e as instâncias TotalCaptureResult são agrupadas e enviadas ao CaptureProcessorImpl para processamento.

  4. CaptureProcessorImpl grava a imagem resultante (formato YUV_420_888 ) na superfície de saída especificada pela chamada onOutputSurface() . Camera2/X converte-o em imagens JPEG, se necessário.

Chaves e resultados de solicitação de captura de suporte

Além da visualização e captura da câmera, os aplicativos podem definir zoom, parâmetros de flash ou acionar um toque para focar. Esses parâmetros podem não ser compatíveis com a implementação da sua extensão.

Os métodos a seguir foram adicionados ao extensions-interface 1.3.0 para permitir que você exponha os parâmetros suportados pela sua implementação:

  • ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys() retorna as chaves de solicitação de captura suportadas pela sua implementação.
  • ImageCaptureExtenderImpl.getAvailableCaptureResultKeys() retorna as chaves do resultado da captura que estão contidas no resultado da captura.

Se o HAL da câmera processar a extensão, Camera2/X recuperará os resultados da captura em CameraCaptureSession.CaptureCallback . No entanto, se o processador for implementado, o Camera2/X recupera os resultados da captura em ProcessResultImpl , que é passado para o método process() em PreviewImageProcessorImpl e CaptureProcessorImpl . Você é responsável por relatar o resultado da captura por meio ProcessResultImpl para Camera2/X.

Consulte a definição da interface CaptureProcessorImpl abaixo como exemplo. Na extensions-interface 1.3.0 ou superior, a segunda chamada process() é invocada:

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);
}

Para operações comuns de câmera, como zoom, toque para focar, flash e compensação de exposição, recomendamos oferecer suporte às seguintes teclas para solicitação e resultado de captura:

  • Ampliação:
    • CaptureRequest#CONTROL_ZOOM_RATIO
    • CaptureRequest#SCALER_CROP_REGION
  • Toque para focar:
    • CaptureRequest#CONTROL_AF_MODE
    • CaptureRequest#CONTROL_AF_TRIGGER
    • CaptureRequest#CONTROL_AF_REGIONS
    • CaptureRequest#CONTROL_AE_REGIONS
    • CaptureRequest#CONTROL_AWB_REGIONS
  • Clarão:
    • CaptureRequest#CONTROL_AE_MODE
    • CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
    • CaptureRequest#FLASH_MODE
  • Compensação de exposição:
    • CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION

Para extensores básicos que implementam versões 1.2.0 ou anteriores, a API CameraX Extensions suporta explicitamente todas as chaves acima. Para extensions-interface 1.3.0, tanto CameraX quanto Camera2 respeitam a lista retornada e suportam apenas as chaves contidas nela. Por exemplo, se você decidir retornar apenas CaptureRequest#CONTROL_ZOOM_RATIO e CaptureRequest#SCALER_CROP_REGION na implementação 1.3.0, isso significa que apenas o zoom é compatível com o aplicativo, enquanto o toque para focar, o flash e a compensação de exposição não são permitidos.

Extensor Avançado

Advanced Extender é um tipo de implementação de fornecedor baseado na API Camera2. Este tipo de Extender foi adicionado na extensions-interface 1.2.0. Dependendo do fabricante do dispositivo, as extensões podem ser implementadas na camada do aplicativo, o que depende dos seguintes fatores:

  • Configuração de stream personalizada: configure streams personalizados como stream RAW ou tenha vários streams para diferentes IDs de câmera física.

  • Capacidade de enviar solicitações Camera2: Suporta uma lógica de interação complicada que pode enviar solicitações de captura com parâmetros baseados nos resultados de solicitações anteriores.

O Advanced Extender fornece um wrapper, ou uma camada intermediária, para que você possa customizar a configuração do fluxo e enviar solicitações de captura sob demanda.

Arquivos para implementar

Para mudar para a implementação do Advanced Extender, o método isAdvancedExtenderImplemented() em ExtensionVersionImpl deve retornar true . Para cada tipo de extensão, os OEMs devem implementar as classes Extender correspondentes. Os arquivos de implementação do Advanced Extender estão no pacote avançado .

Classes extensoras para implementar
Noite advanced/NightAdvancedExtenderImpl.java
HDR advanced/HdrAdvancedExtenderImpl.java
Auto advanced/AutoAdvancedExtenderImpl.java
Bokeh advanced/BokehAdvancedExtenderImpl.java
Retoque facial advanced/BeautyAdvancedExtenderImpl.java

Usamos AdvancedExtenderImpl como espaço reservado no exemplo a seguir. Substitua-o pelo nome do arquivo Extender da extensão que você está implementando.

Vamos ver como Camera2/X invoca a extensions-interface para atingir os três fluxos de aplicativo.

Fluxo de aplicativo 1: verificar a disponibilidade de extensões

AdvancedAppFlow1

Figura 8. Fluxo de aplicativo 1 no Advanced Extender

Primeiro, o aplicativo verifica se a extensão fornecida é compatível.

Fluxo de aplicativo 2: consultar informações

AdvancedAppFlow2

Figura 9. Fluxo de aplicativo 2 no Advanced Extender

Depois de chamar AdvancedExtenderImpl.init() , o aplicativo pode consultar as seguintes informações em AdvancedExtenderImpl :

  • Latência estimada de captura ainda: AdvancedExtenderImpl.getEstimatedCaptureLatencyRange() retorna o intervalo de latência de captura para o aplicativo avaliar se é apropriado habilitar a extensão para o cenário atual.

  • Resoluções suportadas para visualização e captura:

    • AdvancedExtenderImpl.getSupportedPreviewOutputResolutions() retorna um mapa de formato de imagem para a lista de tamanhos que são suportados para formato e tamanho de superfície de visualização. Os OEMs devem suportar pelo menos o formato PRIVATE .

    • AdvancedExtenderImpl.getSupportedCaptureOutputResolutions() retorna o formato e os tamanhos suportados para a superfície de captura estática. Os OEMs devem oferecer suporte à saída no formato JPEG e YUV_420_888 .

    • AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions() retorna os tamanhos suportados para um fluxo YUV_420_888 extra para análise de imagem. Se a superfície YUV de análise de imagem não for compatível, getSupportedYuvAnalysisResolutions() deverá retornar null ou uma lista vazia.

  • Chaves/resultados de solicitação de captura disponíveis (adicionados na extensions-interface 1.3.0): Camera2/X invoca os seguintes métodos para recuperar as chaves de solicitação de captura e chaves de resultado suportadas de sua implementação:

    • AdvancedExtenderImpl.getAvailableCaptureRequestKeys
    • AdvancedExtenderImpl.getAvailableCaptureResultKeys

Para obter mais informações, consulte Chaves e resultados de solicitação de captura de suporte .

Fluxo de aplicativo 3: visualização/captura estática com extensão ativada

AdvancedAppFlow3

Figura 10. Fluxo de aplicativo 3 no Advanced Extender

O diagrama acima mostra o fluxo principal para iniciar a visualização e capturar imagens para o tipo Advanced Extender. Vamos percorrer cada etapa.

  1. Instância SessionProcessorImpl

    A implementação principal do Advanced Extender está em SessionProcessorImpl , que é responsável por fornecer configuração de sessão customizada e enviar solicitações de captura para iniciar a visualização e ainda a solicitação de captura. AdvancedExtenderImpl.createSessionProcessor() é invocado para retornar a instância SessionProcessorImpl .

  2. initSession

    SessionProcessorImpl.initSession() inicializa a sessão para a extensão. É aqui que você aloca recursos e retorna uma configuração de sessão para preparar uma CameraCaptureSession .

    Para os parâmetros de entrada, Camera2/X especifica as configurações da superfície de saída para visualização, captura estática e uma análise de imagem YUV opcional. Esta configuração de superfície de saída ( OutputSurfaceImpl ) contém a superfície, o tamanho e o formato da imagem que são recuperados pelos seguintes métodos em AdvancedExtenderImpl :

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

    Você deve retornar uma instância Camera2SessionConfigImpl , que consiste em uma lista de instâncias Camera2OutputConfigImpl e os parâmetros de sessão usados ​​para configurar CameraCaptureSession . Você é responsável por enviar as imagens corretas da câmera para as superfícies de saída transmitidas pela Camera2/X. Aqui estão algumas opções para ativar a saída:

    • Processamento na câmera HAL: você pode adicionar diretamente as superfícies de saída ao CameraCaptureSession com uma implementação SurfaceOutputConfigImpl . Isso configura a superfície de saída fornecida ao pipeline da câmera e permite que o HAL da câmera processe a imagem.
    • Processando superfície ImageReader intermediária (RAW, YUV, etc): Adicione as superfícies ImageReader intermediárias ao CameraCaptureSession com uma instância ImageReaderOutputConfigImpl .

      Você precisa processar as imagens intermediárias e gravar a imagem resultante na superfície de saída.

    • Use o compartilhamento de superfície Camera2: use o compartilhamento de superfície com outra superfície adicionando qualquer instância Camera2OutputConfigImpl ao método getSurfaceSharingOutputConfigs() de outra instância Camera2OutputConfigImpl . O formato e tamanho da superfície devem ser idênticos.

    Todos Camera2OutputConfigImpl incluindo SurfaceOutputConfigImpl e ImageReaderOutputConfigImpl devem ter um ID exclusivo ( getId() ), que é usado para especificar a superfície de destino e recuperar a imagem de ImageReaderOutputConfigImpl .

  3. onCaptureSessionStart e RequestProcessorImpl

    Quando CameraCaptureSession é iniciado e a estrutura Camera invoca onConfigured() , Camera2/X invoca SessionProcessorImpl.onCaptureSessionStart() com o wrapper de solicitação Camera2 RequestProcessImpl . Camera2/X implementa RequestProcessImpl , que permite executar as solicitações de captura e recuperar imagens se ImageReaderOutputConfigImpl for usado.

    As APIs RequestProcessImpl são semelhantes às APIs Camera2 CameraCaptureSession em termos de execução de solicitações. As diferenças são:

    • A superfície de destino é especificada pelo ID da instância Camera2OutputConfigImpl .
    • A capacidade de recuperar a imagem do ImageReader .

    Você pode chamar RequestProcessorImpl.setImageProcessor() com um ID Camera2OutputConfigImpl especificado para registrar uma instância ImageProcessorImpl para receber imagens.

    A instância RequestProcessImpl torna-se inválida depois que Camera2/X chama SessionProcessorImpl.onCaptureSessionEnd() .

  4. Inicie a visualização e tire uma foto

    Na implementação do Advanced Extender, é possível enviar solicitações de captura por meio da interface RequestProcessorImpl . Camera2/X notifica você para iniciar a solicitação repetida de visualização ou a sequência de captura estática chamando SessionProcessorImpl#startRepeating e SessionProcessorImpl#startCapture respectivamente. Você deve enviar solicitações de captura para atender a essas solicitações de visualização e captura ainda.

    Camera2/X também define os parâmetros de solicitação de captura por meio de SessionProcessorImpl#setParameters . Você deve definir esses parâmetros de solicitação (se os parâmetros forem suportados) nas solicitações repetidas e únicas.

    Você deve oferecer suporte a pelo menos CaptureRequest.JPEG_ORIENTATION e CaptureRequest.JPEG_QUALITY . extensions-interface 1.3.0 suporta chaves de solicitação e resultado, que são expostas pelos seguintes métodos:

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

    Quando os desenvolvedores definem as chaves na lista getAvailableCaptureRequestKeys , você deve ativar os parâmetros e garantir que o resultado da captura contenha as chaves na lista getAvailableCaptureResultKeys .

  5. startTrigger

    SessionProcessorImpl.startTrigger() é invocado para iniciar o gatilho como CaptureRequest.CONTROL_AF_TRIGGER e CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER . Você pode desconsiderar quaisquer chaves de solicitação de captura que não foram anunciadas em AdvancedExtenderImpl.getAvailableCaptureRequestKeys() .

    startTrigger() é suportado desde extensions-interface 1.3.0. Ele permite que os aplicativos implementem toque para focar e flash com extensões.

  6. Limpar

    Ao finalizar uma sessão de captura, SessionProcessorImpl.onCaptureSessionEnd() é invocado antes do fechamento de CameraCaptureSession . Após o encerramento da sessão de captura, deInitSession() executa a limpeza.

Suporte para visualização, captura estática e análise de imagens

Você deve aplicar a extensão para casos de uso de visualização e ainda de captura. No entanto, se a latência for muito alta para mostrar a visualização sem problemas, você poderá aplicar a extensão apenas para captura estática.

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.

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 \

Validation

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.

Frequently asked questions (FAQs)

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 .