API de gestión de búfer HAL3 de cámara

Android 10 presenta API de administración de búfer HAL3 de cámara opcionales que le permiten implementar lógica de administración de búfer para lograr memoria diferente y capturar compensaciones de latencia en implementaciones de cámara HAL.

La cámara HAL 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 N conjuntos de buffers de salida al mismo tiempo.

Por ejemplo, HAL puede 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 dispositivos con Android 9 y versiones anteriores, el marco de la cámara asigna buffers cuando la solicitud está en cola en HAL, por lo que podría haber seis conjuntos de buffers en HAL que no estén en uso. En Android 10, las API de administración de búfer HAL3 de la cámara permiten desacoplar 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.

La Figura 1 muestra un diagrama de la interfaz HAL de la cámara para dispositivos con Android 9 y versiones anteriores. La Figura 2 muestra la interfaz HAL de la cámara en Android 10 con las API de administración del búfer HAL3 de la cámara implementadas.

Gestión de buffer en 9 o inferior

Figura 1. Interfaz HAL de la cámara en Android 9 y versiones anteriores

Gestión de búfer en Android 10

Figura 2. Interfaz HAL de la cámara en Android 10 usando las API de administración de búfer

Implementación de las API de gestión de búfer

Para implementar las API de gestión del búfer, la cámara HAL debe:

La cámara HAL utiliza los métodos requestStreamBuffers y returnStreamBuffers en ICameraDeviceCallback.hal para solicitar y devolver buffers. HAL también debe implementar el método signalStreamFlush en ICameraDeviceSession.hal para indicarle a la cámara HAL que devuelva buffers.

solicitudStreamBuffers

Utilice el método requestStreamBuffers para solicitar buffers desde el marco de la cámara. Cuando se utilizan las API de administración de búfer HAL3 de la cámara, las solicitudes de captura del marco de la cámara no contienen búferes de salida, es decir, el campo bufferId en StreamBuffer es 0 . Por lo tanto, la cámara HAL debe usar requestStreamBuffers para solicitar búfer desde el marco de la cámara.

El método requestStreamBuffers permite a la persona que llama solicitar múltiples buffers de múltiples flujos de salida en una sola llamada, lo que permite menos llamadas HIDL IPC. Sin embargo, las llamadas toman más tiempo cuando se solicitan más buffers 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 cámara HAL utilice un subproceso dedicado de alta prioridad para solicitar búferes.

Si falla una solicitud de búfer, la cámara HAL debe poder manejar adecuadamente errores no fatales. La siguiente lista describe las razones comunes por las que fallan las solicitudes de búfer y cómo la cámara HAL debe manejarlas.

  • La aplicación se desconecta del flujo de salida: este es un error no fatal. La cámara HAL debe enviar ERROR_REQUEST para cualquier solicitud de captura dirigida a una transmisión desconectada y estar lista para procesar solicitudes posteriores con normalidad.
  • Tiempo de espera: esto puede ocurrir cuando una aplicación está ocupada realizando un procesamiento intensivo mientras retiene algunos buffers. La cámara HAL debe enviar ERROR_REQUEST para las solicitudes de captura que no se pueden cumplir debido a un error de tiempo de espera y estar lista para procesar solicitudes posteriores con normalidad.
  • El marco de la cámara está preparando una nueva configuración de transmisión: la cámara HAL debe esperar hasta que se complete la siguiente llamada configureStreams antes de volver a llamar requestStreamBuffers .
  • La cámara HAL ha alcanzado su límite de búfer (el campo maxBuffers ): la cámara HAL debe esperar hasta que devuelva al menos un búfer de la transmisión antes de volver a llamar requestStreamBuffers .

returnStreamBuffers

Utilice el método returnStreamBuffers para devolver buffers adicionales al marco de la cámara. La cámara HAL normalmente devuelve buffers al marco de la cámara a través del método processCaptureResult , pero solo puede dar cuenta de las solicitudes de captura que se han enviado a la cámara HAL. Con el método requestStreamBuffers , es posible que la implementación HAL de la cámara retenga más buffers de los solicitados por el marco de la cámara. Aquí es cuando se debe utilizar el método returnStreamBuffers . Si la implementación HAL nunca contiene más buffers de los solicitados, la implementación HAL de la cámara no necesita llamar al método returnStreamBuffers .

señalStreamFlush

El marco de la cámara llama al método signalStreamFlush para notificar a la cámara HAL que devuelva todos los buffers disponibles. Normalmente se llama a esto cuando el marco de la cámara está a punto de llamar configureStreams y debe drenar el proceso de captura de la cámara. De manera similar al método returnStreamBuffers , si la implementación HAL de una cámara no contiene más buffers de los solicitados, es posible tener una implementación vacía de este método.

Después de que el marco de la cámara llama a signalStreamFlush , el marco deja de enviar nuevas solicitudes de captura a la cámara HAL hasta que todos los buffers se hayan devuelto al marco de la cámara. Cuando se devuelven todos los buffers, las llamadas al método requestStreamBuffers fallan y el marco de la cámara puede continuar su trabajo en un estado limpio. Luego, el marco de la cámara llama al método configureStreams o processCaptureRequest . Si el marco de la cámara llama al método configureStreams , la cámara HAL puede comenzar a solicitar buffers nuevamente después de que la llamada configureStreams regrese exitosamente. Si el marco de la cámara llama al método processCaptureRequest , la cámara HAL puede comenzar a solicitar buffers durante la llamada processCaptureRequest .

La semántica es diferente para el método signalStreamFlush y el método flush . Cuando se llama al método flush , HAL puede cancelar las solicitudes de captura pendientes con ERROR_REQUEST para drenar la canalización lo antes posible. Cuando se llama al método signalStreamFlush , HAL debe finalizar todas las solicitudes de captura pendientes normalmente y devolver todos los buffers al marco 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 marco de la cámara podría llamar a otras API de bloqueo antes de que HAL reciba la llamada signalStreamFlush . Esto significa que el método signalStreamFlush y otros métodos (específicamente el método configureStreams ) pueden llegar a la cámara HAL en un orden diferente al orden en que fueron llamados en el marco de la cámara. Para solucionar este problema de asincronía, el campo streamConfigCounter se agregó a StreamConfiguration y se agregó como argumento al método signalStreamFlush . La implementación HAL de la cámara debe usar el argumento streamConfigCounter para determinar si una llamada signalStreamFlush llega más tarde que su correspondiente llamada configureStreams . Consulte la Figura 3 para ver un ejemplo.

Manejar llamadas que llegan tarde

Figura 3. Cómo la cámara HAL debería detectar y manejar las llamadas de signalStreamFlush que llegan tarde

Cambios de comportamiento al implementar las API de administración del búfer

Cuando utilice las API de administración de búfer para implementar la lógica de administración de búfer, considere los siguientes posibles cambios de comportamiento en la cámara y la implementación HAL de la cámara:

  • Las solicitudes de captura llegan a la cámara HAL más rápido y con mayor frecuencia: sin API de administración de búfer, el marco de la cámara solicita búferes de salida para cada solicitud de captura antes de enviar una solicitud de captura a la cámara HAL. Cuando se utilizan las API de administración de búfer, el marco de la cámara ya no necesita esperar por los búferes y, por lo tanto, puede enviar solicitudes de captura a la cámara HAL antes.

    Además, sin las API de administración de búfer, el marco de la cámara deja de enviar solicitudes de captura si uno de los flujos de salida de la solicitud de captura ha alcanzado la cantidad máxima de búferes que HAL puede contener a la vez (este valor lo designa la cámara HAL en el HalStream::maxBuffers en el valor de retorno de una llamada configureStreams ). Con las API de administración de búfer, este comportamiento de limitación ya no existe y la implementación de HAL de la cámara no debe aceptar llamadas processCaptureRequest cuando HAL tiene demasiadas solicitudes de captura en cola.

  • La latencia de las llamadas requestStreamBuffers varía significativamente: hay muchas razones por las que una llamada requestStreamBuffers puede tardar más que el promedio. Por ejemplo:

    • Para los primeros buffers de una secuencia recién creada, las llamadas pueden tardar más porque el dispositivo necesita asignar memoria.
    • La latencia esperada aumenta en proporción al número de buffers solicitados en cada llamada.
    • La aplicación tiene buffers y está ocupada procesando. Esto puede hacer que las solicitudes de búfer se ralenticen o alcancen un tiempo de espera debido a la falta de búfer o a una CPU ocupada.

Estrategias de gestión de buffers

Las API de gestión de búfer permiten implementar diferentes tipos de estrategias de gestión de búfer. Algunos ejemplos son:

  • Compatible con versiones anteriores: HAL solicita buffers para una solicitud de captura durante la llamada processCaptureRequest . Esta estrategia no proporciona ningún ahorro de memoria, pero puede servir como la primera implementación de las API de administración del búfer, lo que requiere muy pocos cambios de código en la cámara HAL existente.
  • Ahorro de memoria maximizado: la cámara HAL solo solicita buffers de salida inmediatamente antes de que sea necesario llenar uno. Esta estrategia permite maximizar el ahorro de memoria. La posible desventaja es que se producen más bloqueos en la canalización de la cámara cuando las solicitudes de búfer tardan un tiempo inusualmente largo en finalizar.
  • En caché: la cámara HAL almacena en caché algunos buffers para que sea menos probable que se vea afectada por una solicitud de buffer lenta ocasional.

La cámara HAL puede adoptar diferentes estrategias para casos de uso particulares, por ejemplo, usando la estrategia de ahorro de memoria maximizada para casos de uso que usan mucha memoria y usando la estrategia de compatibilidad con versiones anteriores para otros casos de uso.

Ejemplo de implementación en la cámara externa HAL

La cámara externa HAL se introdujo en Android 9 y se puede encontrar en el árbol de fuentes 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 cámara externa HAL implementa la estrategia de ahorro de memoria maximizada mencionada en Estrategias de gestión de búfer en unos cientos de líneas de código C++.