A HAL da câmera exige N solicitações (em que N é igual à profundidade do pipeline) enfileiradas no pipeline, mas geralmente não exige todos os N conjuntos de buffers de saída ao mesmo tempo.
Por exemplo, a HAL pode ter oito solicitações enfileiradas no pipeline, mas só exige buffers de saída para as duas solicitações nas últimas etapas do pipeline. Em dispositivos com o Android 9 e versões anteriores, o framework da câmera aloca buffers quando a solicitação é enfileirada na HAL. Portanto, pode haver seis conjuntos de buffers na HAL que não estão em uso. No Android 10, as APIs de gerenciamento de buffer de HAL3 da câmera permitem a separação 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 sofisticados 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 o 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 de HAL3 da câmera implementadas.
Figura 1. Interface HAL da câmera no Android 9 e versões anteriores
Figura 2. Interface HAL da câmera no Android 10 usando as APIs de gerenciamento de buffer
Implementar as APIs de gerenciamento de buffer
Para implementar as APIs de gerenciamento de buffer, a HAL da câmera precisa:
- Implementar HIDL
ICameraDevice@3.5. - Definir a chave de características da câmera
android.info.supportedBufferManagementVersioncomoHIDL_DEVICE_3_5.
A HAL da câmera usa os
requestStreamBuffers
e os
returnStreamBuffers
métodos em
ICameraDeviceCallback.hal
para solicitar e retornar buffers. A HAL também precisa implementar o
signalStreamFlush
método em
ICameraDeviceSession.hal
para sinalizar a HAL da câmera para retornar buffers.
requestStreamBuffers
Use o
requestStreamBuffers
método para solicitar buffers do framework da câmera. Ao usar as APIs de gerenciamento de buffer de HAL3
da câmera, as solicitações de captura do framework da câmera não
contêm buffers de saída. Ou seja, o campo bufferId em
StreamBuffer
é 0. Portanto, a HAL da câmera precisa usar requestStreamBuffers para solicitar buffers do framework da câmera.
O método requestStreamBuffers permite que o autor da chamada solicite vários buffers de vários fluxos de saída em uma única chamada, permitindo menos chamadas de IPC HIDL. No entanto, as chamadas levam mais tempo quando mais buffers são solicitados ao mesmo tempo, e isso pode afetar negativamente a latência total da solicitação para o resultado.
Além disso, como as chamadas para requestStreamBuffers são serializadas no serviço da câmera, recomendamos que a HAL da câmera use uma linha de execução dedicada de alta prioridade para solicitar buffers.
Se uma solicitação de buffer falhar, a HAL da câmera precisará processar erros não fatais corretamente. A lista a seguir descreve os motivos comuns para a falha de solicitações de buffer e como elas precisam ser processadas pela HAL da câmera.
- O app se desconecta do fluxo de saída:esse é um erro não fatal. A HAL da câmera precisa enviar
ERROR_REQUESTpara qualquer solicitação de captura direcionada a um fluxo desconectado e estar pronta para processar as solicitações subsequentes normalmente. - Tempo limite:isso pode ocorrer quando um app está ocupado fazendo um processamento intenso enquanto mantém alguns buffers. A HAL da câmera precisa
enviar
ERROR_REQUESTpara solicitações de captura que não podem ser atendidas devido a um erro de tempo limite e estar pronta para processar as solicitações subsequentes normalmente. - O framework da câmera está preparando uma nova configuração de fluxo:
a HAL da câmera precisa aguardar até que a próxima chamada
configureStreamsseja concluída antes de chamarrequestStreamBuffersnovamente. - A HAL da câmera atingiu o
limite de buffer
(o campo
maxBuffers) : a HAL da câmera precisa aguardar até retornar pelo menos um buffer do fluxo antes de chamarrequestStreamBuffersnovamente.
returnStreamBuffers
Use o
returnStreamBuffers
método para retornar buffers extras ao framework da câmera. A HAL da câmera normalmente
retorna buffers ao framework da câmera pelo
processCaptureResult
método, mas só pode contabilizar as solicitações de captura que foram enviadas à
HAL da câmera. Com o método requestStreamBuffers, é possível que a implementação da HAL da câmera retenha mais buffers do que o solicitado pelo framework da câmera. É quando o método returnStreamBuffers precisa ser usado. Se a implementação da HAL nunca mantiver mais buffers do que o solicitado, a implementação da HAL da câmera não precisará chamar o método returnStreamBuffers.
signalStreamFlush
O método
signalStreamFlush
é chamado pelo framework da câmera para notificar a HAL da câmera a retornar todos os
buffers disponíveis. Isso normalmente é chamado quando o framework da câmera está prestes a
chamar
configureStreams
e precisa esvaziar o pipeline de captura da câmera. Semelhante ao método returnStreamBuffers, se uma implementação de HAL da câmera não mantiver mais buffers do que o solicitado, será possível ter uma implementação vazia desse método.
Depois que o framework da câmera chama
signalStreamFlush,
ele para de enviar novas solicitações de captura para a HAL da câmera até que todos os
buffers sejam retornados ao framework da câmera. Quando todos os buffers são retornados, as chamadas de método requestStreamBuffers falham, e o framework da câmera pode continuar o trabalho em um estado limpo. Em seguida, o framework da câmera
chama o método
configureStreams
ou
processCaptureRequest. Se o framework da câmera chamar o método configureStreams, a HAL da câmera poderá começar a solicitar buffers novamente depois que a chamada configureStreams for retornada. Se o framework da câmera chamar o método processCaptureRequest, a HAL da câmera poderá começar a solicitar buffers durante a chamada processCaptureRequest.
A semântica é diferente para o signalStreamFlush método e o
flush
método. Quando o método flush é chamado, a HAL pode anular as solicitações de captura pendentes com
ERROR_REQUEST
para esvaziar o pipeline o mais rápido possível. Quando o método signalStreamFlush é chamado, a HAL precisa concluir todas as solicitações de captura pendentes normalmente e retornar todos os buffers ao framework da câmera.
Outra diferença entre o método signalStreamFlush e outros métodos é que signalStreamFlush é um método HIDL unidirecional. Isso significa que o framework da câmera pode chamar outras APIs de bloqueio antes que a HAL receba a chamada signalStreamFlush. Isso significa que o método signalStreamFlush e outros métodos (especificamente o método configureStreams) podem chegar à HAL da câmera em uma ordem diferente da ordem em que foram chamados no framework 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 HAL da câmera precisa usar o argumento streamConfigCounter para determinar se uma chamada signalStreamFlush chega mais tarde do que a chamada configureStreams correspondente. Consulte a Figura 3 para ver um exemplo.
Figura 3. Como a HAL da câmera precisa detectar e processar chamadas signalStreamFlush que chegam tarde
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 mudanças de comportamento possíveis na câmera e na implementação da HAL da câmera:
As solicitações de captura chegam à HAL da câmera mais rápido e com mais frequência:sem as APIs de gerenciamento de buffer, o framework da câmera solicita buffers de saída para cada solicitação de captura antes de enviar uma solicitação de captura para a HAL da câmera. Ao usar as APIs de gerenciamento de buffer, o framework da câmera não precisa mais aguardar buffers e, portanto, pode enviar solicitações de captura para a HAL da câmera mais cedo.
Além disso, sem as APIs de gerenciamento de buffer, o framework 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 a HAL pode manter de uma só vez. Esse valor é designado pela HAL da câmera no campo
HalStream::maxBuffersno 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 da HAL da câmera não pode aceitar chamadasprocessCaptureRequestquando a HAL tem muitas solicitações de captura enfileiradas.A latência da chamada
requestStreamBuffersvaria significativamente:há muitos motivos para que uma chamadarequestStreamBuffersleve mais tempo do que a média. Por exemplo:- Para os primeiros buffers de um fluxo recém-criado, as chamadas podem levar mais tempo porque o dispositivo precisa alocar memória.
- A latência esperada aumenta proporcionalmente ao número de buffers solicitados em cada chamada.
- O app está mantendo buffers e está ocupado processando. Isso pode fazer com que as solicitações de buffer fiquem mais lentas 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 que diferentes tipos de estratégias de gerenciamento de buffer sejam implementados. Por exemplo:
- Compatibilidade com versões anteriores:a HAL solicita buffers para uma solicitação de captura durante a chamada
processCaptureRequest. Essa estratégia não oferece economia de memória, mas pode servir como a primeira implementação das APIs de gerenciamento de buffer, exigindo poucas mudanças de código na HAL da câmera atual. - Economia de memória maximizada:a HAL da câmera só solicita buffers de saída imediatamente antes que um seja necessário para ser preenchido. Essa estratégia permite a economia máxima de memória. A possível desvantagem é mais instabilidade no pipeline da câmera quando as solicitações de buffer levam um tempo incomumente longo para serem concluídas.
- Em cache:a HAL da câmera armazena alguns buffers em cache para que seja menos provável que seja afetada por uma solicitação de buffer lenta ocasional.
A HAL da câmera pode adotar diferentes estratégias para casos de uso específicos. Por exemplo, usar a estratégia de economia de memória maximizada para casos de uso que usam muita memória e usar a estratégia compatível com versões anteriores para outros casos de uso.
Implementação de amostra na HAL da câmera externa
A HAL da câmera externa foi introduzida no Android 9 e pode ser encontrada na
árvore de origem em
hardware/interfaces/camera/device/3.5/.
No Android 10, ela foi atualizada para incluir
ExternalCameraDeviceSession.cpp,
uma implementação da API de gerenciamento de buffer. Essa HAL da câmera externa
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++.