Les fabricants d'appareils peuvent exposer des extensions telles que le bokeh, le mode nuit et le HDR à des développeurs tiers via l'interface Camera Extensions fournie par la bibliothèque du fournisseur OEM. Les développeurs peuvent utiliser l' API Camera2 Extensions et l' API CameraX Extensions pour accéder aux extensions implémentées dans la bibliothèque du fournisseur OEM.
Pour une liste des extensions prises en charge, qui est la même pour Camera2 et CameraX, voir API CameraX Extensions . Si vous souhaitez ajouter une extension, signalez un bogue avec l' Issue Tracker .
Cette page décrit comment implémenter et activer la bibliothèque du fournisseur OEM sur les appareils.
Architecture
Le schéma suivant décrit l'architecture de l'interface Camera Extensions ou extensions-interface
:
Figure 1. Schéma d'architecture des extensions de caméra
Comme indiqué dans le diagramme, pour prendre en charge les extensions de caméra, vous devez implémenter l' extensions-interface
fournie par la bibliothèque du fournisseur OEM. Votre bibliothèque de fournisseur OEM active deux API : l'API d'extensions CameraX et l'API d'extensions Camera2 , qui sont utilisées respectivement par les applications CameraX et Camera2 pour accéder aux extensions de fournisseur.
Implémenter la bibliothèque de fournisseurs OEM
Pour implémenter la bibliothèque du fournisseur OEM, copiez les fichiers camera-extensions-stub
dans un projet de bibliothèque système. Ces fichiers définissent l'interface Camera Extensions.
Les fichiers camera-extensions-stub
sont divisés dans les catégories suivantes :
Fichiers d'interface essentiels (ne pas modifier)
-
PreviewExtenderImpl.java
-
ImageCaptureExtenderImpl.java
-
ExtenderStateListener.java
-
ProcessorImpl.java
-
PreviewImageProcessorImpl.java
-
CaptureProcessorImpl.java
-
CaptureStageImpl.java
-
RequestUpdateProcessorImpl.java
-
ProcessResultImpl.java
-
advanced/AdvancedExtenderImpl.java
-
advanced/Camera2OutputConfigImpl.java
-
advanced/Camera2SessionConfigImpl.java
-
advanced/ImageProcessorImpl.java
-
advanced/ImageReaderOutputConfigImpl.java
-
advanced/ImageReferenceImpl.java
-
advanced/MultiResolutionImageReaderOutputConfigImpl.java
-
advanced/OutputSurfaceImpl.java
-
advanced/RequestProcessorImpl.java
-
advanced/SessionProcessorImpl.java
-
advanced/SurfaceOutputConfigImpl.java
Implémentations obligatoires (ajoutez votre implémentation)
-
ExtensionVersionImpl.java
-
InitializerImpl.java
Classes d'extension Bokeh (implémentez-les si l'extension Bokeh est prise en charge)
-
BokehImageCaptureExtenderImpl.java
-
BokehPreviewExtenderImpl.java
-
advanced/BokehAdvancedExtenderImpl.java
Classes d'extension de nuit (implémentez-les si l'extension de nuit est prise en charge)
-
NightImageCaptureExtenderImpl.java
-
NightPreviewExtenderImpl.java
-
advanced/NightAdvancedExtenderImpl.java
Classes d'extension automatique (implémentez-les si l'extension automatique est prise en charge)
-
AutoImageCaptureExtenderImpl.java
-
AutoPreviewExtenderImpl.java
-
advanced/AutoAdvancedExtenderImpl.java
Classes d'extension HDR (implémentez-les si l'extension HDR est prise en charge)
-
HdrImageCaptureExtenderImpl.java
-
HdrPreviewExtenderImpl.java
-
advanced/HdrAdvancedExtenderImpl.java
Classes d'extension Face Retouch (implémentez-les si l'extension Face Retouch est prise en charge)
-
BeautyImageCaptureExtenderImpl.java
-
BeautyPreviewExtenderImpl.java
-
advanced/BeautyAdvancedExtenderImpl.java
Utilitaires (facultatif, peut être supprimé)
-
advanced/Camera2OutputConfigImplBuilder.java
-
advanced/Camera2SessionConfigImplBuilder.java
Vous n'êtes pas obligé de fournir une implémentation pour chaque extension. Si vous n'implémentez pas d'extension, définissez isExtensionAvailable()
pour renvoyer false
ou supprimez les classes Extender correspondantes. Les API Camera2 et CameraX Extensions signalent à l'application que l'extension n'est pas disponible.
Voyons comment les API Camera2 et CameraX Extensions interagissent avec la bibliothèque du fournisseur pour activer une extension. Le schéma suivant illustre le flux de bout en bout en utilisant l'extension Nuit comme exemple :
Figure 2. Mise en œuvre de l'extension de nuit
Vérification de version :
Camera2/X appelle
ExtensionVersionImpl.checkApiVersion()
pour s'assurer que la versionextensions-interface
implémentée par l'OEM est compatible avec les versions prises en charge par Camera2/X.Initialisation de la bibliothèque fournisseur :
InitializerImpl
a une méthodeinit()
qui initialise la bibliothèque du fournisseur. Camera2/X termine l'initialisation avant d'accéder aux classes Extender.Instancier les classes Extender :
Instancie les classes Extender pour l'extension. Il existe deux types d'extendeur : l'extendeur de base et l'extendeur avancé. Vous devez implémenter un type d'extendeur pour toutes les extensions. Pour plus d'informations, consultez Basic Extender versus Advanced Extender .
Camera2/X instancie et interagit avec les classes Extender pour récupérer des informations et activer l'extension. Pour une extension donnée, Camera2/X peut instancier plusieurs fois les classes Extender. Par conséquent, n'effectuez pas d'initialisation lourde dans le constructeur ou l'appel
init()
. Ne faites le gros du travail que lorsque la session de la caméra est sur le point de démarrer, par exemple lorsqueonInit()
est appelé dans Basic Extender ouinitSession()
est appelé dans Advanced Extender.Pour l'extension Night, les classes Extender suivantes sont instanciées pour le type Basic Extender :
-
NightImageCaptureExtenderImpl.java
-
NightPreviewExtenderImpl.java
Et pour le type Advanced Extender :
-
NightAdvancedExtenderImpl.java
-
Vérifier la disponibilité de l'extension :
Avant d'activer l'extension,
isExtensionAvailable()
vérifie si l'extension est disponible sur l'ID de caméra spécifié via l'instance Extender.Initialisez l'extendeur avec les informations de la caméra :
Camera2/X appelle
init()
sur l'instance Extender et lui transmet l'ID de la caméra etCameraCharacteristics
.Informations sur la requête :
Appelle la classe Extender pour récupérer des informations telles que les résolutions prises en charge, toujours capturer la latence estimée et capturer les clés de demande de l'extendeur en vue de l'activation de l'extension.
Activer l'extension sur l'extendeur :
La classe Extender fournit toutes les interfaces nécessaires pour activer la classe. Il offre un mécanisme pour accrocher l'implémentation OEM dans le pipeline Camera2, comme l'injection de paramètres de demande de capture ou l'activation d'un post-processeur.
Pour le type Advanced Extender, Camera2/X interagit avec
SessionProcessorImpl
pour activer l'extension. Camera2/X récupère l'instanceSessionProcessorImpl
en appelantcreateSessionProcessor()
sur l'extendeur.
Les sections suivantes décrivent le flux d'extension plus en détail.
Vérification de version
Lors du chargement de la bibliothèque du fournisseur OEM à partir de l'appareil lors de l'exécution, Camera2/X vérifie si la bibliothèque est compatible avec la version extensions-interface
. L' extensions-interface
utilise le versioning sémantique, ou MAJOR.MINOR.PATCH, par exemple, 1.1.0 ou 1.2.0. Cependant, seules les versions majeures et mineures sont utilisées lors de la vérification de version.
Pour vérifier la version, Camera2/X appelle ExtensionVersionImpl.checkApiVersion()
avec la version extensions-interface
prise en charge. Camera2/X utilise ensuite la version signalée par la bibliothèque OEM pour déterminer si l'extension peut être activée et quelles fonctionnalités elle doit invoquer.
Compatibilité des versions majeures
Si les principales versions de l' interface d'extension sont différentes entre Camera2/X et la bibliothèque du fournisseur, elle est alors considérée comme incompatible et l'extension est désactivée.
Rétrocompatibilité
Tant que la version majeure est identique, Camera2/X assure la rétrocompatibilité avec les bibliothèques de fournisseurs OEM construites avec des versions extensions-interface
antérieures. Par exemple, si Camera2/X prend en charge extensions-interface
1.3.0, les bibliothèques du fournisseur OEM qui ont implémenté 1.0.0, 1.1.0 et 1.2.0 sont toujours compatibles. Cela signifie également qu'après avoir implémenté une version spécifique de la bibliothèque du fournisseur, Camera2/X s'assure que la bibliothèque est rétrocompatible avec les prochaines versions extension-interface
.
Compatibilité ascendante
La compatibilité ascendante avec les bibliothèques de fournisseurs des extensions-interface
les plus récentes dépend de vous, l'OEM. Si vous avez besoin de certaines fonctionnalités pour implémenter les extensions, vous pouvez activer les extensions à partir d'une certaine version. Dans ce cas, vous pouvez renvoyer la version extensions-interface
prise en charge lorsque la version de la bibliothèque Camera2/X répond aux exigences. Si les versions Camera2/X ne sont pas prises en charge, vous pouvez renvoyer une version incompatible telle que 99.0.0 pour désactiver les extensions.
Initialisation de la bibliothèque du fournisseur
Après avoir vérifié la version extensions-interface
implémentée par la bibliothèque OEM, Camera2/X démarre le processus d'initialisation. La méthode InitializerImpl.init()
signale à la bibliothèque OEM qu'une application tente d'utiliser des extensions.
Camera2/X n'effectue aucun autre appel à la bibliothèque OEM (hormis la vérification de version) jusqu'à ce que la bibliothèque du fournisseur OEM appelle OnExtensionsInitializedCallback.onSuccess()
pour notifier la fin de l'initialisation.
Vous devez implémenter InitializerImpl
à partir d' extensions-interface
1.1.0. Camera2/X ignore l'étape d'initialisation de la bibliothèque si la bibliothèque du fournisseur OEM implémente extensions-interface
1.0.0.
Prolongateur de base contre prolongateur avancé
Il existe deux types d'implémentation extensions-interface
: Basic Extender et Advanced Extender. Advanced Extender est pris en charge depuis extensions-interface
1.2.0.
Implémentez Basic Extender pour les extensions qui traitent les images dans la couche HAL de la caméra ou utilisez un post-processeur capable de traiter les flux YUV.
Implémentez Advanced Extender pour les extensions qui doivent personnaliser la configuration du flux Camera2 et envoyer des demandes de capture si nécessaire.
Voir le tableau suivant pour la comparaison :
Prolongateur de base | Prolongateur avancé | |
---|---|---|
Configurations de flux | Fixé Aperçu : PRIVATE ou YUV_420_888 (si le processeur existe)Capture fixe : JPEG ou YUV_420_888 (si le processeur existe) | Personnalisable par OEM. |
Envoi de la demande de capture | Seul Camera2/X peut envoyer des demandes de capture. Vous pouvez paramétrer ces requêtes. Lorsque le processeur est fourni pour la capture d'image, Camera2/X peut envoyer plusieurs demandes de capture et envoyer toutes les images et les résultats de capture au processeur. | Une instance RequestProcessorImpl vous est fournie pour exécuter la requête de capture camera2 et obtenir les résultats et Image. Camera2/X invoque |
Crochets dans le pipeline de la caméra |
|
|
Convient à | Extensions implémentées dans la caméra HAL ou dans un processeur qui traite les images YUV. |
|
Version d'API prise en charge | Extensions Camera2 : Android 13 ou supérieur Extensions CameraX : camera-extensions 1.1.0 ou supérieures | Extensions Camera2 : Android 12L ou supérieur Extensions CameraX : camera-extensions 1.2.0-alpha03 ou supérieur |
Flux d'application
Le tableau suivant présente trois types de flux d'application et leurs appels d'API Camera Extensions correspondants. Bien que Camera2/X fournisse ces API, vous devez implémenter correctement la bibliothèque du fournisseur pour prendre en charge ces flux, que nous décrivons plus en détail dans une section ultérieure.
Extensions caméra2 | Extensions CameraX | |
---|---|---|
Disponibilité des extensions de requête | CameraExtensionCharacteristics . getSupportedExtensions | ExtensionsManager. isExtensionAvailable |
Informations sur la requête | CameraExtensionCharacteristics. getExtensionSupportedSizes CameraExtensionCharacteristics. getEstimatedCaptureLatencyRangeMillis CameraExtensionCharacteristics. getAvailableCaptureRequestKeys CameraExtensionCharacteristics. getAvailableCaptureResultKeys | ExtensionsManager. getEstimatedCaptureLatencyRange CameraX gère le reste des informations dans la bibliothèque. |
Aperçu et capture fixe avec extension activée | CameraDevice. createExtensionSession | val cameraSelector = ExtensionsManager. getExtensionEnabledCameraSelector bindToLifecycle(lifecycleOwner, cameraSelector, aperçu, ...) |
Prolongateur de base
L'interface Basic Extender fournit des crochets à plusieurs endroits dans le pipeline de la caméra. Chaque type d'extension a des classes Extender correspondantes que les OEM doivent implémenter.
Le tableau suivant répertorie les classes d'extension que les OEM doivent implémenter pour chaque extension :
Classes d'extension à implémenter | |
---|---|
Nuit | NightPreviewExtenderImpl.java |
HDR | HdrPreviewExtenderImpl.java
|
Auto | AutoPreviewExtenderImpl.java
|
Bokeh | BokehPreviewExtenderImpl.java
|
Retouche visage | BeautyPreviewExtenderImpl.java
|
Nous utilisons PreviewExtenderImpl
et ImageCaptureExtenderImpl
comme espaces réservés dans l'exemple suivant. Remplacez-les par les noms des fichiers réels que vous implémentez.
Basic Extender a les fonctionnalités suivantes :
- Injectez les paramètres de session lors de la configuration
CameraCaptureSession
(onPresetSession
). - Vous avertir des événements de démarrage et de fermeture de la session de capture et envoyer une seule requête pour notifier HAL avec les paramètres renvoyés (
onEnableSession
,onDisableSession
). - Injectez les paramètres de capture pour la requête (
PreviewExtenderImpl.getCaptureStage
,ImageCaptureExtenderImpl.getCaptureStages
). - Ajoutez des processeurs pour la prévisualisation et la capture continue capables de traiter le flux
YUV_420_888
.
Voyons comment Camera2/X invoque l' extensions-interface
pour réaliser les trois flux d'application mentionnés ci-dessus.
Flux d'application 1 : Vérifier la disponibilité de l'extension
Figure 3. Flux d'application 1 sur Basic Extender
Dans ce flux, Camera2/X appelle directement la méthode isExtensionAvailable()
de PreviewExtenderImpl
et ImageCaptureExtenderImpl
sans appeler init()
. Les deux classes Extender doivent renvoyer true
pour activer les extensions.
Il s'agit souvent de la première étape pour les applications de vérifier si le type d'extension donné est pris en charge pour un ID de caméra donné avant d'activer l'extension. En effet, certaines extensions ne sont prises en charge que sur certains ID de caméra.
Flux d'application 2 : informations sur les requêtes
Figure 4. Flux d'application 2 sur Basic Extender
Après avoir déterminé si l'extension est disponible, les applications doivent demander les informations suivantes avant d'activer l'extension.
Toujours capturer la plage de latence :
ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
renvoie la plage de latence de capture pour que l'application évalue s'il est approprié d'activer l'extension pour le scénario actuel.Tailles prises en charge pour la surface d'aperçu et de capture :
ImageCaptureExtenderImpl.getSupportedResolutions
etPreviewExtenderImpl.getSupportedResolutions
renvoient une liste des formats d'image et des tailles prises en charge pour le format et la taille de la surface.Clés de demande et de résultat prises en charge : Camera2/X invoque les méthodes suivantes pour récupérer les clés de demande de capture et les clés de résultat prises en charge à partir de votre implémentation :
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
-
ImageCaptureExtenderImpl.getAvailableCapturetResultKeys
-
Camera2/X appelle toujours init()
en premier sur ces classes Extender avant de demander plus d'informations.
Flux d'application 3 : Aperçu/capture fixe avec l'extension activée (mise en œuvre HAL)
Figure 5. Flux d'application 3 sur Basic Extender
Le diagramme ci-dessus illustre le flux principal d'activation de la prévisualisation et de la capture fixe avec une extension sans processeur. Cela signifie que la caméra HAL traite l'extension.
Dans ce flux, Camera2/X appelle d'abord init()
puis onInit
, qui vous avertit qu'une session de caméra est sur le point de démarrer avec les extensions spécifiées. Vous pouvez effectuer une initialisation lourde dans onInit()
.
Lors de la configuration CameraCaptureSession
, Camera2/X invoque onPresetSession
pour obtenir les paramètres de session. Une fois la session de capture configurée avec succès, Camera2/X appelle onEnableSession
en renvoyant une instance CaptureStageImpl
qui contient les paramètres de capture. Camera2/X envoie immédiatement une requête unique avec ces paramètres de capture pour notifier le HAL. De même, avant la fermeture de la session de capture, Camera2/X invoque onDisableSession
puis envoie une seule requête avec les paramètres de capture renvoyés.
La demande répétée déclenchée par Camera2/X contient les paramètres de demande renvoyés par PreviewExtenderImpl.getCaptureStage()
. De plus, la demande de capture fixe contient les paramètres renvoyés par ImageCaptureExtenderImpl.getCaptureStages()
.
Enfin, Camera2/X invoque onDeInit()
une fois la session de caméra terminée. Vous pouvez libérer des ressources dans onDeinit()
.
Processeur de prévisualisation
En plus de la caméra HAL, vous pouvez également implémenter des extensions dans un processeur.
Implémentez PreviewExtenderImpl.getProcessorType
pour spécifier le type de processeur comme expliqué ci-dessous :
PROCESSOR_TYPE_NONE
: aucun processeur. Les images sont traitées dans la caméra HAL.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY
: le type de processeur vous permet de mettre à jour la demande répétée avec de nouveaux paramètres de demande de capture basés sur le dernierTotalCaptureResult
.PreviewExtenderImpl.getProcessor
doit renvoyer une instanceRequestUpdateProcessorImpl
qui traite l'instanceTotalCaptureResult
et renvoie une instanceCaptureStageImpl
pour mettre à jour la demande répétée.PreviewExtenderImpl.getCaptureStage()
doit également refléter le résultat du traitement et renvoyer le dernierCaptureStageImpl
.PROCESSOR_TYPE_IMAGE_PROCESSOR
: ce type vous permet d'implémenter un processeur pour traiter les imagesYUV_420_888
et écrire la sortie sur une surfacePRIVATE
.Vous devez implémenter et renvoyer une instance
PreviewImageProcessorImpl
dansPreviewExtenderImpl.getProcessor
. Le processeur est responsable du traitement des images d'entréeYUV_420_888
. Il doit écrire la sortie au formatPRIVATE
de l'aperçu. Camera2/X utilise une surfaceYUV_420_888
au lieu dePRIVATE
pour configurerCameraCaptureSession
pour l'aperçu.Voir l'illustration suivante pour le flux :
Figure 6. Flux de prévisualisation avec PreviewImageProcessorImpl
L'interface PreviewImageProcessorImpl
étend ProcessImpl
et possède trois méthodes importantes :
onOutputSurface(Surface surface, int imageFormat)
définit la surface de sortie pour le processeur. PourPreviewImageProcessorImpl
,imageFormat
est un format de pixel tel quePixelFormat.RGBA_8888
.onResolutionUpdate(Size size)
définit la taille de l'image d'entrée.onImageFormatUpdate(int imageFormat)
définit le format d'image de l'image d'entrée. Actuellement, il ne peut s'agir queYUV_420_888
.
Processeur de capture d'images
Pour la capture fixe, vous pouvez implémenter un processeur en renvoyant une instance CaptureProcessorImpl
à l'aide de ImageCaptureExtenderImpl.getCaptureProcessor
. Le processeur est chargé de traiter une liste d'images YUV_420_888
capturées et d'instances TotalCaptureResult
et d'écrire la sortie sur une surface YUV_420_888
.
Vous pouvez supposer en toute sécurité que l'aperçu est activé et en cours d'exécution avant d'envoyer la demande de capture d'image fixe.
Voir le flux dans le diagramme ci-dessous :
Figure 7. Toujours capturer le flux avec CaptureProcessorImpl
Camera2/X utilise une surface au format
YUV_420_888
pour la capture fixe afin de configurer la session de capture. Camera2/X prépareCaptureProcessorImpl
en appelant :-
CaptureProcessorImpl.onImageFormatUpdate()
avecYUV_420_888
. -
CaptureProcessorImpl.onResolutionUpdate()
avec la taille de l'image d'entrée. -
CaptureProcessorImpl.onOutputSurface()
avec une surface de sortieYUV_420_888
.
-
ImageCaptureExtenderImpl.getCaptureStages
renvoie une liste deCaptureStageImpl
, où chaque élément correspond à une instanceCaptureRequest
avec des paramètres de capture envoyés par Camera2/X. Par exemple, s'il renvoie une liste de trois instancesCaptureStageImpl
, Camera2/X envoie trois demandes de capture avec les paramètres de capture correspondants à l'aide de l'APIcaptureBurst
.Les images reçues et les instances
TotalCaptureResult
sont regroupées et envoyées àCaptureProcessorImpl
pour traitement.CaptureProcessorImpl
écrit le résultat Image (formatYUV_420_888
) sur la surface de sortie spécifiée par l'appelonOutputSurface()
. Camera2/X le convertit en images JPEG si nécessaire.
Prend en charge les clés et les résultats des demandes de capture
En plus de l'aperçu et de la capture de l'appareil photo, les applications peuvent définir le zoom, les paramètres du flash ou déclencher une mise au point par pression. Ces paramètres peuvent ne pas être compatibles avec l'implémentation de votre extension.
Les méthodes suivantes ont été ajoutées à extensions-interface
1.3.0 pour vous permettre d'exposer les paramètres pris en charge par votre implémentation :
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys()
renvoie les clés de demande de capture prises en charge par votre implémentation. -
ImageCaptureExtenderImpl.getAvailableCaptureResultKeys()
renvoie les clés de résultat de capture contenues dans le résultat de capture.
Si la caméra HAL traite l'extension, Camera2/X récupère les résultats de la capture dans CameraCaptureSession.CaptureCallback
. Cependant, si le processeur est implémenté, Camera2/X récupère les résultats de la capture dans ProcessResultImpl
, qui est transmis à la méthode process()
dans PreviewImageProcessorImpl
et CaptureProcessorImpl
. Vous êtes chargé de signaler le résultat de la capture via ProcessResultImpl
à Camera2/X.
Voir la définition de l'interface CaptureProcessorImpl
ci-dessous à titre d'exemple. Dans extensions-interface
1.3.0 ou supérieur, le deuxième appel process()
est invoqué :
Interface CaptureProcessorImpl extends ProcessorImpl {
// invoked when extensions-interface version < 1.3.0
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
// invoked when extensions-interface version >= 1.3.0
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor);
}
Pour les opérations courantes de l'appareil photo telles que le zoom, la mise au point par pression, le flash et la compensation d'exposition, nous vous recommandons de prendre en charge les touches suivantes pour la demande de capture et le résultat de la capture :
- Zoom:
-
CaptureRequest#CONTROL_ZOOM_RATIO
-
CaptureRequest#SCALER_CROP_REGION
-
- Appuyez pour faire la mise au point :
-
CaptureRequest#CONTROL_AF_MODE
-
CaptureRequest#CONTROL_AF_TRIGGER
-
CaptureRequest#CONTROL_AF_REGIONS
-
CaptureRequest#CONTROL_AE_REGIONS
-
CaptureRequest#CONTROL_AWB_REGIONS
-
- Éclair:
-
CaptureRequest#CONTROL_AE_MODE
-
CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
-
CaptureRequest#FLASH_MODE
-
- La compensation d'exposition:
-
CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
-
Pour les prolongateurs de base qui implémentent 1.2.0 ou des versions antérieures, l'API CameraX Extensions prend explicitement en charge toutes les clés ci-dessus. Pour extensions-interface
1.3.0, CameraX et Camera2 respectent la liste renvoyée et ne prennent en charge que les clés qu'elle contient. Par exemple, si vous décidez de renvoyer uniquement CaptureRequest#CONTROL_ZOOM_RATIO
et CaptureRequest#SCALER_CROP_REGION
dans l'implémentation 1.3.0, cela signifie que seul le zoom est pris en charge pour l'application tandis que la mise au point, le flash et la compensation d'exposition ne sont pas autorisés.
Prolongateur avancé
Advanced Extender est un type d'implémentation de fournisseur basé sur l'API Camera2. Ce type d'extension a été ajouté dans extensions-interface
1.2.0. Selon le fabricant de l'appareil, des extensions peuvent être implémentées dans la couche d'application, qui dépend des facteurs suivants :
Configuration de flux personnalisée : configurez des flux personnalisés tels que le flux RAW ou disposez de plusieurs flux pour différents ID de caméra physique.
Capacité d'envoyer des requêtes Camera2 : Prend en charge une logique d'interaction compliquée qui peut envoyer des requêtes de capture avec des paramètres basés sur les résultats des requêtes précédentes.
Advanced Extender fournit un wrapper, ou une couche intermédiaire, afin que vous puissiez personnaliser la configuration du flux et envoyer des demandes de capture à la demande.
Fichiers à implémenter
Pour passer à l'implémentation d'Advanced Extender, la méthode isAdvancedExtenderImplemented()
dans ExtensionVersionImpl
doit renvoyer true
. Pour chaque type d'extension, les OEM doivent implémenter les classes Extender correspondantes. Les fichiers d'implémentation d'Advanced Extender se trouvent dans le package avancé .
Classes d'extension à implémenter | |
---|---|
Nuit | advanced/NightAdvancedExtenderImpl.java |
HDR | advanced/HdrAdvancedExtenderImpl.java |
Auto | advanced/AutoAdvancedExtenderImpl.java |
Bokeh | advanced/BokehAdvancedExtenderImpl.java |
Retouche du visage | advanced/BeautyAdvancedExtenderImpl.java |
Nous utilisons AdvancedExtenderImpl
comme espace réservé dans l'exemple suivant. Remplacez-le par le nom du fichier Extender pour l'extension que vous implémentez.
Voyons comment Camera2/X invoque l' extensions-interface
pour réaliser les trois flux d'application.
Flux d'application 1 : vérifier la disponibilité des extensions
Figure 8. Flux d'application 1 sur Advanced Extender
Tout d'abord, l'application vérifie si l'extension donnée est prise en charge.
Flux d'application 2 : informations sur les requêtes
Figure 9. Flux d'application 2 sur Advanced Extender
Après avoir appelé AdvancedExtenderImpl.init()
, l'application peut interroger les informations suivantes sur AdvancedExtenderImpl
:
Latence de capture encore estimée :
AdvancedExtenderImpl.getEstimatedCaptureLatencyRange()
renvoie la plage de latence de capture pour que l'application évalue s'il est approprié d'activer l'extension pour le scénario actuel.Résolutions prises en charge pour l'aperçu et la capture fixe :
AdvancedExtenderImpl.getSupportedPreviewOutputResolutions()
renvoie une carte du format d'image à la liste des tailles prises en charge pour le format et la taille de la surface d'aperçu. Les OEM doivent prendre en charge au moins le formatPRIVATE
.AdvancedExtenderImpl.getSupportedCaptureOutputResolutions()
renvoie le format et les tailles pris en charge pour la surface de capture fixe. Les OEM doivent prendre en charge les formats de sortieJPEG
etYUV_420_888
.AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
renvoie les tailles prises en charge pour un fluxYUV_420_888
supplémentaire pour l'analyse d'image. Si la surface YUV d'analyse d'image n'est pas prise en charge,getSupportedYuvAnalysisResolutions()
doit renvoyernull
ou une liste vide.
Clés/résultats de demande de capture disponibles (ajoutés dans
extensions-interface
1.3.0) : Camera2/X invoque les méthodes suivantes pour récupérer les clés de demande de capture et les clés de résultat prises en charge à partir de votre implémentation :-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys
-
Pour plus d'informations, consultez Prise en charge des clés de demande de capture et des résultats .
Flux d'application 3 : Aperçu/capture fixe avec l'extension activée
Figure 10. Flux d'application 3 sur Advanced Extender
Le diagramme ci-dessus montre le flux principal pour démarrer l'aperçu et continuer à capturer pour le type Advanced Extender. Passons en revue chaque étape.
Instance
SessionProcessorImpl
L'implémentation principale d'Advanced Extender se trouve dans
SessionProcessorImpl
, qui est chargé de fournir une configuration de session personnalisée et d'envoyer des demandes de capture pour lancer la demande d'aperçu et de capture.AdvancedExtenderImpl.createSessionProcessor()
est invoqué pour renvoyer l'instanceSessionProcessorImpl
.initSession
SessionProcessorImpl.initSession()
initialise la session pour l'extension. C'est là que vous allouez des ressources et renvoyez une configuration de session pour préparer uneCameraCaptureSession
.Pour les paramètres d'entrée, Camera2/X spécifie les configurations de surface de sortie pour l'aperçu, la capture fixe et une analyse d'image YUV facultative. Cette configuration de surface de sortie (
OutputSurfaceImpl
) contient la surface, la taille et le format d'image qui sont récupérés par les méthodes suivantes dansAdvancedExtenderImpl
:-
getSupportedPreviewOutputResolutions()
-
getSupportedCaptureOutputResolutions()
-
getSupportedYuvAnalysisResolutions()
Vous devez renvoyer une instance
Camera2SessionConfigImpl
, qui se compose d'une liste d'instancesCamera2OutputConfigImpl
et des paramètres de session utilisés pour configurerCameraCaptureSession
. Vous êtes responsable de la sortie des images de caméra correctes sur les surfaces de sortie transmises par Camera2/X. Voici quelques options pour activer la sortie :- Traitement dans la caméra HAL : vous pouvez directement ajouter les surfaces de sortie à
CameraCaptureSession
avec une implémentationSurfaceOutputConfigImpl
. Cela configure la surface de sortie fournie au pipeline de la caméra et permet à la caméra HAL de traiter l'image. Traitement de la surface
ImageReader
intermédiaire (RAW, YUV, etc.) : Ajoutez les surfacesImageReader
intermédiaires àCameraCaptureSession
avec une instanceImageReaderOutputConfigImpl
.Vous devez traiter les images intermédiaires et écrire l'image résultante sur la surface de sortie.
- Utiliser le partage de surface Camera2 : utilisez le partage de surface avec une autre surface en ajoutant n'importe quelle instance
Camera2OutputConfigImpl
à la méthodegetSurfaceSharingOutputConfigs()
d'une autre instanceCamera2OutputConfigImpl
. Le format et la taille de la surface doivent être identiques.
Tous
Camera2OutputConfigImpl
, y comprisSurfaceOutputConfigImpl
etImageReaderOutputConfigImpl
, doivent avoir un ID unique (getId()
), qui est utilisé pour spécifier la surface cible et récupérer l'image à partir deImageReaderOutputConfigImpl
.-
onCaptureSessionStart
etRequestProcessorImpl
Lorsque
CameraCaptureSession
démarre et que le framework Camera appelleonConfigured()
, Camera2/X appelleSessionProcessorImpl.onCaptureSessionStart()
avec le wrapper de requête Camera2RequestProcessImpl
. Camera2/X implémenteRequestProcessImpl
, qui vous permet d' exécuter les requêtes de capture et de récupérer des images siImageReaderOutputConfigImpl
est utilisé.Les API
RequestProcessImpl
sont similaires aux API Camera2CameraCaptureSession
en termes d'exécution des requêtes. Les différences sont :- La surface cible est spécifiée par l'ID de l'instance
Camera2OutputConfigImpl
. - La capacité de récupérer l'image de
ImageReader
.
Vous pouvez appeler
RequestProcessorImpl.setImageProcessor()
avec un IDCamera2OutputConfigImpl
spécifié pour enregistrer une instanceImageProcessorImpl
afin de recevoir des images.L'instance
RequestProcessImpl
devient invalide après que Camera2/X appelleSessionProcessorImpl.onCaptureSessionEnd()
.- La surface cible est spécifiée par l'ID de l'instance
Lancer l'aperçu et prendre une photo
Dans l'implémentation d'Advanced Extender, vous pouvez envoyer des demandes de capture via l'interface
RequestProcessorImpl
. Camera2/X vous avertit de démarrer la demande répétée d'aperçu ou la séquence de capture fixe en appelant respectivementSessionProcessorImpl#startRepeating
etSessionProcessorImpl#startCapture
. Vous devez envoyer des demandes de capture pour satisfaire ces demandes de prévisualisation et de capture fixe.Camera2/X définit également les paramètres de demande de capture via
SessionProcessorImpl#setParameters
. Vous devez définir ces paramètres de demande (si les paramètres sont pris en charge) sur les demandes répétées et uniques.Vous devez prendre en charge au moins
CaptureRequest.JPEG_ORIENTATION
etCaptureRequest.JPEG_QUALITY
.extensions-interface
1.3.0 prend en charge les clés de requête et de résultat, qui sont exposées par les méthodes suivantes :-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys()
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys()
Lorsque les développeurs définissent les clés dans la liste
getAvailableCaptureRequestKeys
, vous devez activer les paramètres et vous assurer que le résultat de la capture contient les clés dans la listegetAvailableCaptureResultKeys
.-
startTrigger
SessionProcessorImpl.startTrigger()
est appelé pour démarrer le déclencheur tel queCaptureRequest.CONTROL_AF_TRIGGER
etCaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
. Vous pouvez ignorer toutes les clés de demande de capture qui n'ont pas été annoncées dansAdvancedExtenderImpl.getAvailableCaptureRequestKeys()
.startTrigger()
est pris en charge depuisextensions-interface
1.3.0. Il permet aux applications d'implémenter le tap-to-focus et le flash avec des extensions.Nettoyer
À la fin d'une session de capture,
SessionProcessorImpl.onCaptureSessionEnd()
est invoqué avant la fermetureCameraCaptureSession
. Une fois la session de capture fermée,deInitSession()
effectue le nettoyage.
Prise en charge de l'aperçu, de la capture d'images fixes et de l'analyse d'images
Vous devez appliquer l'extension à la fois pour les cas d'utilisation de l'aperçu et de la capture. Cependant, si la latence est trop élevée pour afficher l'aperçu en douceur, vous pouvez appliquer l'extension uniquement pour la capture fixe.
Pour le type Basic Extender, indépendamment de l'activation de l'extension pour l'aperçu, vous devez implémenter à la fois ImageCaptureExtenderImpl
et PreviewExtenderImpl
pour une extension donnée. Often, an app also uses a YUV stream to analyze the image content such as finding QR codes or text. To better support this use case , you should support the stream combination of preview, still capture, and a YUV_420_888
stream for configuring CameraCaptureSession
. This means that if you implement a processor, then you have to support the stream combination of three YUV_420_888
streams.
For Advanced Extender, Camera2/X passes three output surfaces to the SessionProcessorImpl.initSession()
call. These output surfaces are for preview , still capture, and image analysis, respectively. You must ensure that preview and still capture output surfaces show the valid output. However, for the image analysis output surface, ensure it's working only when it's non-null. If your implementation can't support the image analysis stream, you can return an empty list in AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
. This ensures the image analysis output surface is always null in SessionProcessorImpl.initSession()
.
Support video capture
The current Camera Extension architecture supports only the preview and still capture use cases. We don't support enabling the extension on the MediaCodec
or MediaRecorder
surfaces for recording the video. However, it's possible for apps to record the preview output.
Supporting MediaCodec
and MediaRecorder
surfaces is under investigation.
Extensions interface version history
The following table shows the Camera Extension interface version history. You should always implement the vendor library with the latest version.
Version | Added features |
---|---|
1.0.0 |
|
1.1.0 |
|
1.2.0 |
|
1.3.0 |
|
Reference implementation
The following reference OEM vendor library implementations are available in frameworks/ex
.
advancedSample
: A basic implementation of Advanced Extender.sample
: A basic implementation of Basic Extender.service_based_sample
: An implementation that demonstrates how to host Camera Extensions in aService
. This implementation contains the following components:oem_library
: A Camera Extensions OEM library for Camera2 and CameraX Extensions APIs that implementsExtensions-Interface
. This acts as a passthrough that forwards calls fromExtensions-Interface
to the service. This library also provides AIDL files and wrapper classes to communicate with the service.Advanced Extender is enabled by default. To enable the Basic Extender, change
ExtensionsVersionImpl#isAdvancedExtenderImplemented
to returnfalse
.extensions_service
: A sample implementation of the Extensions Service. Add your implementation here. The interface to implement in the service is similar to theExtensions-Interface
. For example, implementing theIAdvancedExtenderImpl.Stub
performs the same operations asAdvancedExtenderImpl
.ImageWrapper
andTotalCaptureResultWrapper
are required to makeImage
andTotalCaptureResult
parcelable.
Set up the vendor library on a device
The OEM vendor library isn't built into an app; it's loaded from the device at runtime by Camera2/X. In CameraX, the <uses-library>
tag declares that the androidx.camera.extensions.impl
library, which is defined in the AndroidManifest.xml
file of the camera-extensions
library, is a dependency of CameraX and must be loaded at runtime. In Camera2, the framework loads an extensions service that also declares that the <uses-library>
loads the same androidx.camera.extensions.impl
library at runtime.
This allows third-party apps using extensions to automatically load the OEM vendor library. The OEM library is marked as optional so apps can run on devices that don't have the library on the device. Camera2/X handles this behavior automatically when an app tries to use a camera extension as long as the device manufacturer places the OEM library on the device so that it can be discovered by the app.
To set up the OEM library on a device, do the following:
- Add a permission file, which is required by the
<uses-library>
tag, using the following format:/etc/permissions/ ANY_FILENAME .xml
. For example,/etc/permissions/camera_extensions.xml
. The files in this directory provide a mapping of the library named in<uses-library>
to the actual file path on the device. Use the example below to add the required information to the file.
-
name
must beandroidx.camera.extensions.impl
as that's the library that CameraX searches for. -
file
is the absolute path of the file that contains the extensions implementation (for example,/system/framework/androidx.camera.extensions.impl.jar
).
<?xml version="1.0" encoding="utf-8"?> <permissions> <library name="androidx.camera.extensions.impl" file="OEM_IMPLEMENTED_JAR" /> </permissions>
-
In Android 12 or higher, devices supporting CameraX extensions must have the ro.camerax.extensions.enabled
property set to true
, which allows for querying whether a device supports extensions. To do this, add the following line in the device make file:
PRODUCT_VENDOR_PROPERTIES += \
ro.camerax.extensions.enabled=true \
Validation
To test your implementation of the OEM vendor library during the development stage, use the example app at androidx-main/camera/integration-tests/extensionstestapp/
, which runs through various vendor extensions.
After you complete your implementation, use the Camera Extensions Validation Tool to run automated and manual tests to verify that the vendor library is implemented correctly.
Extended scene mode versus Camera Extensions
For the bokeh extension, in addition to exposing it using Camera Extensions, you can expose the extension using the extended scene mode, which is enabled through the CONTROL_EXTENDED_SCENE_MODE
key. For more implementation details, see Camera Bokeh .
Extended scene mode has fewer restrictions compared to Camera Extensions for camera2 apps. For example, you can enable extended scene mode in a regular CameraCaptureSession
instance that supports flexible stream combinations and capture request parameters. In contrast, camera extensions support only a fixed set of stream types and have limited support for capture request parameters.
A downside of extended scene mode is that you can only implement it in the camera HAL, which means that it must be verified to work across all orthogonal controls available to app developers.
We recommend exposing bokeh using both the extended scene mode and Camera Extensions because apps might prefer to use a particular API to enable bokeh. We recommend first using the extended scene mode because this is the most flexible way for apps to enable the bokeh extension. Then you can implement the camera extensions interface based on the extended scene mode. If implementing bokeh in the camera HAL is difficult, for example, because it requires a post processor running in the app layer to process images, we recommend implementing the bokeh extension using the Camera Extensions interface.
Frequently asked questions (FAQs)
Are there any restrictions on API levels?
Yes. This depends on the Android API feature set that's required by the OEM vendor library implementation. For example, ExtenderStateListener.onPresetSession()
uses the SessionConfiguration.setSessionParameters()
call to set a baseline set of tags. This call is available only on API level 28 and higher. For details on specific interface methods, see the API reference documentation .
Device manufacturers can expose extensions such as bokeh, night mode, and HDR to third-party developers through the Camera Extensions interface provided by the OEM vendor library. Developers can use the Camera2 Extensions API and the CameraX Extensions API to access the extensions implemented in the OEM vendor library.
For a list of supported extensions, which is the same across Camera2 and CameraX, see CameraX Extensions API . If you want to add an extension, file a bug with the Issue Tracker .
This page describes how to implement and enable the OEM vendor library on devices.
Architecture
The following diagram describes the architecture of the Camera Extensions interface or extensions-interface
:
Figure 1. Camera Extensions architecture diagram
As shown in the diagram, to support Camera Extensions, you need to implement the extensions-interface
provided by the OEM vendor library. Your OEM vendor library enables two APIs: CameraX Extensions API and Camera2 Extensions API , which are used by CameraX and Camera2 apps, respectively, to access vendor extensions.
Implement the OEM vendor library
To implement the OEM vendor library, copy the camera-extensions-stub
files into a system library project. These files define the Camera Extensions interface.
The camera-extensions-stub
files are divided into the following categories:
Essential interface files (don't modify)
-
PreviewExtenderImpl.java
-
ImageCaptureExtenderImpl.java
-
ExtenderStateListener.java
-
ProcessorImpl.java
-
PreviewImageProcessorImpl.java
-
CaptureProcessorImpl.java
-
CaptureStageImpl.java
-
RequestUpdateProcessorImpl.java
-
ProcessResultImpl.java
-
advanced/AdvancedExtenderImpl.java
-
advanced/Camera2OutputConfigImpl.java
-
advanced/Camera2SessionConfigImpl.java
-
advanced/ImageProcessorImpl.java
-
advanced/ImageReaderOutputConfigImpl.java
-
advanced/ImageReferenceImpl.java
-
advanced/MultiResolutionImageReaderOutputConfigImpl.java
-
advanced/OutputSurfaceImpl.java
-
advanced/RequestProcessorImpl.java
-
advanced/SessionProcessorImpl.java
-
advanced/SurfaceOutputConfigImpl.java
Mandatory implementations (add your implementation)
-
ExtensionVersionImpl.java
-
InitializerImpl.java
Bokeh extender classes (implement it if Bokeh extension is supported)
-
BokehImageCaptureExtenderImpl.java
-
BokehPreviewExtenderImpl.java
-
advanced/BokehAdvancedExtenderImpl.java
Night extender classes (implement it if Night extension is supported)
-
NightImageCaptureExtenderImpl.java
-
NightPreviewExtenderImpl.java
-
advanced/NightAdvancedExtenderImpl.java
Auto extender classes (implement it if Auto extension is supported)
-
AutoImageCaptureExtenderImpl.java
-
AutoPreviewExtenderImpl.java
-
advanced/AutoAdvancedExtenderImpl.java
HDR extender classes (implement it if HDR extension is supported)
-
HdrImageCaptureExtenderImpl.java
-
HdrPreviewExtenderImpl.java
-
advanced/HdrAdvancedExtenderImpl.java
Face Retouch extender classes (implement it if Face Retouch extension is supported)
-
BeautyImageCaptureExtenderImpl.java
-
BeautyPreviewExtenderImpl.java
-
advanced/BeautyAdvancedExtenderImpl.java
Utilities (optional, can be deleted)
-
advanced/Camera2OutputConfigImplBuilder.java
-
advanced/Camera2SessionConfigImplBuilder.java
You aren't required to provide an implementation for every extension. If you don't implement an extension, set isExtensionAvailable()
to return false
or remove the corresponding Extender classes. The Camera2 and CameraX Extensions APIs report to the app that the extension is unavailable.
Let's walk through how the Camera2 and CameraX Extensions APIs interact with the vendor library to enable an extension. The following diagram illustrates the end-to-end flow using the Night extension as an example:
Figure 2. Night extension implementation
Version verification:
Camera2/X calls
ExtensionVersionImpl.checkApiVersion()
to ensure that the OEM-implementedextensions-interface
version is compatible with Camera2/X supported versions.Vendor library initialization:
InitializerImpl
has a methodinit()
that initializes the vendor library. Camera2/X completes the initialization before accessing the Extender classes.Instantiate Extender classes:
Instantiates the Extender classes for the extension. There are two Extender types: Basic Extender and Advanced Extender. You must implement one Extender type for all Extensions. For more information, see Basic Extender versus Advanced Extender .
Camera2/X instantiates and interacts with the Extender classes to retrieve information and enable the extension. For a given extension, Camera2/X can instantiate the Extender classes multiple times. As a result, don't do heavy-lifting initialization in the constructor or the
init()
call. Do the heavy lifting only when the camera session is about to start, such as whenonInit()
is called in Basic Extender orinitSession()
is called in Advanced Extender.For the Night extension, the following Extender classes are instantiated for the Basic Extender type:
-
NightImageCaptureExtenderImpl.java
-
NightPreviewExtenderImpl.java
And for the Advanced Extender type:
-
NightAdvancedExtenderImpl.java
-
Check extension availability:
Before enabling the extension,
isExtensionAvailable()
checks if the extension is available on the specified camera ID through the Extender instance.Initialize the Extender with camera information:
Camera2/X calls
init()
on the Extender instance and passes it the camera ID andCameraCharacteristics
.Query information:
Invokes the Extender class to retrieve information such as supported resolutions, still capture estimated latency, and capture request keys from the Extender in preparation for enabling the extension.
Enable extension on the Extender:
The Extender class provides all the interfaces needed to enable the class. It offers a mechanism to hook OEM implementation into the Camera2 pipeline such as injecting capture request parameters or enabling a post processor.
For the Advanced Extender type, Camera2/X interacts with
SessionProcessorImpl
to enable the extension. Camera2/X retrieves theSessionProcessorImpl
instance by callingcreateSessionProcessor()
on the Extender.
The following sections describe the extension flow in greater detail.
Version verification
When loading the OEM vendor library from the device at runtime, Camera2/X verifies if the library is compatible with the extensions-interface
version. The extensions-interface
uses semantic versioning, or MAJOR.MINOR.PATCH, for example, 1.1.0 or 1.2.0. However, only the major and minor versions are used during the version verification.
To verify the version, Camera2/X calls ExtensionVersionImpl.checkApiVersion()
with the supported extensions-interface
version. Camera2/X then uses the version reported by the OEM library to determine if the extension can be enabled and what capabilities it should invoke.
Major version compatibility
If the major versions of the extension-interface are different between Camera2/X and the vendor library, then it's considered incompatible and the extension is disabled.
Backward compatibility
As long as the major version is identical, Camera2/X ensures backward compatibility with OEM vendor libraries built with prior extensions-interface
versions. For example, if Camera2/X supports extensions-interface
1.3.0, the OEM vendor libraries that implemented 1.0.0, 1.1.0, and 1.2.0 are still compatible. This also means that after you implement a specific version of the vendor library, Camera2/X makes sure the library is backward compatible with upcoming extension-interface
versions.
Forward compatibility
Forward compatibility with vendor libraries of newer extensions-interface
depends on you, the OEM. If you need some features to implement the extensions, you might want to enable the extensions starting from a certain version. In this case, you can return the supported extensions-interface
version when the Camera2/X library version meets the requirements. If the Camera2/X versions aren't supported, you can return an incompatible version such as 99.0.0 to disable the extensions.
Vendor library initialization
After verifying the extensions-interface
version implemented by the OEM library, Camera2/X starts the initialization process. The InitializerImpl.init()
method signals to the OEM library that an app is trying to use extensions.
Camera2/X makes no other calls to the OEM library (aside from version checking) until the OEM vendor library calls OnExtensionsInitializedCallback.onSuccess()
to notify the completion of initialization.
You must implement InitializerImpl
as of extensions-interface
1.1.0. Camera2/X skips the library initialization step if the OEM vendor library implements extensions-interface
1.0.0.
Basic Extender versus Advanced Extender
There are two types of extensions-interface
implementation: Basic Extender and Advanced Extender. Advanced Extender has been supported since extensions-interface
1.2.0.
Implement Basic Extender for extensions that process images in the camera HAL or use a post processor capable of processing YUV streams.
Implement Advanced Extender for extensions that need to customize the Camera2 stream configuration and send capture requests as needed.
See the following table for the comparison:
Basic Extender | Advanced Extender | |
---|---|---|
Stream configurations | Fixed Preview: PRIVATE or YUV_420_888 (if processor exists)Still capture: JPEG or YUV_420_888 (if processor exists) | Customizable by OEM. |
Sending capture request | Only Camera2/X can send capture requests. You can set the parameters to these requests. When the processor is provided for image capture, Camera2/X can send multiple capture requests and send all the images and capture results to the processor. | A RequestProcessorImpl instance is provided to you to execute the camera2 capture request and get results and Image. Camera2/X invokes |
Hooks in the camera pipeline |
|
|
Suitable for | Extensions implemented in the camera HAL or in a processor that processes YUV images. |
|
Supported API version | Camera2 Extensions: Android 13 or higher CameraX Extensions: camera-extensions 1.1.0 or higher | Camera2 Extensions: Android 12L or higher CameraX Extensions: camera-extensions 1.2.0-alpha03 or higher |
App flows
The following table shows three types of app flows and their corresponding Camera Extensions API calls. While Camera2/X provide these APIs, you must properly implement the vendor library to support these flows, which we describe in more detail in a later section.
Camera2 extensions | CameraX extensions | |
---|---|---|
Query extension availability | CameraExtensionCharacteristics . getSupportedExtensions | ExtensionsManager. isExtensionAvailable |
Query information | CameraExtensionCharacteristics. getExtensionSupportedSizes CameraExtensionCharacteristics. getEstimatedCaptureLatencyRangeMillis CameraExtensionCharacteristics. getAvailableCaptureRequestKeys CameraExtensionCharacteristics. getAvailableCaptureResultKeys | ExtensionsManager. getEstimatedCaptureLatencyRange CameraX handles the rest of the information within the library. |
Preview and still-capture with extension enabled | CameraDevice. createExtensionSession | val cameraSelector = ExtensionsManager. getExtensionEnabledCameraSelector bindToLifecycle(lifecycleOwner, cameraSelector, preview, ...) |
Basic Extender
The Basic Extender interface provides hooks into several places in the camera pipeline. Each extension type has corresponding Extender classes that OEMs need to implement.
The following table lists the Extender classes OEMS need to implement for each extension:
Extender classes to implement | |
---|---|
Night | NightPreviewExtenderImpl.java |
HDR | HdrPreviewExtenderImpl.java
|
Auto | AutoPreviewExtenderImpl.java
|
Bokeh | BokehPreviewExtenderImpl.java
|
Face retouch | BeautyPreviewExtenderImpl.java
|
We use PreviewExtenderImpl
and ImageCaptureExtenderImpl
as placeholders in the following example. Replace these with the names of the actual files you're implementing.
Basic Extender has the following capabilities:
- Inject session parameters when configuring
CameraCaptureSession
(onPresetSession
). - Notify you of the capture session start and closing events and send a single request to notify the HAL with the returned parameters (
onEnableSession
,onDisableSession
). - Inject capture parameters for the request (
PreviewExtenderImpl.getCaptureStage
,ImageCaptureExtenderImpl.getCaptureStages
). - Add processors for preview and still capture that's capable of processing
YUV_420_888
stream.
Let's see how Camera2/X invokes the extensions-interface
to achieve the three app flows mentioned above.
App flow 1: Check extension availability
Figure 3. App flow 1 on Basic Extender
In this flow, Camera2/X directly calls the isExtensionAvailable()
method of both PreviewExtenderImpl
and ImageCaptureExtenderImpl
without calling init()
. Both Extender classes must return true
to enable the extensions.
This is often the first step for apps to check if the given extension type is supported for a given camera ID before enabling the extension. This is because some extensions are supported only on certain camera IDs.
App flow 2: Query information
Figure 4. App flow 2 on Basic Extender
After determining if the extension is available, apps should query the following information before enabling the extension.
Still capture latency range:
ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
returns the range of the capture latency for the app to evaluate if it's appropriate to enable the extension for the current scenario.Supported sizes for the preview and capture surface:
ImageCaptureExtenderImpl.getSupportedResolutions
andPreviewExtenderImpl.getSupportedResolutions
return a list of image formats and the sizes that are supported for surface format and size.Supported request and result keys: Camera2/X invokes the following methods to retrieve the supported capture request keys and result keys from your implementation:
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
-
ImageCaptureExtenderImpl.getAvailableCapturetResultKeys
-
Camera2/X always calls init()
first on these Extender classes before querying for more information.
App flow 3: Preview/still capture with extension enabled (HAL implementation)
Figure 5. App flow 3 on Basic Extender
The above diagram illustrates the main flow of enabling preview and still capture with an extension without any processor. This means the camera HAL processes the extension.
In this flow, Camera2/X first calls init()
then onInit
, which notifies you that a camera session is about to start with the specified extensions. You can do heavy-lifting initialization in onInit()
.
When configuring CameraCaptureSession
, Camera2/X invokes onPresetSession
to get the session parameters. After the capture session is configured successfully, Camera2/X invokes onEnableSession
returning a CaptureStageImpl
instance that contains the capture parameters. Camera2/X immediately sends a single request with these capture parameters to notify the HAL. Similarly, before the capture session is closed, Camera2/X invokes onDisableSession
and then sends a single request with the returned capture parameters.
The repeating request triggered by Camera2/X contains the request parameters returned by PreviewExtenderImpl.getCaptureStage()
. Furthermore, the still capture request contains the parameters returned by ImageCaptureExtenderImpl.getCaptureStages()
.
Finally, Camera2/X invokes onDeInit()
after the camera session has finished. You can release resources in onDeinit()
.
Preview processor
In addition to the camera HAL, you can also implement extensions in a processor.
Implement PreviewExtenderImpl.getProcessorType
to specify the processor type as explained below:
PROCESSOR_TYPE_NONE
: No processor. Images are processed in the camera HAL.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY
: The processor type lets you update the repeating request with new capture request parameters based on the latestTotalCaptureResult
.PreviewExtenderImpl.getProcessor
must return aRequestUpdateProcessorImpl
instance that processes theTotalCaptureResult
instance and returns aCaptureStageImpl
instance to update the repeating request.PreviewExtenderImpl.getCaptureStage()
should also reflect the result of the processing and return the latestCaptureStageImpl
.PROCESSOR_TYPE_IMAGE_PROCESSOR
: This type allows you to implement a processor to processYUV_420_888
images and write the output to aPRIVATE
surface.You need to implement and return a
PreviewImageProcessorImpl
instance inPreviewExtenderImpl.getProcessor
. The processor is responsible for processingYUV_420_888
input images. It should write the output to thePRIVATE
format of preview. Camera2/X uses aYUV_420_888
surface instead ofPRIVATE
to configure theCameraCaptureSession
for preview.See following illustration for the flow:
Figure 6. Preview flow with PreviewImageProcessorImpl
The PreviewImageProcessorImpl
interface extends ProcessImpl
and has three important methods:
onOutputSurface(Surface surface, int imageFormat)
sets the output surface for the processor. ForPreviewImageProcessorImpl
,imageFormat
is a pixel format such asPixelFormat.RGBA_8888
.onResolutionUpdate(Size size)
sets the size of the input image.onImageFormatUpdate(int imageFormat)
sets the image format of the input image. Currently, it can only beYUV_420_888
.
Image capture processor
For still capture, you can implement a processor by returning a CaptureProcessorImpl
instance using ImageCaptureExtenderImpl.getCaptureProcessor
. The processor is responsible to process a list of captured YUV_420_888
images and TotalCaptureResult
instances and write the output to a YUV_420_888
surface.
You can safely assume that preview is enabled and running before sending the still capture request.
See the flow in the diagram below:
Figure 7. Still capture flow with CaptureProcessorImpl
Camera2/X uses a
YUV_420_888
format surface for still capture to configure the capture session. Camera2/X preparesCaptureProcessorImpl
by calling:-
CaptureProcessorImpl.onImageFormatUpdate()
withYUV_420_888
. -
CaptureProcessorImpl.onResolutionUpdate()
with the input image size. -
CaptureProcessorImpl.onOutputSurface()
with an outputYUV_420_888
surface.
-
ImageCaptureExtenderImpl.getCaptureStages
returns a list ofCaptureStageImpl
, where each element maps to aCaptureRequest
instance with capture parameters that are sent by Camera2/X. For example, if it returns a list of threeCaptureStageImpl
instances, Camera2/X sends three capture requests with corresponding capture parameters using thecaptureBurst
API.The received images and
TotalCaptureResult
instances are bundled together and sent toCaptureProcessorImpl
for processing.CaptureProcessorImpl
writes the result Image (YUV_420_888
format) to the output surface specified by theonOutputSurface()
call. Camera2/X converts it into JPEG images if necessary.
Support capture request keys and results
In addition to camera preview and capture, apps can set zoom, flash parameters, or trigger a tap-to-focus. These parameters might not be compatible with your extension implementation.
The following methods have been added to extensions-interface
1.3.0 to allow you to expose the parameters that your implementation supports:
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys()
returns the capture request keys supported by your implementation. -
ImageCaptureExtenderImpl.getAvailableCaptureResultKeys()
returns the capture result keys that are contained in the capture result.
If the camera HAL processes the extension, Camera2/X retrieves the capture results in CameraCaptureSession.CaptureCallback
. However, if the processor is implemented, then Camera2/X retrieves the capture results in ProcessResultImpl
, which is passed to the process()
method in PreviewImageProcessorImpl
and CaptureProcessorImpl
. You're responsible for reporting the capture result through ProcessResultImpl
to Camera2/X.
See the definition of the CaptureProcessorImpl
interface below as an example. In extensions-interface
1.3.0 or higher, the second process()
call is invoked:
Interface CaptureProcessorImpl extends ProcessorImpl {
// invoked when extensions-interface version < 1.3.0
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
// invoked when extensions-interface version >= 1.3.0
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor);
}
For common camera operations like zoom, tap-to-focus, flash, and exposure compensation, we recommend supporting the following keys for both capture request and capture result:
- Zoom:
-
CaptureRequest#CONTROL_ZOOM_RATIO
-
CaptureRequest#SCALER_CROP_REGION
-
- Tap-to-focus:
-
CaptureRequest#CONTROL_AF_MODE
-
CaptureRequest#CONTROL_AF_TRIGGER
-
CaptureRequest#CONTROL_AF_REGIONS
-
CaptureRequest#CONTROL_AE_REGIONS
-
CaptureRequest#CONTROL_AWB_REGIONS
-
- Flash:
-
CaptureRequest#CONTROL_AE_MODE
-
CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
-
CaptureRequest#FLASH_MODE
-
- Exposure compensation:
-
CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
-
For Basic Extenders that implement 1.2.0 or prior versions, the CameraX Extensions API explicitly supports all the above keys. For extensions-interface
1.3.0, both CameraX and Camera2 honor the returned list and support only the keys contained in it. For example, if you decide to return only CaptureRequest#CONTROL_ZOOM_RATIO
and CaptureRequest#SCALER_CROP_REGION
in the 1.3.0 implementation, then that means only zoom is supported for the app while tap-to-focus, flash, and exposure compensation aren't allowed.
Advanced Extender
Advanced Extender is a type of vendor implementation based on the Camera2 API. This Extender type was added in extensions-interface
1.2.0. Depending on the device manufacturer, extensions might be implemented in the app layer, which depends on the following factors:
Custom stream configuration: Configure custom streams like RAW stream or have multiple streams for different physical camera IDs.
Capability to send Camera2 requests: Support a complicated interaction logic that can send capture requests with parameters based on the results of previous requests.
Advanced Extender provides a wrapper, or an intermediate layer, so you can customize the stream configuration and send capture requests on demand.
Files to implement
To switch to the Advanced Extender implementation, the isAdvancedExtenderImplemented()
method in ExtensionVersionImpl
must return true
. For each extension type, OEMs must implement the corresponding Extender classes. The Advanced Extender implementation files are in the advanced package.
Extender classes to implement | |
---|---|
Night | advanced/NightAdvancedExtenderImpl.java |
HDR | advanced/HdrAdvancedExtenderImpl.java |
Auto | advanced/AutoAdvancedExtenderImpl.java |
Bokeh | advanced/BokehAdvancedExtenderImpl.java |
Face Retouch | advanced/BeautyAdvancedExtenderImpl.java |
We use AdvancedExtenderImpl
as a placeholder in the following example. Replace it with the name of the Extender file for the extension you're implementing.
Let's see how Camera2/X invokes the extensions-interface
to achieve the three app flows.
App flow 1: Check extensions availability
Figure 8. App flow 1 on Advanced Extender
First, the app checks if the given extension is supported.
App flow 2: Query information
Figure 9. App flow 2 on Advanced Extender
After calling AdvancedExtenderImpl.init()
, the app can query the following the information on AdvancedExtenderImpl
:
Estimated still capture latency:
AdvancedExtenderImpl.getEstimatedCaptureLatencyRange()
returns the range of the capture latency for the app to evaluate if it is appropriate to enable the extension for the current scenario.Supported resolutions for preview and still capture:
AdvancedExtenderImpl.getSupportedPreviewOutputResolutions()
returns a map of image format to the sizes list that are supported for preview surface format and size. OEMs must support at least thePRIVATE
format.AdvancedExtenderImpl.getSupportedCaptureOutputResolutions()
returns the supported format and sizes for still capture surface. OEMs must support bothJPEG
andYUV_420_888
format output.AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
returns the supported sizes for an extraYUV_420_888
stream for image analysis. If the image analysis YUV surface isn't supported,getSupportedYuvAnalysisResolutions()
should returnnull
or an empty list.
Available capture request keys/results (added in
extensions-interface
1.3.0): Camera2/X invokes the following methods to retrieve the supported capture request keys and result keys from your implementation:-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys
-
For more information, see Support capture request keys and results .
App flow 3: Preview/still capture with extension enabled
Figure 10. App flow 3 on Advanced Extender
The above diagram shows the main flow for starting preview and still capture for the Advanced Extender type. Let's walk through each step.
SessionProcessorImpl
instanceThe core Advanced Extender implementation is in
SessionProcessorImpl
, which is responsible for providing customized session configuration and sending capture requests to initiate the preview and still capture request.AdvancedExtenderImpl.createSessionProcessor()
is invoked to return theSessionProcessorImpl
instance.initSession
SessionProcessorImpl.initSession()
initializes the session for the extension. This is where you allocate resources and return a session configuration for preparing aCameraCaptureSession
.For the input parameters, Camera2/X specifies the output surface configurations for preview, still capture, and an optional YUV image analysis. This output surface configuration (
OutputSurfaceImpl
) contains the surface, size and image format that are retrieved by following methods inAdvancedExtenderImpl
:-
getSupportedPreviewOutputResolutions()
-
getSupportedCaptureOutputResolutions()
-
getSupportedYuvAnalysisResolutions()
You must return a
Camera2SessionConfigImpl
instance, which consists of a list ofCamera2OutputConfigImpl
instances and the session parameters used for configuringCameraCaptureSession
. You're responsible for outputting the correct camera images to the output surfaces passed in by Camera2/X. Here are some options to enable the output:- Processing in camera HAL: You can directly add the output surfaces to
CameraCaptureSession
with aSurfaceOutputConfigImpl
implementation. This configures the supplied output surface to the camera pipeline and allows the camera HAL to process the image. Processing intermediate
ImageReader
surface (RAW, YUV, etc): Add the intermediateImageReader
surfaces to theCameraCaptureSession
with anImageReaderOutputConfigImpl
instance.You need to process the intermediate images and write the result image to the output surface.
- Use Camera2 surface sharing: Use surface sharing with another surface by adding any
Camera2OutputConfigImpl
instance to thegetSurfaceSharingOutputConfigs()
method of anotherCamera2OutputConfigImpl
instance. The surface format and size must be identical.
All
Camera2OutputConfigImpl
includingSurfaceOutputConfigImpl
andImageReaderOutputConfigImpl
must have a unique ID (getId()
), which is used to specify the target surface and retrieve the image fromImageReaderOutputConfigImpl
.-
onCaptureSessionStart
andRequestProcessorImpl
When
CameraCaptureSession
starts and the Camera framework invokesonConfigured()
, then Camera2/X invokesSessionProcessorImpl.onCaptureSessionStart()
with the Camera2 request wrapperRequestProcessImpl
. Camera2/X implementsRequestProcessImpl
, which enables you to execute the capture requests , and retrieve images ifImageReaderOutputConfigImpl
is used.The
RequestProcessImpl
APIs are similar to the Camera2CameraCaptureSession
APIs in terms of executing requests. The differences are:- The target surface is specified by the ID of the
Camera2OutputConfigImpl
instance. - The capability of retrieving the image of the
ImageReader
.
You can call
RequestProcessorImpl.setImageProcessor()
with a specifiedCamera2OutputConfigImpl
ID to register anImageProcessorImpl
instance to receive images.The
RequestProcessImpl
instance becomes invalid after Camera2/X callsSessionProcessorImpl.onCaptureSessionEnd()
.- The target surface is specified by the ID of the
Start the preview and take a picture
In the Advanced Extender implementation, you can send capture requests through the
RequestProcessorImpl
interface. Camera2/X notifies you to start the repeating request for preview or the still capture sequence by callingSessionProcessorImpl#startRepeating
andSessionProcessorImpl#startCapture
respectively. You should send capture requests to satisfy these preview and still-capture requests.Camera2/X also sets the capture request parameters through
SessionProcessorImpl#setParameters
. You must set these request parameters (if parameters are supported) on both the repeating and single requests.You must support at least
CaptureRequest.JPEG_ORIENTATION
andCaptureRequest.JPEG_QUALITY
.extensions-interface
1.3.0 supports request and result keys, which are exposed by the following methods:-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys()
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys()
When developers set the keys in the
getAvailableCaptureRequestKeys
list, you must enable the parameters and ensure the capture result contains the keys in thegetAvailableCaptureResultKeys
list.-
startTrigger
SessionProcessorImpl.startTrigger()
is invoked to start the trigger such asCaptureRequest.CONTROL_AF_TRIGGER
andCaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
. You can disregard any capture request keys that weren't advertised inAdvancedExtenderImpl.getAvailableCaptureRequestKeys()
.startTrigger()
has been supported sinceextensions-interface
1.3.0. It enables apps to implement tap-to-focus and flash with extensions.Clean up
When finishing a capture session,
SessionProcessorImpl.onCaptureSessionEnd()
is invoked ahead of closingCameraCaptureSession
. After the capture session has closed,deInitSession()
performs the clean up.
Support preview, still capture, and image analysis
You should apply the extension for both the preview and still capture use cases. However, if the latency is too high to smoothly show the preview, you can apply the extension only for still capture.
For the Basic Extender type, regardless of enabling the extension for preview, you must implement both ImageCaptureExtenderImpl
and PreviewExtenderImpl
for a given extension. Often, an app also uses a YUV stream to analyze the image content such as finding QR codes or text. To better support this use case , you should support the stream combination of preview, still capture, and a YUV_420_888
stream for configuring CameraCaptureSession
. This means that if you implement a processor, then you have to support the stream combination of three YUV_420_888
streams.
For Advanced Extender, Camera2/X passes three output surfaces to the SessionProcessorImpl.initSession()
call. These output surfaces are for preview , still capture, and image analysis, respectively. You must ensure that preview and still capture output surfaces show the valid output. However, for the image analysis output surface, ensure it's working only when it's non-null. If your implementation can't support the image analysis stream, you can return an empty list in AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
. This ensures the image analysis output surface is always null in SessionProcessorImpl.initSession()
.
Support video capture
The current Camera Extension architecture supports only the preview and still capture use cases. We don't support enabling the extension on the MediaCodec
or MediaRecorder
surfaces for recording the video. However, it's possible for apps to record the preview output.
Supporting MediaCodec
and MediaRecorder
surfaces is under investigation.
Extensions interface version history
The following table shows the Camera Extension interface version history. You should always implement the vendor library with the latest version.
Version | Added features |
---|---|
1.0.0 |
|
1.1.0 |
|
1.2.0 |
|
1.3.0 |
|
Reference implementation
The following reference OEM vendor library implementations are available in frameworks/ex
.
advancedSample
: A basic implementation of Advanced Extender.sample
: A basic implementation of Basic Extender.service_based_sample
: An implementation that demonstrates how to host Camera Extensions in aService
. This implementation contains the following components:oem_library
: A Camera Extensions OEM library for Camera2 and CameraX Extensions APIs that implementsExtensions-Interface
. This acts as a passthrough that forwards calls fromExtensions-Interface
to the service. This library also provides AIDL files and wrapper classes to communicate with the service.Advanced Extender is enabled by default. To enable the Basic Extender, change
ExtensionsVersionImpl#isAdvancedExtenderImplemented
to returnfalse
.extensions_service
: A sample implementation of the Extensions Service. Add your implementation here. The interface to implement in the service is similar to theExtensions-Interface
. For example, implementing theIAdvancedExtenderImpl.Stub
performs the same operations asAdvancedExtenderImpl
.ImageWrapper
andTotalCaptureResultWrapper
are required to makeImage
andTotalCaptureResult
parcelable.
Set up the vendor library on a device
The OEM vendor library isn't built into an app; it's loaded from the device at runtime by Camera2/X. In CameraX, the <uses-library>
tag declares that the androidx.camera.extensions.impl
library, which is defined in the AndroidManifest.xml
file of the camera-extensions
library, is a dependency of CameraX and must be loaded at runtime. In Camera2, the framework loads an extensions service that also declares that the <uses-library>
loads the same androidx.camera.extensions.impl
library at runtime.
This allows third-party apps using extensions to automatically load the OEM vendor library. The OEM library is marked as optional so apps can run on devices that don't have the library on the device. Camera2/X handles this behavior automatically when an app tries to use a camera extension as long as the device manufacturer places the OEM library on the device so that it can be discovered by the app.
To set up the OEM library on a device, do the following:
- Add a permission file, which is required by the
<uses-library>
tag, using the following format:/etc/permissions/ ANY_FILENAME .xml
. For example,/etc/permissions/camera_extensions.xml
. The files in this directory provide a mapping of the library named in<uses-library>
to the actual file path on the device. Use the example below to add the required information to the file.
-
name
must beandroidx.camera.extensions.impl
as that's the library that CameraX searches for. -
file
is the absolute path of the file that contains the extensions implementation (for example,/system/framework/androidx.camera.extensions.impl.jar
).
<?xml version="1.0" encoding="utf-8"?> <permissions> <library name="androidx.camera.extensions.impl" file="OEM_IMPLEMENTED_JAR" /> </permissions>
-
In Android 12 or higher, devices supporting CameraX extensions must have the ro.camerax.extensions.enabled
property set to true
, which allows for querying whether a device supports extensions. To do this, add the following line in the device make file:
PRODUCT_VENDOR_PROPERTIES += \
ro.camerax.extensions.enabled=true \
Validation
To test your implementation of the OEM vendor library during the development stage, use the example app at androidx-main/camera/integration-tests/extensionstestapp/
, which runs through various vendor extensions.
After you complete your implementation, use the Camera Extensions Validation Tool to run automated and manual tests to verify that the vendor library is implemented correctly.
Extended scene mode versus Camera Extensions
For the bokeh extension, in addition to exposing it using Camera Extensions, you can expose the extension using the extended scene mode, which is enabled through the CONTROL_EXTENDED_SCENE_MODE
key. For more implementation details, see Camera Bokeh .
Extended scene mode has fewer restrictions compared to Camera Extensions for camera2 apps. For example, you can enable extended scene mode in a regular CameraCaptureSession
instance that supports flexible stream combinations and capture request parameters. In contrast, camera extensions support only a fixed set of stream types and have limited support for capture request parameters.
A downside of extended scene mode is that you can only implement it in the camera HAL, which means that it must be verified to work across all orthogonal controls available to app developers.
We recommend exposing bokeh using both the extended scene mode and Camera Extensions because apps might prefer to use a particular API to enable bokeh. We recommend first using the extended scene mode because this is the most flexible way for apps to enable the bokeh extension. Then you can implement the camera extensions interface based on the extended scene mode. If implementing bokeh in the camera HAL is difficult, for example, because it requires a post processor running in the app layer to process images, we recommend implementing the bokeh extension using the Camera Extensions interface.
Frequently asked questions (FAQs)
Are there any restrictions on API levels?
Yes. This depends on the Android API feature set that's required by the OEM vendor library implementation. For example, ExtenderStateListener.onPresetSession()
uses the SessionConfiguration.setSessionParameters()
call to set a baseline set of tags. This call is available only on API level 28 and higher. For details on specific interface methods, see the API reference documentation .
Device manufacturers can expose extensions such as bokeh, night mode, and HDR to third-party developers through the Camera Extensions interface provided by the OEM vendor library. Developers can use the Camera2 Extensions API and the CameraX Extensions API to access the extensions implemented in the OEM vendor library.
For a list of supported extensions, which is the same across Camera2 and CameraX, see CameraX Extensions API . If you want to add an extension, file a bug with the Issue Tracker .
This page describes how to implement and enable the OEM vendor library on devices.
Architecture
The following diagram describes the architecture of the Camera Extensions interface or extensions-interface
:
Figure 1. Camera Extensions architecture diagram
As shown in the diagram, to support Camera Extensions, you need to implement the extensions-interface
provided by the OEM vendor library. Your OEM vendor library enables two APIs: CameraX Extensions API and Camera2 Extensions API , which are used by CameraX and Camera2 apps, respectively, to access vendor extensions.
Implement the OEM vendor library
To implement the OEM vendor library, copy the camera-extensions-stub
files into a system library project. These files define the Camera Extensions interface.
The camera-extensions-stub
files are divided into the following categories:
Essential interface files (don't modify)
-
PreviewExtenderImpl.java
-
ImageCaptureExtenderImpl.java
-
ExtenderStateListener.java
-
ProcessorImpl.java
-
PreviewImageProcessorImpl.java
-
CaptureProcessorImpl.java
-
CaptureStageImpl.java
-
RequestUpdateProcessorImpl.java
-
ProcessResultImpl.java
-
advanced/AdvancedExtenderImpl.java
-
advanced/Camera2OutputConfigImpl.java
-
advanced/Camera2SessionConfigImpl.java
-
advanced/ImageProcessorImpl.java
-
advanced/ImageReaderOutputConfigImpl.java
-
advanced/ImageReferenceImpl.java
-
advanced/MultiResolutionImageReaderOutputConfigImpl.java
-
advanced/OutputSurfaceImpl.java
-
advanced/RequestProcessorImpl.java
-
advanced/SessionProcessorImpl.java
-
advanced/SurfaceOutputConfigImpl.java
Mandatory implementations (add your implementation)
-
ExtensionVersionImpl.java
-
InitializerImpl.java
Bokeh extender classes (implement it if Bokeh extension is supported)
-
BokehImageCaptureExtenderImpl.java
-
BokehPreviewExtenderImpl.java
-
advanced/BokehAdvancedExtenderImpl.java
Night extender classes (implement it if Night extension is supported)
-
NightImageCaptureExtenderImpl.java
-
NightPreviewExtenderImpl.java
-
advanced/NightAdvancedExtenderImpl.java
Auto extender classes (implement it if Auto extension is supported)
-
AutoImageCaptureExtenderImpl.java
-
AutoPreviewExtenderImpl.java
-
advanced/AutoAdvancedExtenderImpl.java
HDR extender classes (implement it if HDR extension is supported)
-
HdrImageCaptureExtenderImpl.java
-
HdrPreviewExtenderImpl.java
-
advanced/HdrAdvancedExtenderImpl.java
Face Retouch extender classes (implement it if Face Retouch extension is supported)
-
BeautyImageCaptureExtenderImpl.java
-
BeautyPreviewExtenderImpl.java
-
advanced/BeautyAdvancedExtenderImpl.java
Utilities (optional, can be deleted)
-
advanced/Camera2OutputConfigImplBuilder.java
-
advanced/Camera2SessionConfigImplBuilder.java
You aren't required to provide an implementation for every extension. If you don't implement an extension, set isExtensionAvailable()
to return false
or remove the corresponding Extender classes. The Camera2 and CameraX Extensions APIs report to the app that the extension is unavailable.
Let's walk through how the Camera2 and CameraX Extensions APIs interact with the vendor library to enable an extension. The following diagram illustrates the end-to-end flow using the Night extension as an example:
Figure 2. Night extension implementation
Version verification:
Camera2/X calls
ExtensionVersionImpl.checkApiVersion()
to ensure that the OEM-implementedextensions-interface
version is compatible with Camera2/X supported versions.Vendor library initialization:
InitializerImpl
has a methodinit()
that initializes the vendor library. Camera2/X completes the initialization before accessing the Extender classes.Instantiate Extender classes:
Instantiates the Extender classes for the extension. There are two Extender types: Basic Extender and Advanced Extender. You must implement one Extender type for all Extensions. For more information, see Basic Extender versus Advanced Extender .
Camera2/X instantiates and interacts with the Extender classes to retrieve information and enable the extension. For a given extension, Camera2/X can instantiate the Extender classes multiple times. As a result, don't do heavy-lifting initialization in the constructor or the
init()
call. Do the heavy lifting only when the camera session is about to start, such as whenonInit()
is called in Basic Extender orinitSession()
is called in Advanced Extender.For the Night extension, the following Extender classes are instantiated for the Basic Extender type:
-
NightImageCaptureExtenderImpl.java
-
NightPreviewExtenderImpl.java
And for the Advanced Extender type:
-
NightAdvancedExtenderImpl.java
-
Check extension availability:
Before enabling the extension,
isExtensionAvailable()
checks if the extension is available on the specified camera ID through the Extender instance.Initialize the Extender with camera information:
Camera2/X calls
init()
on the Extender instance and passes it the camera ID andCameraCharacteristics
.Query information:
Invokes the Extender class to retrieve information such as supported resolutions, still capture estimated latency, and capture request keys from the Extender in preparation for enabling the extension.
Enable extension on the Extender:
The Extender class provides all the interfaces needed to enable the class. It offers a mechanism to hook OEM implementation into the Camera2 pipeline such as injecting capture request parameters or enabling a post processor.
For the Advanced Extender type, Camera2/X interacts with
SessionProcessorImpl
to enable the extension. Camera2/X retrieves theSessionProcessorImpl
instance by callingcreateSessionProcessor()
on the Extender.
The following sections describe the extension flow in greater detail.
Version verification
When loading the OEM vendor library from the device at runtime, Camera2/X verifies if the library is compatible with the extensions-interface
version. The extensions-interface
uses semantic versioning, or MAJOR.MINOR.PATCH, for example, 1.1.0 or 1.2.0. However, only the major and minor versions are used during the version verification.
To verify the version, Camera2/X calls ExtensionVersionImpl.checkApiVersion()
with the supported extensions-interface
version. Camera2/X then uses the version reported by the OEM library to determine if the extension can be enabled and what capabilities it should invoke.
Major version compatibility
If the major versions of the extension-interface are different between Camera2/X and the vendor library, then it's considered incompatible and the extension is disabled.
Backward compatibility
As long as the major version is identical, Camera2/X ensures backward compatibility with OEM vendor libraries built with prior extensions-interface
versions. For example, if Camera2/X supports extensions-interface
1.3.0, the OEM vendor libraries that implemented 1.0.0, 1.1.0, and 1.2.0 are still compatible. This also means that after you implement a specific version of the vendor library, Camera2/X makes sure the library is backward compatible with upcoming extension-interface
versions.
Forward compatibility
Forward compatibility with vendor libraries of newer extensions-interface
depends on you, the OEM. If you need some features to implement the extensions, you might want to enable the extensions starting from a certain version. In this case, you can return the supported extensions-interface
version when the Camera2/X library version meets the requirements. If the Camera2/X versions aren't supported, you can return an incompatible version such as 99.0.0 to disable the extensions.
Vendor library initialization
After verifying the extensions-interface
version implemented by the OEM library, Camera2/X starts the initialization process. The InitializerImpl.init()
method signals to the OEM library that an app is trying to use extensions.
Camera2/X makes no other calls to the OEM library (aside from version checking) until the OEM vendor library calls OnExtensionsInitializedCallback.onSuccess()
to notify the completion of initialization.
You must implement InitializerImpl
as of extensions-interface
1.1.0. Camera2/X skips the library initialization step if the OEM vendor library implements extensions-interface
1.0.0.
Basic Extender versus Advanced Extender
There are two types of extensions-interface
implementation: Basic Extender and Advanced Extender. Advanced Extender has been supported since extensions-interface
1.2.0.
Implement Basic Extender for extensions that process images in the camera HAL or use a post processor capable of processing YUV streams.
Implement Advanced Extender for extensions that need to customize the Camera2 stream configuration and send capture requests as needed.
See the following table for the comparison:
Basic Extender | Advanced Extender | |
---|---|---|
Stream configurations | Fixed Preview: PRIVATE or YUV_420_888 (if processor exists)Still capture: JPEG or YUV_420_888 (if processor exists) | Customizable by OEM. |
Sending capture request | Only Camera2/X can send capture requests. You can set the parameters to these requests. When the processor is provided for image capture, Camera2/X can send multiple capture requests and send all the images and capture results to the processor. | A RequestProcessorImpl instance is provided to you to execute the camera2 capture request and get results and Image. Camera2/X invokes |
Hooks in the camera pipeline |
|
|
Suitable for | Extensions implemented in the camera HAL or in a processor that processes YUV images. |
|
Supported API version | Camera2 Extensions: Android 13 or higher CameraX Extensions: camera-extensions 1.1.0 or higher | Camera2 Extensions: Android 12L or higher CameraX Extensions: camera-extensions 1.2.0-alpha03 or higher |
App flows
The following table shows three types of app flows and their corresponding Camera Extensions API calls. While Camera2/X provide these APIs, you must properly implement the vendor library to support these flows, which we describe in more detail in a later section.
Camera2 extensions | CameraX extensions | |
---|---|---|
Query extension availability | CameraExtensionCharacteristics . getSupportedExtensions | ExtensionsManager. isExtensionAvailable |
Query information | CameraExtensionCharacteristics. getExtensionSupportedSizes CameraExtensionCharacteristics. getEstimatedCaptureLatencyRangeMillis CameraExtensionCharacteristics. getAvailableCaptureRequestKeys CameraExtensionCharacteristics. getAvailableCaptureResultKeys | ExtensionsManager. getEstimatedCaptureLatencyRange CameraX handles the rest of the information within the library. |
Preview and still-capture with extension enabled | CameraDevice. createExtensionSession | val cameraSelector = ExtensionsManager. getExtensionEnabledCameraSelector bindToLifecycle(lifecycleOwner, cameraSelector, preview, ...) |
Basic Extender
The Basic Extender interface provides hooks into several places in the camera pipeline. Each extension type has corresponding Extender classes that OEMs need to implement.
The following table lists the Extender classes OEMS need to implement for each extension:
Extender classes to implement | |
---|---|
Night | NightPreviewExtenderImpl.java |
HDR | HdrPreviewExtenderImpl.java
|
Auto | AutoPreviewExtenderImpl.java
|
Bokeh | BokehPreviewExtenderImpl.java
|
Face retouch | BeautyPreviewExtenderImpl.java
|
We use PreviewExtenderImpl
and ImageCaptureExtenderImpl
as placeholders in the following example. Replace these with the names of the actual files you're implementing.
Basic Extender has the following capabilities:
- Inject session parameters when configuring
CameraCaptureSession
(onPresetSession
). - Notify you of the capture session start and closing events and send a single request to notify the HAL with the returned parameters (
onEnableSession
,onDisableSession
). - Inject capture parameters for the request (
PreviewExtenderImpl.getCaptureStage
,ImageCaptureExtenderImpl.getCaptureStages
). - Add processors for preview and still capture that's capable of processing
YUV_420_888
stream.
Let's see how Camera2/X invokes the extensions-interface
to achieve the three app flows mentioned above.
App flow 1: Check extension availability
Figure 3. App flow 1 on Basic Extender
In this flow, Camera2/X directly calls the isExtensionAvailable()
method of both PreviewExtenderImpl
and ImageCaptureExtenderImpl
without calling init()
. Both Extender classes must return true
to enable the extensions.
This is often the first step for apps to check if the given extension type is supported for a given camera ID before enabling the extension. This is because some extensions are supported only on certain camera IDs.
App flow 2: Query information
Figure 4. App flow 2 on Basic Extender
After determining if the extension is available, apps should query the following information before enabling the extension.
Still capture latency range:
ImageCaptureExtenderImpl.getEstimatedCaptureLatencyRange
returns the range of the capture latency for the app to evaluate if it's appropriate to enable the extension for the current scenario.Supported sizes for the preview and capture surface:
ImageCaptureExtenderImpl.getSupportedResolutions
andPreviewExtenderImpl.getSupportedResolutions
return a list of image formats and the sizes that are supported for surface format and size.Supported request and result keys: Camera2/X invokes the following methods to retrieve the supported capture request keys and result keys from your implementation:
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys
-
ImageCaptureExtenderImpl.getAvailableCapturetResultKeys
-
Camera2/X always calls init()
first on these Extender classes before querying for more information.
App flow 3: Preview/still capture with extension enabled (HAL implementation)
Figure 5. App flow 3 on Basic Extender
The above diagram illustrates the main flow of enabling preview and still capture with an extension without any processor. This means the camera HAL processes the extension.
In this flow, Camera2/X first calls init()
then onInit
, which notifies you that a camera session is about to start with the specified extensions. You can do heavy-lifting initialization in onInit()
.
When configuring CameraCaptureSession
, Camera2/X invokes onPresetSession
to get the session parameters. After the capture session is configured successfully, Camera2/X invokes onEnableSession
returning a CaptureStageImpl
instance that contains the capture parameters. Camera2/X immediately sends a single request with these capture parameters to notify the HAL. Similarly, before the capture session is closed, Camera2/X invokes onDisableSession
and then sends a single request with the returned capture parameters.
The repeating request triggered by Camera2/X contains the request parameters returned by PreviewExtenderImpl.getCaptureStage()
. Furthermore, the still capture request contains the parameters returned by ImageCaptureExtenderImpl.getCaptureStages()
.
Finally, Camera2/X invokes onDeInit()
after the camera session has finished. You can release resources in onDeinit()
.
Preview processor
In addition to the camera HAL, you can also implement extensions in a processor.
Implement PreviewExtenderImpl.getProcessorType
to specify the processor type as explained below:
PROCESSOR_TYPE_NONE
: No processor. Images are processed in the camera HAL.PROCESSOR_TYPE_REQUEST_UPDATE_ONLY
: The processor type lets you update the repeating request with new capture request parameters based on the latestTotalCaptureResult
.PreviewExtenderImpl.getProcessor
must return aRequestUpdateProcessorImpl
instance that processes theTotalCaptureResult
instance and returns aCaptureStageImpl
instance to update the repeating request.PreviewExtenderImpl.getCaptureStage()
should also reflect the result of the processing and return the latestCaptureStageImpl
.PROCESSOR_TYPE_IMAGE_PROCESSOR
: This type allows you to implement a processor to processYUV_420_888
images and write the output to aPRIVATE
surface.You need to implement and return a
PreviewImageProcessorImpl
instance inPreviewExtenderImpl.getProcessor
. The processor is responsible for processingYUV_420_888
input images. It should write the output to thePRIVATE
format of preview. Camera2/X uses aYUV_420_888
surface instead ofPRIVATE
to configure theCameraCaptureSession
for preview.See following illustration for the flow:
Figure 6. Preview flow with PreviewImageProcessorImpl
The PreviewImageProcessorImpl
interface extends ProcessImpl
and has three important methods:
onOutputSurface(Surface surface, int imageFormat)
sets the output surface for the processor. ForPreviewImageProcessorImpl
,imageFormat
is a pixel format such asPixelFormat.RGBA_8888
.onResolutionUpdate(Size size)
sets the size of the input image.onImageFormatUpdate(int imageFormat)
sets the image format of the input image. Currently, it can only beYUV_420_888
.
Image capture processor
For still capture, you can implement a processor by returning a CaptureProcessorImpl
instance using ImageCaptureExtenderImpl.getCaptureProcessor
. The processor is responsible to process a list of captured YUV_420_888
images and TotalCaptureResult
instances and write the output to a YUV_420_888
surface.
You can safely assume that preview is enabled and running before sending the still capture request.
See the flow in the diagram below:
Figure 7. Still capture flow with CaptureProcessorImpl
Camera2/X uses a
YUV_420_888
format surface for still capture to configure the capture session. Camera2/X preparesCaptureProcessorImpl
by calling:-
CaptureProcessorImpl.onImageFormatUpdate()
withYUV_420_888
. -
CaptureProcessorImpl.onResolutionUpdate()
with the input image size. -
CaptureProcessorImpl.onOutputSurface()
with an outputYUV_420_888
surface.
-
ImageCaptureExtenderImpl.getCaptureStages
returns a list ofCaptureStageImpl
, where each element maps to aCaptureRequest
instance with capture parameters that are sent by Camera2/X. For example, if it returns a list of threeCaptureStageImpl
instances, Camera2/X sends three capture requests with corresponding capture parameters using thecaptureBurst
API.The received images and
TotalCaptureResult
instances are bundled together and sent toCaptureProcessorImpl
for processing.CaptureProcessorImpl
writes the result Image (YUV_420_888
format) to the output surface specified by theonOutputSurface()
call. Camera2/X converts it into JPEG images if necessary.
Support capture request keys and results
In addition to camera preview and capture, apps can set zoom, flash parameters, or trigger a tap-to-focus. These parameters might not be compatible with your extension implementation.
The following methods have been added to extensions-interface
1.3.0 to allow you to expose the parameters that your implementation supports:
-
ImageCaptureExtenderImpl.getAvailableCaptureRequestKeys()
returns the capture request keys supported by your implementation. -
ImageCaptureExtenderImpl.getAvailableCaptureResultKeys()
returns the capture result keys that are contained in the capture result.
If the camera HAL processes the extension, Camera2/X retrieves the capture results in CameraCaptureSession.CaptureCallback
. However, if the processor is implemented, then Camera2/X retrieves the capture results in ProcessResultImpl
, which is passed to the process()
method in PreviewImageProcessorImpl
and CaptureProcessorImpl
. You're responsible for reporting the capture result through ProcessResultImpl
to Camera2/X.
See the definition of the CaptureProcessorImpl
interface below as an example. In extensions-interface
1.3.0 or higher, the second process()
call is invoked:
Interface CaptureProcessorImpl extends ProcessorImpl {
// invoked when extensions-interface version < 1.3.0
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results);
// invoked when extensions-interface version >= 1.3.0
void process(Map<Integer, Pair<Image, TotalCaptureResult>> results,
ProcessResultImpl resultCallback, Executor executor);
}
For common camera operations like zoom, tap-to-focus, flash, and exposure compensation, we recommend supporting the following keys for both capture request and capture result:
- Zoom:
-
CaptureRequest#CONTROL_ZOOM_RATIO
-
CaptureRequest#SCALER_CROP_REGION
-
- Tap-to-focus:
-
CaptureRequest#CONTROL_AF_MODE
-
CaptureRequest#CONTROL_AF_TRIGGER
-
CaptureRequest#CONTROL_AF_REGIONS
-
CaptureRequest#CONTROL_AE_REGIONS
-
CaptureRequest#CONTROL_AWB_REGIONS
-
- Flash:
-
CaptureRequest#CONTROL_AE_MODE
-
CaptureRequest#CONTROL_AE_PRECAPTURE_TRIGGER
-
CaptureRequest#FLASH_MODE
-
- Exposure compensation:
-
CaptureRequest#CONTROL_AE_EXPOSURE_COMPENSATION
-
For Basic Extenders that implement 1.2.0 or prior versions, the CameraX Extensions API explicitly supports all the above keys. For extensions-interface
1.3.0, both CameraX and Camera2 honor the returned list and support only the keys contained in it. For example, if you decide to return only CaptureRequest#CONTROL_ZOOM_RATIO
and CaptureRequest#SCALER_CROP_REGION
in the 1.3.0 implementation, then that means only zoom is supported for the app while tap-to-focus, flash, and exposure compensation aren't allowed.
Advanced Extender
Advanced Extender is a type of vendor implementation based on the Camera2 API. This Extender type was added in extensions-interface
1.2.0. Depending on the device manufacturer, extensions might be implemented in the app layer, which depends on the following factors:
Custom stream configuration: Configure custom streams like RAW stream or have multiple streams for different physical camera IDs.
Capability to send Camera2 requests: Support a complicated interaction logic that can send capture requests with parameters based on the results of previous requests.
Advanced Extender provides a wrapper, or an intermediate layer, so you can customize the stream configuration and send capture requests on demand.
Files to implement
To switch to the Advanced Extender implementation, the isAdvancedExtenderImplemented()
method in ExtensionVersionImpl
must return true
. For each extension type, OEMs must implement the corresponding Extender classes. The Advanced Extender implementation files are in the advanced package.
Extender classes to implement | |
---|---|
Night | advanced/NightAdvancedExtenderImpl.java |
HDR | advanced/HdrAdvancedExtenderImpl.java |
Auto | advanced/AutoAdvancedExtenderImpl.java |
Bokeh | advanced/BokehAdvancedExtenderImpl.java |
Face Retouch | advanced/BeautyAdvancedExtenderImpl.java |
We use AdvancedExtenderImpl
as a placeholder in the following example. Replace it with the name of the Extender file for the extension you're implementing.
Let's see how Camera2/X invokes the extensions-interface
to achieve the three app flows.
App flow 1: Check extensions availability
Figure 8. App flow 1 on Advanced Extender
First, the app checks if the given extension is supported.
App flow 2: Query information
Figure 9. App flow 2 on Advanced Extender
After calling AdvancedExtenderImpl.init()
, the app can query the following the information on AdvancedExtenderImpl
:
Estimated still capture latency:
AdvancedExtenderImpl.getEstimatedCaptureLatencyRange()
returns the range of the capture latency for the app to evaluate if it is appropriate to enable the extension for the current scenario.Supported resolutions for preview and still capture:
AdvancedExtenderImpl.getSupportedPreviewOutputResolutions()
returns a map of image format to the sizes list that are supported for preview surface format and size. OEMs must support at least thePRIVATE
format.AdvancedExtenderImpl.getSupportedCaptureOutputResolutions()
returns the supported format and sizes for still capture surface. OEMs must support bothJPEG
andYUV_420_888
format output.AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
returns the supported sizes for an extraYUV_420_888
stream for image analysis. If the image analysis YUV surface isn't supported,getSupportedYuvAnalysisResolutions()
should returnnull
or an empty list.
Available capture request keys/results (added in
extensions-interface
1.3.0): Camera2/X invokes the following methods to retrieve the supported capture request keys and result keys from your implementation:-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys
-
For more information, see Support capture request keys and results .
App flow 3: Preview/still capture with extension enabled
Figure 10. App flow 3 on Advanced Extender
The above diagram shows the main flow for starting preview and still capture for the Advanced Extender type. Let's walk through each step.
SessionProcessorImpl
instanceThe core Advanced Extender implementation is in
SessionProcessorImpl
, which is responsible for providing customized session configuration and sending capture requests to initiate the preview and still capture request.AdvancedExtenderImpl.createSessionProcessor()
is invoked to return theSessionProcessorImpl
instance.initSession
SessionProcessorImpl.initSession()
initializes the session for the extension. This is where you allocate resources and return a session configuration for preparing aCameraCaptureSession
.For the input parameters, Camera2/X specifies the output surface configurations for preview, still capture, and an optional YUV image analysis. This output surface configuration (
OutputSurfaceImpl
) contains the surface, size and image format that are retrieved by following methods inAdvancedExtenderImpl
:-
getSupportedPreviewOutputResolutions()
-
getSupportedCaptureOutputResolutions()
-
getSupportedYuvAnalysisResolutions()
You must return a
Camera2SessionConfigImpl
instance, which consists of a list ofCamera2OutputConfigImpl
instances and the session parameters used for configuringCameraCaptureSession
. You're responsible for outputting the correct camera images to the output surfaces passed in by Camera2/X. Here are some options to enable the output:- Processing in camera HAL: You can directly add the output surfaces to
CameraCaptureSession
with aSurfaceOutputConfigImpl
implementation. This configures the supplied output surface to the camera pipeline and allows the camera HAL to process the image. Processing intermediate
ImageReader
surface (RAW, YUV, etc): Add the intermediateImageReader
surfaces to theCameraCaptureSession
with anImageReaderOutputConfigImpl
instance.You need to process the intermediate images and write the result image to the output surface.
- Use Camera2 surface sharing: Use surface sharing with another surface by adding any
Camera2OutputConfigImpl
instance to thegetSurfaceSharingOutputConfigs()
method of anotherCamera2OutputConfigImpl
instance. The surface format and size must be identical.
All
Camera2OutputConfigImpl
includingSurfaceOutputConfigImpl
andImageReaderOutputConfigImpl
must have a unique ID (getId()
), which is used to specify the target surface and retrieve the image fromImageReaderOutputConfigImpl
.-
onCaptureSessionStart
andRequestProcessorImpl
When
CameraCaptureSession
starts and the Camera framework invokesonConfigured()
, then Camera2/X invokesSessionProcessorImpl.onCaptureSessionStart()
with the Camera2 request wrapperRequestProcessImpl
. Camera2/X implementsRequestProcessImpl
, which enables you to execute the capture requests , and retrieve images ifImageReaderOutputConfigImpl
is used.The
RequestProcessImpl
APIs are similar to the Camera2CameraCaptureSession
APIs in terms of executing requests. The differences are:- The target surface is specified by the ID of the
Camera2OutputConfigImpl
instance. - The capability of retrieving the image of the
ImageReader
.
You can call
RequestProcessorImpl.setImageProcessor()
with a specifiedCamera2OutputConfigImpl
ID to register anImageProcessorImpl
instance to receive images.The
RequestProcessImpl
instance becomes invalid after Camera2/X callsSessionProcessorImpl.onCaptureSessionEnd()
.- The target surface is specified by the ID of the
Start the preview and take a picture
In the Advanced Extender implementation, you can send capture requests through the
RequestProcessorImpl
interface. Camera2/X notifies you to start the repeating request for preview or the still capture sequence by callingSessionProcessorImpl#startRepeating
andSessionProcessorImpl#startCapture
respectively. You should send capture requests to satisfy these preview and still-capture requests.Camera2/X also sets the capture request parameters through
SessionProcessorImpl#setParameters
. You must set these request parameters (if parameters are supported) on both the repeating and single requests.You must support at least
CaptureRequest.JPEG_ORIENTATION
andCaptureRequest.JPEG_QUALITY
.extensions-interface
1.3.0 supports request and result keys, which are exposed by the following methods:-
AdvancedExtenderImpl.getAvailableCaptureRequestKeys()
-
AdvancedExtenderImpl.getAvailableCaptureResultKeys()
When developers set the keys in the
getAvailableCaptureRequestKeys
list, you must enable the parameters and ensure the capture result contains the keys in thegetAvailableCaptureResultKeys
list.-
startTrigger
SessionProcessorImpl.startTrigger()
is invoked to start the trigger such asCaptureRequest.CONTROL_AF_TRIGGER
andCaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER
. You can disregard any capture request keys that weren't advertised inAdvancedExtenderImpl.getAvailableCaptureRequestKeys()
.startTrigger()
has been supported sinceextensions-interface
1.3.0. It enables apps to implement tap-to-focus and flash with extensions.Clean up
When finishing a capture session,
SessionProcessorImpl.onCaptureSessionEnd()
is invoked ahead of closingCameraCaptureSession
. After the capture session has closed,deInitSession()
performs the clean up.
Support preview, still capture, and image analysis
You should apply the extension for both the preview and still capture use cases. However, if the latency is too high to smoothly show the preview, you can apply the extension only for still capture.
For the Basic Extender type, regardless of enabling the extension for preview, you must implement both ImageCaptureExtenderImpl
and PreviewExtenderImpl
for a given extension. Often, an app also uses a YUV stream to analyze the image content such as finding QR codes or text. To better support this use case , you should support the stream combination of preview, still capture, and a YUV_420_888
stream for configuring CameraCaptureSession
. This means that if you implement a processor, then you have to support the stream combination of three YUV_420_888
streams.
For Advanced Extender, Camera2/X passes three output surfaces to the SessionProcessorImpl.initSession()
call. These output surfaces are for preview , still capture, and image analysis, respectively. You must ensure that preview and still capture output surfaces show the valid output. However, for the image analysis output surface, ensure it's working only when it's non-null. If your implementation can't support the image analysis stream, you can return an empty list in AdvancedExtenderImpl.getSupportedYuvAnalysisResolutions()
. This ensures the image analysis output surface is always null in SessionProcessorImpl.initSession()
.
Support video capture
The current Camera Extension architecture supports only the preview and still capture use cases. We don't support enabling the extension on the MediaCodec
or MediaRecorder
surfaces for recording the video. However, it's possible for apps to record the preview output.
Supporting MediaCodec
and MediaRecorder
surfaces is under investigation.
Extensions interface version history
The following table shows the Camera Extension interface version history. You should always implement the vendor library with the latest version.
Version | Added features |
---|---|
1.0.0 |
|
1.1.0 |
|
1.2.0 |
|
1.3.0 |
|
Reference implementation
The following reference OEM vendor library implementations are available in frameworks/ex
.
advancedSample
: A basic implementation of Advanced Extender.sample
: A basic implementation of Basic Extender.service_based_sample
: An implementation that demonstrates how to host Camera Extensions in aService
. This implementation contains the following components:oem_library
: A Camera Extensions OEM library for Camera2 and CameraX Extensions APIs that implementsExtensions-Interface
. This acts as a passthrough that forwards calls fromExtensions-Interface
to the service. This library also provides AIDL files and wrapper classes to communicate with the service.Advanced Extender is enabled by default. To enable the Basic Extender, change
ExtensionsVersionImpl#isAdvancedExtenderImplemented
to returnfalse
.extensions_service
: A sample implementation of the Extensions Service. Add your implementation here. The interface to implement in the service is similar to theExtensions-Interface
. For example, implementing theIAdvancedExtenderImpl.Stub
performs the same operations asAdvancedExtenderImpl
.ImageWrapper
andTotalCaptureResultWrapper
are required to makeImage
andTotalCaptureResult
parcelable.
Set up the vendor library on a device
The OEM vendor library isn't built into an app; it's loaded from the device at runtime by Camera2/X. In CameraX, the <uses-library>
tag declares that the androidx.camera.extensions.impl
library, which is defined in the AndroidManifest.xml
file of the camera-extensions
library, is a dependency of CameraX and must be loaded at runtime. In Camera2, the framework loads an extensions service that also declares that the <uses-library>
loads the same androidx.camera.extensions.impl
library at runtime.
This allows third-party apps using extensions to automatically load the OEM vendor library. The OEM library is marked as optional so apps can run on devices that don't have the library on the device. Camera2/X handles this behavior automatically when an app tries to use a camera extension as long as the device manufacturer places the OEM library on the device so that it can be discovered by the app.
To set up the OEM library on a device, do the following:
- Add a permission file, which is required by the
<uses-library>
tag, using the following format:/etc/permissions/ ANY_FILENAME .xml
. For example,/etc/permissions/camera_extensions.xml
. The files in this directory provide a mapping of the library named in<uses-library>
to the actual file path on the device. Use the example below to add the required information to the file.
-
name
must beandroidx.camera.extensions.impl
as that's the library that CameraX searches for. -
file
is the absolute path of the file that contains the extensions implementation (for example,/system/framework/androidx.camera.extensions.impl.jar
).
<?xml version="1.0" encoding="utf-8"?> <permissions> <library name="androidx.camera.extensions.impl" file="OEM_IMPLEMENTED_JAR" /> </permissions>
-
In Android 12 or higher, devices supporting CameraX extensions must have the ro.camerax.extensions.enabled
property set to true
, which allows for querying whether a device supports extensions. To do this, add the following line in the device make file:
PRODUCT_VENDOR_PROPERTIES += \
ro.camerax.extensions.enabled=true \
Validation
To test your implementation of the OEM vendor library during the development stage, use the example app at androidx-main/camera/integration-tests/extensionstestapp/
, which runs through various vendor extensions.
After you complete your implementation, use the Camera Extensions Validation Tool to run automated and manual tests to verify that the vendor library is implemented correctly.
Extended scene mode versus Camera Extensions
For the bokeh extension, in addition to exposing it using Camera Extensions, you can expose the extension using the extended scene mode, which is enabled through the CONTROL_EXTENDED_SCENE_MODE
key. For more implementation details, see Camera Bokeh .
Extended scene mode has fewer restrictions compared to Camera Extensions for camera2 apps. For example, you can enable extended scene mode in a regular CameraCaptureSession
instance that supports flexible stream combinations and capture request parameters. In contrast, camera extensions support only a fixed set of stream types and have limited support for capture request parameters.
A downside of extended scene mode is that you can only implement it in the camera HAL, which means that it must be verified to work across all orthogonal controls available to app developers.
We recommend exposing bokeh using both the extended scene mode and Camera Extensions because apps might prefer to use a particular API to enable bokeh. We recommend first using the extended scene mode because this is the most flexible way for apps to enable the bokeh extension. Then you can implement the camera extensions interface based on the extended scene mode. If implementing bokeh in the camera HAL is difficult, for example, because it requires a post processor running in the app layer to process images, we recommend implementing the bokeh extension using the Camera Extensions interface.
Frequently asked questions (FAQs)
Are there any restrictions on API levels?
Yes. This depends on the Android API feature set that's required by the OEM vendor library implementation. For example, ExtenderStateListener.onPresetSession()
uses the SessionConfiguration.setSessionParameters()
call to set a baseline set of tags. This call is available only on API level 28 and higher. For details on specific interface methods, see the API reference documentation .