Android 10 introduit des API de gestion de tampon HAL3 de l'appareil photo facultatives qui vous permettent d'implémenter une logique de gestion de tampon pour obtenir différents compromis de mémoire et de latence de capture dans les implémentations HAL de l'appareil photo.
Le HAL de l'appareil photo nécessite N requêtes (où N est égal à la profondeur du pipeline) mises en file d'attente dans son pipeline, mais il ne nécessite souvent pas tous les N ensembles de tampons de sortie en même temps.
Par exemple, le HAL peut avoir huit requêtes en file d'attente dans le pipeline, mais il ne nécessite que des tampons de sortie pour les deux requêtes des dernières étapes du pipeline. Sur les appareils équipés d'Android 9 ou d'une version antérieure, le framework de l'appareil photo alloue des tampons lorsque la requête est mise en file d'attente dans le HAL. Il peut donc y avoir six ensembles de tampons dans le HAL qui ne sont pas utilisés. Dans Android 10, les API de gestion des tampons HAL3 de l'appareil photo permettent de découpler les tampons de sortie pour libérer les six ensembles de tampons. Cela peut entraîner des centaines de mégaoctets d'économies 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 présente un schéma de l'interface HAL de l'appareil photo pour les appareils équipés d'Android 9 ou version antérieure. La figure 2 montre l'interface HAL de l'appareil photo dans Android 10 avec les API de gestion des tampons HAL3 de l'appareil photo implémentées.
Figure 1 : Interface HAL de l'appareil photo sous Android 9 ou version antérieure
Figure 2. Interface HAL de l'appareil photo sous 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, le HAL de l'appareil photo doit:
- Implémentez HIDL
ICameraDevice@3.5
. - Définissez la clé de caractéristiques de l'appareil photo
android.info.supportedBufferManagementVersion
surHIDL_DEVICE_3_5
.
Le HAL de la caméra utilise les méthodes requestStreamBuffers
et returnStreamBuffers
dans ICameraDeviceCallback.hal
pour demander et renvoyer des tampons. Le HAL doit également implémenter la méthode signalStreamFlush
dans ICameraDeviceSession.hal
pour signaler au HAL de la caméra qu'il doit renvoyer des tampons.
requestStreamBuffers
Utilisez la méthode requestStreamBuffers
pour demander des tampons au framework de l'appareil photo. Lorsque vous utilisez les API de gestion des tampons HAL3 de l'appareil photo, les requêtes de capture du framework de l'appareil photo ne contiennent pas de tampons de sortie. Autrement dit, le champ bufferId
dans StreamBuffer
est 0
. Par conséquent, le HAL de l'appareil photo doit utiliser requestStreamBuffers
pour demander des tampons au framework de l'appareil photo.
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 de la requête au résultat.
De plus, comme les appels à requestStreamBuffers
sont sérialisés dans le service de la caméra, il est recommandé que le HAL de la caméra utilise un thread dédié à haute priorité pour demander des tampons.
Si une requête de mise en mémoire tampon échoue, le HAL de la caméra doit pouvoir 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 le 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 normalement les requêtes suivantes. - Expiration:cela peut se produire lorsqu'une application effectue 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 normalement les requêtes suivantes. - Le framework de la caméra prépare une nouvelle configuration de flux:le HAL de la caméra doit attendre la fin de l'appel
configureStreams
suivant avant d'appeler à nouveaurequestStreamBuffers
. - La HAL de la caméra a atteint sa limite de mémoire tampon (champ
maxBuffers
): La HAL de la caméra doit attendre de renvoyer au moins un tampon du flux avant d'appeler à nouveaurequestStreamBuffers
.
returnStreamBuffers
Utilisez la méthode returnStreamBuffers
pour renvoyer des tampons supplémentaires au framework de la caméra. Le HAL de la caméra renvoie normalement des tampons au framework de la caméra via la méthode processCaptureResult
, mais il ne peut tenir compte que des requêtes de capture qui ont été envoyées au HAL de la caméra. Avec la méthode requestStreamBuffers
, l'implémentation du HAL de l'appareil photo peut conserver plus de tampons que ce qui a été demandé par le framework de l'appareil photo. La méthode returnStreamBuffers
doit alors être utilisée. Si l'implémentation HAL ne contient jamais plus de tampons que ce qui est demandé, il n'est pas nécessaire d'appeler la méthode returnStreamBuffers
.
signalStreamFlush
La méthode signalStreamFlush
est appelée par le framework de l'appareil photo pour avertir l'HAL de la caméra qu'il doit renvoyer tous les tampons à portée de main. Cette méthode est généralement appelée lorsque le framework de l'appareil photo est sur le point d'appeler configureStreams
et doit vider le pipeline de capture de l'appareil photo. Comme pour la méthode returnStreamBuffers
, si une implémentation du 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 l'appareil photo a appelé signalStreamFlush
, il cesse d'envoyer de nouvelles requêtes de capture à l'HAL de la caméra jusqu'à ce que tous les tampons aient été renvoyés au framework de l'appareil photo. Lorsque tous les tampons sont renvoyés, les appels de méthode requestStreamBuffers
échouent et le framework de l'appareil photo peut continuer à fonctionner normalement. Le framework de la caméra appelle ensuite la méthode configureStreams
ou processCaptureRequest
. Si le framework de l'appareil photo appelle la méthode configureStreams
, le HAL de l'appareil photo peut recommencer à demander des tampons une fois que l'appel configureStreams
a bien été renvoyé. Si le framework de la caméra appelle la méthode processCaptureRequest
, le HAL de la caméra peut commencer à demander des tampons pendant l'appel processCaptureRequest
.
La sémantique est différente pour la méthode signalStreamFlush
et la méthode flush
. Lorsque la méthode flush
est appelée, le HAL peut interrompre 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, le HAL doit terminer normalement toutes les requêtes de capture en attente et renvoyer tous les tampons au framework de l'appareil photo.
Une autre différence entre la méthode signalStreamFlush
et les autres méthodes est que signalStreamFlush
est une méthode HIDL à sens unique, ce qui signifie que le framework de l'appareil photo peut appeler d'autres API bloquantes avant que le 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 au 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'asynchronie, le champ streamConfigCounter
a été ajouté à StreamConfiguration
et en tant qu'argument à la méthode signalStreamFlush
. L'implémentation du HAL de l'appareil photo doit utiliser l'argument streamConfigCounter
pour déterminer si un appel signalStreamFlush
arrive plus tard que son appel configureStreams
correspondant. Reportez-vous à la Figure 3 pour obtenir un exemple.
Figure 3. Comment le HAL de la caméra doit détecter et gérer les appels signalStreamFlush qui arrivent en retard
Changements de comportement lors de la mise en œuvre 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 l'implémentation de la caméra et du HAL de la caméra:
Les requêtes de capture arrivent plus rapidement et plus fréquemment au HAL de l'appareil photo:sans API de gestion des tampons, le framework de l'appareil photo demande des tampons de sortie pour chaque requête de capture avant d'envoyer une requête de capture au HAL de l'appareil photo. Lorsque vous utilisez les API de gestion des tampons, le framework de l'appareil photo n'a plus besoin d'attendre les tampons et peut donc envoyer des requêtes de capture plus tôt au HAL de la caméra.
De plus, sans API de gestion des tampons, le framework de l'appareil photo 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 le HAL peut contenir à la fois (cette valeur est désignée par le HAL de l'appareil photo dans le champ
HalStream::maxBuffers
dans la valeur renvoyée d'un appelconfigureStreams
). Avec les API de gestion des tampons, ce comportement de limitation n'existe plus et l'implémentation du HAL de l'appareil photo ne doit pas accepter les appelsprocessCaptureRequest
lorsque le HAL a trop de requêtes de capture en file d'attente.La latence des appels
requestStreamBuffers
varie considérablement:de nombreuses raisons peuvent expliquer qu'un appelrequestStreamBuffers
prenne plus de temps que la moyenne. 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 détient des tampons et est en cours de traitement. 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 de mettre en œuvre différents types de stratégies de gestion des tampons. Par exemple :
- Rétrocompatibilité:le 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, ce qui nécessite très peu de modifications de code dans le HAL de l'appareil photo existant. - Économies de mémoire maximales:le HAL de l'appareil photo ne demande des tampons de sortie qu'immédiatement avant qu'un d'entre eux ne soit nécessaire. Cette stratégie permet de maximiser les économies de mémoire. L'inconvénient potentiel est une augmentation des à-coups du pipeline de l'appareil photo lorsque les requêtes de tampon prennent un temps inhabituellement long à se terminer.
- Mis en cache:le HAL de la caméra met en cache quelques tampons afin qu'il soit moins susceptible d'être affecté par une requête de tampon lente occasionnelle.
La HAL de l'appareil photo peut adopter différentes stratégies pour des cas d'utilisation particuliers. Par exemple, vous pouvez utiliser la stratégie d'optimisation de la mémoire pour les cas d'utilisation qui utilisent beaucoup de mémoire et la stratégie rétrocompatible pour les autres cas d'utilisation.
Exemple d'implémentation dans le HAL de la caméra externe
Le HAL de la caméra externe a été introduit dans Android 9 et est disponible dans l'arborescence source sur hardware/interfaces/camera/device/3.5/
.
Sous Android 10, il a été mis à jour pour inclure ExternalCameraDeviceSession.cpp
, une implémentation de l'API de gestion des tampons. Ce HAL de caméra externe implémente la stratégie d'économie de mémoire maximisée mentionnée dans les stratégies de gestion des tampons en quelques centaines de lignes de code C++.