Éléments, playlists et pistes multimédias

Cet article vous montre comment utiliser la classe MediaSource, qui fournit une manière commune de référencer et de lire des médias à partir de différentes sources telles que des fichiers locaux ou distants, et expose un modèle commun pour accéder aux données des médias, indépendamment du format de média sous-jacent. La classe MediaPlaybackItem étend les fonctionnalités de MediaSource, vous permettant de gérer et de sélectionner parmi plusieurs pistes audio, vidéo et métadonnées contenues dans un élément multimédia. MediaPlaybackList vous permet de créer des listes de lecture à partir d’un ou plusieurs éléments de lecture multimédia.

Créer et lire une MediaSource

Créez une nouvelle instance de MediaSource en appelant l’une des méthodes de fabrique exposées par la classe:

Après avoir créé un objet MediaSource, vous pouvez le lire avec un MediaPlayer en définissant la propriété Source. À partir de Windows 10, version 1607, vous pouvez attribuer un objet MediaPlayer à un contrôle MediaPlayerElement en appelant SetMediaPlayer afin de rendre le contenu du lecteur multimédia dans une page XAML. C’est la méthode préférée par rapport à l’utilisation de MediaElement. Pour plus d’informations sur l’utilisation de MediaPlayer, consultez Lire des fichiers audio et vidéo avec MediaPlayer.

L’exemple suivant montre comment lire un fichier multimédia sélectionné par l’utilisateur dans un objet MediaPlayer en utilisant MediaSource.

Vous devrez inclure les espaces de noms Windows.Media.Core et Windows.Media.Playback pour mener à bien ce scénario.

using Windows.Media.Core;
using Windows.Media.Playback;

Déclarez une variable de type MediaSource. Pour les exemples dans cet article, la source multimédia est déclarée en tant que membre de classe afin qu’elle puisse être accédée depuis plusieurs emplacements.

MediaSource _mediaSource;

Déclarez une variable pour stocker l’objet MediaPlayer et, si vous souhaitez rendre le contenu multimédia dans XAML, ajoutez un contrôle MediaPlayerElement à votre page.

MediaPlayer _mediaPlayer;
<MediaPlayerElement x:Name="mediaPlayerElement"/>

Pour permettre à l’utilisateur de choisir un fichier multimédia à lire, utilisez un FileOpenPicker. Avec l’objet StorageFile retourné par la méthode PickSingleFileAsync du sélecteur, initialisez un nouvel objet MediaObject en appelant MediaSource.CreateFromStorageFile. Enfin, définissez la source multimédia comme source de lecture pour le MediaElement en appelant la méthode SetPlaybackSource.

//Create a new picker
var filePicker = new Windows.Storage.Pickers.FileOpenPicker();

//make a collection of all video types you want to support (for testing we are adding just 3).
string[] fileTypes = new string[] {".wmv", ".mp4", ".mkv"};   
   
//Add your fileTypes to the FileTypeFilter list of filePicker.
foreach (string fileType in fileTypes)
{
    filePicker.FileTypeFilter.Add(fileType);
}

//Set picker start location to the video library
filePicker.SuggestedStartLocation = PickerLocationId.VideosLibrary;

//Retrieve file from picker
StorageFile file = await filePicker.PickSingleFileAsync();

if (!(file is null))
{
    _mediaSource = MediaSource.CreateFromStorageFile(file);
    _mediaPlayer = new MediaPlayer();
    _mediaPlayer.Source = _mediaSource;
    mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
}

Par défaut, le MediaPlayer ne commence pas la lecture automatiquement lorsque la source multimédia est définie. Vous pouvez démarrer la lecture manuellement en appelant Play.

_mediaPlayer.Play();

Vous pouvez également définir la propriété AutoPlay du MediaPlayer sur true pour indiquer au lecteur de commencer la lecture dès que la source multimédia est définie.

_mediaPlayer.AutoPlay = true;

Créer une MediaSource à partir d’une DownloadOperation

À partir de Windows, version 1803, vous pouvez créer un objet MediaSource à partir d’une DownloadOperation.

StorageFile destinationFile = await KnownFolders.VideosLibrary.CreateFileAsync("file.mp4", CreationCollisionOption.GenerateUniqueName);

var downloader = new BackgroundDownloader();
var downloadOperation = downloader.CreateDownload(new Uri("http://server.com/file.mp4"), destinationFile);
MediaSource mediaSource =
      MediaSource.CreateFromDownloadOperation(downloadOperation);

Notez que bien que vous puissiez créer une MediaSource à partir d’un téléchargement sans le démarrer ou définir sa propriété IsRandomAccessRequired sur true, vous devez faire les deux avant de tenter de rattacher la MediaSource à un MediaPlayer ou MediaPlayerElement pour la lecture.

downloadOperation.IsRandomAccessRequired = true;
var startAsyncTask = downloadOperation.StartAsync().AsTask();
mediaPlayerElement.Source = mediaSource;

Gérer plusieurs pistes audio, vidéo et métadonnées avec MediaPlaybackItem

Utiliser une MediaSource pour la lecture est pratique car elle fournit une manière commune de lire des médias à partir de différentes sources, mais un comportement plus avancé peut être accédé en créant un objet MediaPlaybackItem à partir de la MediaSource. Cela inclut la capacité à accéder et à gérer plusieurs pistes audio, vidéo et de données pour un élément multimédia.

Déclarez une variable pour stocker votre objet MediaPlaybackItem.

MediaPlaybackItem _mediaPlaybackItem;

Créez un objet MediaPlaybackItem en appelant le constructeur et en passant un objet MediaSource initialisé.

Si votre application prend en charge plusieurs pistes audio, vidéo ou de données dans un élément de lecture multimédia, enregistrez des gestionnaires d’événements pour les événements AudioTracksChanged, VideoTracksChanged ou TimedMetadataTracksChanged.

Enfin, définissez la source de lecture du MediaElement ou du MediaPlayer sur votre MediaPlaybackItem.

_mediaSource = MediaSource.CreateFromStorageFile(file);
_mediaPlaybackItem = new MediaPlaybackItem(_mediaSource);

_mediaPlaybackItem.AudioTracksChanged += PlaybackItem_AudioTracksChanged;
_mediaPlaybackItem.VideoTracksChanged += MediaPlaybackItem_VideoTracksChanged;
_mediaPlaybackItem.TimedMetadataTracksChanged += MediaPlaybackItem_TimedMetadataTracksChanged;

_mediaPlayer = new MediaPlayer();
_mediaPlayer.Source = _mediaPlaybackItem;
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);

Remarque

Une MediaSource ne peut être associée qu’à un seul MediaPlaybackItem. Après avoir créé un MediaPlaybackItem à partir d’une source, tenter de créer un autre élément de lecture à partir de la même source entraînera une erreur. De plus, après avoir créé un MediaPlaybackItem à partir d’une source multimédia, vous ne pouvez pas définir directement l’objet MediaSource comme source pour un MediaPlayer mais devez plutôt utiliser le MediaPlaybackItem.

L’événement VideoTracksChanged est déclenché après qu’un MediaPlaybackItem contenant plusieurs pistes vidéo est attribué en tant que source de lecture, et peut être déclenché à nouveau si la liste des pistes vidéo pour l’élément change. Le gestionnaire de cet événement vous donne la possibilité de mettre à jour votre interface utilisateur pour permettre à l’utilisateur de passer entre les pistes disponibles. Cet exemple utilise un ComboBox pour afficher les pistes vidéo disponibles.

<ComboBox x:Name="videoTracksComboBox" SelectionChanged="videoTracksComboBox_SelectionChanged"/>

Dans le gestionnaire VideoTracksChanged, parcourez toutes les pistes de la liste VideoTracks de l’élément de lecture. Pour chaque piste, créez un nouveau ComboBoxItem. Si la piste n’a pas déjà d’étiquette, une étiquette est générée à partir de l’indice de la piste. La propriété Tag de l’élément de liste déroulante est définie sur l’indice de piste pour qu’elle puisse être identifiée ultérieurement. Enfin, l’élément est ajouté à la liste déroulante. Notez que ces opérations sont effectuées dans un appel CoreDispatcher.RunAsync car tous les changements d’interface utilisateur doivent être effectués sur le thread d’interface utilisateur et cet événement est déclenché sur un autre thread.

private async void MediaPlaybackItem_VideoTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        videoTracksComboBox.Items.Clear();
        for (int index = 0; index < sender.VideoTracks.Count; index++)
        {
            var videoTrack = sender.VideoTracks[index];
            ComboBoxItem item = new ComboBoxItem();
            item.Content = String.IsNullOrEmpty(videoTrack.Label) ? $"Track {index}" : videoTrack.Label;
            item.Tag = index;
            videoTracksComboBox.Items.Add(item);
        }
    });
}

Dans le gestionnaire SelectionChanged pour la liste déroulante, l’indice de piste est récupéré à partir de la propriété Tag de l’élément sélectionné. En définissant la propriété SelectedIndex de la liste VideoTracks de l’élément de lecture multimédia sur l’indice spécifié, le MediaElement ou MediaPlayer bascule vers la piste vidéo active.

private void videoTracksComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    int trackIndex = (int)((ComboBoxItem)((ComboBox)sender).SelectedItem).Tag;
    _mediaPlaybackItem.VideoTracks.SelectedIndex = trackIndex;
}

La gestion des éléments multimédias avec plusieurs pistes audio fonctionne exactement de la même manière qu’avec les pistes vidéo. Gérez l’événement AudioTracksChanged pour mettre à jour votre interface utilisateur avec les pistes audio trouvées dans la liste AudioTracks de l’élément de lecture. Lorsque l’utilisateur sélectionne une piste audio, définissez la propriété SelectedIndex de la liste AudioTracks pour que le MediaElement ou le MediaPlayer bascule vers la piste audio active à l’index spécifié.

<ComboBox x:Name="audioTracksComboBox" SelectionChanged="audioTracksComboBox_SelectionChanged"/>
private async void PlaybackItem_AudioTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        audioTracksComboBox.Items.Clear();
        for (int index = 0; index < sender.AudioTracks.Count; index++)
        {
            var audioTrack = sender.AudioTracks[index];
            ComboBoxItem item = new ComboBoxItem();
            item.Content = String.IsNullOrEmpty(audioTrack.Label) ? $"Track {index}" : audioTrack.Label;
            item.Tag = index;
            videoTracksComboBox.Items.Add(item);
        }
    });
}
private void audioTracksComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    int trackIndex = (int)((ComboBoxItem)((ComboBox)sender).SelectedItem).Tag;
    _mediaPlaybackItem.AudioTracks.SelectedIndex = trackIndex;
}

En plus de l’audio et de la vidéo, un objet MediaPlaybackItem peut contenir zéro ou plusieurs objets TimedMetadataTrack. Une piste de métadonnées temporelles peut contenir du texte de sous-titres ou de légendes, ou elle peut contenir des données personnalisées propres à votre application. Une piste de métadonnées temporelles contient une liste de repères représentés par des objets qui héritent de IMediaCue, tels qu’un DataCue ou un TimedTextCue. Chaque repère a un temps de démarrage et une durée qui déterminent quand le repère est activé et pour combien de temps.

De manière similaire aux pistes audio et vidéo, les pistes de métadonnées temporelles pour un élément multimédia peuvent être découvertes en gérant l’événement TimedMetadataTracksChanged d’un MediaPlaybackItem. Cependant, avec les pistes de métadonnées temporelles, l’utilisateur peut vouloir activer plus d’une piste de métadonnées à la fois. De plus, en fonction du scénario de votre application, vous pouvez vouloir activer ou désactiver automatiquement les pistes de métadonnées, sans intervention de l’utilisateur. À des fins d’illustration, cet exemple ajoute un ToggleButton pour chaque piste de métadonnées dans un élément multimédia pour permettre à l’utilisateur d’activer et de désactiver la piste. La propriété Tag de chaque bouton est définie sur l’index de la piste de métadonnées associée afin qu’elle puisse être identifiée lorsque le bouton est basculé.

<StackPanel x:Name="MetadataButtonPanel" Orientation="Horizontal"/>
private async void MediaPlaybackItem_TimedMetadataTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        for (int index = 0; index < sender.TimedMetadataTracks.Count; index++)
        {
            var timedMetadataTrack = sender.TimedMetadataTracks[index];

            ToggleButton toggle = new ToggleButton()
            {
                Content = String.IsNullOrEmpty(timedMetadataTrack.Label) ? $"Track {index}" : timedMetadataTrack.Label,
                Tag = (uint)index
            };
            toggle.Checked += Toggle_Checked;
            toggle.Unchecked += Toggle_Unchecked;

            MetadataButtonPanel.Children.Add(toggle);
        }
    });
}

Comme plus d’une piste de métadonnées peut être active à la fois, vous ne définissez pas simplement l’index actif pour la liste de pistes de métadonnées. Au lieu de cela, appelez la méthode SetPresentationMode de l’objet MediaPlaybackItem, en passant l’index de la piste que vous voulez basculer, puis en fournissant une valeur de l’énumération TimedMetadataTrackPresentationMode. Le mode de présentation que vous choisissez dépend de l’implémentation de votre application. Dans cet exemple, la piste de métadonnées est définie sur PlatformPresented lorsqu’elle est activée. Pour les pistes basées sur du texte, cela signifie que le système affichera automatiquement les repères de texte dans la piste. Lorsque le bouton bascule est désactivé, le mode de présentation est réglé sur Disabled, ce qui signifie qu’aucun texte n’est affiché et aucun événement de repère n’est déclenché. Les événements de repère sont discutés plus loin dans cet article.

private void Toggle_Checked(object sender, RoutedEventArgs e) =>         
    _mediaPlaybackItem.TimedMetadataTracks.SetPresentationMode((uint)((ToggleButton)sender).Tag,
        TimedMetadataTrackPresentationMode.PlatformPresented);
private void Toggle_Unchecked(object sender, RoutedEventArgs e) =>         
    _mediaPlaybackItem.TimedMetadataTracks.SetPresentationMode((uint)((ToggleButton)sender).Tag,
        TimedMetadataTrackPresentationMode.Disabled);

Lorsque vous traitez les pistes de métadonnées, vous pouvez accéder à l’ensemble de repères dans la piste en accédant aux propriétés Cues ou ActiveCues. Vous pouvez le faire pour mettre à jour votre interface utilisateur pour afficher les emplacements de repères pour un élément multimédia.

Gérez les codecs non pris en charge et les erreurs inconnues lors de l’ouverture des éléments multimédias

À partir de Windows 10, version 1607, vous pouvez vérifier si le codec requis pour lire un élément multimédia est pris en charge ou partiellement pris en charge sur le périphérique sur lequel votre application est en cours d’exécution. Dans le gestionnaire d’événements pour les événements de changement de pistes de MediaPlaybackItem, tels que AudioTracksChanged, vérifiez d’abord si le changement de piste est une insertion d’une nouvelle piste. Si tel est le cas, vous pouvez obtenir une référence à la piste insérée en utilisant l’indice passé dans le paramètre IVectorChangedEventArgs.Index avec la collection de pistes appropriée du paramètre MediaPlaybackItem, telle que la collection AudioTracks.

Une fois que vous avez une référence à la piste insérée, vérifiez DecoderStatus de la propriété SupportInfo de la piste. Si la valeur est FullySupported, alors le codec approprié nécessaire pour lire la piste est présent sur le périphérique. Si la valeur est Degraded, alors la piste peut être lue par le système, mais la lecture sera dégradée de quelque manière que ce soit. Par exemple, une piste audio 5.1 peut être lue en stéréo 2 canaux à la place. Si c’est le cas, vous voudrez peut-être mettre à jour votre interface utilisateur pour alerter l’utilisateur de la dégradation. Si la valeur est UnsupportedSubtype ou UnsupportedEncoderProperties, alors la piste ne peut pas être lue du tout avec les codecs actuels sur le périphérique. Vous pouvez souhaiter alerter l’utilisateur et ignorer la lecture de l’élément ou implémenter une interface utilisateur pour permettre à l’utilisateur de télécharger le codec correct. La méthode GetEncodingProperties de la piste peut être utilisée pour déterminer le codec requis pour la lecture.

Enfin, vous pouvez vous inscrire à l’événement OpenFailed de la piste, qui sera déclenché si la piste est prise en charge sur le périphérique mais a échoué à s’ouvrir en raison d’une erreur inconnue dans le pipeline.

private async void SnippetAudioTracksChanged_CodecCheck(MediaPlaybackItem sender, IVectorChangedEventArgs args)
{
    if (args.CollectionChange == CollectionChange.ItemInserted)
    {
        var insertedTrack = sender.AudioTracks[(int)args.Index];

        var decoderStatus = insertedTrack.SupportInfo.DecoderStatus;
        if (decoderStatus != MediaDecoderStatus.FullySupported)
        {
            if (decoderStatus == MediaDecoderStatus.Degraded)
            {
                ShowMessageToUser($"Track {insertedTrack.Name} can play but playback will be degraded. {insertedTrack.SupportInfo.DegradationReason}");
            }
            else
            {
                // status is MediaDecoderStatus.UnsupportedSubtype or MediaDecoderStatus.UnsupportedEncoderProperties
                ShowMessageToUser($"Track {insertedTrack.Name} uses an unsupported media format.");
            }

            Windows.Media.MediaProperties.AudioEncodingProperties props = insertedTrack.GetEncodingProperties();
            await HelpUserInstallCodec(props);
        }
        else
        {
            insertedTrack.OpenFailed += InsertedTrack_OpenFailed;
        }
    }

}

Dans le gestionnaire d’événements OpenFailed, vérifiez si le statut de MediaSource est inconnu, et le cas échéant, vous pouvez sélectionner un autre piste à lire de manière programmatique, permettre à l’utilisateur de choisir une autre piste ou abandonner la lecture.

private async void InsertedTrack_OpenFailed(AudioTrack sender, AudioTrackOpenFailedEventArgs args)
{
    LogError(args.ExtendedError.HResult);

    if (sender.SupportInfo.MediaSourceStatus == MediaSourceStatus.Unknown)
    {
        await SelectAnotherTrackOrSkipPlayback(sender.PlaybackItem);
    }
}

Définir les propriétés d’affichage utilisées par les commandes de transport multimédia du système

À partir de Windows 10, version 1607, les médias lus dans un objet MediaPlayer sont automatiquement intégrés aux commandes de transport multimédia du système (SMTC) par défaut. Vous pouvez spécifier les métadonnées qui seront affichées par le SMTC en mettant à jour les propriétés d’affichage pour un objet MediaPlaybackItem. Obtenez un objet représentant les propriétés d’affichage pour un élément en appelant GetDisplayProperties. Définissez si l’élément de lecture est de la musique ou une vidéo en définissant la propriété Type. Ensuite, définissez les propriétés de l’objet VideoProperties ou MusicProperties. Appelez ApplyDisplayProperties pour mettre à jour les propriétés de l’élément selon les valeurs fournies. Généralement, une application récupérera dynamiquement les valeurs d’affichage à partir d’un service web, mais l’exemple suivant illustre ce processus avec des valeurs codées en dur.

MediaItemDisplayProperties props = mediaPlaybackItem.GetDisplayProperties();
props.Type = Windows.Media.MediaPlaybackType.Video;
props.VideoProperties.Title = "Video title";
props.VideoProperties.Subtitle = "Video subtitle";
props.VideoProperties.Genres.Add("Documentary");
mediaPlaybackItem.ApplyDisplayProperties(props);
props = mediaPlaybackItem.GetDisplayProperties();
props.Type = Windows.Media.MediaPlaybackType.Music;
props.MusicProperties.Title = "Song title";
props.MusicProperties.Artist = "Song artist";
props.MusicProperties.Genres.Add("Polka");
mediaPlaybackItem.ApplyDisplayProperties(props);

Ajouter du texte synchronisé externe avec TimedTextSource

Pour certains scénarios, vous pouvez avoir des fichiers externes contenant du texte synchronisé associé à un élément multimédia, tels que des fichiers séparés contenant des sous-titres pour différentes langues. Utilisez la classe TimedTextSource pour charger des fichiers texte synchronisés externes à partir d’un flux ou d’un URI.

Cet exemple utilise une collection Dictionary pour stocker une liste des sources de texte synchronisé pour l’élément multimédia en utilisant l’URI source et l’objet TimedTextSource comme paire clé/valeur afin de les identifier après leur résolution.

Dictionary<TimedTextSource, Uri> timedTextSourceMap;

Créez un nouveau TimedTextSource pour chaque fichier texte synchronisé externe en appelant CreateFromUri. Ajoutez une entrée au Dictionary pour la source de texte synchronisé. Ajoutez un gestionnaire pour l’événement TimedTextSource.Resolved pour gérer si l’élément n’a pas pu être chargé ou pour définir des propriétés supplémentaires après que l’élément a été chargé avec succès.

Enregistrez tous vos objets TimedTextSource avec MediaSource en les ajoutant à la collection ExternalTimedTextSources. Notez que les sources de texte synchronisé externes sont ajoutées directement à MediaSource et non à MediaPlaybackItem créé à partir de la source. Pour mettre à jour votre interface utilisateur pour refléter les pistes de texte externes, enregistrez et gérez l’événement TimedMetadataTracksChanged comme décrit précédemment dans cet article.

// Create the TimedTextSource and add entry to URI map
var timedTextSourceUri_En = new Uri("http://contoso.com/MyClipTimedText_en.srt");
var timedTextSource_En = TimedTextSource.CreateFromUri(timedTextSourceUri_En);
timedTextSourceMap[timedTextSource_En] = timedTextSourceUri_En;
timedTextSource_En.Resolved += TimedTextSource_Resolved;

var timedTextSourceUri_Pt = new Uri("http://contoso.com/MyClipTimedText_pt.srt");
var timedTextSource_Pt = TimedTextSource.CreateFromUri(timedTextSourceUri_Pt);
timedTextSourceMap[timedTextSource_Pt] = timedTextSourceUri_Pt;
timedTextSource_Pt.Resolved += TimedTextSource_Resolved;

// Add the TimedTextSource to the MediaSource
_mediaSource.ExternalTimedTextSources.Add(timedTextSource_En);
_mediaSource.ExternalTimedTextSources.Add(timedTextSource_Pt);

_mediaPlaybackItem = new MediaPlaybackItem(_mediaSource);
_mediaPlaybackItem.TimedMetadataTracksChanged += MediaPlaybackItem_TimedMetadataTracksChanged;

_mediaPlayer = new MediaPlayer();
_mediaPlayer.Source = _mediaPlaybackItem;
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);

Dans le gestionnaire de l’événement TimedTextSource.Resolved, vérifiez la propriété Error de l’objet TimedTextSourceResolveResultEventArgs passé dans le gestionnaire pour déterminer si une erreur s’est produite lors de la tentative de chargement des données de texte synchronisé. Si l’élément a été résolu avec succès, vous pouvez utiliser ce gestionnaire pour mettre à jour des propriétés supplémentaires de la piste résolue. Cet exemple ajoute un libellé pour chaque piste basé sur l’URI précédemment stocké dans le Dictionary.

private void TimedTextSource_Resolved(TimedTextSource sender, TimedTextSourceResolveResultEventArgs args)
{
    var timedTextSourceUri = timedTextSourceMap[sender];

    if (!(args.Error is null))
    {
        // Show that there was an error in your UI
        ShowMessageToUser($"There was an error resolving track: {timedTextSourceUri}");
        return;
    }

    // Add a label for each resolved track
    var timedTextSourceUriString = timedTextSourceUri.AbsoluteUri;
    if (timedTextSourceUriString.Contains("_en"))
    {
        args.Tracks[0].Label = "English";
    }
    else if (timedTextSourceUriString.Contains("_pt"))
    {
        args.Tracks[0].Label = "Portuguese";
    }
}

Pour une liste des formats de texte synchronisé pris en charge sur Windows, voir les codecs pris en charge.

Ajouter des pistes de métadonnées supplémentaires

Vous pouvez créer dynamiquement des pistes de métadonnées personnalisées en code et les associer à une source multimédia. Les pistes que vous créez peuvent contenir du texte de sous-titres ou de légendes, ou elles peuvent contenir vos données d’application propriétaires.

Créez une nouvelle TimedMetadataTrack en appelant le constructeur et en spécifiant un ID, l’identificateur de langue et une valeur de l’énumération TimedMetadataKind. Enregistrez des gestionnaires pour les événements CueEntered et CueExited. Ces événements sont déclenchés lorsque l’heure de début d’un repère est atteinte et lorsque la durée d’un repère a expiré, respectivement.

Créez un nouvel objet cue, approprié pour le type de piste de métadonnées que vous avez créé, et définissez l’ID, l’heure de début et la durée de la piste. Cet exemple crée une piste de données, donc un ensemble d’objets DataCue sont générés et un tampon contenant des données spécifiques à l’application est fourni pour chaque repère. Pour enregistrer la nouvelle piste, ajoutez-la à la collection ExternalTimedMetadataTracks de l’objet MediaSource.

À partir de Windows 10, version 1703, la propriété DataCue.Properties expose un PropertySet que vous pouvez utiliser pour stocker des propriétés personnalisées sous forme de paires clé/données qui peuvent être récupérées dans les événements CueEntered et CueExited.

TimedMetadataTrack metadataTrack = new TimedMetadataTrack("ID_0", "en-us", TimedMetadataKind.Data);
metadataTrack.Label = "Custom data track";
metadataTrack.CueEntered += MetadataTrack_DataCueEntered;
metadataTrack.CueExited += MetadataTrack_CueExited;

// Example cue data
string data = "Cue data";
byte[] bytes = new byte[data.Length * sizeof(char)];
System.Buffer.BlockCopy(data.ToCharArray(), 0, bytes, 0, bytes.Length);
Windows.Storage.Streams.IBuffer buffer = bytes.AsBuffer();

for (int i = 0; i < 10; i++)
{
    DataCue cue = new DataCue();
    cue.Id = "ID_" + i;
    cue.Data = buffer;
    cue.Properties["AdUrl"] = "http://contoso.com/ads/123";
    cue.StartTime = TimeSpan.FromSeconds(3 + i * 3);
    cue.Duration = TimeSpan.FromSeconds(2);

    metadataTrack.AddCue(cue);
}

_mediaSource.ExternalTimedMetadataTracks.Add(metadataTrack);

L’événement CueEntered est déclenché lorsqu’une heure de début de repère est atteinte tant que la piste associée a un mode de présentation de ApplicationPresented, Hidden ou PlatformPresented. Les événements de repère ne sont pas déclenchés pour les pistes de métadonnées lorsque le mode de présentation de la piste est Disabled. Cet exemple affiche simplement les données personnalisées associées au repère dans la fenêtre de débogage.

private void MetadataTrack_DataCueEntered(TimedMetadataTrack sender, MediaCueEventArgs args)
{
    DataCue cue = (DataCue)args.Cue;
    string data = System.Text.Encoding.Unicode.GetString(cue.Data.ToArray());
    System.Diagnostics.Debug.WriteLine("Cue entered: " + data);
    System.Diagnostics.Debug.WriteLine("Custom prop value: " + cue.Properties["AdUrl"]);
}

Cet exemple ajoute une piste de texte personnalisée en spécifiant TimedMetadataKind.Caption lors de la création de la piste et en utilisant des objets TimedTextCue pour ajouter des repères à la piste.

TimedMetadataTrack metadataTrack = new TimedMetadataTrack("TrackID_0", "en-us", TimedMetadataKind.Caption);
metadataTrack.Label = "Custom text track";
metadataTrack.CueEntered += MetadataTrack_TextCueEntered;

for (int i = 0; i < 10; i++)
{
    TimedTextCue cue = new TimedTextCue()
    {
        Id = "TextCueID_" + i,
        StartTime = TimeSpan.FromSeconds(i * 3),
        Duration = TimeSpan.FromSeconds(2)
    };

    cue.Lines.Add(new TimedTextLine() { Text = "This is a custom timed text cue." });
    metadataTrack.AddCue(cue);
}

_mediaSource.ExternalTimedMetadataTracks.Add(metadataTrack);
private void MetadataTrack_TextCueEntered(TimedMetadataTrack sender, MediaCueEventArgs args)
{
    TimedTextCue cue = (TimedTextCue)args.Cue;
    System.Diagnostics.Debug.WriteLine("Cue entered: " + cue.Id + " " + cue.Lines[0].Text);
}

Lecture d’une liste d’éléments multimédias avec MediaPlaybackList

La classe MediaPlaybackList vous permet de créer une liste de médias, représentée par des objets MediaPlaybackItem.

Notez que les éléments dans une MediaPlaybackList sont lus en utilisant une lecture sans interruption. Le système utilise les métadonnées fournies dans les fichiers encodés en MP3 ou AAC pour déterminer le délai ou la compensation de bourrage nécessaires pour une lecture sans interruption. Si les fichiers encodés en MP3 ou AAC ne fournissent pas ces métadonnées, le système détermine le délai ou le bourrage de manière heuristique. Pour les formats sans perte, tels que PCM, FLAC ou ALAC, le système ne prend aucune mesure car ces encodeurs n’introduisent pas de délai ou de bourrage.

Pour commencer, déclarez une variable pour stocker votre MediaPlaybackList.

MediaPlaybackList _mediaPlaybackList;

Créez un MediaPlaybackItem pour chaque élément multimédia que vous souhaitez ajouter à votre liste en utilisant la même procédure décrite précédemment dans cet article. Initialisez votre objet MediaPlaybackList et ajoutez les éléments de lecture multimédia à celui-ci. Enregistrez un gestionnaire pour l’événement CurrentItemChanged. Cet événement vous permet de mettre à jour votre interface utilisateur pour refléter l’élément multimédia actuellement en cours de lecture. Vous pouvez également vous inscrire à l’événement ItemOpened, qui est déclenché lorsqu’un élément de la liste est ouvert avec succès, et à l’événement ItemFailed, qui est déclenché lorsqu’un élément de la liste ne peut pas être ouvert.

À partir de Windows 10, version 1703, vous pouvez spécifier le nombre maximal d’objets MediaPlaybackItem dans la MediaPlaybackList que le système conservera ouverts après leur lecture en définissant la propriété MaxPlayedItemsToKeepOpen. Lorsqu’un MediaPlaybackItem est conservé ouvert, la lecture de l’élément peut commencer instantanément lorsque l’utilisateur passe à cet élément car l’élément n’a pas besoin d’être rechargé. Cependant, conserver les éléments ouverts augmente également la consommation de mémoire de votre application, vous devriez donc considérer l’équilibre entre la réactivité et l’utilisation de la mémoire lors de la définition de cette valeur.

Pour activer la lecture de votre liste, définissez la source du MediaPlayer sur votre MediaPlaybackList.

_mediaPlaybackList = new MediaPlaybackList();

var files = await filePicker.PickMultipleFilesAsync();

foreach (var file in files)
{
    var mediaPlaybackItem = new MediaPlaybackItem(MediaSource.CreateFromStorageFile(file));
    _mediaPlaybackList.Items.Add(mediaPlaybackItem);
}

_mediaPlaybackList.CurrentItemChanged += MediaPlaybackList_CurrentItemChanged;
_mediaPlaybackList.ItemOpened += MediaPlaybackList_ItemOpened;
_mediaPlaybackList.ItemFailed += MediaPlaybackList_ItemFailed;

_mediaPlaybackList.MaxPlayedItemsToKeepOpen = 3;

_mediaPlayer = new MediaPlayer();
_mediaPlayer.Source = _mediaPlaybackList;
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);

Dans le gestionnaire d’événements CurrentItemChanged, mettez à jour votre interface utilisateur pour refléter l’élément multimédia actuellement en cours de lecture, que vous pouvez récupérer en utilisant la propriété NewItem de l’objet CurrentMediaPlaybackItemChangedEventArgs passé dans l’événement. N’oubliez pas que si vous mettez à jour l’interface utilisateur à partir de cet événement, vous devriez le faire dans un appel à CoreDispatcher.RunAsync pour que les mises à jour soient effectuées sur le thread de l’interface utilisateur.

À partir de Windows 10, version 1703, vous pouvez vérifier la propriété CurrentMediaPlaybackItemChangedEventArgs.Reason pour obtenir une valeur qui indique la raison du changement d’élément, comme le passage d’éléments par programmation de l’application, l’élément précédemment lu atteignant sa fin ou une erreur se produisant.

private void MediaPlaybackList_CurrentItemChanged(MediaPlaybackList sender, CurrentMediaPlaybackItemChangedEventArgs args) => 
    LogTelemetryData($"CurrentItemChanged reason: {args.Reason.ToString()}");

Appelez MovePrevious ou MoveNext pour que le lecteur multimédia lise l’élément précédent ou suivant dans votre MediaPlaybackList.

private void prevButton_Click(object sender, RoutedEventArgs e) =>  _mediaPlaybackList.MovePrevious();
private void nextButton_Click(object sender, RoutedEventArgs e) => _mediaPlaybackList.MoveNext();

Définissez la propriété ShuffleEnabled pour spécifier si le lecteur multimédia doit lire les éléments de votre liste dans un ordre aléatoire.

private async void shuffleButton_Click(object sender, RoutedEventArgs e)
{
    _mediaPlaybackList.ShuffleEnabled = !_mediaPlaybackList.ShuffleEnabled;

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        shuffleButton.FontWeight =
            _mediaPlaybackList.ShuffleEnabled ? Windows.UI.Text.FontWeights.Bold : Windows.UI.Text.FontWeights.Light;
    });
}

Définissez la propriété AutoRepeatEnabled pour spécifier si le lecteur multimédia doit boucler la lecture de votre liste.

private async void autoRepeatButton_Click(object sender, RoutedEventArgs e)
{
    _mediaPlaybackList.AutoRepeatEnabled = !_mediaPlaybackList.AutoRepeatEnabled;

    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
    {
        autoRepeatButton.FontWeight =
            _mediaPlaybackList.AutoRepeatEnabled ? Windows.UI.Text.FontWeights.Bold : Windows.UI.Text.FontWeights.Light;
    });
}

Gérer l’échec des éléments multimédias dans une liste de lecture

L’événement ItemFailed est déclenché lorsqu’un élément de la liste ne parvient pas à s’ouvrir. La propriété ErrorCode de l’objet MediaPlaybackItemError passé dans le gestionnaire énumère la cause spécifique de l’échec lorsque c’est possible, y compris les erreurs de réseau, les erreurs de décodage ou les erreurs de cryptage.

private void MediaPlaybackList_ItemFailed(MediaPlaybackList sender, MediaPlaybackItemFailedEventArgs args)
{
    LogError(args.Error.ErrorCode.ToString());
    LogError(args.Error.ExtendedError.HResult);
}

Désactiver la lecture des éléments dans une liste de lecture

À partir de Windows 10, version 1703, vous pouvez désactiver la lecture d’un ou de plusieurs éléments dans une MediaPlaybackItemList en définissant la propriété IsDisabledInPlaybackList d’un MediaPlaybackItem sur false.

Un scénario typique pour cette fonctionnalité est pour les applications qui diffusent de la musique en continu depuis Internet. L’application peut écouter les changements de l’état de connexion réseau de l’appareil et désactiver la lecture des éléments qui ne sont pas entièrement téléchargés. Dans l’exemple suivant, un gestionnaire est inscrit pour l’événement NetworkInformation.NetworkStatusChanged.

Windows.Networking.Connectivity.NetworkInformation.NetworkStatusChanged += NetworkInformation_NetworkStatusChanged;

Dans le gestionnaire de NetworkStatusChanged, vérifiez si GetInternet Connecter ionProfile retourne null, ce qui indique que le réseau n’est pas connecté. Si tel est le cas, parcourez tous les éléments de la liste de lecture et si la TotalDownloadProgress pour l’élément est inférieure à 1, ce qui signifie que l’élément n’est pas entièrement téléchargé, désactivez l’élément. Si la connexion réseau est activée, effectuez parcourez tous les éléments de la liste de lecture et activez chaque élément.

private void NetworkInformation_NetworkStatusChanged(object sender)
{
    if (Windows.Networking.Connectivity.NetworkInformation.GetInternetConnectionProfile() == null)
    {
        // Check download status of each item in the list. (TotalDownloadProgress < 1 means not completely downloaded)
        foreach (var item in _mediaPlaybackList.Items)
        {
            if (item.TotalDownloadProgress < 1)
            {
                item.IsDisabledInPlaybackList = true;
            }
        }
    }
    else
    {
        // Connected to internet, re-enable all playlist items
        foreach (var item in _mediaPlaybackList.Items)
        {
            item.IsDisabledInPlaybackList = true;
        }
    }
}

Report de la liaison du contenu multimédia pour les éléments dans une liste de lecture en utilisant MediaBinder

Dans les exemples précédents, une MediaSource est créée à partir d’un fichier, d’une URL ou d’un flux, après quoi un MediaPlaybackItem est créé et ajouté à une MediaPlaybackList. Pour certains scénarios, comme si l’utilisateur est facturé pour la visualisation du contenu, vous voudrez peut-être différer la récupération du contenu d’une MediaSource jusqu’à ce que l’élément dans la liste de lecture soit prêt à être réellement lu. Pour implémenter ce scénario, créez une instance de la classe MediaBinder. Définissez la propriété Token sur une chaîne définie par l’application qui identifie le contenu pour lequel vous souhaitez différer la récupération, puis inscrivez un gestionnaire pour l’événement Binding. Ensuite, créez une MediaSource à partir du Binder en appelant MediaSource.CreateFromMediaBinder. Ensuite, créez un MediaPlaybackItem à partir de la MediaSource et ajoutez-le à la liste de lecture comme d’habitude.

_mediaPlaybackList = new MediaPlaybackList();

var binder = new MediaBinder();
binder.Token = "MyBindingToken1";
binder.Binding += Binder_Binding;
_mediaPlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromMediaBinder(binder)));

binder = new MediaBinder();
binder.Token = "MyBindingToken2";
binder.Binding += Binder_Binding;
_mediaPlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromMediaBinder(binder)));

_mediaPlayer = new MediaPlayer();
_mediaPlayer.Source = _mediaPlaybackList;
mediaPlayerElement.SetMediaPlayer(_mediaPlayer);

Lorsque le système détermine que le contenu associé au MediaBinder doit être récupéré, il déclenchera l’événement Binding. Dans le gestionnaire de cet événement, vous pouvez récupérer l’instance de MediaBinder à partir de MediaBindingEventArgs passé dans l’événement. Récupérez la chaîne spécifiée pour la propriété Token et utilisez-la pour déterminer quel contenu doit être récupéré. MediaBindingEventArgs fournit des méthodes pour définir le contenu lié dans plusieurs représentations différentes, y compris SetStorageFile, SetStream, SetStreamReference et SetUri.

private void Binder_Binding(MediaBinder sender, MediaBindingEventArgs args)
{
    // Get a deferral if you need to perform async operations
    // var deferral = args.GetDeferral();

    var contentUri = new Uri("http://contoso.com/media/" + args.MediaBinder.Token);
    args.SetUri(contentUri);

    // Call complete after your async operations are complete
    // deferral.Complete();
}

Notez que si vous effectuez des opérations asynchrones, telles que des requêtes web, dans le gestionnaire d’événements Binding, vous devriez appeler la méthode MediaBindingEventArgs.GetDeferral pour indiquer au système d’attendre que votre opération se termine avant de continuer. Appelez Deferral.Complete une fois l’opération terminée pour demander au système de continuer.

À partir de Windows 10, version 1703, vous pouvez fournir un AdaptiveMediaSource comme contenu lié en appelant SetAdaptiveMediaSource. Pour plus d’informations sur l’utilisation du streaming adaptatif dans votre application, veuillez consulter la rubrique Adaptive streaming.