O Android 10 apresenta APIs opcionais de gerenciamento de buffer HAL3 de câmera que permitem implementar lógica de gerenciamento de buffer para obter diferentes compensações de memória e capturar latência em implementações HAL de câmera.
A câmera HAL requer N solicitações (onde N é igual à profundidade do pipeline ) enfileiradas em seu pipeline, mas geralmente não requer todos os N conjuntos de buffers de saída ao mesmo tempo.
Por exemplo, o HAL pode ter oito solicitações enfileiradas no pipeline, mas requer apenas buffers de saída para as duas solicitações nos últimos estágios do pipeline. Em dispositivos que executam o Android 9 e versões anteriores, a estrutura da câmera aloca buffers quando a solicitação é enfileirada no HAL, portanto, pode haver seis conjuntos de buffers no HAL que não estão em uso. No Android 10, as APIs de gerenciamento de buffer HAL3 da câmera permitem o desacoplamento dos buffers de saída para liberar os seis conjuntos de buffers. Isso pode levar a centenas de megabytes de economia de memória em dispositivos de última geração e também pode ser benéfico para dispositivos com pouca memória.
A Figura 1 mostra um diagrama da interface HAL da câmera para dispositivos com Android 9 e versões anteriores. A Figura 2 mostra a interface HAL da câmera no Android 10 com as APIs de gerenciamento de buffer HAL3 da câmera implementadas.
Figura 1. Interface HAL da câmera no Android 9 e inferior
Figura 2. Interface HAL da câmera no Android 10 usando APIs de gerenciamento de buffer
Implementando as APIs de gerenciamento de buffer
Para implementar as APIs de gerenciamento de buffer, o HAL da câmera deve:
- Implemente HIDL
ICameraDevice@3.5
. - Defina a chave de características da câmera
android.info.supportedBufferManagementVersion
comoHIDL_DEVICE_3_5
.
A câmera HAL usa os métodos requestStreamBuffers
e returnStreamBuffers
em ICameraDeviceCallback.hal
para solicitar e retornar buffers. O HAL também deve implementar o método signalStreamFlush
em ICameraDeviceSession.hal
para sinalizar o HAL da câmera para retornar buffers.
requestStreamBuffers
Use o método requestStreamBuffers
para solicitar buffers da estrutura da câmera. Ao usar as APIs de gerenciamento de buffer HAL3 da câmera, as solicitações de captura da estrutura da câmera não contêm buffers de saída, ou seja, o campo bufferId
em StreamBuffer
é 0
. Portanto, o HAL da câmera deve usar requestStreamBuffers
para solicitar buffers da estrutura da câmera.
O método requestStreamBuffers
permite que o chamador solicite vários buffers de vários fluxos de saída em uma única chamada, permitindo menos chamadas HIDL IPC. No entanto, as chamadas demoram mais quando mais buffers são solicitados ao mesmo tempo e isso pode afetar negativamente a latência total da solicitação ao resultado. Além disso, como as chamadas para requestStreamBuffers
são serializadas no serviço de câmera, é recomendado que o HAL da câmera use um thread dedicado de alta prioridade para solicitar buffers.
Se uma solicitação de buffer falhar, o HAL da câmera deverá ser capaz de lidar adequadamente com erros não fatais. A lista a seguir descreve os motivos comuns pelos quais as solicitações de buffer falham e como elas devem ser tratadas pelo HAL da câmera.
- O aplicativo se desconecta do fluxo de saída: este é um erro não fatal. A câmera HAL deve enviar
ERROR_REQUEST
para qualquer solicitação de captura direcionada a um fluxo desconectado e estar pronta para processar solicitações subsequentes normalmente. - Tempo limite: isso pode ocorrer quando um aplicativo está ocupado fazendo processamento intensivo enquanto mantém alguns buffers. O HAL da câmera deve enviar
ERROR_REQUEST
para solicitações de captura que não podem ser atendidas devido a um erro de tempo limite e estar pronto para processar solicitações subsequentes normalmente. - A estrutura da câmera está preparando uma nova configuração de stream: O HAL da câmera deve esperar até que a próxima chamada
configureStreams
seja concluída antes de chamarrequestStreamBuffers
novamente. - O HAL da câmera atingiu seu limite de buffer (campo
maxBuffers
): O HAL da câmera deve esperar até retornar pelo menos um buffer do fluxo antes de chamarrequestStreamBuffers
novamente.
returnStreamBuffers
Use o método returnStreamBuffers
para retornar buffers extras para a estrutura da câmera. O HAL da câmera normalmente retorna buffers para a estrutura da câmera por meio do método processCaptureResult
, mas só pode contabilizar solicitações de captura que foram enviadas ao HAL da câmera. Com o método requestStreamBuffers
, é possível que a implementação HAL da câmera retenha mais buffers do que o solicitado pela estrutura da câmera. É quando o método returnStreamBuffers
deve ser usado. Se a implementação HAL nunca contiver mais buffers do que o solicitado, a implementação HAL da câmera não precisará chamar o método returnStreamBuffers
.
sinalStreamFlush
O método signalStreamFlush
é chamado pela estrutura da câmera para notificar o HAL da câmera para retornar todos os buffers disponíveis. Isso normalmente é chamado quando a estrutura da câmera está prestes a chamar configureStreams
e deve drenar o pipeline de captura da câmera. Semelhante ao método returnStreamBuffers
, se uma implementação HAL de câmera não contiver mais buffers do que o solicitado, é possível ter uma implementação vazia desse método.
Depois que a estrutura da câmera chama signalStreamFlush
, a estrutura para de enviar novas solicitações de captura para o HAL da câmera até que todos os buffers tenham sido retornados à estrutura da câmera. Quando todos os buffers são retornados, as chamadas do método requestStreamBuffers
falham e a estrutura da câmera pode continuar seu trabalho em um estado limpo. A estrutura da câmera então chama o método configureStreams
ou processCaptureRequest
. Se a estrutura da câmera chamar o método configureStreams
, o HAL da câmera poderá começar a solicitar buffers novamente depois que a chamada configureStreams
retornar com êxito. Se a estrutura da câmera chamar o método processCaptureRequest
, o HAL da câmera poderá começar a solicitar buffers durante a chamada processCaptureRequest
.
A semântica é diferente para o método signalStreamFlush
e para o método flush
. Quando o método flush
é chamado, o HAL pode abortar solicitações de captura pendentes com ERROR_REQUEST
para drenar o pipeline o mais rápido possível. Quando o método signalStreamFlush
é chamado, o HAL deve finalizar todas as solicitações de captura pendentes normalmente e retornar todos os buffers para a estrutura da câmera.
Outra diferença entre o método signalStreamFlush
e outros métodos é que signalStreamFlush
é um método HIDL unidirecional , o que significa que a estrutura da câmera pode chamar outras APIs de bloqueio antes que o HAL receba a chamada signalStreamFlush
. Isso significa que o método signalStreamFlush
e outros métodos (especificamente o método configureStreams
) podem chegar ao HAL da câmera em uma ordem diferente da ordem em que foram chamados na estrutura da câmera. Para resolver esse problema de assincronia, o campo streamConfigCounter
foi adicionado ao StreamConfiguration
e adicionado como um argumento ao método signalStreamFlush
. A implementação HAL da câmera deve usar o argumento streamConfigCounter
para determinar se uma chamada signalStreamFlush
chega depois de sua chamada configureStreams
correspondente. Veja um exemplo na Figura 3.
Figura 3. Como o HAL da câmera deve detectar e tratar chamadas signalStreamFlush que chegam atrasadas
Mudanças de comportamento ao implementar as APIs de gerenciamento de buffer
Ao usar as APIs de gerenciamento de buffer para implementar a lógica de gerenciamento de buffer, considere as seguintes possíveis alterações de comportamento na câmera e na implementação de HAL da câmera:
As solicitações de captura chegam ao HAL da câmera com mais rapidez e frequência: sem APIs de gerenciamento de buffer, a estrutura da câmera solicita buffers de saída para cada solicitação de captura antes de enviar uma solicitação de captura ao HAL da câmera. Ao usar APIs de gerenciamento de buffer, a estrutura da câmera não precisa mais esperar por buffers e pode, portanto, enviar solicitações de captura para o HAL da câmera mais cedo.
Além disso, sem APIs de gerenciamento de buffer, a estrutura da câmera para de enviar solicitações de captura se um dos fluxos de saída da solicitação de captura atingir o número máximo de buffers que o HAL pode conter por vez (esse valor é designado pelo HAL da câmera no arquivo
HalStream::maxBuffers
no valor de retorno de uma chamadaconfigureStreams
). Com as APIs de gerenciamento de buffer, esse comportamento de limitação não existe mais e a implementação HAL da câmera não deve aceitar chamadasprocessCaptureRequest
quando o HAL tiver muitas solicitações de captura enfileiradas.A latência da chamada
requestStreamBuffers
varia significativamente: há muitos motivos pelos quais uma chamadarequestStreamBuffers
pode demorar mais que a média. Por exemplo:- Para os primeiros buffers de um fluxo recém-criado, as chamadas podem demorar mais porque o dispositivo precisa alocar memória.
- A latência esperada aumenta proporcionalmente ao número de buffers solicitados em cada chamada.
- O aplicativo está armazenando buffers e ocupado processando. Isso pode fazer com que as solicitações de buffer fiquem lentas ou atinjam o tempo limite devido à falta de buffers ou a uma CPU ocupada.
Estratégias de gerenciamento de buffer
As APIs de gerenciamento de buffer permitem a implementação de diferentes tipos de estratégias de gerenciamento de buffer. Alguns exemplos são:
- Compatível com versões anteriores: o HAL solicita buffers para uma solicitação de captura durante a chamada
processCaptureRequest
. Essa estratégia não proporciona nenhuma economia de memória, mas pode servir como a primeira implementação das APIs de gerenciamento de buffer, exigindo muito poucas alterações de código no HAL da câmera existente. - Economia de memória maximizada: O HAL da câmera solicita apenas buffers de saída imediatamente antes que um deles precise ser preenchido. Essa estratégia permite economia maximizada de memória. A desvantagem potencial é mais instabilidade no pipeline da câmera quando as solicitações de buffer demoram muito para serem concluídas.
- Armazenado em cache: O HAL da câmera armazena em cache alguns buffers para que seja menos provável que seja afetado por uma solicitação ocasional de buffer lento.
A câmera HAL pode adotar estratégias diferentes para casos de uso específicos, por exemplo, usando a estratégia de economia de memória maximizada para casos de uso que usam muita memória e usando a estratégia de compatibilidade retroativa para outros casos de uso.
Exemplo de implementação na câmera externa HAL
A câmera externa HAL foi introduzida no Android 9 e pode ser encontrada na árvore de origem em hardware/interfaces/camera/device/3.5/
. No Android 10, ele foi atualizado para incluir ExternalCameraDeviceSession.cpp
, uma implementação da API de gerenciamento de buffer. Esta câmera externa HAL implementa a estratégia de economia maximizada de memória mencionada em Estratégias de gerenciamento de buffer em algumas centenas de linhas de código C++.