Capture photo, vidéo et audio de base à l’aide de MediaCapture

Cet article présente la manière la plus simple de capturer des photos et des vidéos à l’aide de la classe MediaCapture. La classe MediaCapture expose un ensemble robuste d’applications qui fournissent un contrôle de bas niveau sur le pipeline de capture et permettent des scénarios de capture avancés, mais cet article a pour but de vous aider à ajouter rapidement et facilement la capture de médias de base à votre application. Pour en savoir plus sur les fonctionnalités de MediaCapture, consultez la section Caméra.

Si vous souhaitez simplement capturer une photo ou une vidéo et n’avez pas l’intention d’ajouter des fonctionnalités de capture de médias supplémentaires, ou si vous ne souhaitez pas créer votre propre interface utilisateur de caméra, vous pouvez utiliser la classe CameraCaptureUI, qui vous permet de lancer simplement l’application de caméra intégrée de Windows et de recevoir le fichier photo ou vidéo qui a été capturé. Pour plus d’informations, voir Capturer des photos et des vidéos avec l’interface utilisateur de l’appareil photo intégré de Windows.

Le code de cet article a été adapté à partir de l’exemple du kit de démarrage Camera. Vous pouvez télécharger l’exemple pour voir le code utilisé dans son contexte ou pour utiliser l’exemple comme point de départ pour votre propre application.

Ajouter des déclarations de capacités au manifeste de l’application

Pour que votre application puisse accéder à l’appareil photo d’un appareil, vous devez déclarer que votre application utilise les capacités de la webcam et du microphone de l’appareil. Si vous souhaitez enregistrer les photos et les vidéos capturées dans la bibliothèque Pictures ou Videos de l’utilisateur, vous devez également déclarer les capacités picturesLibrary et videosLibrary.

Pour ajouter des capacités au manifeste de l’application

  1. Dans Microsoft Visual Studio, dans Explorateur de solutions, ouvrez le concepteur du manifeste de l’application en double-cliquant sur l’élément package.appxmanifest.
  2. Sélectionnez l’onglet Fonctionnalités.
  3. Cochez la case Webcam et la case Microphone.
  4. Pour l’accès à la bibliothèque d’images et de vidéos, cochez les cases Bibliothèque d’images et Bibliothèque de vidéos.

Initialiser l’objet MediaCapture

Toutes les méthodes de capture décrites dans cet article nécessitent une première étape d’initialisation de l’objet MediaCapture en appelant le constructeur, puis en appelant InitializeAsync. Comme l’objet MediaCapture sera accessible à partir de plusieurs applications, déclarez une variable de classe pour contenir l’objet. Mettez en œuvre un gestionnaire pour l’événement Failed de l’objet MediaCapture afin d’être informé de l’échec d’une opération de capture.

MediaCapture mediaCapture;
bool isPreviewing;
mediaCapture = new MediaCapture();
await mediaCapture.InitializeAsync();
mediaCapture.Failed += MediaCapture_Failed;

Configurer la préversion de l’appareil photo

Il est possible de capturer des photos, des vidéos et de l’audio à l’aide de MediaCapture sans afficher la préversion de l’appareil photo, mais vous souhaitez généralement afficher le flux de prévisualisation afin que l’utilisateur puisse voir ce qui est capturé. Par ailleurs, certaines fonctionnalités de MediaCapture nécessitent l’exécution du flux de préversion avant de pouvoir être activées, notamment la mise au point automatique, l’exposition automatique et la balance des blancs automatique. Pour savoir comment configurer la prévisualisation de l’appareil photo, voir Afficher la prévisualisation de l’appareil photo.

Capture d’une photo dans un SoftwareBitmap

La classe SoftwareBitmap a été introduite dans Windows 10 pour fournir une représentation commune des images à travers plusieurs fonctionnalités. Si vous souhaitez capturer une photo puis utiliser immédiatement l’image capturée dans votre application, par exemple en l’affichant dans XAML, au lieu de la capturer dans un fichier, vous devez la capturer dans un SoftwareBitmap. Vous avez toujours la possibilité d’enregistrer l’image sur le disque ultérieurement.

Après avoir initialisé l’objet MediaCapture, vous pouvez capturer une photo dans un SoftwareBitmap à l’aide de la classe LowLagPhotoCapture. Obtenez une instance de cette classe en appelant PrepareLowLagPhotoCaptureAsync, en passant un objet ImageEncodingProperties spécifiant le format d’image que vous souhaitez. CreateUncompressed crée un encodage non compressé avec le format de pixels spécifié. Prenez une photo en appelant CaptureAsync, qui renvoie un objet CapturedPhoto. Obtenez un SoftwareBitmap en accédant à la propriété Frame puis à la propriété SoftwareBitmap.

Si vous le souhaitez, vous pouvez capturer plusieurs photos en appelant plusieurs fois CaptureAsync. Lorsque vous avez terminé la capture, appelez FinishAsync pour fermer la session LowLagPhotoCapture et libérer les ressources associées. Après avoir appelé FinishAsync, pour recommencer à capturer des photos, vous devrez appeler à nouveau PrepareLowLagPhotoCaptureAsync pour réinitialiser la session de capture avant d’appeler CaptureAsync.

// Prepare and capture photo
var lowLagCapture = await mediaCapture.PrepareLowLagPhotoCaptureAsync(ImageEncodingProperties.CreateUncompressed(MediaPixelFormat.Bgra8));

var capturedPhoto = await lowLagCapture.CaptureAsync();
var softwareBitmap = capturedPhoto.Frame.SoftwareBitmap;

await lowLagCapture.FinishAsync();

À partir de Windows, version 1803, vous pouvez accéder à la propriété BitmapProperties de la classe CapturedFrame renvoyée par CaptureAsync pour récupérer des métadonnées sur la photo capturée. Vous pouvez transmettre ces données à un BitmapEncoder pour enregistrer les métadonnées dans un fichier. Auparavant, il n’existait aucun moyen d’accéder à ces données pour les formats d’image non compressés. Vous pouvez également accéder à la propriété ControlValues pour récupérer un objet CapturedFrameControlValues qui décrit les valeurs de contrôle, telles que l’exposition et la balance des blancs, pour la trame capturée.

Pour plus d’informations sur l’utilisation de BitmapEncoder et sur le travail avec l’objet SoftwareBitmap, y compris sur la manière d’en afficher un dans une page XAML, voir Créer, modifier et enregistrer des images bitmap.

Pour plus d’informations sur la définition des valeurs de contrôle des appareils de capture, voir Contrôles des appareils de capture pour la photo et la vidéo.

Démarrage avec Windows 10, version 1803, vous pouvez obtenir les métadonnées, telles que les informations EXIF, pour les photos capturées au format non compressé en accédant à la propriété BitmapProperties de la CapturedFrame renvoyée par MediaCapture. Dans les versions précédentes, ces données n’étaient accessibles que dans l’en-tête des photos capturées dans un format de fichier compressé. Vous pouvez fournir ces données à un BitmapEncoder lors de l’écriture manuelle d’un fichier image. Pour plus d’informations sur le codage des images bitmap, voir Créer, modifier et enregistrer des images bitmap. Vous pouvez également accéder aux valeurs de contrôle de la trame, telles que les paramètres d’exposition et de flash, utilisées lors de la capture de l’image en accédant à la propriété ControlValues. Pour plus d’informations, voir Contrôles d’appareil pour la capture de photos et de vidéos.

Capture d’une photo dans un fichier

Une application de photographie typique enregistrera une photo capturée sur le disque ou sur un stockage cloud et devra ajouter des métadonnées, telles que l’orientation de la photo, au fichier. L’exemple suivant vous montre comment capturer une photo dans un fichier. Vous avez toujours la possibilité de créer ultérieurement un SoftwareBitmap à partir du fichier image.

La technique présentée dans cet exemple permet de capturer la photo dans un flux en mémoire, puis de transcoder la photo du flux vers un fichier sur disque. Cet exemple utilise GetLibraryAsync pour obtenir la bibliothèque d’images de l’utilisateur, puis la propriété SaveFolder pour obtenir un dossier d’enregistrement par défaut. N’oubliez pas d’ajouter la capacité Pictures Library au manifeste de votre application pour accéder à ce dossier. CreateFileAsync crée un nouveau StorageFile dans lequel la photo sera enregistrée.

Créez un InMemoryRandomAccessStream, puis appelez CapturePhotoToStreamAsync pour capturer une photo dans le flux, en lui transmettant le flux et un objet ImageEncodingProperties spécifiant le format d’image à utiliser. Vous pouvez créer des propriétés d’encodage personnalisées en initialisant l’objet vous-même, mais la classe fournit des méthodes statiques, comme ImageEncodingProperties.CreateJpeg pour les formats d’encodage courants. Ensuite, créez un flux de fichiers vers le fichier de sortie en appelant OpenAsync. Créez un BitmapDecoder pour décoder l’image à partir du flux en mémoire, puis créez un BitmapEncoder pour encoder l’image dans le fichier en appelant CreateForTranscodingAsync.

Vous pouvez éventuellement créer un objet BitmapPropertySet et appeler ensuite SetPropertiesAsync sur l’encodeur d’image pour inclure des métadonnées sur la photo dans le fichier image. Pour plus d’informations sur les propriétés d’encodage, voir Métadonnées d’image. La gestion correcte de l’orientation de l’appareil est essentielle pour la plupart des applications de photographie. Pour plus d’informations, voir Gérer l’orientation de l’appareil avec MediaCapture.

Enfin, appelez FlushAsync sur l’objet encodeur pour transcoder la photo du flux en mémoire vers le fichier.

var myPictures = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Pictures);
StorageFile file = await myPictures.SaveFolder.CreateFileAsync("photo.jpg", CreationCollisionOption.GenerateUniqueName);

using (var captureStream = new InMemoryRandomAccessStream())
{
    await mediaCapture.CapturePhotoToStreamAsync(ImageEncodingProperties.CreateJpeg(), captureStream);

    using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
    {
        var decoder = await BitmapDecoder.CreateAsync(captureStream);
        var encoder = await BitmapEncoder.CreateForTranscodingAsync(fileStream, decoder);

        var properties = new BitmapPropertySet {
            { "System.Photo.Orientation", new BitmapTypedValue(PhotoOrientation.Normal, PropertyType.UInt16) }
        };
        await encoder.BitmapProperties.SetPropertiesAsync(properties);

        await encoder.FlushAsync();
    }
}

Pour plus d’informations sur l’utilisation des fichiers et des dossiers, consultez la section Fichiers, dossiers et bibliothèques.

Capturez une vidéo

Ajoutez rapidement la capture vidéo à votre application en utilisant la classe LowLagMediaRecording. Commencez par déclarer une variable de classe pour l’objet.

LowLagMediaRecording _mediaRecording;

Ensuite, créez un objet StorageFile dans lequel la vidéo sera enregistrée. Notez que pour enregistrer dans la vidéothèque de l’utilisateur, comme indiqué dans cet exemple, vous devez ajouter la capacité Bibliothèque de vidéos au manifeste de votre application. Appelez PrepareLowLagRecordToStorageFileAsync pour initialiser l’enregistrement multimédia, en transmettant le fichier de stockage et un objet MediaEncodingProfile spécifiant l’encodage de la vidéo. La classe fournit des méthodes statiques, comme CreateMp4, pour créer des profils d’encodage vidéo courants.

Enfin, appelez StartAsync pour commencer à capturer la vidéo.

var myVideos = await Windows.Storage.StorageLibrary.GetLibraryAsync(Windows.Storage.KnownLibraryId.Videos);
StorageFile file = await myVideos.SaveFolder.CreateFileAsync("video.mp4", CreationCollisionOption.GenerateUniqueName);
_mediaRecording = await mediaCapture.PrepareLowLagRecordToStorageFileAsync(
        MediaEncodingProfile.CreateMp4(VideoEncodingQuality.Auto), file);
await _mediaRecording.StartAsync();

Pour arrêter l’enregistrement vidéo, appelez StopAsync.

await _mediaRecording.StopAsync();

Vous pouvez continuer à appeler StartAsync et StopAsync pour capturer d’autres vidéos. Lorsque vous avez terminé la capture de vidéos, appelez FinishAsync pour vous débarrasser de la session de capture et nettoyer les ressources associées. Après cet appel, vous devez à nouveau appeler PrepareLowLagRecordToStorageFileAsync pour réinitialiser la session de capture avant d’appeler StartAsync.

await _mediaRecording.FinishAsync();

Lors de la capture vidéo, vous devez enregistrer un gestionnaire pour l’événement RecordLimitationExceeded de l’objet MediaCapture, qui sera déclenché par le système d’exploitation si vous dépassez la limite d’un seul enregistrement, qui est actuellement de trois heures. Dans le gestionnaire de l’événement, vous devez finaliser votre enregistrement en appelant StopAsync.

mediaCapture.RecordLimitationExceeded += MediaCapture_RecordLimitationExceeded;
private async void MediaCapture_RecordLimitationExceeded(MediaCapture sender)
{
    await _mediaRecording.StopAsync();
    System.Diagnostics.Debug.WriteLine("Record limitation exceeded.");
}

Lire et éditer les fichiers vidéo capturés

Une fois que vous avez capturé une vidéo dans un fichier, vous pouvez charger le fichier et le lire dans l’interface utilisateur de votre application. Pour ce faire, vous pouvez utiliser le contrôle XAML MediaPlayerElement et un MediaPlayer associé. Pour plus d’informations sur la lecture de médias dans une page XAML, voir Lire des fichiers audio et vidéo avec MediaPlayer.

Vous pouvez également créer un objet MediaClip à partir d’un fichier vidéo en appelant CreateFromFileAsync. Une composition média offre des fonctionnalités d’édition vidéo de base, telles que l’organisation de la séquence des objets MediaClip, la réduction de la longueur de la vidéo, la création de calques, l’ajout de musique de fond et l’application d’effets vidéo. Pour plus d’informations sur l’utilisation des compositions de médias, voir Compositions de médias et édition.

Mise en pause et reprise d’un enregistrement vidéo

Vous pouvez mettre en pause un enregistrement vidéo, puis reprendre l’enregistrement sans créer de fichier de sortie distinct en appelant PauseAsync, puis ResumeAsync.

await _mediaRecording.PauseAsync(Windows.Media.Devices.MediaCapturePauseBehavior.ReleaseHardwareResources);
await _mediaRecording.ResumeAsync();

À partir de Windows 10, version 1607, vous pouvez mettre en pause un enregistrement vidéo et recevoir la dernière trame capturée avant la mise en pause de l’enregistrement. Vous pouvez ensuite superposer cette trame à la préversion de la caméra pour permettre à l’utilisateur d’aligner la caméra sur la trame mise en pause avant de reprendre l’enregistrement. L’appel à PauseWithResultAsync renvoie un objet MediaCapturePauseResult. La propriété LastFrame est un objet VideoFrame représentant la dernière trame. Pour afficher la trame dans XAML, obtenez la représentation SoftwareBitmap de la trame vidéo. Actuellement, seules les images au format BGRA8 avec une chaîne alpha prémultipliée ou vide sont prises en charge ; appelez donc Convert si nécessaire pour obtenir le format correct. Créez un nouvel objet SoftwareBitmapSource et appelez SetBitmapAsync pour l’initialiser. Enfin, définissez la propriété Source d’un contrôle XAML Image pour afficher l’image. Pour que cette astuce fonctionne, votre image doit être alignée sur le contrôle CaptureElement et avoir une valeur d’opacité inférieure à un. N’oubliez pas que vous ne pouvez modifier l’interface utilisateur que sur le threading de l’interface utilisateur, donc faites cet appel à l’intérieur de RunAsync.

PauseWithResultAsync renvoie également la durée de la vidéo enregistrée dans le segment précédent, au cas où vous auriez besoin de connaître la durée totale de l’enregistrement.

MediaCapturePauseResult result = 
    await _mediaRecording.PauseWithResultAsync(Windows.Media.Devices.MediaCapturePauseBehavior.RetainHardwareResources);

var pausedFrame = result.LastFrame.SoftwareBitmap;
if(pausedFrame.BitmapPixelFormat != BitmapPixelFormat.Bgra8 || pausedFrame.BitmapAlphaMode != BitmapAlphaMode.Ignore)
{
    pausedFrame = SoftwareBitmap.Convert(pausedFrame, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore);
}

var source = new SoftwareBitmapSource();
await source.SetBitmapAsync(pausedFrame);

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    PauseImage.Source = source;
    PauseImage.Visibility = Visibility.Visible;
});

_totalRecordedTime += result.RecordDuration;

Lorsque vous reprenez l’enregistrement, vous pouvez définir la source de l’image sur null et la masquer.

await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    PauseImage.Source = null;
    PauseImage.Visibility = Visibility.Collapsed;
});

await _mediaRecording.ResumeAsync();

Notez que vous pouvez également obtenir une trame de résultat lorsque vous arrêtez la vidéo en appelant StopWithResultAsync.

Capture audio

Vous pouvez rapidement ajouter la capture audio à votre application en utilisant la même technique que celle présentée ci-dessus pour la capture vidéo. L’exemple ci-dessous crée un fichier StorageFile dans le dossier de données de l’application. Appelez PrepareLowLagRecordToStorageFileAsync pour initialiser la session de capture, en transmettant le fichier et un MediaEncodingProfile qui est généré dans cet exemple par la méthode statique CreateMp3. Pour commencer l’enregistrement, appelez StartAsync.

mediaCapture.RecordLimitationExceeded += MediaCapture_RecordLimitationExceeded;

var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file = await localFolder.CreateFileAsync("audio.mp3", CreationCollisionOption.GenerateUniqueName);
_mediaRecording = await mediaCapture.PrepareLowLagRecordToStorageFileAsync(
        MediaEncodingProfile.CreateMp3(AudioEncodingQuality.High), file);
await _mediaRecording.StartAsync();

Appelez StopAsync pour arrêter l’enregistrement audio.

await _mediaRecording.StopAsync();

Vous pouvez appeler StartAsync et StopAsync plusieurs fois pour enregistrer plusieurs fichiers audio. Lorsque vous avez terminé la capture audio, appelez FinishAsync pour vous débarrasser de la session de capture et nettoyer les ressources associées. Après cet appel, vous devez à nouveau appeler PrepareLowLagRecordToStorageFileAsync pour réinitialiser la session de capture avant d’appeler StartAsync.

await _mediaRecording.FinishAsync();

Détecter et répondre aux changements de niveau audio par le système.

À partir de Windows 10, version 1803, votre application peut détecter lorsque le système abaisse ou coupe le niveau audio des flux de capture et de rendu audio de votre application. Par exemple, le système peut couper les flux de votre application lorsqu’elle passe en arrière-plan. La classe AudioStateMonitor vous permet de vous enregistrer pour recevoir un événement lorsque le système modifie le volume d’un flux audio. Obtenez une instance d’AudioStateMonitor pour surveiller les flux de capture audio en appelant CreateForCaptureMonitoring. Obtenez une instance pour la surveillance des flux de rendu audio en appelant CreateForRenderMonitoring. Enregistrez un gestionnaire pour l’événement SoundLevelChanged de chaque moniteur afin d’être informé lorsque l’audio de la catégorie de flux correspondante est modifiée par le système.

// Namespaces for monitoring audio state
using Windows.Media;
using Windows.Media.Audio;
AudioStateMonitor captureAudioStateMonitor;
AudioStateMonitor renderAudioStateMonitor;
captureAudioStateMonitor = AudioStateMonitor.CreateForCaptureMonitoring();
captureAudioStateMonitor.SoundLevelChanged += CaptureAudioStateMonitor_SoundLevelChanged; ;

renderAudioStateMonitor = AudioStateMonitor.CreateForRenderMonitoring();
renderAudioStateMonitor.SoundLevelChanged += RenderAudioStateMonitor_SoundLevelChanged; ;

Dans le gestionnaire SoundLevelChanged du flux de capture, vous pouvez vérifier la propriété SoundLevel de l’émetteur AudioStateMonitor pour déterminer le nouveau niveau sonore. Notez qu’un flux de capture ne doit jamais être abaissé, ou « ducké », par le système. Il ne doit jamais être mis en sourdine ou ramené à son volume maximal. Si le flux audio est coupé, vous pouvez arrêter une capture en cours. Si le flux audio est rétabli à plein volume, vous pouvez recommencer la capture. L’exemple suivant utilise des variables de classe booléennes pour savoir si l’application est en train de capturer de l’audio et si la capture a été interrompue en raison du changement d’état de l’audio. Ces variables sont utilisées pour déterminer quand il convient d’arrêter ou de démarrer la capture audio par programme.

bool isCapturingAudio = false;
bool capturingStoppedForAudioState = false;
private void CaptureAudioStateMonitor_SoundLevelChanged(AudioStateMonitor sender, object args)
{
    switch (sender.SoundLevel)
    {
        case SoundLevel.Full:
            if(capturingStoppedForAudioState)
            {
                StartAudioCapture();
                capturingStoppedForAudioState = false;
            }  
            break;
        case SoundLevel.Muted:
            if(isCapturingAudio)
            {
                StopAudioCapture();
                capturingStoppedForAudioState = true;
            }
            break;
        case SoundLevel.Low:
            // This should never happen for capture
            Debug.WriteLine("Unexpected audio state.");
            break;
    }
}

L’exemple de code suivant illustre une implémentation du gestionnaire SoundLevelChanged pour le rendu audio. En fonction du scénario de votre application et du type de contenu que vous lisez, vous souhaiterez peut-être interrompre la lecture audio lorsque le niveau sonore est modifié. Pour plus d’informations sur la gestion des changements de niveau sonore pour la lecture de médias, consultez la section Lire des fichiers audio et vidéo avec MediaPlayer.

private void RenderAudioStateMonitor_SoundLevelChanged(AudioStateMonitor sender, object args)
{
    if ((sender.SoundLevel == SoundLevel.Full) ||
  (sender.SoundLevel == SoundLevel.Low && !isPodcast))
    {
        mediaPlayer.Play();
    }
    else if ((sender.SoundLevel == SoundLevel.Muted) ||
         (sender.SoundLevel == SoundLevel.Low && isPodcast))
    {
        // Pause playback if we’re muted or if we’re playing a podcast and are ducked
        mediaPlayer.Pause();
    }
}