Os fabricantes de dispositivos podem expor extensões como bokeh, modo noturno e HDR para desenvolvedores terceirizados usando a interface de extensões de câmera fornecida pela biblioteca do fornecedor OEM. Os desenvolvedores podem usar a API Extensions do Camera2 e a API Extensions do CameraX para acessar as extensões implementadas na biblioteca do fornecedor OEM.
Para conferir uma lista de extensões compatíveis, que é a mesma no Camera2 e no CameraX, consulte API CameraX Extensions. Se quiser adicionar uma extensão, informe um bug com o Issue Tracker.
Nesta página, descrevemos 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
:
Figura 1. Diagrama da arquitetura das extensões de câmera
Como mostrado no diagrama, para oferecer suporte às extensões de câmera, é necessário
implementar o extensions-interface
fornecido pela biblioteca do fornecedor OEM. A
biblioteca do fornecedor OEM ativa duas APIs:
API Extensions do CameraX e
API Extensions do Camera2,
que são usadas pelos apps CameraX e Camera2, respectivamente, para acessar
extensões do fornecedor.
Implementar a biblioteca do fornecedor OEM
Para implementar a biblioteca do fornecedor OEM, copie os arquivos
camera-extensions-stub
para um projeto de biblioteca do sistema. Esses arquivos definem a interface Camera Extensions.
Os arquivos camera-extensions-stub
são divididos nas seguintes categorias:
Arquivos essenciais da interface (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 de extensão do bokeh (implemente se a extensão do bokeh for compatível)
BokehImageCaptureExtenderImpl.java
BokehPreviewExtenderImpl.java
advanced/BokehAdvancedExtenderImpl.java
Classes de extensão noturna (implemente se a extensão noturna for compatível)
NightImageCaptureExtenderImpl.java
NightPreviewExtenderImpl.java
advanced/NightAdvancedExtenderImpl.java
Classes de extensão automática (implemente se a extensão automática for compatível)
AutoImageCaptureExtenderImpl.java
AutoPreviewExtenderImpl.java
advanced/AutoAdvancedExtenderImpl.java
Classes de extensão de HDR (implemente se a extensão de HDR for compatível)
HdrImageCaptureExtenderImpl.java
HdrPreviewExtenderImpl.java
advanced/HdrAdvancedExtenderImpl.java
Classes de extensão de retoque facial (implemente se a extensão de retoque facial for compatível)
BeautyImageCaptureExtenderImpl.java
BeautyPreviewExtenderImpl.java
advanced/BeautyAdvancedExtenderImpl.java
Utilitários (opcional, pode ser excluído)
advanced/Camera2OutputConfigImplBuilder.java
advanced/Camera2SessionConfigImplBuilder.java
Não é necessário fornecer uma implementação para cada extensão. Se você
não implementar uma extensão, defina isExtensionAvailable()
para retornar false
ou
remova as classes Extender correspondentes. As APIs Camera2 e CameraX Extensions
informam ao app que a extensão não está disponível.
Vamos explicar como as APIs Extensions do Camera2 e do CameraX interagem com a biblioteca do fornecedor para ativar uma extensão. O diagrama a seguir ilustra o fluxo de ponta a ponta usando a extensão Night como exemplo:
Figura 2. Implementação da extensão noturna
Verificação de versão:
O Camera2/X chama
ExtensionVersionImpl.checkApiVersion()
para garantir que a versãoextensions-interface
implementada pelo OEM seja compatível com as versões compatíveis do Camera2/X.Inicialização da biblioteca do fornecedor:
O
InitializerImpl
tem um métodoinit()
que inicializa a biblioteca do fornecedor. O Camera2/X conclui a inicialização antes de acessar as classes Extender.Instancie classes Extender:
Instancia as classes Extender para a extensão. Há dois tipos de Extender: Basic Extender e Advanced Extender. É necessário implementar um tipo de extensor para todas as extensões. Para mais informações, consulte Extensor básico x Extensor avançado.
O Camera2/X cria instâncias e interage com as classes Extender para recuperar informações e ativar a extensão. Para uma determinada extensão, o Camera2/X pode instanciar as classes Extender várias vezes. Como resultado, não faça inicializações pesadas no construtor ou na chamada
init()
. Faça o trabalho pesado apenas quando a sessão da câmera estiver prestes a começar, como quandoonInit()
é chamado no Basic Extender ouinitSession()
é chamado no Advanced Extender.Para a extensão Night, as seguintes classes de extensão são instanciadas para o tipo de extensão Basic:
NightImageCaptureExtenderImpl.java
NightPreviewExtenderImpl.java
E para o tipo Advanced Extender:
NightAdvancedExtenderImpl.java
Verificar a disponibilidade da extensão:
Antes de ativar a extensão, o
isExtensionAvailable()
verifica se ela está disponível no ID da câmera especificada pela instância do Extender.Inicialize o Extender com informações da câmera:
O Camera2/X chama
init()
na instância do Extender e transmite o ID da câmera eCameraCharacteristics
.Informações da consulta:
Invoca a classe Extender para recuperar informações como resoluções compatíveis, captura de latência estimada e chaves de solicitação do Extender em preparação para ativar a extensão.
Ative a extensão no Extender:
A classe Extender fornece todas as interfaces necessárias para ativar a classe. Ele oferece um mecanismo para conectar a implementação do OEM ao pipeline da Camera2, como a injeção de parâmetros de solicitação de captura ou a ativação de um pós-processador.
Para o tipo de extensor avançado, o Camera2/X interage com
SessionProcessorImpl
para ativar a extensão. O Camera2/X recupera a instânciaSessionProcessorImpl
chamandocreateSessionProcessor()
no Extender.
As seções a seguir descrevem o fluxo de extensão em mais detalhes.
Verificação de versão
Ao carregar a biblioteca do fornecedor OEM do dispositivo no ambiente de execução, o Camera2/X
verifica se a biblioteca é compatível com a versão do extensions-interface
.
O extensions-interface
usa o controle de versões semântico, ou
PRINCIPAL.SECUNDÁRIA.PATCH, por exemplo, 1.1.0 ou 1.2.0. No entanto, apenas as versões principal e secundária são usadas durante a verificação.
Para verificar a versão, o Camera2/X chama
ExtensionVersionImpl.checkApiVersion()
com a versão
extensions-interface
compatível. O Camera2/X usa a versão informada pela
biblioteca do OEM para determinar se a extensão pode ser ativada e quais recursos
ela deve invocar.
Compatibilidade com versões principais
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
Desde que a versão principal seja idêntica, o Camera2/X garante compatibilidade com versões anteriores com bibliotecas de fornecedores OEM criadas com versões extensions-interface
anteriores. Por exemplo, se o Camera2/X for compatível com
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 futuras do extension-interface
.
Compatibilidade com versões futuras
A compatibilidade futura com bibliotecas de fornecedores de extensions-interface
mais recentes
depende de você, o OEM. Se você precisar de alguns recursos para implementar as extensões,
convém ativar as extensões a partir de uma determinada versão. Nesse
caso, retorne a versão extensions-interface
compatível quando a versão da biblioteca
Camera2/X atender aos requisitos. Se as versões do Camera2/X
não forem compatíveis, retorne uma versão incompatível, como 99.0.0, para
desativar as extensões.
Inicialização da biblioteca do fornecedor
Depois de verificar a versão do extensions-interface
implementada pela biblioteca
do OEM, a Camera2/X inicia o processo de inicialização. O método
InitializerImpl.init()
sinaliza para a biblioteca do OEM que um app está tentando
usar extensões.
O Camera2/X não faz outras chamadas para a biblioteca do OEM (além da verificação de versão)
até que a biblioteca do fornecedor do OEM chame OnExtensionsInitializedCallback.onSuccess()
para notificar a conclusão da inicialização.
É necessário implementar
InitializerImpl
a partir do extensions-interface
1.1.0. O Camera2/X pula a etapa de inicialização da biblioteca se a biblioteca do fornecedor OEM implementar o extensions-interface
1.0.0.
Extensor básico x Extensor avançado
Há dois tipos de implementação do extensions-interface
: Basic Extender e Advanced Extender. O Advanced Extender tem suporte desde
extensions-interface
1.2.0.
Implemente o Basic Extender para extensões que processam imagens no HAL da câmera ou usam um pós-processador capaz de processar streams YUV.
Implemente o Advanced Extender para extensões que precisam personalizar a configuração de fluxo do Camera2 e enviar solicitações de captura conforme necessário.
Confira a tabela a seguir para a comparação:
Extensor básico | Extensor avançado | |
---|---|---|
Configurações de transmissão | Corrigido Prévia: PRIVATE ou YUV_420_888 (se o processador existir) Captura estática: JPEG ou YUV_420_888 (se o processador existir)
|
Personalizável pelo OEM. |
Enviando solicitação de captura | Somente o Camera2/X pode enviar solicitações de captura. É possível definir os parâmetros para essas solicitações. Quando o processador é fornecido para captura de imagem, o Camera2/X pode enviar várias solicitações de captura e enviar todas as imagens e resultados de captura para o processador. | Uma instância RequestProcessorImpl é fornecida para você executar a solicitação de captura da Camera2 e receber resultados e imagens.
O Camera2/X invoca |
Hooks no pipeline da câmera |
|
|
Adequado para | Extensões implementadas na HAL da câmera ou em um processador que processa imagens YUV. |
|
Versão da API compatível | Extensões do Camera2: Android 13 ou versões mais recentes Extensões do CameraX: camera-extensions 1.1.0 ou versões mais recentes |
Extensões do Camera2: Android 12L ou mais recente Extensões do CameraX: camera-extensions 1.2.0-alpha03 ou mais recente |
Fluxos de apps
A tabela a seguir mostra três tipos de fluxos de apps e as chamadas de API Camera Extensions correspondentes. Embora o Camera2/X forneça essas APIs, é necessário implementar corretamente a biblioteca do fornecedor para oferecer suporte a esses fluxos, que descrevemos em mais detalhes em uma seção posterior.
Extensões do Camera2 | Extensões do CameraX | |
---|---|---|
Disponibilidade da extensão de consulta | CameraExtensionCharacteristics
.getSupportedExtensions
|
ExtensionsManager.
isExtensionAvailable
|
Informações da consulta | CameraExtensionCharacteristics.
getExtensionSupportedSizes
CameraExtensionCharacteristics.
getEstimatedCaptureLatencyRangeMillis
CameraExtensionCharacteristics.
getAvailableCaptureRequestKeys
CameraExtensionCharacteristics.
getAvailableCaptureResultKeys
|
ExtensionsManager.
getEstimatedCaptureLatencyRange
O CameraX processa o restante das informações na biblioteca. |
Visualizar e capturar imagens estáticas com a extensão ativada | CameraDevice.
createExtensionSession
|
val cameraSelector = ExtensionsManager.
getExtensionEnabledCameraSelector
|
Extensor básico
A interface Basic Extender fornece hooks em vários lugares no pipeline da câmera. Cada tipo de extensão tem classes Extender correspondentes que os OEMs precisam implementar.
A tabela a seguir lista as classes de extensão que os OEMs precisam implementar para cada extensão:
Classes de extensão para implementar | |
---|---|
Noite | NightPreviewExtenderImpl.java
|
HDR | HdrPreviewExtenderImpl.java
|
Automóveis | AutoPreviewExtenderImpl.java
|
Bokeh | BokehPreviewExtenderImpl.java
|
Retoque facial | BeautyPreviewExtenderImpl.java
|
Usamos PreviewExtenderImpl
e ImageCaptureExtenderImpl
como marcadores no exemplo a seguir. Substitua esses nomes pelos nomes dos arquivos
reais que você está implementando.
O Basic Extender tem os seguintes recursos:
- Injete parâmetros de sessão ao configurar
CameraCaptureSession
(onPresetSession
). - Notificar você sobre os eventos de início e encerramento 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 prévia e captura de imagens estáticas capazes de processar o fluxo
YUV_420_888
.
Vamos ver como o Camera2/X invoca o extensions-interface
para alcançar os três fluxos de
apps mencionados acima.
Fluxo do app 1: verificar a disponibilidade da extensão
Figura 3. Fluxo de app 1 no Basic Extender
Nesse fluxo, o Camera2/X chama diretamente o método isExtensionAvailable()
de
PreviewExtenderImpl
e ImageCaptureExtenderImpl
sem chamar
init()
. As duas classes de extensão precisam retornar true
para ativar as extensões.
Essa é geralmente a primeira etapa para os apps verificarem se o tipo de extensão especificado é compatível com um determinado ID de câmera antes de ativar a extensão. Isso ocorre porque algumas extensões são compatíveis apenas com determinados IDs de câmera.
Fluxo do app 2: informações da consulta
Figura 4. Fluxo de app 2 no Basic Extender
Depois de determinar se a extensão está disponível, os apps precisam consultar as seguintes informações antes de ativar a extensão.
Intervalo de latência de captura estática:o
ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
retorna o intervalo de latência de captura para que o app avalie se é adequado ativar a extensão para o cenário atual.Tamanhos compatíveis para a superfície de visualização e captura:
ImageCaptureExtenderImpl.getSupportedResolutions
ePreviewExtenderImpl.getSupportedResolutions
retornam uma lista de formatos de imagem e os tamanhos compatíveis para formato e tamanho da superfície.Chaves de solicitação e resultado compatíveis:o Camera2/X invoca os seguintes métodos para recuperar as chaves de solicitação e resultado de captura compatíveis da sua implementação:
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
ImageCaptureExtenderImpl.getAvailableCapturetResultKeys
O Camera2/X sempre chama init()
primeiro nessas classes Extender antes de consultar
mais informações.
Fluxo do app 3: captura de prévia/imagem estática com extensão ativada (implementação da HAL)
Figura 5. Fluxo de app 3 no Basic Extender
O diagrama acima ilustra o fluxo principal de ativação da captura de visualização e ainda com uma extensão sem processador. Isso significa que o HAL da câmera processa a extensão.
Nesse fluxo, o Camera2/X primeiro chama init()
e depois onInit
, que notifica você
que uma sessão de câmera está prestes a começar com as extensões especificadas.
Você pode fazer a inicialização pesada em onInit()
.
Ao configurar CameraCaptureSession
, o Camera2/X invoca
onPresetSession
para receber os parâmetros da sessão. Depois que a sessão de captura é
configurada, o Camera2/X invoca onEnableSession
retornando uma
instância CaptureStageImpl
que contém os parâmetros de captura. O Camera2/X
envia imediatamente uma única solicitação com esses parâmetros de captura para notificar o
HAL. Da mesma forma, antes de a sessão de captura ser fechada, o Camera2/X invoca
onDisableSession
e envia uma única solicitação com os parâmetros de captura
retornados.
A solicitação repetida acionada pelo Camera2/X contém os parâmetros de solicitação
retornados por PreviewExtenderImpl.getCaptureStage()
. Além disso, a solicitação de captura de imagem
contém os parâmetros retornados por
ImageCaptureExtenderImpl.getCaptureStages()
.
Por fim, o Camera2/X invoca onDeInit()
depois que a sessão da câmera é concluída.
Você pode liberar recursos em onDeinit()
.
Processador de visualização
Além da HAL da câmera, também é possível implementar extensões em um processador.
Implemente PreviewExtenderImpl.getProcessorType
para especificar o tipo de processador, conforme explicado abaixo:
PROCESSOR_TYPE_NONE
:nenhum processador. As imagens são processadas no HAL da câmera.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 noTotalCaptureResult
mais recente.PreviewExtenderImpl.getProcessor
precisa retornar uma instânciaRequestUpdateProcessorImpl
que processa a instânciaTotalCaptureResult
e retorna uma instânciaCaptureStageImpl
para atualizar a solicitação repetida.PreviewExtenderImpl.getCaptureStage()
também precisa refletir o resultado do processamento e retornar oCaptureStageImpl
mais recente.PROCESSOR_TYPE_IMAGE_PROCESSOR
:esse tipo permite implementar um processador para processar imagensYUV_420_888
e gravar a saída em uma superfíciePRIVATE
.Você precisa implementar e retornar uma instância
PreviewImageProcessorImpl
emPreviewExtenderImpl.getProcessor
. O processador é responsável por processar imagens de entradaYUV_420_888
. Ele precisa gravar a saída no formatoPRIVATE
da prévia. O Camera2/X usa uma superfícieYUV_420_888
em vez dePRIVATE
para configurar oCameraCaptureSession
para visualização.Confira a ilustração a seguir para o fluxo:
Figura 6. Fluxo de prévia com PreviewImageProcessorImpl
A interface PreviewImageProcessorImpl
estende ProcessImpl
e tem três métodos importantes:
onOutputSurface(Surface surface, int imageFormat)
define a superfície de saída para o processador. ParaPreviewImageProcessorImpl
,imageFormat
é um formato de pixel, comoPixelFormat.RGBA_8888
.onResolutionUpdate(Size size)
define o tamanho da imagem de entrada.onImageFormatUpdate(int imageFormat)
define o formato da imagem de entrada. No momento, só pode serYUV_420_888
.
Processador de captura de imagem
Para captura de imagens estáticas, é possível 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 presumir que a prévia está ativada e em execução antes de enviar a solicitação de captura de imagem estática.
Confira o fluxo no diagrama abaixo:
Figura 7. Ainda capture o fluxo com CaptureProcessorImpl
O Camera2/X usa uma superfície de formato
YUV_420_888
para captura de imagens estáticas e configurar a sessão de captura. O Camera2/X preparaCaptureProcessorImpl
chamando:CaptureProcessorImpl.onImageFormatUpdate()
comYUV_420_888
.CaptureProcessorImpl.onResolutionUpdate()
com o tamanho da imagem de entrada.CaptureProcessorImpl.onOutputSurface()
com uma superfície de saídaYUV_420_888
.
ImageCaptureExtenderImpl.getCaptureStages
retorna uma lista deCaptureStageImpl
, em que cada elemento é mapeado para uma instânciaCaptureRequest
com parâmetros de captura enviados pelo Camera2/X. Por exemplo, se ele retornar uma lista de três instânciasCaptureStageImpl
, o Camera2/X enviará três solicitações de captura com parâmetros de captura correspondentes usando a APIcaptureBurst
.As imagens recebidas e as instâncias de
TotalCaptureResult
são agrupadas e enviadas paraCaptureProcessorImpl
para processamento.CaptureProcessorImpl
grava a imagem resultante (formatoYUV_420_888
) na superfície de saída especificada pela chamadaonOutputSurface()
. O Camera2/X a converte em imagens JPEG, se necessário.
Aceitar chaves e resultados de solicitações de captura
Além da visualização e captura da câmera, os apps 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 extensão.
Os seguintes métodos foram adicionados ao extensions-interface
1.3.0 para permitir
que você exponha os parâmetros compatíveis com sua implementação:
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys()
retorna as chaves de solicitação de captura compatíveis com sua implementação.ImageCaptureExtenderImpl.getAvailableCaptureResultKeys()
retorna as chaves de resultado da captura contidas no resultado da captura.
Se a HAL da câmera processar a extensão, o Camera2/X vai recuperar os resultados da captura em CameraCaptureSession.CaptureCallback
. No entanto, se o processador for implementado, o Camera2/X vai recuperar os resultados da captura em
ProcessResultImpl
, que é transmitido para o método process()
em
PreviewImageProcessorImpl
e
CaptureProcessorImpl
.
Você é responsável por informar o resultado da captura usando ProcessResultImpl
para Camera2/X.
Confira a definição da interface CaptureProcessorImpl
abaixo como exemplo.
No extensions-interface
1.3.0 ou versões mais recentes, 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 da câmera, como zoom, toque para focar, flash e compensação de exposição, recomendamos oferecer suporte às seguintes chaves para solicitação e resultado de captura:
- Zoom:
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
- Flash:
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 a versão 1.2.0 ou anterior, a API CameraX
Extensions oferece suporte explícito a todas as chaves acima. Para
extensions-interface
1.3.0, o CameraX e o Camera2 respeitam a lista retornada
e oferecem suporte apenas às 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 será compatível com o app, enquanto o toque para foco, o flash e a compensação de exposição não serão permitidos.
Extensor avançado
O Advanced Extender é um tipo de implementação do fornecedor com base na API Camera2.
Esse tipo de extensão foi adicionado no extensions-interface
1.2.0. Dependendo do fabricante do dispositivo, as extensões podem ser implementadas na camada de app, o que depende dos seguintes fatores:
Configuração de stream personalizada:configure streams personalizadas, como a RAW, ou tenha várias streams para diferentes IDs de câmera física.
Capacidade de enviar solicitações da Camera2:compatibilidade com 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 oferece um wrapper ou uma camada intermediária para que você possa personalizar a configuração de stream 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
precisa retornar true
. Para cada tipo de extensão, os OEMs precisam implementar as
classes Extender correspondentes. Os arquivos de implementação do Advanced Extender estão no pacote advanced.
Classes de extensão a serem implementadas | |
---|---|
Noite | advanced/NightAdvancedExtenderImpl.java
|
HDR | advanced/HdrAdvancedExtenderImpl.java
|
Automóveis | advanced/AutoAdvancedExtenderImpl.java
|
Bokeh | advanced/BokehAdvancedExtenderImpl.java
|
Retoque facial | advanced/BeautyAdvancedExtenderImpl.java
|
Usamos AdvancedExtenderImpl
como marcador de posição no exemplo a seguir.
Substitua pelo nome do arquivo Extender da extensão que você está
implementando.
Vamos ver como o Camera2/X invoca o extensions-interface
para alcançar os três fluxos
de apps.
Fluxo do app 1: verificar a disponibilidade de extensões
Figura 8. Fluxo de app 1 no Advanced Extender
Primeiro, o app verifica se a extensão especificada é compatível.
Fluxo do app 2: informações da consulta
Figura 9. Fluxo de app 2 no Advanced Extender
Depois de chamar AdvancedExtenderImpl.init()
, o app pode consultar as
seguintes informações em AdvancedExtenderImpl
:
Latência estimada de captura estática:o
AdvancedExtenderImpl.getEstimatedCaptureLatencyRange()
retorna o intervalo da latência de captura para que o app avalie se é adequado ativar a extensão para o cenário atual.Resoluções compatíveis para visualização e captura estática:
AdvancedExtenderImpl.getSupportedPreviewOutputResolutions()
retorna um mapa do formato da imagem para a lista de tamanhos compatíveis com o formato e o tamanho da superfície de visualização. Os OEMs precisam ser compatíveis com pelo menos o formatoPRIVATE
.AdvancedExtenderImpl.getSupportedCaptureOutputResolutions()
retorna o formato e os tamanhos compatíveis para a superfície de captura de imagens estáticas. Os OEMs precisam oferecer suporte à saída nos formatosJPEG
eYUV_420_888
.AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
retorna os tamanhos compatíveis para um fluxoYUV_420_888
extra para análise de imagem. Se a superfície YUV de análise de imagem não for compatível,getSupportedYuvAnalysisResolutions()
vai retornarnull
ou uma lista vazia.
Chaves/resultados de solicitação de captura disponíveis (adicionado no
extensions-interface
1.3.0): o Camera2/X invoca os seguintes métodos para recuperar as chaves de solicitação de captura e de resultado compatíveis da sua implementação:AdvancedExtenderImpl.getAvailableCaptureRequestKeys
AdvancedExtenderImpl.getAvailableCaptureResultKeys
Para mais informações, consulte Suporte a chaves e resultados de solicitação de captura.
Fluxo do app 3: captura de prévia/imagem estática com extensão ativada
Figura 10. Fluxo de app 3 no Advanced Extender
O diagrama acima mostra o fluxo principal para iniciar a prévia e a captura de imagem para o tipo de extensor avançado. Vamos analisar cada etapa.
Instância do
SessionProcessorImpl
A implementação principal do Advanced Extender está em
SessionProcessorImpl
, que é responsável por fornecer configuração de sessão personalizada e enviar solicitações de captura para iniciar a visualização e ainda capturar a solicitação.AdvancedExtenderImpl.createSessionProcessor()
é invocado para retornar a instânciaSessionProcessorImpl
.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 umCameraCaptureSession
.Para os parâmetros de entrada, o Camera2/X especifica as configurações de superfície de saída para prévia, captura de imagem estática e uma análise de imagem YUV opcional. Essa configuração de superfície de saída (
OutputSurfaceImpl
) contém a superfície, o tamanho e o formato da imagem recuperados pelos seguintes métodos emAdvancedExtenderImpl
:getSupportedPreviewOutputResolutions()
getSupportedCaptureOutputResolutions()
getSupportedYuvAnalysisResolutions()
É necessário retornar uma instância
Camera2SessionConfigImpl
, que consiste em uma lista de instânciasCamera2OutputConfigImpl
e os parâmetros de sessão usados para configurarCameraCaptureSession
. Você é responsável por gerar as imagens corretas da câmera para as superfícies de saída transmitidas por Camera2/X. Confira algumas opções para ativar a saída:- Processamento na HAL da câmera:é possível adicionar diretamente as superfícies de saída
a
CameraCaptureSession
com uma implementação deSurfaceOutputConfigImpl
. Isso configura a superfície de saída fornecida para o pipeline da câmera e permite que a HAL da câmera processe a imagem. Processamento da superfície intermediária
ImageReader
(RAW, YUV etc.): adicione as superfícies intermediáriasImageReader
aoCameraCaptureSession
com uma instânciaImageReaderOutputConfigImpl
.É necessário processar as imagens intermediárias e gravar a imagem resultante na superfície de saída.
- Usar o compartilhamento de superfície do Camera2:use o compartilhamento de superfície com outra superfície
adicionando qualquer instância
Camera2OutputConfigImpl
ao métodogetSurfaceSharingOutputConfigs()
de outra instânciaCamera2OutputConfigImpl
. O formato e o tamanho da superfície precisam ser idênticos.
Todos os
Camera2OutputConfigImpl
, incluindoSurfaceOutputConfigImpl
eImageReaderOutputConfigImpl
, precisam ter um ID exclusivo (getId()
), que é usado para especificar a superfície de destino e recuperar a imagem deImageReaderOutputConfigImpl
.onCaptureSessionStart
eRequestProcessorImpl
Quando
CameraCaptureSession
é iniciado e o framework Camera invocaonConfigured()
, o Camera2/X invocaSessionProcessorImpl.onCaptureSessionStart()
com o wrapper de solicitaçãoRequestProcessImpl
do Camera2. O Camera2/X implementaRequestProcessImpl
, que permite executar as solicitações de captura e recuperar imagens seImageReaderOutputConfigImpl
for usado.As APIs
RequestProcessImpl
são semelhantes às APIs Camera2CameraCaptureSession
em termos de execução de solicitações. As diferenças são:- A plataforma de destino é especificada pelo ID da instância
Camera2OutputConfigImpl
. - A capacidade de recuperar a imagem do
ImageReader
.
Você pode chamar
RequestProcessorImpl.setImageProcessor()
com um IDCamera2OutputConfigImpl
especificado para registrar uma instânciaImageProcessorImpl
e receber imagens.A instância
RequestProcessImpl
se torna inválida depois que o Camera2/X chamaSessionProcessorImpl.onCaptureSessionEnd()
.- A plataforma de destino é especificada pelo ID da instância
Iniciar a visualização e tirar uma foto
Na implementação do Advanced Extender, é possível enviar solicitações de captura pela interface
RequestProcessorImpl
. O Camera2/X notifica você para iniciar a solicitação repetida de visualização ou a sequência de captura de fotos chamandoSessionProcessorImpl#startRepeating
eSessionProcessorImpl#startCapture
, respectivamente. Envie solicitações de captura para atender a essas solicitações de prévia e captura de imagem.A Camera2/X também define os parâmetros de solicitação de captura usando
SessionProcessorImpl#setParameters
. Você precisa definir esses parâmetros de solicitação (se compatíveis) nas solicitações únicas e repetidas.É preciso oferecer suporte a pelo menos
CaptureRequest.JPEG_ORIENTATION
eCaptureRequest.JPEG_QUALITY
. Oextensions-interface
1.3.0 é compatível com 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
, é necessário ativar os parâmetros e garantir que o resultado da captura contenha as chaves na listagetAvailableCaptureResultKeys
.startTrigger
SessionProcessorImpl.startTrigger()
é invocado para iniciar o gatilho, comoCaptureRequest.CONTROL_AF_TRIGGER
eCaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
. Você pode ignorar as chaves de solicitação de captura que não foram anunciadas emAdvancedExtenderImpl.getAvailableCaptureRequestKeys()
.O
startTrigger()
é compatível desde oextensions-interface
1.3.0. Ele permite que os apps implementem o toque para foco e o flash com extensões.Limpar
Ao terminar uma sessão de captura,
SessionProcessorImpl.onCaptureSessionEnd()
é invocado antes de fecharCameraCaptureSession
. Depois que a sessão de captura for fechada, odeInitSession()
fará a limpeza.
Suporte para prévia, captura de imagens estáticas e análise de imagens
Você precisa aplicar a extensão para os casos de uso de visualização e captura de imagens estáticas. No entanto, se a latência for muito alta para mostrar a prévia sem problemas, você poderá aplicar a extensão apenas para captura de imagens estáticas.
Para o tipo de extensão básica, independente de ativar a extensão para visualização,
é necessário implementar ImageCaptureExtenderImpl
e PreviewExtenderImpl
para uma determinada extensão. Muitas vezes, um app também usa um stream YUV para analisar o
conteúdo da imagem, como encontrar códigos QR ou texto. Para oferecer melhor suporte a esse caso de uso
, é necessário oferecer suporte à combinação de streams de visualização, captura de fotos e um
stream YUV_420_888
para configurar CameraCaptureSession
. Isso significa que, se você implementar um processador, precisará oferecer suporte à combinação de fluxo de três fluxos YUV_420_888
.
Para o Advanced Extender, o Camera2/X transmite três superfícies de saída para a chamada
SessionProcessorImpl.initSession()
. Essas superfícies de saída são para visualização
, captura de imagens estáticas e análise de imagens, respectivamente. Verifique se as superfícies de saída de prévia e captura de imagens mostram a saída válida. No entanto, para a superfície de saída da análise de imagem, verifique se ela está funcionando apenas quando não é nula. Se a implementação não puder oferecer suporte ao fluxo de análise de imagens, retorne uma lista vazia em AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
. Isso garante que a superfície de saída da análise de imagem seja sempre nula em SessionProcessorImpl.initSession()
.
Suporte para captura de vídeo
A arquitetura atual da extensão da câmera oferece suporte apenas aos casos de uso de visualização e captura de imagens estáticas. Não é possível ativar a extensão nas plataformas MediaCodec
ou MediaRecorder
para gravar o vídeo. No entanto, é possível
que os apps gravem a saída da prévia.
Estamos investigando a compatibilidade com plataformas MediaCodec
e MediaRecorder
.
Metadados específicos da extensão
No Android 14 e em versões mais recentes, os metadados específicos da extensão
permitem que os clientes de extensão de câmera definam e recebam configurações
e resultados de solicitação de captura específicos da extensão. Especificamente, os clientes de extensão de câmera
podem usar o parâmetro de solicitação de captura EXTENSION_STRENGTH
para controlar
a intensidade da extensão e o resultado da captura EXTENSION_CURRENT_TYPE
para
indicar o tipo de extensão ativada.
Capturar solicitações
O parâmetro de solicitação de captura
EXTENSION_STRENGTH
controla a intensidade do efeito de pós-processamento da extensão. O resultado da captura correspondente inclui o valor de intensidade padrão se esse parâmetro não for definido explicitamente pelo cliente. Esse parâmetro pode ser aplicado da seguinte forma para esses tipos de extensão:
BOKEH
: controla a quantidade de desfoque.HDR
eNIGHT
: controlam a quantidade de imagens combinadas e o brilho da imagem final.FACE_RETOUCH
: controla a quantidade de melhoria estética e suavização da pele.
O intervalo compatível para o parâmetro EXTENSION_STRENGTH
é entre 0
e 100
. 0
indica que não há processamento de extensão ou passagem simples, e 100
indica a intensidade máxima da extensão do efeito de processamento.
Para adicionar suporte a EXTENSION_STRENGTH
, use as APIs de parâmetros específicos do fornecedor introduzidas na versão 1.3.0 da interface da biblioteca de extensões. Para mais informações, consulte
getAvailableCaptureRequestKeys()
:
Capturar resultados
O resultado da captura
EXTENSION_CURRENT_TYPE
permite que as implementações de extensões notifiquem os clientes sobre o tipo de
extensão ativa.
Como as extensões que usam o tipo AUTO
alternam dinamicamente entre tipos de extensão, como HDR
e NIGHT
, dependendo das condições da cena, os apps de extensões de câmera podem usar EXTENSION_CURRENT_TYPE
para mostrar informações sobre a extensão atual selecionada pela extensão AUTO
.
Estimativa de latência de captura estática em tempo real
No Android 14 e versões mais recentes, os clientes de extensão de câmera
podem consultar estimativas de latência de captura estática em tempo real com base nas condições de cena e
ambiente usando
getRealtimeStillCaptureLatency()
. Esse método oferece estimativas mais precisas do que o método estático getEstimatedCaptureLatencyRangeMillis()
. Com base na estimativa de latência, os apps podem decidir pular o processamento
da extensão ou mostrar uma indicação para notificar os usuários sobre uma operação
de longa duração.
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();
Para oferecer suporte a estimativas de latência de captura estática em tempo real, implemente o seguinte:
- Extensões básicas:
ImageCaptureExtenderImpl.getRealtimeCaptureLatency()
- Extensões avançadas:
SessionProcessorImpl.getRealtimeCaptureLatency
Callbacks de progresso do processamento de captura
No Android 14 e versões mais recentes, os clientes de extensão de câmera podem receber callbacks para o progresso de operações de processamento de captura de imagens estáticas de longa duração. Os apps podem mostrar o progresso atual aos usuários para melhorar a experiência geral.
Os apps podem usar o seguinte código para integrar esse recurso:
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
}
}
…
}
Para oferecer suporte a callbacks de progresso do processamento de captura, a implementação do fornecedor da extensão precisa chamar os seguintes callbacks com o valor de progresso atual:
- Extensões básicas:
ProcessResultImpl.onCaptureProcessProgressed()
- Extensões avançadas:
CaptureCallback.onCaptureProcessProgressed()
Captura estática de PostView
No Android 14 e versões mais recentes, as extensões de câmera podem
fornecer uma pós-visualização (imagem de prévia) usando
setPostviewOutputConfiguration
.
Para melhorar a experiência do usuário, os apps podem mostrar uma imagem de pós-visualização como um marcador de posição quando uma extensão está com maior latência de processamento e substituir a imagem quando a final estiver disponível. Os apps podem configurar
e emitir solicitações de captura pós-visualização usando o seguinte código de referência:
{
…
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();
…
}
Para oferecer suporte à captura de imagens estáticas pós-visualização, a implementação do fornecedor precisa implementar o seguinte:
Extensões básicas:
CaptureProcessorImpl.onPostviewOutputSurface
eCaptureProcessorImpl.processWithPostview
Extensões avançadas:
SessionProcessorImpl.startCaptureWithPostview
Suporte de saída SurfaceView
No Android 14 e versões mais recentes, os clientes de extensão da câmera
podem usar caminhos de renderização de visualização otimizados para energia e performance registrando uma
instância SurfaceView
para saída de visualização em solicitações repetidas.
Para oferecer suporte à saída SurfaceView
, a implementação da extensão do fornecedor precisa ser
capaz de transmitir e gerar prévias para instâncias SurfaceView
. Para
verificar se isso é compatível, execute o módulo SurfaceViewExtensionPreviewTest.java
do CTS.
Tipos de sessão específicos do fornecedor
O recurso permite que as implementações de extensão do fornecedor selecionem um tipo de sessão específico do fornecedor que será definido na sessão interna de captura da câmera em vez do valor padrão.
O recurso funciona totalmente dentro do framework e da pilha do fornecedor e não tem impacto na API visível para o cliente/público.
Para selecionar um tipo de sessão específico do fornecedor, implemente o seguinte nas bibliotecas de extensão:
* ExtenderStateListener.onSessionType()
para extensões básicas
* Camera2SessionConfigImpl.getSessionType()
para extensões avançadas
Histórico de versões da interface das extensões
A tabela a seguir mostra o histórico de versões da interface Camera Extension. Sempre implemente a biblioteca do fornecedor com a versão mais recente.
Versão | Recursos adicionados |
---|---|
1.0.0 |
|
1.1.0 |
|
1.2.0 |
|
1.3.0 |
|
1.4.0 |
|
Implementação de referência
As seguintes implementações de biblioteca de fornecedores OEM de referência estão disponíveis em
frameworks/ex
.
advancedSample
: uma implementação básica do Advanced Extender.sample
: uma implementação básica do Basic Extender.service_based_sample
: uma implementação que demonstra como hospedar extensões de câmera em umService
. Essa implementação contém os seguintes componentes:oem_library
: uma biblioteca OEM de extensões da câmera para as APIs Camera2 e CameraX Extensions que implementaExtensions-Interface
. Ele funciona como uma transmissão que encaminha chamadas deExtensions-Interface
para o serviço. Essa biblioteca também fornece arquivos AIDL e classes wrapper para se comunicar com o serviço.O Advanced Extender está ativado por padrão. Para ativar o Basic Extender, mude
ExtensionsVersionImpl#isAdvancedExtenderImplemented
para retornarfalse
.extensions_service
: Uma implementação de amostra do serviço de extensões. Adicione sua implementação aqui. A interface a ser implementada no serviço é semelhante àExtensions-Interface
. Por exemplo, a implementação deIAdvancedExtenderImpl.Stub
executa as mesmas operações queAdvancedExtenderImpl
.ImageWrapper
eTotalCaptureResultWrapper
são obrigatórios para tornarImage
eTotalCaptureResult
parceláveis.
Configurar a biblioteca do fornecedor em um dispositivo
A biblioteca do fornecedor OEM não é integrada a um app. Ela é carregada do dispositivo
no tempo de execução pelo Camera2/X. No CameraX, a tag <uses-library>
declara que a biblioteca androidx.camera.extensions.impl
, definida no arquivo AndroidManifest.xml
da biblioteca camera-extensions
, é uma dependência do CameraX e precisa ser carregada no ambiente de execução. No Camera2, o framework carrega um serviço de extensões que
também declara que o <uses-library>
carrega a mesma biblioteca
androidx.camera.extensions.impl
durante a execução.
Isso permite que apps de terceiros que usam extensões carreguem automaticamente a biblioteca do fornecedor OEM. A biblioteca do OEM é marcada como opcional para que os apps possam ser executados em dispositivos que não têm a biblioteca. O Camera2/X processa esse comportamento automaticamente quando um app tenta usar uma extensão de câmera, desde que o fabricante do dispositivo coloque a biblioteca OEM no dispositivo para que ela possa ser descoberta pelo app.
Para configurar a biblioteca do OEM em um dispositivo, faça o seguinte:
- Adicione um arquivo de permissão, que é exigido pela tag
<uses-library>
, usando o seguinte formato:/etc/permissions/ANY_FILENAME.xml
. Por exemplo,/etc/permissions/camera_extensions.xml
. Os arquivos nesse diretório fornecem um mapeamento da biblioteca nomeada em<uses-library>
para o caminho real do arquivo no dispositivo. Use o exemplo abaixo para adicionar as informações necessárias ao arquivo.
name
precisa serandroidx.camera.extensions.impl
, já que é a biblioteca que o CameraX procura.file
é o caminho absoluto do arquivo que contém a implementação das extensões (por exemplo,/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>
No Android 12 ou versões mais recentes, os dispositivos com suporte a extensões CameraX
precisam definir a propriedade ro.camerax.extensions.enabled
como true
,
o que possibilita consultar se um dispositivo oferece suporte a extensões.
Para fazer isso, adicione a seguinte linha ao arquivo de criação do dispositivo:
PRODUCT_VENDOR_PROPERTIES += \
ro.camerax.extensions.enabled=true \
Validação
Para testar sua implementação da biblioteca do fornecedor OEM durante a
etapa de desenvolvimento, use o app de exemplo em
androidx-main/camera/integration-tests/extensionstestapp/
,
que passa por várias extensões do fornecedor.
Depois de concluir a implementação, use a ferramenta de validação de extensões de câmera para executar testes automatizados e manuais e verificar se a biblioteca do fornecedor foi implementada corretamente.
Modo de cena estendido x extensões de câmera
Para a extensão de bokeh, além de expor usando extensões de câmera, você
pode expor a extensão usando o modo de cena estendido, que é ativado pela
chave
CONTROL_EXTENDED_SCENE_MODE
.
Para mais detalhes de implementação, consulte Bokeh da câmera.
O modo de cena estendido tem menos restrições em comparação com as extensões de câmera para
apps camera2. Por exemplo, é possível ativar o modo de cena estendido em
uma instância CameraCaptureSession
comum que oferece suporte a combinações
flexíveis de streams e parâmetros de solicitação de captura. Em contrapartida, as extensões de câmera
só oferecem suporte a um conjunto fixo de tipos de stream e têm suporte limitado para parâmetros de
solicitação de captura.
Uma desvantagem do modo de cena estendido é que ele só pode ser implementado no HAL da câmera, o que significa que ele precisa ser verificado para funcionar em todos os controles ortogonais disponíveis para desenvolvedores de apps.
Recomendamos expor o efeito bokeh usando o modo de cena estendido e as extensões do CameraX, porque os apps podem preferir usar uma API específica para ativar o efeito. Recomendamos usar primeiro o modo de cena estendido, porque essa é a maneira mais flexível para os apps ativarem a extensão de desfoque. Em seguida, implemente a interface de extensões de câmera com base no modo de cena estendido. Se for difícil implementar o efeito bokeh na HAL da câmera, por exemplo, porque ele exige um pós- processador em execução na camada do app para processar imagens, recomendamos implementar a extensão bokeh usando a interface Camera Extensions.
Perguntas frequentes
Há alguma restrição nos níveis de API?
Sim. Isso depende do conjunto de recursos da API Android exigido pela implementação da biblioteca do fornecedor
OEM. Por exemplo, ExtenderStateListener.onPresetSession()
usa a chamada SessionConfiguration.setSessionParameters()
para definir um conjunto de tags de base. Essa chamada está disponível apenas no nível 28 da API e em versões mais recentes. Para detalhes sobre métodos de interface específicos, consulte a
documentação de referência da API.