La HAL de la cámara requiere N solicitudes (donde N es igual a la profundidad de la canalización) en cola en su canalización, pero, a menudo, no requiere todos los conjuntos de búferes de salida al mismo tiempo.
Por ejemplo, la HAL podría tener ocho solicitudes en cola en la canalización, pero solo requiere búferes de salida para las dos solicitudes en las últimas etapas de la canalización. En los dispositivos que ejecutan Android 9 y versiones anteriores, el framework de la cámara asigna búferes cuando la solicitud está en cola en la HAL, por lo que podría haber seis conjuntos de búferes en la HAL que no estén en uso. En Android 10, las APIs de administración de búfer de la HAL3 de la cámara permiten la separación de los búferes de salida para liberar los seis conjuntos de búferes. Esto puede generar cientos de megabytes de ahorro de memoria en dispositivos de alta gama y también puede ser beneficioso para dispositivos con poca memoria.
En la Figura 1, se muestra un diagrama de la interfaz de la HAL de la cámara para dispositivos que ejecutan Android 9 y versiones anteriores. En la Figura 2, se muestra la interfaz de la HAL de la cámara en Android 10 con las APIs de administración de búfer de la HAL3 de la cámara implementadas.
Figura 1: Interfaz de la HAL de la cámara en Android 9 y versiones anteriores
Figura 2: Interfaz de la HAL de la cámara en Android 10 con las APIs de administración de búfer
Implementa las APIs de administración de búfer
Para implementar las APIs de administración de búfer, la HAL de la cámara debe hacer lo siguiente:
- Implementar HIDL
ICameraDevice@3.5 - Establecer la clave de características de la cámara
android.info.supportedBufferManagementVersionenHIDL_DEVICE_3_5.
La HAL de la cámara usa los
requestStreamBuffers
y
returnStreamBuffers
métodos en
ICameraDeviceCallback.hal
para solicitar y mostrar búferes. La HAL también debe implementar el
signalStreamFlush
método en
ICameraDeviceSession.hal
para indicarle a la HAL de la cámara que muestre búferes.
requestStreamBuffers
Usa el
requestStreamBuffers
método para solicitar búferes del framework de la cámara. Cuando se usan las APIs de administración de búfer de la HAL3
de la cámara, las solicitudes de captura del framework de la cámara no
contienen búferes de salida, es decir, el campo bufferId en
StreamBuffer
es 0. Por lo tanto, la HAL de la cámara debe usar requestStreamBuffers para solicitar búferes del framework de la cámara.
El método requestStreamBuffers permite que el llamador solicite varios búferes de varias transmisiones de salida en una sola llamada, lo que permite menos llamadas IPC de HIDL. Sin embargo, las llamadas tardan más cuando se solicitan más búferes al mismo tiempo, y esto podría afectar negativamente la latencia total de solicitud a resultado.
Además, debido a que las llamadas a requestStreamBuffers se serializan en el servicio de cámara, se recomienda que la HAL de la cámara use un subproceso de alta prioridad dedicado para solicitar búferes.
Si falla una solicitud de búfer, la HAL de la cámara debe poder controlar correctamente los errores no fatales. En la siguiente lista, se describen los motivos comunes por los que fallan las solicitudes de búfer y cómo debe controlarlas la HAL de la cámara.
- La app se desconecta de la transmisión de salida: Este es un error no fatal. La HAL de la cámara debe enviar
ERROR_REQUESTpara cualquier solicitud de captura que apunte a una transmisión desconectada y estar lista para procesar las solicitudes posteriores con normalidad. - Tiempo de espera agotado: Esto puede ocurrir cuando una app está ocupada realizando un procesamiento intensivo mientras retiene algunos búferes. La HAL de la cámara debe
enviar
ERROR_REQUESTpara las solicitudes de captura que no se puedan completar debido a un error de tiempo de espera agotado y estar lista para procesar las solicitudes posteriores con normalidad. - El framework de la cámara está preparando una nueva configuración de transmisión:
La HAL de la cámara debe esperar hasta que se complete la siguiente
configureStreamsllamada se complete antes de volver a llamar arequestStreamBuffersde nuevo. - La HAL de la cámara alcanzó su
límite de búfer
(el campo
maxBuffers): La HAL de la cámara debe esperar hasta que muestre al menos un búfer de la transmisión antes de volver a llamar arequestStreamBuffers.
returnStreamBuffers
Usa el
returnStreamBuffers
método para mostrar búferes adicionales al framework de la cámara. Por lo general, la HAL de la cámara muestra búferes al framework de la cámara a través del método
processCaptureResult
, pero solo puede tener en cuenta las solicitudes de captura que se enviaron a la
HAL de la cámara. Con el método requestStreamBuffers, es posible que la implementación de la HAL de la cámara retenga más búferes de los que solicitó el framework de la cámara. Es entonces cuando se debe usar el método returnStreamBuffers. Si la implementación de la HAL nunca retiene más búferes de los solicitados, la implementación de la HAL de la cámara no necesita llamar al método returnStreamBuffers.
signalStreamFlush
El framework de la cámara llama al
signalStreamFlush
método para notificar a la HAL de la cámara que muestre todos los
búferes disponibles. Por lo general, se llama cuando el framework de la cámara está a punto de
llamar
configureStreams
y debe vaciar la canalización de captura de la cámara. Al igual que el método returnStreamBuffers, si una implementación de la HAL de la cámara no retiene más búferes de los solicitados, es posible tener una implementación vacía de este método.
Después de que el framework de la cámara llama a
signalStreamFlush,
el framework deja de enviar solicitudes de captura nuevas a la HAL de la cámara hasta que se devuelvan todos los
búferes al framework de la cámara. Cuando se devuelven todos los búferes, fallan las llamadas al método requestStreamBuffers, y el framework de la cámara puede continuar su trabajo en un estado limpio. Luego, el framework de la cámara
llama al método
configureStreams
o
processCaptureRequest. Si el framework de la cámara llama al método configureStreams, la HAL de la cámara puede comenzar a solicitar búferes nuevamente después de que la llamada a configureStreams se muestre correctamente. Si el framework de la cámara llama al método processCaptureRequest, la HAL de la cámara puede comenzar a solicitar búferes durante la llamada a processCaptureRequest.
La semántica es diferente para el método signalStreamFlush y el
flush
método. Cuando se llama al método flush, la HAL puede anular las solicitudes de captura pendientes
con
ERROR_REQUEST
para vaciar la canalización lo antes posible. Cuando se llama al método signalStreamFlush, la HAL debe finalizar todas las solicitudes de captura pendientes con normalidad y mostrar todos los búferes al framework de la cámara.
Otra diferencia entre el método signalStreamFlush y otros métodos es que signalStreamFlush es un método HIDL unidireccional, lo que significa que el framework de la cámara podría llamar a otras APIs de bloqueo antes de que la HAL reciba la llamada a signalStreamFlush. Esto significa que el método signalStreamFlush y otros métodos (específicamente el método configureStreams) podrían llegar a la HAL de la cámara en un orden diferente al orden en que se llamaron en el framework de la cámara. Para abordar este problema de asincronía, se agregó el campo streamConfigCounter a StreamConfiguration y se agregó como argumento al método signalStreamFlush. La implementación de la HAL de la cámara debe usar el argumento streamConfigCounter para determinar si una llamada a signalStreamFlush llega más tarde que su llamada correspondiente a configureStreams. Consulta la Figura 3 para ver un ejemplo.
Figura 3: Cómo la HAL de la cámara debe detectar y controlar las llamadas a signalStreamFlush que llegan tarde
Cambios de comportamiento cuando se implementan las APIs de administración de búfer
Cuando uses las APIs de administración de búfer para implementar la lógica de administración de búfer, considera los siguientes posibles cambios de comportamiento en la cámara y la implementación de la HAL de la cámara:
Las solicitudes de captura llegan a la HAL de la cámara más rápido y con mayor frecuencia: Sin las APIs de administración de búfer, el framework de la cámara solicita búferes de salida para cada solicitud de captura antes de enviar una solicitud de captura a la HAL de la cámara. Cuando se usan las APIs de administración de búfer, el framework de la cámara ya no necesita esperar los búferes y, por lo tanto, puede enviar solicitudes de captura a la HAL de la cámara antes.
Además, sin las APIs de administración de búfer, el framework de la cámara deja de enviar solicitudes de captura si una de las transmisiones de salida de la solicitud de captura alcanzó la cantidad máxima de búferes que la HAL puede retener a la vez (este valor se designa con la HAL de la cámara en el campo
HalStream::maxBuffersen el valor que muestra una llamada aconfigureStreams). Con las APIs de administración de búfer, este comportamiento de limitación ya no existe, y la implementación de la HAL de la cámara no debe aceptar llamadas aprocessCaptureRequestcuando la HAL tiene demasiadas solicitudes de captura en cola.La latencia de la llamada a
requestStreamBuffersvaría significativamente: Hay muchos motivos por los que una llamada arequestStreamBufferspodría tardar más que el promedio. Por ejemplo:- Para los primeros búferes de una transmisión recién creada, las llamadas pueden tardar más porque el dispositivo necesita asignar memoria.
- La latencia esperada aumenta en proporción a la cantidad de búferes solicitados en cada llamada.
- La app retiene búferes y está ocupada procesando. Esto puede hacer que las solicitudes de búfer se ralenticen o alcancen un tiempo de espera agotado debido a la falta de búferes o a una CPU ocupada.
Estrategias de administración de búfer
Las APIs de administración de búfer permiten implementar diferentes tipos de estrategias de administración de búfer. Por ejemplo:
- Retrocompatibilidad: La HAL solicita búferes para una solicitud de captura durante la llamada a
processCaptureRequest. Esta estrategia no proporciona ningún ahorro de memoria, pero puede servir como la primera implementación de las APIs de administración de búfer, ya que requiere muy pocos cambios de código en la HAL de la cámara existente. - Ahorro de memoria maximizado: La HAL de la cámara solo solicita búferes de salida inmediatamente antes de que se necesite uno para completar. Esta estrategia permite maximizar el ahorro de memoria. La posible desventaja es que la canalización de la cámara se sacuda más cuando las solicitudes de búfer tardan demasiado en finalizar.
- Almacenamiento en caché: La HAL de la cámara almacena en caché algunos búferes para que sea menos probable que se vea afectada por una solicitud de búfer lenta ocasional.
La HAL de la cámara puede adoptar diferentes estrategias para casos de uso particulares, por ejemplo, usar la estrategia de ahorro de memoria maximizado para casos de uso que usan mucha memoria y usar la estrategia retrocompatible para otros casos de uso.
Implementación de muestra en la HAL de la cámara externa
La HAL de la cámara externa se introdujo en Android 9 y se puede encontrar en el
árbol de origen en
hardware/interfaces/camera/device/3.5/.
En Android 10, se actualizó para incluir
ExternalCameraDeviceSession.cpp,
una implementación de la API de administración de búfer. Esta HAL de la cámara externa
implementa la estrategia de ahorro de memoria maximizado que se menciona en Estrategias de administración de búfer en unos cientos de líneas de
código C++.