API de gestion des tampons HAL3 de l'appareil photo

Android 10 introduit des API de gestion des tampons HAL3 de caméra facultatives qui vous permettent d'implémenter une logique de gestion des tampons pour obtenir différents compromis en termes de mémoire et de latence de capture dans les implémentations HAL de caméra.

La HAL de la caméra nécessite que N requêtes (où N est égal à la profondeur du pipeline) soient mises en file d'attente dans son pipeline, mais elle ne nécessite souvent pas les N ensembles de tampons de sortie en même temps.

Par exemple, la HAL peut avoir huit requêtes mises en file d'attente dans le pipeline, mais elle ne nécessite des tampons de sortie que pour les deux requêtes des dernières étapes du pipeline. Sur les appareils exécutant Android 9 ou une version antérieure, le framework de la caméra alloue des tampons lorsque la requête est mise en file d'attente dans la HAL. Il peut donc y avoir six ensembles de tampons dans la HAL qui ne sont pas utilisés. Dans Android 10, les API de gestion des tampons HAL3 de la caméra permettent de dissocier les tampons de sortie pour libérer les six ensembles de tampons. Cela peut permettre d'économiser des centaines de mégaoctets de mémoire sur les appareils haut de gamme et peut également être bénéfique pour les appareils à faible mémoire.

La figure 1 montre un schéma de l'interface HAL de la caméra pour les appareils exécutant Android 9 ou une version antérieure. La figure 2 montre l'interface HAL de la caméra dans Android 10 avec les API de gestion des tampons HAL3 de la caméra implémentées.

Gestion du tampon dans la version 9 ou antérieure

Figure 1. Interface HAL de la caméra dans Android 9 ou une version antérieure

Gestion des tampons dans Android 10

Figure 2. Interface HAL de la caméra dans Android 10 à l'aide des API de gestion des tampons

Implémenter les API de gestion des tampons

Pour implémenter les API de gestion des tampons, la HAL de la caméra doit :

La HAL de la caméra utilise les requestStreamBuffers et les returnStreamBuffers méthodes dans ICameraDeviceCallback.hal pour demander et renvoyer des tampons. La HAL doit également implémenter la signalStreamFlush méthode dans ICameraDeviceSession.hal pour signaler à la HAL de la caméra de renvoyer des tampons.

requestStreamBuffers

Utilisez la requestStreamBuffers méthode pour demander des tampons au framework de la caméra. Lorsque vous utilisez les API de gestion des tampons HAL3 de la caméra, les requêtes de capture du framework de la caméra ne contiennent pas de tampons de sortie, c'est-à-dire que le champ bufferId dans StreamBuffer est 0. Par conséquent, la HAL de la caméra doit utiliser requestStreamBuffers pour demander des tampons au framework de la caméra.

La méthode requestStreamBuffers permet à l'appelant de demander plusieurs tampons à partir de plusieurs flux de sortie en un seul appel, ce qui réduit le nombre d'appels IPC HIDL. Toutefois, les appels prennent plus de temps lorsque plusieurs tampons sont demandés en même temps, ce qui peut avoir un impact négatif sur la latence totale entre la requête et le résultat. De plus, comme les appels à requestStreamBuffers sont sérialisés dans le service de la caméra, il est recommandé que la HAL de la caméra utilise un thread dédié à haute priorité pour demander des tampons.

Si une requête de tampon échoue, la HAL de la caméra doit être en mesure de gérer correctement les erreurs non fatales. La liste suivante décrit les raisons courantes pour lesquelles les requêtes de tampon échouent et comment elles doivent être gérées par la HAL de la caméra.

  • L'application se déconnecte du flux de sortie : il s'agit d'une erreur non fatale. La HAL de la caméra doit envoyer ERROR_REQUEST pour toute requête de capture ciblant un flux déconnecté et être prête à traiter les requêtes suivantes normalement.
  • Délai avant expiration : cela peut se produire lorsqu'une application est occupée à effectuer un traitement intensif tout en conservant certains tampons. La HAL de la caméra doit envoyer ERROR_REQUEST pour les requêtes de capture qui ne peuvent pas être traitées en raison d'une erreur de délai avant expiration et être prête à traiter les requêtes suivantes normalement.
  • Le framework de la caméra prépare une nouvelle configuration de flux la HAL de la caméra doit attendre la fin du prochain appel configureStreams avant d'appeler requestStreamBuffers à nouveau.
  • La HAL de la caméra a atteint sa limite de tampons (champ maxBuffers) : la HAL de la caméra doit attendre qu'elle renvoie au moins un tampon du flux avant d'appeler requestStreamBuffers à nouveau.

returnStreamBuffers

Utilisez la returnStreamBuffers méthode pour renvoyer des tampons supplémentaires au framework de la caméra. La HAL de la caméra renvoie normalement des tampons au framework de la caméra via la processCaptureResult méthode, mais elle ne peut prendre en compte que les requêtes de capture qui ont été envoyées à la HAL de la caméra. Avec la méthode requestStreamBuffers, l'implémentation de la HAL de la caméra peut conserver plus de tampons que ce qui a été demandé par le framework de la caméra. C'est à ce moment-là que la méthode returnStreamBuffers doit être utilisée. Si l'implémentation de la HAL ne contient jamais plus de tampons que demandé, elle n'a pas besoin d'appeler la méthode returnStreamBuffers.

signalStreamFlush

La méthode signalStreamFlush est appelée par le framework de la caméra pour notifier à la HAL de la caméra de renvoyer tous les tampons disponibles. Elle est normalement appelée lorsque le framework de la caméra est sur le point d'appeler call configureStreams et doit vider le pipeline de capture de la caméra. Comme pour la méthode returnStreamBuffers, si une implémentation de la HAL de la caméra ne contient pas plus de tampons que demandé, il est possible d'avoir une implémentation vide de cette méthode.

Une fois que le framework de la caméra appelle signalStreamFlush, il cesse d'envoyer de nouvelles requêtes de capture à la HAL de la caméra jusqu'à ce que tous les tampons aient été renvoyés au framework de la caméra. Lorsque tous les tampons sont renvoyés, les appels de la méthode requestStreamBuffers échouent et le framework de la caméra peut poursuivre son travail dans un état propre. Le framework de la caméra appelle ensuite la méthode configureStreams ou processCaptureRequest. Si le framework de la caméra appelle la méthode configureStreams, la HAL de la caméra peut recommencer à demander des tampons une fois que l'appel configureStreams est renvoyé. Si le framework de la caméra appelle la méthode processCaptureRequest, la HAL de la caméra peut commencer à demander des tampons lors de l'appel processCaptureRequest.

La sémantique est différente pour la signalStreamFlush méthode et la flush méthode. Lorsque la méthode flush est appelée, la HAL peut abandonner les requêtes de capture en attente avec ERROR_REQUEST pour vider le pipeline dès que possible. Lorsque la méthode signalStreamFlush est appelée, la HAL doit terminer toutes les requêtes de capture en attente normalement et renvoyer tous les tampons au framework de la caméra.

Une autre différence entre la méthode signalStreamFlush et les autres méthodes est que signalStreamFlush est une méthode HIDL unidirectionnelle. Cela signifie que le framework de la caméra peut appeler d'autres API bloquantes avant que la HAL ne reçoive l'appel signalStreamFlush. Cela signifie que la méthode signalStreamFlush et d'autres méthodes (en particulier la méthode configureStreams) peuvent arriver à la HAL de la caméra dans un ordre différent de celui dans lequel elles ont été appelées dans le framework de la caméra. Pour résoudre ce problème d'asynchronisme, le champ streamConfigCounter a été ajouté à StreamConfiguration et ajouté en tant qu'argument à la méthode signalStreamFlush. L'implémentation de la HAL de la caméra doit utiliser l'argument streamConfigCounter pour déterminer si un appel signalStreamFlush arrive après l'appel configureStreams correspondant. Pour obtenir un exemple, consultez la figure 3.

Gérer les appels qui arrivent en retard

Figure 3. Comment la HAL de la caméra doit détecter et gérer les appels signalStreamFlush qui arrivent en retard

Changements de comportement lors de l'implémentation des API de gestion des tampons

Lorsque vous utilisez les API de gestion des tampons pour implémenter la logique de gestion des tampons, tenez compte des modifications de comportement possibles suivantes pour la caméra et l'implémentation de la HAL de la caméra :

  • Les requêtes de capture arrivent plus rapidement et plus fréquemment à la HAL de la caméra : sans les API de gestion des tampons, le framework de la caméra demande des tampons de sortie pour chaque requête de capture avant d'envoyer une requête de capture à la HAL de la caméra. Lorsque vous utilisez les API de gestion des tampons, le framework de la caméra n'a plus besoin d'attendre les tampons et peut donc envoyer des requêtes de capture à la HAL de la caméra plus tôt.

    De plus, sans les API de gestion des tampons, le framework de la caméra cesse d'envoyer des requêtes de capture si l'un des flux de sortie de la requête de capture a atteint le nombre maximal de tampons que la HAL peut contenir à la fois (cette valeur est désignée par la HAL de la caméra dans le champ HalStream::maxBuffers de la valeur renvoyée d'un appel configureStreams). Avec les API de gestion des tampons, ce comportement de limitation n'existe plus et l'implémentation de la HAL de la caméra ne doit pas accepter les appels processCaptureRequest lorsque la HAL a trop de requêtes de capture mises en file d'attente.

  • La latence des appels requestStreamBuffers varie considérablement : il existe de nombreuses raisons pour lesquelles un appel requestStreamBuffers peut prendre plus de temps que la moyenne. Par exemple :

    • Pour les premiers tampons d'un flux nouvellement créé, les appels peuvent prendre plus de temps, car l'appareil doit allouer de la mémoire.
    • La latence attendue augmente proportionnellement au nombre de tampons demandés dans chaque appel.
    • L'application contient des tampons et est occupée à traiter des données. Cela peut entraîner un ralentissement des requêtes de tampon ou un délai avant expiration en raison d'un manque de tampons ou d'un processeur occupé.

Stratégies de gestion des tampons

Les API de gestion des tampons permettent d'implémenter différents types de stratégies de gestion des tampons. Par exemple :

  • Rétrocompatibilité : la HAL demande des tampons pour une requête de capture lors de l'appel processCaptureRequest. Cette stratégie n'offre aucune économie de mémoire, mais peut servir de première implémentation des API de gestion des tampons, nécessitant très peu de modifications de code dans la HAL de la caméra existante.
  • Économies de mémoire maximales : la HAL de la caméra ne demande des tampons de sortie qu'immédiatement avant qu'il ne soit nécessaire de les remplir. Cette stratégie permet de maximiser les économies de mémoire. L'inconvénient potentiel est un plus grand nombre d'à-coups dans le pipeline de la caméra lorsque les requêtes de tampon mettent un temps anormalement long à se terminer.
  • Mise en cache : la HAL de la caméra met en cache quelques tampons afin qu'elle soit moins susceptible d'être affectée par une requête de tampon lente occasionnelle.

La HAL de la caméra peut adopter différentes stratégies pour des cas d'utilisation spécifiques. Par exemple, elle peut utiliser la stratégie d'économie de mémoire maximale pour les cas d'utilisation qui consomment beaucoup de mémoire et la stratégie rétrocompatible pour les autres cas d'utilisation.

Exemple d'implémentation dans la HAL de la caméra externe

La HAL de la caméra externe a été introduite dans Android 9 et se trouve dans l' arborescence source à l' adressehardware/interfaces/camera/device/3.5/. Dans Android 10, elle a été mise à jour pour inclure ExternalCameraDeviceSession.cpp, une implémentation de l'API de gestion des tampons. Cette HAL de la caméra externe implémente la stratégie d'économie de mémoire maximale mentionnée dans Stratégies de gestion des tampons en quelques centaines de lignes de code C++.