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 una lógica de administración de búfer para lograr una memoria diferente y capturar compensaciones de latencia en las implementaciones de HAL de cámara.

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 N conjuntos de búferes 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 los dispositivos que ejecutan Android 9 y versiones anteriores, el marco de la cámara asigna búferes cuando la solicitud se pone 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 API de administración de búfer HAL3 de la cámara permiten el desacoplamiento 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 gama alta 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 que ejecutan 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 de búfer HAL3 de la cámara implementadas.

Gestión de búfer 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 administración de búfer

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

La cámara HAL usa los métodos requestStreamBuffers y returnStreamBuffers en ICameraDeviceCallback.hal para solicitar y devolver búferes. La HAL también debe implementar el método signalStreamFlush en ICameraDeviceSession.hal para señalar a la cámara HAL que devuelva los búferes.

solicitarStreamBuffers

Utilice el método requestStreamBuffers para solicitar búferes del marco de la cámara. Cuando se usan 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úfer 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 marco de la cámara.

El método requestStreamBuffers permite a la persona que llama solicitar múltiples búferes 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 búfer al mismo tiempo y esto podría afectar negativamente la latencia total de la solicitud al resultado. Además, debido a que las llamadas a requestStreamBuffers se serializan en el servicio de la 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 ser capaz de manejar correctamente los errores no fatales. La siguiente lista describe las razones comunes por las que fallan las solicitudes de búfer y cómo debe manejarlas la HAL de la cámara.

  • La aplicación se desconecta del flujo de salida: este es un error no fatal. La HAL de la cámara debe enviar ERROR_REQUEST para cualquier solicitud de captura dirigida a una transmisión desconectada y estar lista para procesar las solicitudes posteriores con normalidad.
  • Tiempo de espera: esto puede ocurrir cuando una aplicación está ocupada realizando un procesamiento intensivo mientras mantiene algunos búferes. 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 las solicitudes posteriores con normalidad.
  • El marco 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 llamada a configureStreams antes de volver a llamar a requestStreamBuffers .
  • La HAL de la cámara ha alcanzado su límite de búfer (el campo maxBuffers ): la HAL de la cámara debe esperar hasta que devuelva al menos un búfer de la secuencia antes de volver a llamar a requestStreamBuffers .

devolverStreamBuffers

Utilice el método returnStreamBuffers para devolver búferes adicionales al marco de la cámara. La HAL de la cámara normalmente devuelve búferes 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 HAL de la cámara. Con el método requestStreamBuffers , es posible que la implementación HAL de la cámara retenga más búferes de los que ha solicitado el marco de la cámara. Aquí es cuando se debe usar el método returnStreamBuffers . Si la implementación de HAL nunca contiene más búferes de los solicitados, la implementación de HAL de la cámara no necesita llamar al método returnStreamBuffers .

señalStreamFlush

El framework de la cámara llama al método signalStreamFlush para notificar a la HAL de la cámara que devuelva todos los búfer disponibles. Esto normalmente se llama cuando el marco de la cámara está a punto de llamar a configureStreams y debe drenar la canalización de captura de la cámara. De manera similar al método returnStreamBuffers , si la implementación de HAL de una cámara no contiene más búferes 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 HAL de la cámara hasta que todos los búfer se hayan devuelto al marco de la cámara. Cuando se devuelven todos los búferes, 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 trabajo de la cámara llama al método configureStreams , la HAL de la cámara puede comenzar a solicitar búfer nuevamente después de que la llamada a configureStreams se devuelve correctamente. Si el marco 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 método de flush . Cuando se llama al método de flush , 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 normalmente todas las solicitudes de captura pendientes y devolver todos los búferes 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 puede llamar a otras API de bloqueo antes de que HAL reciba la llamada de 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 abordar este problema de asincronía, el campo streamConfigCounter se agregó a StreamConfiguration y se agregó como argumento al método signalStreamFlush . La implementación de HAL de la cámara debe usar el argumento streamConfigCounter para determinar si una llamada de signalStreamFlush llega más tarde que su llamada de configureStreams correspondiente. Consulte la Figura 3 para ver un ejemplo.

Manejo de llamadas que llegan tarde

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

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

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

  • Las solicitudes de captura llegan a la HAL de la cámara más rápido y con mayor frecuencia: sin las 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 HAL de la cámara. Al usar las API de administración de búfer, el marco de la cámara ya no necesita esperar a los búfer y, por lo tanto, puede enviar solicitudes de captura a la HAL de la cámara 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 la HAL puede contener al mismo tiempo (este valor lo designa la HAL de la cámara 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 la llamada de requestStreamBuffers varía significativamente: hay muchas razones por las que una llamada de requestStreamBuffers puede tardar más tiempo que el promedio. Por ejemplo:

    • Para los primeros búferes 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 búferes y está ocupada procesando. Esto puede hacer que las solicitudes de búfer se ralenticen o superen el tiempo de espera debido a la falta de búferes o a una CPU ocupada.

Estrategias de gestión de reservas

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

  • Compatible con versiones anteriores: 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 API de administración de 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 búferes de salida inmediatamente antes de que se necesite llenar uno. Esta estrategia permite maximizar el ahorro de memoria. La desventaja potencial es que la canalización de la cámara se bloquea más cuando las solicitudes de búfer tardan un tiempo inusualmente largo en finalizar.
  • En caché: la cámara HAL almacena en caché algunos búfer para que sea menos probable que se vea afectada por una solicitud de búfer lenta ocasional.

La cámara HAL puede adoptar diferentes estrategias para casos de uso particulares, por ejemplo, usar la estrategia de ahorro de memoria maximizada para casos de uso que usan mucha memoria y usar la estrategia compatible 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 HAL de cámara externa implementa la estrategia de ahorro de memoria maximizada mencionada en Estrategias de administración de búfer en unos pocos cientos de líneas de código C++.