UWP: Traiter des fichiers multimédias en arrière-plan

In Mobile Development by Christian HissibiniLeave a Comment

Cet article vous montre comment utiliser MediaProcessingTrigger et une tâche en arrière-plan pour traiter des fichiers multimédias en arrière-plan.

L’exemple d’application décrit dans cet article permet à l’utilisateur de sélectionner un fichier multimédia d’entrée à transcoder et de spécifier un fichier de sortie pour le résultat de transcodage. Ensuite, une tâche en arrière-plan est lancée pour effectuer l’opération de transcodage. Outre le transcodage, MediaProcessingTrigger est destiné à prendre en charge différents scénarios de traitement multimédia, notamment le rendu de compositions multimédias sur disque et le chargement de fichiers multimédias traités une fois le traitement terminé.

Pour obtenir des informations plus détaillées sur les différentes fonctionnalités des applications Windows universelles utilisées dans cet exemple, voir :

Créer une tâche de traitement multimédia en arrière-plan

Pour ajouter une tâche en arrière-plan à votre solution existante dans Microsoft Visual Studio, entrez un nom pour votre composition.

  1. Dans le menu Fichier, sélectionnez Ajouter, puis Nouveau projet….
  2. Sélectionnez le type de projet Composant Windows Runtime (Universel Windows).
  3. Entrez un nom pour votre nouveau projet de composant. Cet exemple utilise le nom de projetMediaProcessingBackgroundTask.
  4. Cliquez sur OK.

Dans l’Explorateur de solutions, cliquez avec le bouton droit sur l’icône du fichier « Class1.cs » qui est créé par défaut et sélectionnez Renommer. Renommez le fichier «MediaProcessingTask.cs». Lorsque Visual Studio vous demande si vous souhaitez renommer toutes les références à cette classe, cliquez sur Oui.

Dans le fichier de classe renommé, ajoutez les directives using suivantes pour inclure ces espaces de noms dans votre projet.C#Copier

using Windows.ApplicationModel.Background;
using Windows.Storage;
using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;
using Windows.Media.MediaProperties;
using Windows.Media.Transcoding;
using System.Threading;

Mettez à jour votre déclaration de classe pour faire en sorte que votre classe hérite de IBackgroundTask.C#Copier

public sealed class MediaProcessingTask : IBackgroundTask
{

Ajoutez les variables membres suivantes à votre classe:

  • Un objet IBackgroundTaskInstance qui sera utilisé pour mettre à jour l’application au premier plan avec la progression de la tâche en arrière-plan.
  • Un objet BackgroundTaskDeferral qui empêche le système d’arrêter votre tâche en arrière-plan pendant que le transcodage multimédia est exécuté en mode asynchrone.
  • Un objet CancellationTokenSource qui peut être utilisé pour annuler l’opération de transcodage asynchrone.
  • L’objet MediaTranscoder qui sera utilisé pour transcoder des fichiers multimédias.

C#Copier

IBackgroundTaskInstance backgroundTaskInstance;
BackgroundTaskDeferral deferral;
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
MediaTranscoder transcoder;

Le système appelle la méthode Run d’une tâche en arrière-plan lorsque la tâche est lancée. Définissez l’objet IBackgroundTasktransmis dans la méthode sur la variable membre correspondante. Enregistrez un gestionnaire de l’événement Canceled, qui sera déclenché si le système a besoin d’arrêter la tâche en arrière-plan. Ensuite, affectez à la propriété Progress la valeur zéro.

Appelez ensuite la méthode GetDeferral de l’objet de tâche en arrière-plan pour obtenir un report. Cela indique au système de ne pas arrêter votre tâche car vous exécutez des opérations asynchrones.

Ensuite, appelez la méthode d’assistance TranscodeFileAsync qui est définie dans la section suivante. Si l’opération se termine correctement, une méthode d’assistance est appelée pour lancer une notification toast afin d’avertir l’utilisateur que le transcodage est terminé.

À la fin de la méthode Run, appelez Complete sur l’objet de report pour indiquer au système que votre tâche en arrière-plan est terminée et peut être fermée.C#Copier

public async void Run(IBackgroundTaskInstance taskInstance)
{
    Debug.WriteLine("In background task Run method");

    backgroundTaskInstance = taskInstance;
    taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
    taskInstance.Progress = 0;

    deferral = taskInstance.GetDeferral();
    Debug.WriteLine("Background " + taskInstance.Task.Name + " is called @ " + (DateTime.Now).ToString());

    try
    {
        await TranscodeFileAsync();
        ApplicationData.Current.LocalSettings.Values["TranscodingStatus"] = "Completed Successfully";
        SendToastNotification("File transcoding complete.");

    }
    catch (Exception e)
    {
        Debug.WriteLine("Exception type: {0}", e.ToString());
        ApplicationData.Current.LocalSettings.Values["TranscodingStatus"] = "Error ocurred: " + e.ToString();
    }


    deferral.Complete();
}

Dans la méthode d’assistance TranscodeFileAsync, les noms de fichiers des fichiers d’entrée et de sortie pour les opérations de transcodage sont récupérés à partir de l’objet LocalSettings de votre application. Ces valeurs seront définies par votre application au premier plan. Créez un objet StorageFile pour les fichiers d’entrée et de sortie, puis créez un profil d’encodage à utiliser pour le transcodage.

Appelez PrepareFileTranscodeAsync en passant dans le fichier d’entrée, le fichier de sortie et le profil d’encodage. L’objetPrepareTranscodeResult renvoyé à partir de cet appel vous permet de savoir si le transcodage peut être effectué. Si la propriétéCanTranscode est true, appelez TranscodeAsync pour effectuer l’opération de transcodage.

La méthode AsTask vous permet de suivre la progression de l’opération asynchrone ou de l’annuler. Créez un objet Progress en spécifiant les unités de progression souhaitées et le nom de la méthode qui sera appelée pour vous informer de la progression actuelle de la tâche. Passez l’objet Progress dans la méthode AsTask avec le jeton d’annulation qui vous permet d’annuler la tâche.C#Copier

private async Task TranscodeFileAsync()
{
    transcoder = new MediaTranscoder();

    try
    {
        var settings = ApplicationData.Current.LocalSettings;

        settings.Values["TranscodingStatus"] = "Started";

        var inputFileName = ApplicationData.Current.LocalSettings.Values["InputFileName"] as string;
        var outputFileName = ApplicationData.Current.LocalSettings.Values["OutputFileName"] as string;

        if (inputFileName == null || outputFileName == null)
        {
            return;
        }


        // retrieve the transcoding information
        var inputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(inputFileName);
        var outputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(outputFileName);

        // create video encoding profile                
        MediaEncodingProfile encodingProfile = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD720p);

        Debug.WriteLine("PrepareFileTranscodeAsync");
        settings.Values["TranscodingStatus"] = "Preparing to transcode ";
        PrepareTranscodeResult preparedTranscodeResult = await transcoder.PrepareFileTranscodeAsync(
            inputFile, 
            outputFile, 
            encodingProfile);

        if (preparedTranscodeResult.CanTranscode)
        {
            var startTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
            Debug.WriteLine("Starting transcoding @" + startTime);

            var progress = new Progress<double>(TranscodeProgress);
            settings.Values["TranscodingStatus"] = "Transcoding ";
            settings.Values["ProcessingFileName"] = inputFileName;
            await preparedTranscodeResult.TranscodeAsync().AsTask(cancelTokenSource.Token, progress);

        }
        else
        {
            Debug.WriteLine("Source content could not be transcoded.");
            Debug.WriteLine("Transcode status: " + preparedTranscodeResult.FailureReason.ToString());
            var endTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
            Debug.WriteLine("End time = " + endTime);
        }
    }
    catch (Exception e)
    {
        Debug.WriteLine("Exception type: {0}", e.ToString());
        throw;
    }
}

Dans la méthode que vous avez utilisée pour créer l’objet de progression à l’étape précédente, Progress, définissez la progression de l’instance de tâche en arrière-plan. Cela transmettra la progression à l’application au premier plan, si celle-ci est en cours d’exécution.C#Copier

void TranscodeProgress(double percent)
{
    Debug.WriteLine("Transcoding progress:  " + percent.ToString().Split('.')[0] + "%");
    backgroundTaskInstance.Progress = (uint)percent;
}

La méthode d’assistance SendToastNotification crée une notification toast en obtenant un modèle de document XML pour un toast uniquement constitué de texte. L’élément de texte du XML de toast est défini, puis un objet ToastNotification est créé à partir du document XML. Enfin, le toast est affiché à l’utilisateur en appelant ToastNotifier.Show.C#Copier

private void SendToastNotification(string toastMessage)
{
    ToastTemplateType toastTemplate = ToastTemplateType.ToastText01;
    XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);

    //Supply text content for your notification
    XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
    toastTextElements[0].AppendChild(toastXml.CreateTextNode(toastMessage));

    //Create the toast notification based on the XML content you've specified.
    ToastNotification toast = new ToastNotification(toastXml);

    //Send your toast notification.
    ToastNotificationManager.CreateToastNotifier().Show(toast);
}

Dans le gestionnaire de l’événement Canceled, qui est appelé lorsque le système annule la tâche en arrière-plan, vous pouvez consigner l’erreur à des fins de télémétrie.C#Copier

private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
    Debug.WriteLine("Background " + sender.Task.Name + " Cancel Requested..." + reason.ToString());
}

Enregistrer et lancer la tâche en arrière-plan

Avant de pouvoir lancer la tâche en arrière-plan à partir de votre application au premier plan, vous devez mettre à jour le fichier Package.appmanifest de votre application au premier plan pour indiquer au système que votre application utilise une tâche en arrière-plan.

  1. Dans l’Explorateur de solutions, double-cliquez sur l’icône du fichier Package.appmanifest pour ouvrir l’éditeur du manifeste.
  2. Sélectionnez l’onglet Déclarations.
  3. Dans Déclarations disponibles, sélectionnez Tâches en arrière-plan, puis cliquez sur Ajouter.
  4. Sous Déclarations prises en charge, vérifiez que l’élément Tâches en arrière-plan est sélectionné. Sous Propriétés, cochez la case Traitement multimédia.
  5. Dans la zone de texte Point d’entrée, spécifiez l’espace de noms et le nom de classe de votre test en arrière-plan, séparés par un point. Pour cet exemple, l’entrée est: csharp MediaProcessingBackgroundTask.MediaProcessingTask Ensuite, vous devez ajouter une référence à votre tâche en arrière-plan à votre application au premier plan.
  6. Dans l’Explorateur de solutions, sous votre projet d’application au premier plan, cliquez avec le bouton droit sur le dossier Références et sélectionnez Ajouter une référence….
  7. Développez le nœud Projets et sélectionnez Solution.
  8. Cochez la case en regard de votre projet de tâche en arrière-plan, puis cliquez sur OK.

Le reste du code dans cet exemple doit être ajouté à votre application au premier plan. Tout d’abord, vous devez ajouter les espaces de noms suivants à votre projet.C#Copier

using Windows.ApplicationModel.Background;
using Windows.Storage;

Ensuite, ajoutez les variables membres suivantes qui sont nécessaires pour enregistrer la tâche en arrière-plan.C#Copier

MediaProcessingTrigger mediaProcessingTrigger;
string backgroundTaskBuilderName = "TranscodingBackgroundTask";
BackgroundTaskRegistration taskRegistration;

La méthode d’assistance PickFilesToTranscode utilise des objets FileOpenPicker et FileSavePicker pour ouvrir les fichiers d’entrée et de sortie pour le transcodage. L’utilisateur peut sélectionner des fichiers situés à un emplacement auquel votre application n’a pas accès. Pour vous assurer que votre tâche en arrière-plan peut ouvrir les fichiers, ajoutez-les à l’objet FutureAccessList de votre application.

Enfin, définissez les entrées pour les noms de fichiers d’entrée et de sortie dans l’objet LocalSettings de votre application. La tâche en arrière-plan récupère les noms de fichiers à partir de cet emplacement.C#Copier

private async void PickFilesToTranscode()
{
    var openPicker = new Windows.Storage.Pickers.FileOpenPicker();

    openPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.VideosLibrary;
    openPicker.FileTypeFilter.Add(".wmv");
    openPicker.FileTypeFilter.Add(".mp4");

    StorageFile source = await openPicker.PickSingleFileAsync();

    var savePicker = new Windows.Storage.Pickers.FileSavePicker();

    savePicker.SuggestedStartLocation =
        Windows.Storage.Pickers.PickerLocationId.VideosLibrary;

    savePicker.DefaultFileExtension = ".mp4";
    savePicker.SuggestedFileName = "New Video";

    savePicker.FileTypeChoices.Add("MPEG4", new string[] { ".mp4" });

    StorageFile destination = await savePicker.PickSaveFileAsync();

    if(source == null || destination == null)
    {
        return;
    }

    var storageItemAccessList = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList;
    storageItemAccessList.Add(source);
    storageItemAccessList.Add(destination);

    ApplicationData.Current.LocalSettings.Values["InputFileName"] = source.Path;
    ApplicationData.Current.LocalSettings.Values["OutputFileName"] = destination.Path;
}

Pour enregistrer la tâche en arrière-plan, créez des objets MediaProcessingTrigger et BackgroundTaskBuilder. Définissez le nom du générateur de tâches en arrière-plan afin de pouvoir l’identifier ultérieurement. Définissez TaskEntryPoint sur l’espace de noms et la chaîne de noms de classe utilisés dans le fichier manifeste. Affectez la propriété Trigger à l’instance MediaProcessingTrigger.

Avant d’enregistrer la tâche, assurez-vous que vous annulez l’enregistrement de toutes les tâches précédemment enregistrées en parcourant la collection AllTasks et en appelant Unregister sur toutes les tâches portant le nom que vous avez spécifié dans la propriété BackgroundTaskBuilder.Name.

Enregistrez la tâche en arrière-plan en appelant Register. Enregistrez des gestionnaires des événements Completed et Progress.C#Copier

private void RegisterBackgroundTask()
{
    // New a MediaProcessingTrigger
    mediaProcessingTrigger = new MediaProcessingTrigger();

    var builder = new BackgroundTaskBuilder();

    builder.Name = backgroundTaskBuilderName;
    builder.TaskEntryPoint = "MediaProcessingBackgroundTask.MediaProcessingTask";
    builder.SetTrigger(mediaProcessingTrigger);

    // unregister old ones
    foreach (var cur in BackgroundTaskRegistration.AllTasks)
    {
        if (cur.Value.Name == backgroundTaskBuilderName)
        {
            cur.Value.Unregister(true);
        }
    }

    taskRegistration = builder.Register();
    taskRegistration.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
    taskRegistration.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);

    return;
}

Une application standard s’inscrire leur tâche en arrière-plan lorsque l’application est lancée initialement, comme dans l’événement OnNavigatedTo .

Lancez la tâche en arrière-plan en appelant la méthode RequestAsync de l’objet MediaProcessingTrigger. L’objet MediaProcessingTriggerResult renvoyé par cette méthode vous permet de savoir si la tâche en arrière-plan a été démarrée. Si ce n’est pas le cas, il vous permet de savoir pourquoi la tâche en arrière-plan n’a pas été lancée.C#Copier

private async void LaunchBackgroundTask()
{
    var success = true;

    if (mediaProcessingTrigger != null)
    {
        MediaProcessingTriggerResult activationResult;
        activationResult = await mediaProcessingTrigger.RequestAsync();

        switch (activationResult)
        {
            case MediaProcessingTriggerResult.Allowed:
                // Task starting successfully
                break;

            case MediaProcessingTriggerResult.CurrentlyRunning:
            // Already Triggered

            case MediaProcessingTriggerResult.DisabledByPolicy:
            // Disabled by system policy

            case MediaProcessingTriggerResult.UnknownError:
                // All other failures
                success = false;
                break;
        }

        if (!success)
        {
            // Unregister the media processing trigger background task
            taskRegistration.Unregister(true);
        }
    }

}

Une application standard lancera la tâche en arrière-plan en réponse à une interaction utilisateur, comme dans l’événement Clickd’un contrôle de l’interface utilisateur.

Le gestionnaire d’événements OnProgress est appelé lorsque la tâche en arrière-plan met à jour la progression de l’opération. Vous pouvez utiliser cette opportunité pour mettre à jour votre interface utilisateur avec les informations de progression.C#Copier

private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
{
    string progress = "Progress: " + args.Progress + "%";
    Debug.WriteLine(progress);
}

Le gestionnaire d’événements OnCompleted est appelé lorsque l’exécution de la tâche en arrière-plan est terminée. Il s’agit d’une autre opportunité de mettre à jour votre interface utilisateur pour fournir des informations d’état à l’utilisateur.C#Copier

private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
    Debug.WriteLine(" background task complete");
}

Leave a Comment