API Camera

Le framework Android est compatible avec diverses caméras et fonctionnalités de caméra disponibles sur les appareils, ce qui vous permet de capturer des photos et des vidéos dans vos applications. Ce document présente une approche simple et rapide de la capture d'images et de vidéos, et décrit une approche avancée pour créer des expériences de caméra personnalisées pour vos utilisateurs.

Remarque:Cette page décrit la classe Camera, qui est désormais obsolète. Nous vous recommandons d'utiliser la bibliothèque Jetpack CameraX ou, pour des cas d'utilisation spécifiques, la classe camera2. CameraX et Camera2 fonctionnent sur Android 5.0 (niveau d'API 21) ou version ultérieure.

Points à prendre en compte

Avant d'autoriser votre application à utiliser des appareils photo sur les appareils Android, vous devez vous poser quelques questions sur la façon dont votre application prévoit d'utiliser cette fonctionnalité matérielle.

  • Configuration requise pour la caméra : l'utilisation d'un appareil photo est-elle si importante pour votre application que vous ne souhaitez pas qu'elle soit installée sur un appareil sans appareil photo ? Si tel est le cas, vous devez déclarer l'exigence relative à la caméra dans le fichier manifeste.
  • Quick Picture ou Custom Camera : Comment votre application utilisera-t-elle l'appareil photo ? Vous souhaitez juste prendre une photo ou un extrait vidéo, ou votre application proposera-t-elle une nouvelle façon d'utiliser les appareils photo ? Si vous souhaitez créer une photo ou un clip rapide, envisagez d'utiliser des applications d'appareil photo existantes. Pour développer une fonctionnalité d'appareil photo personnalisée, consultez la section Créer une application d'appareil photo.
  • Exigence concernant les services de premier plan : Quand votre application interagit-elle avec la caméra ? Sur Android 9 (niveau d'API 28) ou version ultérieure, les applications exécutées en arrière-plan ne peuvent pas accéder à l'appareil photo. Par conséquent, vous devez utiliser l'appareil photo lorsque votre application est au premier plan ou dans le cadre d'un service de premier plan.
  • Stockage : les images ou les vidéos générées par votre application sont-elles destinées à être uniquement visibles par votre application ou partagées afin que d'autres applications telles que Galerie, ou d'autres applications de médias et de réseaux sociaux puissent les utiliser ? Voulez-vous que les photos et les vidéos soient disponibles même si votre application est désinstallée ? Consultez la section Enregistrer des fichiers multimédias pour découvrir comment implémenter ces options.

Principes de base

Le framework Android prend en charge la capture d'images et de vidéos via l'API android.hardware.camera2 ou l'appareil photo Intent. Voici les classes pertinentes:

android.hardware.camera2
Ce package est la principale API permettant de contrôler les caméras des appareils. Il peut être utilisé pour prendre des photos ou enregistrer des vidéos lorsque vous créez une application d'appareil photo.
Camera
Cette classe est l'ancienne API obsolète permettant de contrôler les caméras des appareils.
SurfaceView
Cette classe permet de présenter à l'utilisateur un aperçu en direct de la caméra.
MediaRecorder
Cette classe permet d'enregistrer une vidéo à l'aide de la caméra.
Intent
Un type d'action d'intent MediaStore.ACTION_IMAGE_CAPTURE ou MediaStore.ACTION_VIDEO_CAPTURE peut être utilisé pour capturer des images ou des vidéos sans utiliser directement l'objet Camera.

Déclarations du fichier manifeste

Avant de commencer le développement de votre application avec l'API Camera, vous devez vous assurer que votre fichier manifeste contient les déclarations appropriées pour permettre l'utilisation de l'appareil photo et d'autres fonctionnalités associées.

  • Autorisation d'accès à l'appareil photo : votre application doit demander l'autorisation d'utiliser l'appareil photo d'un appareil.
    <uses-permission android:name="android.permission.CAMERA" />
    

    Remarque:Si vous utilisez l'appareil photo en appelant une application d'appareil photo existante, votre application n'a pas besoin de demander cette autorisation.

  • Fonctionnalités de l'appareil photo : votre application doit également déclarer l'utilisation des fonctionnalités de l'appareil photo, par exemple :
    <uses-feature android:name="android.hardware.camera" />
    

    Pour obtenir la liste des fonctionnalités de la caméra, consultez la documentation de référence sur les fonctionnalités du fichier manifeste.

    Si vous ajoutez des fonctionnalités de caméra à votre fichier manifeste, Google Play empêche l'installation de votre application sur les appareils qui n'incluent pas de caméra ou qui ne sont pas compatibles avec les fonctionnalités de caméra que vous spécifiez. Pour en savoir plus sur l'utilisation du filtrage basé sur les fonctionnalités avec Google Play, consultez Google Play et le filtrage basé sur les fonctionnalités.

    Si votre application peut utiliser une fonctionnalité d'appareil photo ou d'appareil photo pour fonctionner correctement, mais qu'elle ne l'exige pas, vous devez le spécifier dans le fichier manifeste en incluant l'attribut android:required et en le définissant sur false:

    <uses-feature android:name="android.hardware.camera" android:required="false" />
    
  • Autorisation de stockage : votre application peut enregistrer des images ou des vidéos sur la mémoire de stockage externe de l'appareil (carte SD) si elle cible Android 10 (niveau d'API 29) ou une version antérieure, et spécifie ce qui suit dans le fichier manifeste.
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    
  • Autorisation d'enregistrement audio : pour enregistrer du contenu audio avec capture vidéo, votre application doit demander l'autorisation de capture audio.
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    
  • Autorisation de localisation : Si votre application tague des images avec des informations de localisation GPS, vous devez demander l'autorisation ACCESS_FINE_LOCATION. Notez que si votre application cible Android 5.0 (niveau d'API 21) ou une version ultérieure, vous devez également déclarer qu'elle utilise le GPS de l'appareil:

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    ...
    <!-- Needed only if your app targets Android 5.0 (API level 21) or higher. -->
    <uses-feature android:name="android.hardware.location.gps" />
    

    Pour en savoir plus sur l'obtention de la position de l'utilisateur, consultez Stratégies de localisation.

Utiliser des applications d'appareil photo existantes

Un moyen rapide de prendre des photos ou des vidéos dans votre application sans trop de code supplémentaire consiste à utiliser un Intent pour appeler une application d'appareil photo Android existante. Pour en savoir plus, consultez les leçons Prendre des photos simplement et Enregistrer des vidéos simplement.

Créer une application d'appareil photo

Certains développeurs peuvent avoir besoin d'une interface utilisateur de caméra personnalisée pour l'apparence de leur application ou fournissant des fonctionnalités spéciales. Écrire votre propre code de prise de vue peut offrir une expérience plus attrayante à vos utilisateurs.

Remarque: Le guide suivant concerne l'ancienne API Camera, qui est obsolète. Pour les applications d'appareil photo nouvelles ou avancées, la nouvelle API android.hardware.camera2 est recommandée.

Pour créer une interface de caméra personnalisée pour votre application, procédez comme suit:

  • Detect and Access Camera (Détecter et accéder à la caméra) : créez du code pour vérifier l'existence des caméras et demander l'accès.
  • Créer une classe Preview : créez une classe d'aperçu de l'appareil photo qui étend SurfaceView et implémente l'interface SurfaceHolder. Cette classe offre un aperçu des images en direct de la caméra.
  • Créer une mise en page d'aperçu : une fois que vous disposez de la classe d'aperçu de la caméra, créez une mise en page de vue qui intègre l'aperçu et les commandes de l'interface utilisateur de votre choix.
  • Configurer des écouteurs pour la capture : connectez des écouteurs pour vos commandes d'interface afin de lancer la capture d'image ou de vidéo en réponse aux actions de l'utilisateur, telles qu'un appui sur un bouton.
  • Capture and Save Files (Capturer et enregistrer les fichiers) : configurez le code de capture d'images ou de vidéos, et d'enregistrement du résultat.
  • Libérer la caméra : une fois la caméra utilisée, votre application doit la libérer correctement pour être utilisée par d'autres applications.

Le matériel de l'appareil photo est une ressource partagée qui doit être gérée avec soin afin que votre application ne soit pas en conflit avec d'autres applications susceptibles de vouloir l'utiliser. Les sections suivantes expliquent comment détecter le matériel de l'appareil photo, comment demander l'accès à un appareil photo, comment capturer des photos ou des vidéos, et comment libérer l'appareil photo lorsque votre application a terminé de l'utiliser.

Attention:N'oubliez pas de libérer l'objet Camera en appelant Camera.release() lorsque votre application a fini de l'utiliser. Si votre application ne libère pas correctement l'appareil photo, toutes les tentatives ultérieures d'accès à l'appareil photo, y compris celles de votre propre application, échoueront et peuvent entraîner l'arrêt de votre application ou d'autres applications.

Détection du matériel de l'appareil photo...

Si votre application ne nécessite pas spécifiquement d'appareil photo à l'aide d'une déclaration de fichier manifeste, vous devez vérifier si une caméra est disponible au moment de l'exécution. Pour effectuer cette vérification, utilisez la méthode PackageManager.hasSystemFeature(), comme indiqué dans l'exemple de code ci-dessous:

Kotlin

/** Check if this device has a camera */
private fun checkCameraHardware(context: Context): Boolean {
    if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
        // this device has a camera
        return true
    } else {
        // no camera on this device
        return false
    }
}

Java

/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        // this device has a camera
        return true;
    } else {
        // no camera on this device
        return false;
    }
}

Les appareils Android peuvent disposer de plusieurs appareils photo, par exemple une caméra arrière pour la photographie et une caméra avant pour les appels vidéo. Android 2.3 (niveau d'API 9) ou version ultérieure vous permet de vérifier le nombre d'appareils photo disponibles sur un appareil à l'aide de la méthode Camera.getNumberOfCameras().

Accès aux caméras

Si vous avez déterminé que l'appareil sur lequel votre application s'exécute est équipé d'une caméra, vous devez demander l'accès à cette caméra en obtenant une instance de Camera (sauf si vous utilisez un intent pour accéder à l'appareil photo).

Pour accéder à l'appareil photo principal, utilisez la méthode Camera.open() et veillez à intercepter toutes les exceptions, comme indiqué dans le code ci-dessous:

Kotlin

/** A safe way to get an instance of the Camera object. */
fun getCameraInstance(): Camera? {
    return try {
        Camera.open() // attempt to get a Camera instance
    } catch (e: Exception) {
        // Camera is not available (in use or does not exist)
        null // returns null if camera is unavailable
    }
}

Java

/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
    Camera c = null;
    try {
        c = Camera.open(); // attempt to get a Camera instance
    }
    catch (Exception e){
        // Camera is not available (in use or does not exist)
    }
    return c; // returns null if camera is unavailable
}

Attention:Vérifiez toujours les exceptions lorsque vous utilisez Camera.open(). Si vous ne recherchez pas les exceptions si la caméra est utilisée ou n'existe pas, le système arrêtera votre application.

Sur les appareils équipés d'Android 2.3 (niveau d'API 9) ou version ultérieure, vous pouvez accéder à des appareils photo spécifiques à l'aide de Camera.open(int). L'exemple de code ci-dessus permet d'accéder à la première caméra arrière d'un appareil équipé de plusieurs caméras.

Vérification des fonctionnalités de la caméra

Une fois que vous avez obtenu l'accès à une caméra, vous pouvez obtenir plus d'informations sur ses fonctionnalités à l'aide de la méthode Camera.getParameters() et en vérifiant les capacités prises en charge dans l'objet Camera.Parameters renvoyé. Lorsque vous utilisez le niveau d'API 9 ou supérieur, utilisez Camera.getCameraInfo() pour déterminer si une caméra se trouve à l'avant ou à l'arrière de l'appareil, ainsi que l'orientation de l'image.

Créer une classe Preview

Pour que les utilisateurs puissent prendre des photos ou enregistrer des vidéos de manière efficace, ils doivent être en mesure de voir ce que voit l'appareil photo de l'appareil. Une classe d'aperçu d'appareil photo est un SurfaceView qui peut afficher les données d'image en direct provenant d'une caméra, afin que les utilisateurs puissent encadrer et capturer une photo ou une vidéo.

L'exemple de code suivant montre comment créer une classe d'aperçu de l'appareil photo de base pouvant être incluse dans une mise en page View. Cette classe implémente SurfaceHolder.Callback afin de capturer les événements de rappel permettant de créer et de détruire la vue, qui sont nécessaires pour attribuer l'entrée de l'aperçu de la caméra.

Kotlin

/** A basic Camera preview class */
class CameraPreview(
        context: Context,
        private val mCamera: Camera
) : SurfaceView(context), SurfaceHolder.Callback {

    private val mHolder: SurfaceHolder = holder.apply {
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        addCallback(this@CameraPreview)
        // deprecated setting, but required on Android versions prior to 3.0
        setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        mCamera.apply {
            try {
                setPreviewDisplay(holder)
                startPreview()
            } catch (e: IOException) {
                Log.d(TAG, "Error setting camera preview: ${e.message}")
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        if (mHolder.surface == null) {
            // preview surface does not exist
            return
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview()
        } catch (e: Exception) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        mCamera.apply {
            try {
                setPreviewDisplay(mHolder)
                startPreview()
            } catch (e: Exception) {
                Log.d(TAG, "Error starting camera preview: ${e.message}")
            }
        }
    }
}

Java

/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}

Si vous souhaitez définir une taille spécifique pour l'aperçu de l'appareil photo, définissez-la dans la méthode surfaceChanged(), comme indiqué dans les commentaires ci-dessus. Lorsque vous définissez la taille de l'aperçu, vous devez utiliser les valeurs de getSupportedPreviewSizes(). Ne définissez pas de valeurs arbitraires dans la méthode setPreviewSize().

Remarque:Avec l'introduction de la fonctionnalité Multifenêtre sur Android 7.0 (niveau d'API 24) ou version ultérieure, vous ne pouvez plus supposer que le format de l'aperçu est identique à votre activité, même après avoir appelé setDisplayOrientation(). En fonction de la taille et du format de la fenêtre, vous devrez peut-être adapter un aperçu de l'appareil photo large à une mise en page orientée portrait, ou inversement, en utilisant une mise en page au format letterbox.

Placer un aperçu dans une mise en page

Une classe d'aperçu de l'appareil photo, comme dans l'exemple de la section précédente, doit être placée dans la mise en page d'une activité avec les autres commandes de l'interface utilisateur permettant de prendre une photo ou de filmer une vidéo. Cette section vous explique comment créer une mise en page et une activité de base pour l'aperçu.

Le code de mise en page suivant fournit une vue très basique qui peut être utilisée pour afficher un aperçu de la caméra. Dans cet exemple, l'élément FrameLayout est destiné à être le conteneur de la classe d'aperçu de l'appareil photo. Ce type de mise en page permet de superposer des informations ou des commandes supplémentaires sur les images d'aperçu en direct de la caméra.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
  <FrameLayout
    android:id="@+id/camera_preview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_weight="1"
    />

  <Button
    android:id="@+id/button_capture"
    android:text="Capture"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    />
</LinearLayout>

Sur la plupart des appareils, l'orientation par défaut de l'aperçu de l'appareil photo est le mode paysage. Cet exemple de mise en page spécifie une mise en page horizontale (paysage). Le code ci-dessous définit l'orientation de l'application en mode paysage. Pour simplifier l'affichage d'un aperçu d'appareil photo, vous devez définir l'orientation de l'activité d'aperçu de votre application en mode paysage en ajoutant ce qui suit à votre fichier manifeste.

<activity android:name=".CameraActivity"
          android:label="@string/app_name"

          android:screenOrientation="landscape">
          <!-- configure this activity to use landscape orientation -->

          <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Remarque:Il n'est pas nécessaire que l'aperçu de l'appareil photo soit en mode Paysage. À partir d'Android 2.2 (niveau d'API 8), vous pouvez utiliser la méthode setDisplayOrientation() pour définir la rotation de l'image d'aperçu. Pour modifier l'orientation de l'aperçu à mesure que l'utilisateur réoriente le téléphone, dans la méthode surfaceChanged() de votre classe d'aperçu, commencez par arrêter l'aperçu en modifiant l'orientation avec Camera.stopPreview(), puis redémarrez l'aperçu avec Camera.startPreview().

Dans l'activité de la vue de caméra, ajoutez votre classe d'aperçu à l'élément FrameLayout présenté dans l'exemple ci-dessus. L'activité de la caméra doit également s'assurer qu'elle la libère lorsqu'elle est mise en pause ou éteinte. L'exemple suivant montre comment modifier une activité de caméra pour associer la classe d'aperçu affichée dans la section Créer une classe d'aperçu.

Kotlin

class CameraActivity : Activity() {

    private var mCamera: Camera? = null
    private var mPreview: CameraPreview? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Create an instance of Camera
        mCamera = getCameraInstance()

        mPreview = mCamera?.let {
            // Create our Preview view
            CameraPreview(this, it)
        }

        // Set the Preview view as the content of our activity.
        mPreview?.also {
            val preview: FrameLayout = findViewById(R.id.camera_preview)
            preview.addView(it)
        }
    }
}

Java

public class CameraActivity extends Activity {

    private Camera mCamera;
    private CameraPreview mPreview;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // Create an instance of Camera
        mCamera = getCameraInstance();

        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(this, mCamera);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(mPreview);
    }
}

Remarque:La méthode getCameraInstance() de l'exemple ci-dessus fait référence à l'exemple de méthode présenté dans la section Accéder aux appareils photo.

Prise de photos

Une fois que vous avez créé une classe d'aperçu et une mise en page de vue dans laquelle l'afficher, vous pouvez commencer à capturer des images avec votre application. Dans le code de votre application, vous devez configurer des écouteurs pour que vos commandes d'interface utilisateur répondent à une action de l'utilisateur en prenant une photo.

Pour récupérer une image, utilisez la méthode Camera.takePicture(). Cette méthode nécessite trois paramètres qui reçoivent des données de l'appareil photo. Pour recevoir des données au format JPEG, vous devez implémenter une interface Camera.PictureCallback afin de recevoir les données d'image et de les écrire dans un fichier. Le code suivant illustre une implémentation de base de l'interface Camera.PictureCallback permettant d'enregistrer une image reçue de l'appareil photo.

Kotlin

private val mPicture = Camera.PictureCallback { data, _ ->
    val pictureFile: File = getOutputMediaFile(MEDIA_TYPE_IMAGE) ?: run {
        Log.d(TAG, ("Error creating media file, check storage permissions"))
        return@PictureCallback
    }

    try {
        val fos = FileOutputStream(pictureFile)
        fos.write(data)
        fos.close()
    } catch (e: FileNotFoundException) {
        Log.d(TAG, "File not found: ${e.message}")
    } catch (e: IOException) {
        Log.d(TAG, "Error accessing file: ${e.message}")
    }
}

Java

private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {

        File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        if (pictureFile == null){
            Log.d(TAG, "Error creating media file, check storage permissions");
            return;
        }

        try {
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        } catch (FileNotFoundException e) {
            Log.d(TAG, "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d(TAG, "Error accessing file: " + e.getMessage());
        }
    }
};

Déclenchez la capture d'une image en appelant la méthode Camera.takePicture(). L'exemple de code suivant montre comment appeler cette méthode à partir d'un bouton View.OnClickListener.

Kotlin

val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    // get an image from the camera
    mCamera?.takePicture(null, null, picture)
}

Java

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            // get an image from the camera
            mCamera.takePicture(null, null, picture);
        }
    }
);

Remarque:Le membre mPicture dans l'exemple suivant fait référence à l'exemple de code ci-dessus.

Attention:N'oubliez pas de libérer l'objet Camera en appelant Camera.release() lorsque votre application a fini de l'utiliser. Pour savoir comment libérer la caméra, consultez Déserrer la caméra.

Enregistrement de vidéos

La capture vidéo à l'aide du framework Android nécessite une gestion minutieuse de l'objet Camera et une coordination avec la classe MediaRecorder. Lorsque vous enregistrez une vidéo avec Camera, vous devez gérer les appels Camera.lock() et Camera.unlock() pour autoriser MediaRecorder à accéder au matériel de l'appareil photo, en plus des appels Camera.open() et Camera.release().

Remarque:À partir d'Android 4.0 (niveau d'API 14), les appels Camera.lock() et Camera.unlock() sont gérés automatiquement.

Contrairement à la prise de photos avec l'appareil photo d'un appareil, la capture vidéo nécessite un ordre d'appel très particulier. Vous devez suivre un ordre d'exécution spécifique pour préparer et capturer une vidéo avec votre application, comme indiqué ci-dessous.

  1. Open Camera (Ouvrir l'appareil photo) : utilisez Camera.open() pour obtenir une instance de l'objet appareil photo.
  2. Connect Preview (Aperçu de la connexion) : préparez un aperçu d'image de caméra en direct en connectant un SurfaceView à la caméra à l'aide de Camera.setPreviewDisplay().
  3. Démarrer l'aperçu : appelez Camera.startPreview() pour commencer à afficher les images en direct de la caméra.
  4. Démarrer l'enregistrement de la vidéo – Vous devez effectuer les étapes suivantes pour enregistrer une vidéo :
    1. Déverrouiller la caméra : déverrouillez l'appareil photo afin que MediaRecorder puisse l'utiliser en appelant Camera.unlock().
    2. Configurer MediaRecorder : appelez les méthodes MediaRecorder suivantes dans cet ordre. Pour en savoir plus, consultez la documentation de référence sur MediaRecorder.
      1. setCamera() : définissez l'appareil photo à utiliser pour la capture vidéo. Utilisez l'instance actuelle de Camera de votre application.
      2. setAudioSource() : définissez la source audio à l'aide de MediaRecorder.AudioSource.CAMCORDER.
      3. setVideoSource() : définissez la source vidéo à l'aide de MediaRecorder.VideoSource.CAMERA.
      4. Définissez le format et l'encodage de la sortie vidéo. Pour Android 2.2 (niveau d'API 8) ou version ultérieure, utilisez la méthode MediaRecorder.setProfile et obtenez une instance de profil à l'aide de CamcorderProfile.get(). Pour les versions d'Android antérieures à la version 2.2, vous devez définir le format de sortie vidéo et les paramètres d'encodage :
        1. setOutputFormat() : définissez le format de sortie, spécifiez le paramètre par défaut ou MediaRecorder.OutputFormat.MPEG_4.
        2. setAudioEncoder() : définissez le type d'encodage audio, le paramètre par défaut ou MediaRecorder.AudioEncoder.AMR_NB.
        3. setVideoEncoder() : définissez le type d'encodage vidéo, spécifiez le paramètre par défaut ou MediaRecorder.VideoEncoder.MPEG_4_SP.
      5. setOutputFile() : définissez le fichier de sortie en utilisant getOutputMediaFile(MEDIA_TYPE_VIDEO).toString() à partir de l'exemple de méthode de la section Enregistrer des fichiers multimédias.
      6. setPreviewDisplay() : spécifiez l'élément de mise en page d'aperçu SurfaceView pour votre application. Utilisez le même objet que celui que vous avez spécifié pour la Preview Connect.

      Attention:Vous devez appeler ces méthodes de configuration MediaRecorder dans cet ordre, sinon votre application rencontrera des erreurs et l'enregistrement échouera.

    3. Prepare MediaRecorder : préparez le MediaRecorder avec les paramètres de configuration fournis en appelant MediaRecorder.prepare().
    4. Start MediaRecorder (Démarrer MediaRecorder) : permet de lancer l'enregistrement d'une vidéo en appelant MediaRecorder.start().
  5. Stop Recording Video (Arrêter l'enregistrement vidéo) : appelez les méthodes suivantes dans l'ordre pour terminer l'enregistrement vidéo :
    1. Arrêter MediaRecorder : arrêtez l'enregistrement d'une vidéo en appelant MediaRecorder.stop().
    2. Réinitialiser MediaRecorder : vous pouvez éventuellement supprimer les paramètres de configuration de l'enregistreur en appelant MediaRecorder.reset().
    3. Release MediaRecorder : libérez le MediaRecorder en appelant MediaRecorder.release().
    4. Verrouiller la caméra : verrouillez la caméra afin que les futures sessions MediaRecorder puissent l'utiliser en appelant Camera.lock(). À partir d'Android 4.0 (niveau d'API 14), cet appel n'est pas nécessaire, sauf si l'appel MediaRecorder.prepare() échoue.
  6. Stop the Preview (Arrêter l'aperçu) : lorsque votre activité a fini d'utiliser la caméra, arrêtez l'aperçu à l'aide de Camera.stopPreview().
  7. Libérer la caméra : libérez la caméra afin que d'autres applications puissent l'utiliser en appelant Camera.release().

Remarque:Il est possible d'utiliser MediaRecorder sans d'abord créer d'aperçu de l'appareil photo et d'ignorer les premières étapes de cette procédure. Toutefois, comme les utilisateurs préfèrent généralement voir un aperçu avant de commencer un enregistrement, ce processus n'est pas abordé ici.

Conseil:Si votre application est généralement utilisée pour enregistrer des vidéos, définissez setRecordingHint(boolean) sur true avant de lancer l'aperçu. Ce paramètre permet de réduire le temps nécessaire au démarrage de l'enregistrement.

Configurer MediaRecorder

Lorsque vous utilisez la classe MediaRecorder pour enregistrer des vidéos, vous devez effectuer les étapes de configuration dans un ordre spécifique, puis appeler la méthode MediaRecorder.prepare() pour vérifier et implémenter la configuration. L'exemple de code suivant montre comment configurer et préparer correctement la classe MediaRecorder pour l'enregistrement vidéo.

Kotlin

private fun prepareVideoRecorder(): Boolean {
    mediaRecorder = MediaRecorder()

    mCamera?.let { camera ->
        // Step 1: Unlock and set camera to MediaRecorder
        camera?.unlock()

        mediaRecorder?.run {
            setCamera(camera)

            // Step 2: Set sources
            setAudioSource(MediaRecorder.AudioSource.CAMCORDER)
            setVideoSource(MediaRecorder.VideoSource.CAMERA)

            // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
            setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH))

            // Step 4: Set output file
            setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString())

            // Step 5: Set the preview output
            setPreviewDisplay(mPreview?.holder?.surface)

            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
            setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)


            // Step 6: Prepare configured MediaRecorder
            return try {
                prepare()
                true
            } catch (e: IllegalStateException) {
                Log.d(TAG, "IllegalStateException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            } catch (e: IOException) {
                Log.d(TAG, "IOException preparing MediaRecorder: ${e.message}")
                releaseMediaRecorder()
                false
            }
        }

    }
    return false
}

Java

private boolean prepareVideoRecorder(){

    mCamera = getCameraInstance();
    mediaRecorder = new MediaRecorder();

    // Step 1: Unlock and set camera to MediaRecorder
    mCamera.unlock();
    mediaRecorder.setCamera(mCamera);

    // Step 2: Set sources
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

    // Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
    mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

    // Step 4: Set output file
    mediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

    // Step 5: Set the preview output
    mediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

    // Step 6: Prepare configured MediaRecorder
    try {
        mediaRecorder.prepare();
    } catch (IllegalStateException e) {
        Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    } catch (IOException e) {
        Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
        releaseMediaRecorder();
        return false;
    }
    return true;
}

Avant la version 2.2 d'Android (niveau d'API 8), vous devez définir directement les paramètres de format de sortie et de format d'encodage, au lieu d'utiliser CamcorderProfile. Cette approche est illustrée dans le code suivant:

Kotlin

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder?.apply {
        setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
        setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT)
        setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)
    }

Java

    // Step 3: Set output format and encoding (for versions prior to API Level 8)
    mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
    mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
    mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);

Les paramètres d'enregistrement vidéo suivants pour MediaRecorder sont définis par défaut. Toutefois, vous pouvez ajuster ces paramètres pour votre application:

Démarrage et arrêt de MediaRecorder

Lorsque vous démarrez et arrêtez un enregistrement vidéo à l'aide de la classe MediaRecorder, vous devez suivre un ordre spécifique, comme indiqué ci-dessous.

  1. Déverrouiller l'appareil photo avec Camera.unlock()
  2. Configurez MediaRecorder comme indiqué dans l'exemple de code ci-dessus.
  3. Démarrer l'enregistrement avec MediaRecorder.start()
  4. Enregistrer la vidéo
  5. Arrêter l'enregistrement avec MediaRecorder.stop()
  6. Relâchez l'enregistreur multimédia avec MediaRecorder.release()
  7. Verrouiller la caméra avec Camera.lock()

L'exemple de code suivant montre comment raccorder un bouton pour démarrer et arrêter correctement un enregistrement vidéo à l'aide de la caméra et de la classe MediaRecorder.

Remarque:Lorsque vous terminez un enregistrement vidéo, ne relâchez pas la caméra, sinon l'aperçu s'arrêtera.

Kotlin

var isRecording = false
val captureButton: Button = findViewById(R.id.button_capture)
captureButton.setOnClickListener {
    if (isRecording) {
        // stop recording and release camera
        mediaRecorder?.stop() // stop the recording
        releaseMediaRecorder() // release the MediaRecorder object
        mCamera?.lock() // take camera access back from MediaRecorder

        // inform the user that recording has stopped
        setCaptureButtonText("Capture")
        isRecording = false
    } else {
        // initialize video camera
        if (prepareVideoRecorder()) {
            // Camera is available and unlocked, MediaRecorder is prepared,
            // now you can start recording
            mediaRecorder?.start()

            // inform the user that recording has started
            setCaptureButtonText("Stop")
            isRecording = true
        } else {
            // prepare didn't work, release the camera
            releaseMediaRecorder()
            // inform user
        }
    }
}

Java

private boolean isRecording = false;

// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(
    new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (isRecording) {
                // stop recording and release camera
                mediaRecorder.stop();  // stop the recording
                releaseMediaRecorder(); // release the MediaRecorder object
                mCamera.lock();         // take camera access back from MediaRecorder

                // inform the user that recording has stopped
                setCaptureButtonText("Capture");
                isRecording = false;
            } else {
                // initialize video camera
                if (prepareVideoRecorder()) {
                    // Camera is available and unlocked, MediaRecorder is prepared,
                    // now you can start recording
                    mediaRecorder.start();

                    // inform the user that recording has started
                    setCaptureButtonText("Stop");
                    isRecording = true;
                } else {
                    // prepare didn't work, release the camera
                    releaseMediaRecorder();
                    // inform user
                }
            }
        }
    }
);

Remarque:Dans l'exemple ci-dessus, la méthode prepareVideoRecorder() fait référence à l'exemple de code présenté sur la page Configurer MediaRecorder. Cette méthode permet de verrouiller l'appareil photo, de configurer et de préparer l'instance MediaRecorder.

Desserrer la caméra

Les caméras sont des ressources partagées par les applications installées sur un appareil. Votre application peut utiliser l'appareil photo après avoir obtenu une instance de Camera. Vous devez donc veiller à libérer l'objet appareil photo lorsque votre application cesse de l'utiliser et dès que votre application est suspendue (Activity.onPause()). Si votre application ne libère pas correctement l'appareil photo, toutes les tentatives ultérieures d'accès à l'appareil photo, y compris celles provenant de votre propre application, échoueront et risquent d'entraîner l'arrêt de votre application ou d'autres applications.

Pour libérer une instance de l'objet Camera, utilisez la méthode Camera.release(), comme indiqué dans l'exemple de code ci-dessous.

Kotlin

class CameraActivity : Activity() {
    private var mCamera: Camera?
    private var preview: SurfaceView?
    private var mediaRecorder: MediaRecorder?

    override fun onPause() {
        super.onPause()
        releaseMediaRecorder() // if you are using MediaRecorder, release it first
        releaseCamera() // release the camera immediately on pause event
    }

    private fun releaseMediaRecorder() {
        mediaRecorder?.reset() // clear recorder configuration
        mediaRecorder?.release() // release the recorder object
        mediaRecorder = null
        mCamera?.lock() // lock camera for later use
    }

    private fun releaseCamera() {
        mCamera?.release() // release the camera for other applications
        mCamera = null
    }
}

Java

public class CameraActivity extends Activity {
    private Camera mCamera;
    private SurfaceView preview;
    private MediaRecorder mediaRecorder;

    ...

    @Override
    protected void onPause() {
        super.onPause();
        releaseMediaRecorder();       // if you are using MediaRecorder, release it first
        releaseCamera();              // release the camera immediately on pause event
    }

    private void releaseMediaRecorder(){
        if (mediaRecorder != null) {
            mediaRecorder.reset();   // clear recorder configuration
            mediaRecorder.release(); // release the recorder object
            mediaRecorder = null;
            mCamera.lock();           // lock camera for later use
        }
    }

    private void releaseCamera(){
        if (mCamera != null){
            mCamera.release();        // release the camera for other applications
            mCamera = null;
        }
    }
}

Attention:Si votre application ne libère pas correctement l'appareil photo, toutes les tentatives ultérieures d'accès à l'appareil photo, y compris celles effectuées par votre propre application, échoueront et peuvent entraîner l'arrêt de votre application ou d'autres applications.

Enregistrement de fichiers multimédias

Les fichiers multimédias créés par les utilisateurs, comme les images et les vidéos, doivent être enregistrés dans le répertoire de stockage externe d'un appareil (carte SD) afin d'économiser de l'espace système et de permettre aux utilisateurs d'accéder à ces fichiers sans leur appareil. Il existe de nombreux emplacements de répertoire pour enregistrer des fichiers multimédias sur un appareil. Toutefois, en tant que développeur, vous ne devez prendre en compte que deux emplacements standards:

  • Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) : cette méthode renvoie l'emplacement standard, partagé et recommandé pour enregistrer des photos et des vidéos. Ce répertoire est partagé (public) afin que d'autres applications puissent facilement rechercher, lire, modifier et supprimer les fichiers enregistrés à cet emplacement. Si votre application est désinstallée par l'utilisateur, les fichiers multimédias enregistrés à cet emplacement ne seront pas supprimés. Pour éviter d'interférer avec les images et vidéos existantes des utilisateurs, vous devez créer un sous-répertoire pour les fichiers multimédias de votre application dans ce répertoire, comme indiqué dans l'exemple de code ci-dessous. Cette méthode est disponible dans Android 2.2 (niveau d'API 8). Pour les appels équivalents dans les versions d'API antérieures, consultez Enregistrer des fichiers partagés.
  • Context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) : cette méthode renvoie un emplacement standard pour enregistrer les images et les vidéos associées à votre application. Si votre application est désinstallée, tous les fichiers enregistrés à cet emplacement sont supprimés. La sécurité n'est pas appliquée aux fichiers situés à cet emplacement et d'autres applications peuvent les lire, les modifier et les supprimer.

L'exemple de code suivant montre comment créer un emplacement File ou Uri pour un fichier multimédia pouvant être utilisé lors de l'appel de l'appareil photo d'un appareil avec Intent ou dans le cadre de la création d'une application Appareil photo.

Kotlin

val MEDIA_TYPE_IMAGE = 1
val MEDIA_TYPE_VIDEO = 2

/** Create a file Uri for saving an image or video */
private fun getOutputMediaFileUri(type: Int): Uri {
    return Uri.fromFile(getOutputMediaFile(type))
}

/** Create a File for saving an image or video */
private fun getOutputMediaFile(type: Int): File? {
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    val mediaStorageDir = File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "MyCameraApp"
    )
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    mediaStorageDir.apply {
        if (!exists()) {
            if (!mkdirs()) {
                Log.d("MyCameraApp", "failed to create directory")
                return null
            }
        }
    }

    // Create a media file name
    val timeStamp = SimpleDateFormat("yyyyMMdd_HHmmss").format(Date())
    return when (type) {
        MEDIA_TYPE_IMAGE -> {
            File("${mediaStorageDir.path}${File.separator}IMG_$timeStamp.jpg")
        }
        MEDIA_TYPE_VIDEO -> {
            File("${mediaStorageDir.path}${File.separator}VID_$timeStamp.mp4")
        }
        else -> null
    }
}

Java

public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;

/** Create a file Uri for saving an image or video */
private static Uri getOutputMediaFileUri(int type){
      return Uri.fromFile(getOutputMediaFile(type));
}

/** Create a File for saving an image or video */
private static File getOutputMediaFile(int type){
    // To be safe, you should check that the SDCard is mounted
    // using Environment.getExternalStorageState() before doing this.

    File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
              Environment.DIRECTORY_PICTURES), "MyCameraApp");
    // This location works best if you want the created images to be shared
    // between applications and persist after your app has been uninstalled.

    // Create the storage directory if it does not exist
    if (! mediaStorageDir.exists()){
        if (! mediaStorageDir.mkdirs()){
            Log.d("MyCameraApp", "failed to create directory");
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    File mediaFile;
    if (type == MEDIA_TYPE_IMAGE){
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "IMG_"+ timeStamp + ".jpg");
    } else if(type == MEDIA_TYPE_VIDEO) {
        mediaFile = new File(mediaStorageDir.getPath() + File.separator +
        "VID_"+ timeStamp + ".mp4");
    } else {
        return null;
    }

    return mediaFile;
}

Remarque:Environment.getExternalStoragePublicDirectory() est disponible sur Android 2.2 (niveau d'API 8) ou version ultérieure. Si vous ciblez des appareils équipés de versions antérieures d'Android, utilisez plutôt Environment.getExternalStorageDirectory(). Pour en savoir plus, consultez Enregistrer des fichiers partagés.

Pour que l'URI accepte les profils professionnels, commencez par convertir l'URI du fichier en URI de contenu. Ajoutez ensuite l'URI de contenu à EXTRA_OUTPUT d'un Intent.

Pour en savoir plus sur l'enregistrement de fichiers sur un appareil Android, consultez Stockage des données.

Fonctionnalités de l'appareil photo

Android est compatible avec de nombreuses fonctionnalités de l'appareil photo que vous pouvez contrôler avec votre application d'appareil photo, telles que le format d'image, le mode flash, les paramètres de mise au point et bien d'autres. Cette section liste les fonctionnalités courantes de la caméra et explique brièvement comment les utiliser. La plupart des fonctionnalités de la caméra sont accessibles et définies à l'aide de l'objet Camera.Parameters. Cependant, plusieurs fonctionnalités importantes nécessitent plus que de simples paramètres dans Camera.Parameters. Ces fonctionnalités sont abordées dans les sections suivantes:

Pour obtenir des informations générales sur l'utilisation des fonctionnalités contrôlées via Camera.Parameters, consultez la section Utiliser les fonctionnalités de l'appareil photo. Pour en savoir plus sur l'utilisation des fonctionnalités contrôlées via l'objet "camera parameters" (paramètres de caméra), suivez les liens de la liste des fonctionnalités ci-dessous vers la documentation de référence de l'API.

Tableau 1. Fonctionnalités courantes de l'appareil photo, triées en fonction du niveau d'API Android dans lequel elles ont été introduites.

Fonctionnalité Niveau d'API Description
Détection de visages 14 Identifier des visages humains dans une image et les utiliser pour la mise au point, les mesures et l'équilibre des blancs
Zones de mesure 14 Spécifiez une ou plusieurs zones d'une image pour calculer la balance des blancs
Domaines d'expertise 14 Définissez une ou plusieurs zones d'une image à utiliser pour la mise au point
White Balance Lock 14 Arrêter ou démarrer les réglages automatiques de la balance des blancs
Exposure Lock 14 Activer ou désactiver les ajustements automatiques de l'exposition
Video Snapshot 14 Prendre une photo pendant l'enregistrement d'une vidéo (prise d'image)
Vidéo en accéléré 11 Enregistrer des images avec des délais définis pour enregistrer une vidéo en accéléré
Multiple Cameras 9 Compatibilité avec plusieurs caméras sur un même appareil, y compris les caméras avant et arrière
Focus Distance 9 Indique la distance entre l'appareil photo et les objets qui semblent au premier plan.
Zoom 8 Configurer l'agrandissement de l'image
Exposure Compensation 8 Augmenter ou diminuer le niveau d'exposition à la lumière
GPS Data 5 Inclure ou omettre les données de localisation géographique dans l'image
White Balance 5 Définir le mode de balance des blancs, qui affecte les valeurs des couleurs dans l'image capturée
Focus Mode 5 Définir la mise au point de l'appareil photo sur un sujet (automatique, fixe, macro ou infini, par exemple)
Scene Mode 5 Appliquez un mode prédéfini pour des types de photos spécifiques, par exemple des scènes de nuit, de plage, de neige ou à bougies.
JPEG Quality 5 Définir le niveau de compression d'une image JPEG, qui augmente ou réduit la qualité et la taille du fichier de sortie de l'image
Flash Mode 5 Activer ou désactiver le flash, ou utiliser le paramètre automatique
Color Effects 5 Appliquez un effet de couleur à l'image capturée (noir et blanc, ton sépia ou négatif, par exemple).
Anti-Banding 5 Réduit l'effet des bandes sur les dégradés de couleurs par la compression JPEG
Picture Format 1 Indiquer le format de fichier de l'image
Picture Size 1 Spécifier les dimensions en pixels de l'image enregistrée

Remarque:Ces fonctionnalités ne sont pas compatibles avec tous les appareils en raison de différences matérielles et d'implémentations logicielles. Pour savoir comment vérifier la disponibilité des fonctionnalités sur l'appareil sur lequel votre application s'exécute, consultez la section Vérifier la disponibilité des fonctionnalités.

Vérifier la disponibilité des fonctionnalités

Lorsque vous envisagez d'utiliser les fonctionnalités de l'appareil photo sur des appareils Android, il faut tout d'abord comprendre que toutes les fonctionnalités de l'appareil photo ne sont pas compatibles avec tous les appareils. En outre, les appareils compatibles avec une fonctionnalité particulière peuvent les prendre en charge à différents niveaux ou avec des options différentes. Par conséquent, une partie de votre processus de décision lorsque vous développez une application d'appareil photo consiste à décider quelles fonctionnalités de l'appareil photo vous souhaitez prendre en charge et à quel niveau. Une fois cette décision prise, vous devez prévoir d'inclure du code dans votre application d'appareil photo afin de vérifier si le matériel de l'appareil est compatible avec ces fonctionnalités et échoue en conséquence si une fonctionnalité n'est pas disponible.

Vous pouvez vérifier la disponibilité des fonctionnalités de la caméra en obtenant une instance de l'objet de paramètres d'une caméra et en vérifiant les méthodes pertinentes. L'exemple de code suivant vous montre comment obtenir un objet Camera.Parameters et vérifier si l'appareil photo est compatible avec la fonctionnalité de mise au point automatique:

Kotlin

val params: Camera.Parameters? = camera?.parameters
val focusModes: List<String>? = params?.supportedFocusModes
if (focusModes?.contains(Camera.Parameters.FOCUS_MODE_AUTO) == true) {
    // Autofocus mode is supported
}

Java

// get Camera parameters
Camera.Parameters params = camera.getParameters();

List<String> focusModes = params.getSupportedFocusModes();
if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
  // Autofocus mode is supported
}

Vous pouvez utiliser la technique ci-dessus pour la plupart des fonctionnalités de l'appareil photo. L'objet Camera.Parameters fournit une méthode getSupported...(), is...Supported() ou getMax...() pour déterminer si une fonctionnalité est compatible (et dans quelle mesure).

Si votre application nécessite certaines fonctionnalités de l'appareil photo pour fonctionner correctement, vous pouvez les exiger en ajoutant des ajouts au fichier manifeste de votre application. Lorsque vous déclarez l'utilisation de fonctionnalités spécifiques de l'appareil photo, telles que le flash et l'autofocus, Google Play limite l'installation de votre application sur les appareils non compatibles. Pour obtenir la liste des fonctionnalités de la caméra pouvant être déclarées dans le fichier manifeste de votre application, consultez la documentation de référence sur les fonctionnalités.

Utiliser les fonctionnalités de l'appareil photo

La plupart des fonctionnalités de la caméra sont activées et contrôlées à l'aide d'un objet Camera.Parameters. Pour obtenir cet objet, vous devez d'abord obtenir une instance de l'objet Camera, appeler la méthode getParameters(), modifier l'objet de paramètre renvoyé, puis le replacer dans l'objet appareil photo, comme illustré dans l'exemple de code suivant:

Kotlin

val params: Camera.Parameters? = camera?.parameters
params?.focusMode = Camera.Parameters.FOCUS_MODE_AUTO
camera?.parameters = params

Java

// get Camera parameters
Camera.Parameters params = camera.getParameters();
// set the focus mode
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
// set Camera parameters
camera.setParameters(params);

Cette technique fonctionne pour presque toutes les fonctionnalités de la caméra. La plupart des paramètres peuvent être modifiés à tout moment après avoir obtenu une instance de l'objet Camera. Les modifications apportées aux paramètres sont généralement visibles immédiatement par l'utilisateur dans l'aperçu de l'appareil photo de l'application. Côté logiciel, plusieurs images peuvent être nécessaires pour que les modifications de paramètres soient prises en compte, car le matériel de l'appareil photo traite les nouvelles instructions, puis envoie les données d'image mises à jour.

Important:Certaines fonctionnalités de la caméra ne peuvent pas être modifiées à votre gré. En particulier, pour modifier la taille ou l'orientation de l'aperçu de l'appareil photo, vous devez d'abord arrêter l'aperçu, modifier la taille de l'aperçu, puis redémarrer l'aperçu. À partir d'Android 4.0 (niveau d'API 14), vous pouvez modifier l'orientation de l'aperçu sans redémarrer l'aperçu.

D'autres fonctionnalités de l'appareil photo nécessitent davantage de code pour être implémentées, y compris les suivantes:

  • Mesures et zones de mise au point
  • Détection de visages
  • Vidéo en accéléré

Les sections suivantes décrivent brièvement comment mettre en œuvre ces fonctionnalités.

Mesures et zones de mise au point

Dans certains scénarios photographiques, la mise au point automatique et la mesure de la luminosité peuvent ne pas produire les résultats souhaités. À partir d'Android 4.0 (niveau d'API 14), votre application d'appareil photo peut fournir des commandes supplémentaires pour permettre à votre application ou aux utilisateurs de spécifier des zones d'une image à utiliser pour déterminer les paramètres de mise au point ou de niveau de luminosité, puis de transmettre ces valeurs au matériel photo pour les utiliser lors de la capture d'images ou de vidéos.

Les zones de mesure et de mise au point fonctionnent de manière très semblable aux autres fonctionnalités de l'appareil photo, dans la mesure où vous les contrôlez via des méthodes dans l'objet Camera.Parameters. Le code suivant montre comment définir deux zones de mesure de la luminosité pour une instance de Camera:

Kotlin

// Create an instance of Camera
camera = getCameraInstance()

// set Camera parameters
val params: Camera.Parameters? = camera?.parameters

params?.apply {
    if (maxNumMeteringAreas > 0) { // check that metering areas are supported
        meteringAreas = ArrayList<Camera.Area>().apply {
            val areaRect1 = Rect(-100, -100, 100, 100) // specify an area in center of image
            add(Camera.Area(areaRect1, 600)) // set weight to 60%
            val areaRect2 = Rect(800, -1000, 1000, -800) // specify an area in upper right of image
            add(Camera.Area(areaRect2, 400)) // set weight to 40%
        }
    }
    camera?.parameters = this
}

Java

// Create an instance of Camera
camera = getCameraInstance();

// set Camera parameters
Camera.Parameters params = camera.getParameters();

if (params.getMaxNumMeteringAreas() > 0){ // check that metering areas are supported
    List<Camera.Area> meteringAreas = new ArrayList<Camera.Area>();

    Rect areaRect1 = new Rect(-100, -100, 100, 100);    // specify an area in center of image
    meteringAreas.add(new Camera.Area(areaRect1, 600)); // set weight to 60%
    Rect areaRect2 = new Rect(800, -1000, 1000, -800);  // specify an area in upper right of image
    meteringAreas.add(new Camera.Area(areaRect2, 400)); // set weight to 40%
    params.setMeteringAreas(meteringAreas);
}

camera.setParameters(params);

L'objet Camera.Area contient deux paramètres de données: un objet Rect permettant de spécifier une zone dans le champ de vision de la caméra et une valeur de pondération, qui indique à la caméra le niveau d'importance à accorder à cette zone dans la mesure de la luminosité ou les calculs de mise au point.

Le champ Rect d'un objet Camera.Area décrit une forme rectangulaire mappée sur une grille d'unités de 2 000 x 2 000. Les coordonnées -1000, -1000 représentent les coins supérieur gauche de l'image de l'appareil photo, et les coordonnées 1 000 et 1000 représentent l'angle inférieur droit de l'image, comme illustré ci-dessous.

Figure 1 : Les lignes rouges représentent le système de coordonnées permettant de spécifier un Camera.Area dans un aperçu d'appareil photo. Le cadre bleu indique l'emplacement et la forme d'une zone de caméra avec les valeurs Rect de 333 333 667 667.

Les limites de ce système de coordonnées correspondent toujours au bord extérieur de l'image visible dans l'aperçu de l'appareil photo. Elles ne sont pas réduites ni développées avec le niveau de zoom. De même, la rotation de l'aperçu de l'image à l'aide de Camera.setDisplayOrientation() ne remappe pas le système de coordonnées.

Détection de visages

Pour les photos qui incluent des personnes, les visages sont généralement la partie la plus importante de l'image. Ils doivent être utilisés pour déterminer à la fois la mise au point et l'équilibre des blancs lors de la capture d'une image. Le framework Android 4.0 (niveau d'API 14) fournit des API permettant d'identifier des visages et de calculer les paramètres de l'image à l'aide de la technologie de reconnaissance des visages.

Remarque:Lorsque la fonctionnalité de détection de visages est en cours d'exécution, setWhiteBalance(String), setFocusAreas(List<Camera.Area>) et setMeteringAreas(List<Camera.Area>) n'ont aucun effet.

Pour utiliser la fonctionnalité de détection de visages dans votre application Appareil photo, vous devez suivre quelques étapes générales:

  • Vérifier que la détection des visages est disponible sur l'appareil
  • Créer un écouteur de détection des visages
  • Ajouter l'écouteur de détection de visages à l'objet Appareil photo
  • Démarrer la détection des visages après l'aperçu (et après chaque redémarrage de l'aperçu)

La fonctionnalité de détection des visages n'est pas disponible sur tous les appareils. Vous pouvez vérifier que cette fonctionnalité est compatible en appelant getMaxNumDetectedFaces(). Vous trouverez un exemple de cette vérification dans l'exemple de méthode startFaceDetection() ci-dessous.

Pour recevoir une notification et répondre à la détection d'un visage, votre application d'appareil photo doit définir un écouteur pour les événements de détection de visages. Pour ce faire, vous devez créer une classe d'écouteur qui implémente l'interface Camera.FaceDetectionListener, comme indiqué dans l'exemple de code ci-dessous.

Kotlin

internal class MyFaceDetectionListener : Camera.FaceDetectionListener {

    override fun onFaceDetection(faces: Array<Camera.Face>, camera: Camera) {
        if (faces.isNotEmpty()) {
            Log.d("FaceDetection", ("face detected: ${faces.size}" +
                    " Face 1 Location X: ${faces[0].rect.centerX()}" +
                    "Y: ${faces[0].rect.centerY()}"))
        }
    }
}

Java

class MyFaceDetectionListener implements Camera.FaceDetectionListener {

    @Override
    public void onFaceDetection(Face[] faces, Camera camera) {
        if (faces.length > 0){
            Log.d("FaceDetection", "face detected: "+ faces.length +
                    " Face 1 Location X: " + faces[0].rect.centerX() +
                    "Y: " + faces[0].rect.centerY() );
        }
    }
}

Après avoir créé cette classe, vous la définissez dans l'objet Camera de votre application, comme indiqué dans l'exemple de code ci-dessous:

Kotlin

camera?.setFaceDetectionListener(MyFaceDetectionListener())

Java

camera.setFaceDetectionListener(new MyFaceDetectionListener());

Votre application doit lancer la fonction de détection de visages chaque fois que vous lancez (ou redémarrez) l'aperçu de l'appareil photo. Créez une méthode pour lancer la détection de visages afin de pouvoir l'appeler si nécessaire, comme indiqué dans l'exemple de code ci-dessous.

Kotlin

fun startFaceDetection() {
    // Try starting Face Detection
    val params = mCamera?.parameters
    // start face detection only *after* preview has started

    params?.apply {
        if (maxNumDetectedFaces > 0) {
            // camera supports face detection, so can start it:
            mCamera?.startFaceDetection()
        }
    }
}

Java

public void startFaceDetection(){
    // Try starting Face Detection
    Camera.Parameters params = mCamera.getParameters();

    // start face detection only *after* preview has started
    if (params.getMaxNumDetectedFaces() > 0){
        // camera supports face detection, so can start it:
        mCamera.startFaceDetection();
    }
}

Vous devez lancer la détection de visages chaque fois que vous lancez (ou redémarrez) l'aperçu de l'appareil photo. Si vous utilisez la classe d'aperçu illustrée dans la section Créer une classe d'aperçu, ajoutez votre méthode startFaceDetection() aux méthodes surfaceCreated() et surfaceChanged() de votre classe d'aperçu, comme indiqué dans l'exemple de code ci-dessous.

Kotlin

override fun surfaceCreated(holder: SurfaceHolder) {
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // start face detection feature
    } catch (e: IOException) {
        Log.d(TAG, "Error setting camera preview: ${e.message}")
    }
}

override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
    if (holder.surface == null) {
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null")
        return
    }
    try {
        mCamera.stopPreview()
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: ${e.message}")
    }
    try {
        mCamera.setPreviewDisplay(holder)
        mCamera.startPreview()

        startFaceDetection() // re-start face detection feature
    } catch (e: Exception) {
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: ${e.message}")
    }
}

Java

public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // start face detection feature

    } catch (IOException e) {
        Log.d(TAG, "Error setting camera preview: " + e.getMessage());
    }
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {

    if (holder.getSurface() == null){
        // preview surface does not exist
        Log.d(TAG, "holder.getSurface() == null");
        return;
    }

    try {
        mCamera.stopPreview();

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error stopping camera preview: " + e.getMessage());
    }

    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.startPreview();

        startFaceDetection(); // re-start face detection feature

    } catch (Exception e){
        // ignore: tried to stop a non-existent preview
        Log.d(TAG, "Error starting camera preview: " + e.getMessage());
    }
}

Remarque:N'oubliez pas d'appeler cette méthode après avoir appelé startPreview(). N'essayez pas de lancer la détection de visages dans la méthode onCreate() de l'activité principale de votre application d'appareil photo, car l'aperçu n'est pas disponible à ce stade de l'exécution de votre application.

Vidéo en accéléré

Une vidéo en accéléré permet aux utilisateurs de créer des extraits vidéo combinant des photos prises à quelques secondes ou minutes d'intervalle. Cette fonctionnalité utilise MediaRecorder pour enregistrer les images pour une séquence en accéléré.

Pour enregistrer une vidéo en accéléré avec MediaRecorder, vous devez configurer l'objet Enregistreur comme si vous enregistriez une vidéo normale, en définissant un nombre faible d'images par seconde et en utilisant l'un des paramètres de qualité du mode Accéléré, comme illustré dans l'exemple de code ci-dessous.

Kotlin

mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH))
mediaRecorder.setCaptureRate(0.1) // capture a frame every 10 seconds

Java

// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_HIGH));
...
// Step 5.5: Set the video capture rate to a low number
mediaRecorder.setCaptureRate(0.1); // capture a frame every 10 seconds

Ces paramètres doivent être définis dans le cadre d'une procédure de configuration plus large pour MediaRecorder. Pour obtenir un exemple de code de configuration complet, consultez la section Configurer MediaRecorder. Une fois la configuration terminée, vous démarrez l'enregistrement vidéo comme s'il s'agissait d'un extrait vidéo normal. Pour en savoir plus sur la configuration et l'exécution de MediaRecorder, consultez la section Enregistrer des vidéos.

Les exemples Camera2Video et HdrViewfinder illustrent plus en détail l'utilisation des API abordées sur cette page.

Champs de l'appareil photo nécessitant une autorisation

Les applications exécutant Android version 10 (niveau 29 d'API) ou ultérieure doivent disposer de l'autorisation CAMERA pour accéder aux valeurs des champs suivants renvoyés par la méthode getCameraCharacteristics():

  • LENS_POSE_ROTATION
  • LENS_POSE_TRANSLATION
  • LENS_INTRINSIC_CALIBRATION
  • LENS_RADIAL_DISTORTION
  • LENS_POSE_REFERENCE
  • LENS_DISTORTION
  • LENS_INFO_HYPERFOCAL_DISTANCE
  • LENS_INFO_MINIMUM_FOCUS_DISTANCE
  • SENSOR_REFERENCE_ILLUMINANT1
  • SENSOR_REFERENCE_ILLUMINANT2
  • SENSOR_CALIBRATION_TRANSFORM1
  • SENSOR_CALIBRATION_TRANSFORM2
  • SENSOR_COLOR_TRANSFORM1
  • SENSOR_COLOR_TRANSFORM2
  • SENSOR_FORWARD_MATRIX1
  • SENSOR_FORWARD_MATRIX2

Exemples de code supplémentaires

Pour télécharger des applications exemples, consultez l'exemple Camera2Basic et l'application exemple officielle CameraX.