APIs de gerenciamento de buffer HAL3 da câmera

O Android 10 apresenta APIs de gerenciamento de buffer HAL3 de câmera opcionais que permitem implementar a lógica de gerenciamento de buffer para obter diferentes compensações de memória e capturar latência em implementações de 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 exige 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 inferior, a estrutura da câmera aloca buffers quando a solicitação é enfileirada no HAL, de modo que 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 que executam o Android 9 e inferior. 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.

Gerenciamento de buffer em 9 ou inferior

Figura 1. Interface HAL da câmera no Android 9 e inferior

Gerenciamento de buffer no Android 10

Figura 2. Interface da câmera HAL no Android 10 usando as 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:

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, é recomendável 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 deve 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. A câmera HAL deve enviar ERROR_REQUEST para solicitações de captura que não podem ser atendidas devido a um erro de tempo limite e estar pronta para processar solicitações subsequentes normalmente.
  • A estrutura da câmera está preparando uma nova configuração de fluxo: A câmera HAL deve aguardar até que a próxima chamada configureStreams seja concluída antes de chamar requestStreamBuffers novamente.
  • O HAL da câmera atingiu seu limite de buffer (o campo maxBuffers ): O HAL da câmera deve esperar até que retorne pelo menos um buffer do fluxo antes de chamar requestStreamBuffers 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 levar em conta as solicitações de captura que foram enviadas para o HAL da câmera. Com o método requestStreamBuffers , é possível que a implementação da câmera HAL retenha mais buffers do que o que foi solicitado pela estrutura da câmera. É quando o método returnStreamBuffers deve ser usado. Se a implementação de HAL nunca tiver mais buffers do que o solicitado, a implementação de HAL da câmera não precisará chamar o método returnStreamBuffers .

signalStreamFlush

O método signalStreamFlush é chamado pela estrutura da câmera para notificar a câmera HAL 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 de HAL de câmera não armazenar 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 sejam 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 , a câmera HAL 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 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, a 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 a StreamConfiguration e adicionado como um argumento ao método signalStreamFlush . A implementação da câmera HAL deve usar o argumento streamConfigCounter para determinar se uma chamada signalStreamFlush chega depois de sua chamada configureStreams correspondente. Consulte a Figura 3 para obter um exemplo.

Lidar com chamadas que chegam atrasadas

Figura 3. Como a câmera HAL deve detectar e tratar as 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 implementação de HAL de câmera e 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 para o HAL da câmera. Ao usar as APIs de gerenciamento de buffer, a estrutura da câmera não precisa mais esperar por buffers e, portanto, pode 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 atingiu o número máximo de buffers que o HAL pode conter ao mesmo tempo (esse valor é designado pelo HAL da câmera no HalStream::maxBuffers no valor de retorno de uma chamada configureStreams ). Com as APIs de gerenciamento de buffer, esse comportamento de limitação não existe mais e a implementação do HAL da câmera não deve aceitar chamadas processCaptureRequest quando o HAL tiver muitas solicitações de captura enfileiradas.

  • A latência da chamada requestStreamBuffers varia significativamente: há muitos motivos pelos quais uma chamada requestStreamBuffers pode demorar mais do 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á mantendo buffers e está ocupado processando. Isso pode fazer com que as solicitações de buffer diminuam ou atinjam um 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 oferece nenhuma economia de memória, mas pode servir como a primeira implementação das APIs de gerenciamento de buffer, exigindo 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 seja necessário para ser preenchido. Essa estratégia permite economias de memória maximizadas. A desvantagem potencial é mais instabilidade no pipeline da câmera quando as solicitações de buffer levam um tempo incomumente longo para serem concluídas.
  • 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 diferentes estratégias 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 com versões anteriores para outros casos de uso.

Implementação de exemplo 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. Essa câmera externa HAL implementa a estratégia de economia de memória maximizada mencionada em Estratégias de gerenciamento de buffer em algumas centenas de linhas de código C++.