Os fabricantes de dispositivos podem expor extensões, como bokeh, modo noturno e HDR, a desenvolvedores de terceiros pela interface de extensões da câmera fornecida pela biblioteca 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 conferir uma lista de extensões com suporte, que é a mesma para o Camera2 e o CameraX, consulte API Extensions do CameraX. Se você quiser adicionar uma extensão, informe 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 das extensões da câmera
ou extensions-interface
:
Figura 1. Diagrama da arquitetura das extensões de câmera
Conforme mostrado no diagrama, para oferecer suporte às extensões de câmera, é necessário
implementar o extensions-interface
fornecido pela biblioteca do fornecedor OEM. Sua
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
as extensões do fornecedor.
Implementar a biblioteca de fornecedor 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 de extensão do Bokeh (implemente se a extensão do Bokeh tiver suporte)
BokehImageCaptureExtenderImpl.java
BokehPreviewExtenderImpl.java
advanced/BokehAdvancedExtenderImpl.java
Classes de extensão noturna (implemente se a extensão noturna tiver suporte)
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 tiver suporte)
HdrImageCaptureExtenderImpl.java
HdrPreviewExtenderImpl.java
advanced/HdrAdvancedExtenderImpl.java
Classes de extensão do retoque facial (implemente se a extensão do retoque facial tiver suporte)
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 de extensão correspondentes. As APIs de extensões do Camera2 e CameraX
informam ao app que a extensão está indisponível.
Vamos mostrar como as APIs Camera2 e CameraX Extensions interagem com a biblioteca do fornecedor para ativar uma extensão. O diagrama a seguir ilustra o fluxo completo usando a extensão Night como exemplo:
Figura 2. Implementação da extensão do Modo noturno
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 com suporte do Camera2/X.Inicialização da biblioteca do fornecedor:
InitializerImpl
tem um métodoinit()
que inicializa a biblioteca do fornecedor. A Camera2/X conclui a inicialização antes de acessar as classes do extensor.Criar instâncias de classes de extensão:
Cria instâncias das classes de extensão para a extensão. Há dois tipos de extensor: básico e avançado. É necessário implementar um tipo de extensor para todas as extensões. Para mais informações, consulte Extensão básica e avançada.
O Camera2/X instancia e interage com as classes de extensão para extrair informações e ativar a extensão. Para uma determinada extensão, o Camera2/X pode instanciar as classes de extensão várias vezes. Como resultado, não faça a inicialização de tarefas pesadas 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 quandoonInit()
for chamado no Basic Extender ouinitSession()
for chamado no Advanced Extender.Para a extensão Night, as seguintes classes de extensão são instanciadas para o tipo de extensão básica:
NightImageCaptureExtenderImpl.java
NightPreviewExtenderImpl.java
E para o tipo de extensor avançado:
NightAdvancedExtenderImpl.java
Confira a disponibilidade da extensão:
Antes de ativar a extensão,
isExtensionAvailable()
verifica se ela está disponível no ID da câmera especificado pela instância do extensor.Inicializar o extensor com informações da câmera:
O Camera2/X chama
init()
na instância do extensor e transmite o ID da câmera eCameraCharacteristics
.Informações da consulta:
Invoca a classe de extensor para extrair informações, como resoluções compatíveis, ainda capturar a latência estimada e capturar chaves de solicitação do extensão em preparação para ativar a extensão.
Ativar a extensão no extensor:
A classe Extender fornece todas as interfaces necessárias para ativar a classe. Ele oferece um mecanismo para vincular a implementação do OEM ao pipeline da Camera2, como injetar parâmetros de solicitação de captura ou ativar um pós-processador.
Para o tipo de extensor avançado, o Camera2/X interage com
SessionProcessorImpl
para ativar a extensão. A Camera2/X recupera a instância deSessionProcessorImpl
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, a Camera2/X
verifica se a biblioteca é compatível com a versão 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 principais e secundárias são usadas durante a verificação de versão.
Para verificar a versão, o Camera2/X chama
ExtensionVersionImpl.checkApiVersion()
com a versão
extensions-interface
com suporte. A Camera2/X usa a versão informada pela
biblioteca OEM para determinar se a extensão pode ser ativada e quais recursos
ela precisa invocar.
Compatibilidade com a versão principal
Se as versões principais da extension-interface 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 anteriores de 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,
ative as extensões a partir de uma determinada versão. Nesse
caso, você pode retornar a versão extensions-interface
com suporte quando a
versão da biblioteca Camera2/X atender aos requisitos. Se as versões Camera2/X
não tiverem suporte, você poderá retornar 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 extensions-interface
implementada pela biblioteca
OEM, a Camera2/X inicia o processo de inicialização. O
método InitializerImpl.init()
sinaliza para a biblioteca OEM que um app está tentando
usar extensões.
A Camera2/X não faz outras chamadas para a biblioteca OEM (exceto a verificação de versão)
até que a biblioteca do fornecedor OEM chame OnExtensionsInitializedCallback.onSuccess()
para notificar a conclusão da inicialização.
É necessário implementar
InitializerImpl
a partir da extensions-interface
1.1.0. O Camera2/X pula a etapa de inicialização
da biblioteca se a biblioteca do fornecedor OEM implementar extensions-interface
1.0.0.
Extensor básico x Extensor avançado
Há dois tipos de implementação de extensions-interface
: extensor básico e
extensão avançada. O suporte para o Advanced Extender está disponível desde a
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 fluxo da Camera2 e enviar solicitações de captura conforme necessário.
Confira a comparação na tabela a seguir:
Extensor básico | Extensor avançado | |
---|---|---|
Configurações de transmissão | Corrigido Pré-visualização: PRIVATE ou YUV_420_888 (se o processador existir) Captura de imagem: JPEG ou YUV_420_888 (se o processador existir)
|
Personalizável pelo OEM. |
Enviar 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, a Camera2/X pode enviar várias solicitações de captura e enviar todas as imagens e capturar os resultados para o processador. | Uma instância RequestProcessorImpl é fornecida para
executar a solicitação de captura da camera2 e receber resultados e imagens.
A Camera2/X invoca |
Ganchos no pipeline da câmera |
|
|
Indicado para | Extensões implementadas na HAL da câmera ou em um processador que processa imagens YUV. |
|
Versão da API com suporte | Extensões da Camera2: Android 13 ou mais recente Extensões da CameraX: camera-extensions 1.1.0 ou mais recente |
Extensões da 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 app e as chamadas da 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 serão descritos em mais detalhes em uma seção posterior.
Extensões do Camera2 | Extensões do CameraX | |
---|---|---|
Disponibilidade da expansã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. |
Visualização e captura de fotos com a extensão ativada | CameraDevice.
createExtensionSession
|
val cameraSelector = ExtensionsManager.
getExtensionEnabledCameraSelector
|
Extensor básico
A interface do extensor básico oferece ganchos em vários lugares no pipeline da câmera. Cada tipo de extensão tem classes correspondentes que os OEMs precisam implementar.
A tabela a seguir lista as classes de extensor que os OEMs precisam implementar para cada extensão:
Classes de extensão a serem implementadas | |
---|---|
Noite | NightPreviewExtenderImpl.java
|
HDR | HdrPreviewExtenderImpl.java
|
Automático | AutoPreviewExtenderImpl.java
|
Bokeh | BokehPreviewExtenderImpl.java
|
Retoque facial | BeautyPreviewExtenderImpl.java
|
Usamos PreviewExtenderImpl
e ImageCaptureExtenderImpl
como marcadores de posição
no exemplo abaixo. Substitua esses nomes pelos nomes dos arquivos
que você está implementando.
O extensor básico tem os seguintes recursos:
- Injete parâmetros de sessão ao configurar
CameraCaptureSession
(onPresetSession
). - Notifica você sobre os eventos de início e encerramento da sessão de captura e envia uma única
solicitação para notificar a 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 capture ainda capaz de processar
o stream
YUV_420_888
.
Vamos conferir como o Camera2/X invoca o extensions-interface
para alcançar os três
fluxos de app mencionados acima.
Fluxo do app 1: verificar a disponibilidade da extensão
Figura 3. Fluxo de app 1 no extensor básico
Nesse fluxo, o Camera2/X chama diretamente o método isExtensionAvailable()
de
PreviewExtenderImpl
e ImageCaptureExtenderImpl
sem chamar
init()
. Ambas as classes de extensão precisam retornar true
para ativar as extensões.
Essa é geralmente a primeira etapa para que os apps verifiquem se o tipo de extensão oferece suporte a um determinado ID de câmera antes de ativar a extensão. Isso ocorre porque algumas extensões têm suporte apenas para determinados IDs de câmera.
Fluxo do app 2: informações da consulta
Figura 4. Fluxo de app 2 no extensor básico
Depois de determinar se a extensão está disponível, os apps precisam consultar as informações a seguir antes de ativar a extensão.
Intervalo de latência de captura estática:
ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
retorna o intervalo de latência de captura para que o app avalie se é apropriado ativar a extensão para o cenário atual.Tamanhos compatíveis para a visualização e a superfície de captura:
ImageCaptureExtenderImpl.getSupportedResolutions
ePreviewExtenderImpl.getSupportedResolutions
retornam uma lista de formatos de imagem e os tamanhos compatíveis com o formato e o tamanho da superfície.Chaves de solicitação e resultado compatíveis:a Camera2/X invoca os seguintes métodos para extrair as chaves de solicitação de captura e as chaves de resultado compatíveis da sua implementação:
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
ImageCaptureExtenderImpl.getAvailableCapturetResultKeys
O Camera2/X sempre chama init()
primeiro nessas classes de extensão antes de consultar
para mais informações.
Fluxo do app 3: visualização/captura de foto com extensão ativada (implementação do HAL)
Figura 5. Fluxo de app 3 no extensor básico
O diagrama acima ilustra o fluxo principal de ativação da visualização e da captura de fotos com uma extensão sem processador. Isso significa que o HAL da câmera processa a extensão.
Nesse fluxo, a Camera2/X chama primeiro init()
e depois onInit
, que notifica que
uma sessão da câmera está prestes a começar com as extensões especificadas.
É possível fazer a inicialização de tarefas pesadas em onInit()
.
Ao configurar CameraCaptureSession
, a 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 de 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, a Camera2/X invoca
onDisableSession
e envia uma única solicitação com os parâmetros de captura
retornados.
A solicitação repetida acionada pela Camera2/X contém os parâmetros de solicitação
retornados por PreviewExtenderImpl.getCaptureStage()
. Além disso, a solicitação de captura de imagem
contendo os parâmetros retornados por
ImageCaptureExtenderImpl.getCaptureStages()
.
Por fim, o Camera2/X invoca onDeInit()
após a sessão da câmera terminar.
Você pode liberar recursos em onDeinit()
.
Pré-visualizar o processador
Além da 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
: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. OPreviewExtenderImpl.getCaptureStage()
também precisa refletir o resultado do processamento e retornar oCaptureStageImpl
mais recente.PROCESSOR_TYPE_IMAGE_PROCESSOR
:com esse tipo, é possível 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 de
PreviewImageProcessorImpl
emPreviewExtenderImpl.getProcessor
. O processador é responsável pelo processamento de imagens de entradaYUV_420_888
. Ele precisa gravar a saída no formatoPRIVATE
da visualização. O Camera2/X usa uma plataformaYUV_420_888
em vez dePRIVATE
para configurar oCameraCaptureSession
para visualização.Confira a ilustração a seguir do fluxo:
Figura 6. Fluxo de visualização 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 pixels, 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ó é possível usarYUV_420_888
.
Processador de captura de imagem
Para capturas de tela, é possível implementar um processador retornando uma
instância de CaptureProcessorImpl
usando ImageCaptureExtenderImpl.getCaptureProcessor
. O processador é
responsável por processar uma lista de imagens YUV_420_888
e
instâncias TotalCaptureResult
capturadas e gravar a saída em uma superfície YUV_420_888
.
Você pode presumir que a visualização 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. Fluxo de captura de fotos com CaptureProcessorImpl
O Camera2/X usa uma superfície de formato
YUV_420_888
para a captura de fotos estáticas para configurar a sessão de captura. A 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 vai enviar três solicitações de captura com os 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 do resultado (formatoYUV_420_888
) na superfície de saída especificada pela chamadaonOutputSurface()
. O Camera2/X as converte em imagens JPEG, se necessário.
Suporte a 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 o recurso de tocar para focar. Esses parâmetros podem não ser compatíveis com a implementação da extensão.
Os métodos a seguir 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 a implementação.ImageCaptureExtenderImpl.getAvailableCaptureResultKeys()
retorna as chaves de resultado de 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.
Na extensions-interface
1.3.0 ou mais recente, 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 o suporte às seguintes chaves para a solicitação de captura e o resultado da 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 é compatível com o app, enquanto o toque para focar, o flash e a compensação
de exposição não são permitidos.
Extensor avançado
O Advanced Extender é um tipo de implementação do fornecedor baseada na API Camera2.
Esse tipo de extensor foi adicionado na extensions-interface
1.2.0. Dependendo
do fabricante do dispositivo, as extensões podem ser implementadas na camada do app,
o que depende dos seguintes fatores:
Configuração de fluxo personalizado:configure fluxos personalizados, como o fluxo RAW, ou tenha vários fluxos para diferentes IDs de câmera física.
Capacidade de enviar solicitações da Camera2:ofereça suporte a uma lógica de interação complicada que possa enviar solicitações de captura com parâmetros com base nos resultados de solicitações anteriores.
O Advanced Extender fornece um wrapper, ou uma camada intermediária, para que você possa personalizar a configuração do stream e enviar solicitações de captura sob demanda.
Arquivos a implementar
Para alternar para a implementação do extensor avançado, o
método isAdvancedExtenderImplemented()
em
ExtensionVersionImpl
precisa retornar true
. Para cada tipo de extensão, os OEMs precisam implementar as
classes de extensor 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ático | advanced/AutoAdvancedExtenderImpl.java
|
Bokeh | advanced/BokehAdvancedExtenderImpl.java
|
Retocar rosto | advanced/BeautyAdvancedExtenderImpl.java
|
Usamos AdvancedExtenderImpl
como marcador de posição no exemplo a seguir.
Substitua pelo nome do arquivo do extensor da extensão que você está
implementando.
Vamos conferir como o Camera2/X invoca o extensions-interface
para alcançar os três
fluxos do app.
Fluxo do app 1: verificar a disponibilidade das extensões
Figura 8. Fluxo de app 1 no Advanced Extender
Primeiro, o app verifica se a extensão tem suporte.
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
informações em AdvancedExtenderImpl
:
Latência de captura estática estimada:
AdvancedExtenderImpl.getEstimatedCaptureLatencyRange()
retorna o intervalo de latência de captura para que o app avalie se é apropriado 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 de imagem para a lista de tamanhos que têm suporte para o formato e o tamanho da superfície de visualização. Os OEMs precisam oferecer suporte a pelo menos o formatoPRIVATE
.AdvancedExtenderImpl.getSupportedCaptureOutputResolutions()
retorna o formato e os tamanhos aceitos para a superfície de captura de fotos. Os OEMs precisam oferecer suporte à saída de formatoJPEG
eYUV_420_888
.AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
retorna os tamanhos aceitos para um fluxoYUV_420_888
extra para análise de imagem. Se a análise de imagem não tiver suporte à superfície YUV,getSupportedYuvAnalysisResolutions()
vai retornarnull
ou uma lista vazia.
Chaves/resultados de solicitação de captura disponíveis (adicionadas na
extensions-interface
1.3.0): o Camera2/X invoca os seguintes métodos para extrair as chaves de solicitação de captura e de resultado compatíveis da 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: visualização/captura de foto com extensão ativada
Figura 10. Fluxo de app 3 no Advanced Extender
O diagrama acima mostra o fluxo principal para iniciar a visualização e a captura de imagem estática para o tipo de extensor avançado. Vamos analisar cada etapa.
Instância
SessionProcessorImpl
A implementação principal do Advanced Extender está em
SessionProcessorImpl
, que é responsável por fornecer a configuração personalizada da sessão e enviar solicitações de captura para iniciar a visualização e a captura.AdvancedExtenderImpl.createSessionProcessor()
é invocado para retornar a instânciaSessionProcessorImpl
.initSession
SessionProcessorImpl.initSession()
inicializa a sessão da 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 da superfície de saída para visualização, captura de imagens 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 que são 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 enviar as imagens da câmera corretas 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
ao
CameraCaptureSession
com uma implementaçãoSurfaceOutputConfigImpl
. Isso configura a superfície de saída fornecida para o pipeline da câmera e permite que o HAL da câmera processe a imagem. Processamento de superfície
ImageReader
intermediária (RAW, YUV etc.): adicione as superfíciesImageReader
intermediárias aoCameraCaptureSession
com uma instânciaImageReaderOutputConfigImpl
.Você precisa processar as imagens intermediárias e gravar a imagem do resultado 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 extrair a imagem deImageReaderOutputConfigImpl
.onCaptureSessionStart
eRequestProcessorImpl
Quando
CameraCaptureSession
é iniciado e o framework da câmera 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 APIsCameraCaptureSession
da Camera2 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
.
É possível chamar
RequestProcessorImpl.setImageProcessor()
com um IDCamera2OutputConfigImpl
especificado para registrar uma instânciaImageProcessorImpl
para receber imagens.A instância
RequestProcessImpl
se torna inválida depois que o Camera2/X chamaSessionProcessorImpl.onCaptureSessionEnd()
.- A superfície de destino é especificada pelo ID da
instância
Iniciar a visualização e tirar uma foto
Na implementação do extensor avançado, é possível enviar solicitações de captura pela interface
RequestProcessorImpl
. A 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. Você precisa enviar solicitações de captura para atender a essas solicitações de visualização e captura de fotos.A Camera2/X também define os parâmetros de solicitação de captura usando
SessionProcessorImpl#setParameters
. Defina esses parâmetros de solicitação (se houver suporte) nas solicitações únicas e recorrentes.É necessário oferecer suporte a pelo menos
CaptureRequest.JPEG_ORIENTATION
eCaptureRequest.JPEG_QUALITY
. Oextensions-interface
1.3.0 oferece suporte a 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 acionador, comoCaptureRequest.CONTROL_AF_TRIGGER
eCaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
. Desconsidere as chaves de solicitação de captura que não foram anunciadas emAdvancedExtenderImpl.getAvailableCaptureRequestKeys()
.O
startTrigger()
tem suporte desde a versão 1.3.0 doextensions-interface
. Ele permite que os apps implementem o toque para focar e o flash com extensões.Limpeza
Ao terminar uma sessão de captura,
SessionProcessorImpl.onCaptureSessionEnd()
é invocado antes de fecharCameraCaptureSession
. Depois que a sessão de captura é fechada,deInitSession()
faz a limpeza.
Oferecer suporte a visualização, captura de fotos e análise de imagens
Aplique a extensão para os casos de uso de visualização e captura de fotos. 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 de fotos.
Para o tipo de extensor básico, independentemente 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 fluxo de visualização, captura de fotos e um
fluxo YUV_420_888
para configurar CameraCaptureSession
. Isso significa
que, se você implementar um processador, precisará oferecer suporte à combinação
de três streams YUV_420_888
.
Para o Advanced Extender, o Camera2/X transmite três superfícies de saída para a
chamada SessionProcessorImpl.initSession()
. Essas plataformas de saída são para visualização, captura de fotos e análise de imagens, respectivamente. É necessário garantir que a visualização
e as superfícies de saída de captura mostrem a saída válida. No entanto, para a superfície de saída da análise
de imagem, verifique se ela funciona apenas quando não é nula. Se a
implementação não oferecer suporte ao fluxo de análise de imagem, você poderá retornar uma lista
vazia em AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
. Isso
garante que a plataforma 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 fotos. 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 de visualização.
A compatibilidade com as plataformas MediaCodec
e MediaRecorder
está em investigação.
Metadados específicos da extensão
No Android 14 e versões mais recentes, os metadados específicos da extensão
permitem que os clientes de extensão da 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
da 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 ativado.
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 de captura correspondente inclui o valor de força padrão se esse parâmetro não for definido
explicitamente pelo cliente. Esse parâmetro pode ser aplicado da seguinte forma para estes
tipos de extensão:
BOKEH
: controla a quantidade de desfoque.HDR
eNIGHT
: controlam a quantidade de imagens mescladas e o brilho da imagem final.FACE_RETOUCH
: controla a quantidade de melhoria cosmética e suavização da pele.
O intervalo com suporte para o parâmetro EXTENSION_STRENGTH
fica entre 0
e
100
, com 0
indicando nenhum processamento de extensão ou passagem simples e
100
indicando a intensidade máxima de extensão do efeito de processamento.
Para adicionar suporte a EXTENSION_STRENGTH
, use as APIs de parâmetro
específicos do fornecedor introduzidas na versão 1.3.0 da interface
da biblioteca de extensão. Para mais informações, consulte
getAvailableCaptureRequestKeys()
:
Capturar resultados
O resultado da captura de
EXTENSION_CURRENT_TYPE
permite que as implementações de extensão notifiquem os clientes sobre o tipo de extensão
ativo.
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 da câmera
podem consultar estimativas de latência de captura estática em tempo real com base nas condições da cena e
do ambiente usando
getRealtimeStillCaptureLatency()
. Esse
método fornece 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
de extensões ou mostrar uma indicação para notificar os usuários sobre uma operação
demorada.
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
Capturar callbacks de progresso do processamento
No Android 14 e versões mais recentes, os clientes de extensão da câmera podem receber callbacks para o progresso de operações de processamento de captura de fotos 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 visualização) usando
setPostviewOutputConfiguration
.
Para melhorar a experiência do usuário, os apps podem mostrar uma imagem pós-visualização como um
marcador de posição quando uma extensão estiver com latência de processamento aumentada
e substituir a imagem quando a imagem final estiver disponível. Os apps podem configurar
e emitir solicitações de captura de postview 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 imagem estática 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 à 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 desempenho registrando uma
instância SurfaceView
para a saída de visualização de solicitações repetidas.
Para oferecer suporte à saída SurfaceView
, a implementação da extensão do fornecedor precisa
ser capaz de transmitir e gerar a prévia para instâncias SurfaceView
. Para
verificar se há suporte, execute o módulo CTS
SurfaceViewExtensionPreviewTest.java
.
Tipos de sessão específicos do fornecedor
O recurso permite que as implementações de extensões de fornecedores selecionem um tipo de sessão específico do fornecedor que será definido na sessão de captura interna 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 para suas 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 da extensão da câmera. Você sempre deve implementar 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 referência da biblioteca do fornecedor OEM estão disponíveis em
frameworks/ex
.
advancedSample
: uma implementação básica do Advanced Extender.sample
: uma implementação básica do extensor básico.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 de câmera para as APIs Camera2 e CameraX Extensions que implementaExtensions-Interface
. Isso funciona como um encaminhamento 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 é ativado por padrão. Para ativar o extensor básico, mude
ExtensionsVersionImpl#isAdvancedExtenderImplemented
para retornarfalse
.extensions_service
: um exemplo de implementação 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 necessários para tornarImage
eTotalCaptureResult
parceláveis.
Configurar a biblioteca do fornecedor em um dispositivo
A biblioteca do fornecedor OEM não está integrada a um app. Ela é carregada do dispositivo
no momento da 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 momento da 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
no momento de 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. A 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 é necessário para a 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 de arquivo real no dispositivo. Use o exemplo abaixo para adicionar as informações necessárias ao arquivo.
name
precisa serandroidx.camera.extensions.impl
, porque essa é a biblioteca que o CameraX procura.file
é o caminho absoluto do arquivo que contém a implementação de 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 e versões mais recentes, os dispositivos com suporte a extensões
CameraX precisam definir a propriedade ro.camerax.extensions.enabled
como true
,
o que permite consultar se um dispositivo oferece suporte a extensões.
Para fazer isso, adicione a seguinte linha no arquivo de fabricação do dispositivo:
PRODUCT_VENDOR_PROPERTIES += \
ro.camerax.extensions.enabled=true \
Validação
Para testar a implementação da biblioteca do fornecedor OEM durante o
estágio de desenvolvimento, use o app de exemplo em
androidx-main/camera/integration-tests/extensionstestapp/
,
que é executado em 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 estendida x extensões de câmera
Para a extensão de bokeh, além de expor usando extensões da câmera, você
pode expor a extensão usando o modo de cena estendida, 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 estendida em
uma instância CameraCaptureSession
regular que oferece suporte a combinações de fluxo
flexíveis e captura de parâmetros de solicitação. Em contraste, as extensões de câmera
oferecem suporte apenas a um conjunto fixo de tipos de streaming e têm suporte limitado para parâmetros de solicitação
de captura.
Uma desvantagem do modo de cena estendida é 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 bokeh usando o modo de cena estendida e as extensões da câmera, porque os apps podem preferir usar uma API específica para ativar o bokeh. Recomendamos usar primeiro o modo de cena estendida, porque essa é a maneira mais flexível de ativar a extensão de bokeh em apps. Em seguida, é possível implementar a interface de extensões da câmera com base no modo de cena estendido. Se a implementação do bokeh na HAL da câmera for difícil, por exemplo, porque exige um pós- processador em execução na camada do app para processar imagens, recomendamos implementar a extensão de bokeh usando a interface de extensões da câmera.
Perguntas frequentes
Há alguma restrição nos níveis da API?
Sim. Isso depende do conjunto de recursos da API do Android que é necessário para a implementação da biblioteca
do fornecedor OEM. Por exemplo,
ExtenderStateListener.onPresetSession()
usa a chamada
SessionConfiguration.setSessionParameters()
para definir um conjunto de referência de tags. Essa chamada está disponível apenas no nível 28
da API e versões mais recentes. Para detalhes sobre métodos de interface específicos, consulte a
documentação de referência da API.