Processar arquivos de mídia em segundo planoProcess media files in the background

Este artigo mostra como usar o MediaProcessingTrigger e uma tarefa em segundo plano para processar arquivos de mídia em segundo plano.This article shows you how to use the MediaProcessingTrigger and a background task to process media files in the background.

O aplicativo de exemplo descrito neste artigo permite que o usuário selecione um arquivo de mídia de entrada para transcodificar e especificar um arquivo de saída para o resultado da transcodificação.The example app described in this article allows the user to select an input media file to transcode and specify an output file for the transcoding result. Em seguida, uma tarefa em segundo plano é iniciada para executar a operação de transcodificação.Then, a background task is launched to perform the transcoding operation. O objetivo do MediaProcessingTrigger é dar suporte a diferentes situações de processamento de mídia, além de transcodificar, incluindo renderização de composições de mídia para disco e carregamento de arquivos de mídia processados depois que o processamento é concluído.The MediaProcessingTrigger is intended to support many different media processing scenarios besides transcoding, including rendering media compositions to disk and uploading processed media files after processing is complete.

Para mais detalhes sobre os diferentes recursos do aplicativo Universal do Windows utilizados nessa amostra, consulte:For more detailed information on the different Universal Windows app features utilized in this sample, see:

Criar uma tarefa de processamento de mídia em segundo planoCreate a media processing background task

Para adicionar uma tarefa em segundo plano à sua solução existente no Microsoft Visual Studio, insira um nome para seu computadorTo add a background task to your existing solution in Microsoft Visual Studio, Enter a name for your comp

  1. No menu Arquivo, selecione Adicionar e, em seguida, Novo Projeto....From the File menu, select Add and then New Project....
  2. Selecione o tipo de projeto Componente do Tempo de Execução do Windows (Windows Universal).Select the project type Windows Runtime Component (Universal Windows).
  3. Insira um nome para o seu projeto de componente novo.Enter a name for your new component project. Este exemplo usa o nome de projeto MediaProcessingBackgroundTask.This example uses the project name MediaProcessingBackgroundTask.
  4. Clique em OK.Click OK.

Em Gerenciador de Soluções, clique com o botão direito no ícone do arquivo "Class1.cs" que é criado por padrão e selecione Renomear.In Solution Explorer, right-click the icon for the "Class1.cs" file that is created by default and select Rename. Renomeie o arquivo para "MediaProcessingTask.cs".Rename the file to "MediaProcessingTask.cs". Quando o Visual Studio perguntar se você deseja renomear todas as referências a essa classe, clique em Sim.When Visual Studio asks if you want to rename all of the references to this class, click Yes.

No arquivo de classe renomeado, adicione a seguinte diretiva using para incluir esses namespaces no seu projeto.In the renamed class file, add the following using directives to include these namespaces in your project.

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;

Atualize sua declaração de classe para fazer a sua classe herdar de IBackgroundTask.Update your class declaration to make your class inherit from IBackgroundTask.

public sealed class MediaProcessingTask : IBackgroundTask
{

Adicione as variáveis de membro a seguir à sua classe:Add the following member variables to your class:

  • Um IBackgroundTaskInstance que será usado para atualizar o aplicativo em primeiro plano com o progresso da tarefa em segundo plano.An IBackgroundTaskInstance that will be used to update the foreground app with the progress of the background task.
  • Um BackgroundTaskDeferral que evita que o sistema desligue a sua tarefa em segundo plano enquanto a transcodificação de mídia está sendo executada.A BackgroundTaskDeferral that keeps the system from shutting down your background task while media transcoding is being performed asynchronously.
  • Um objeto CancellationTokenSource que pode ser usado para cancelar a operação de transcodificação assíncrona.A CancellationTokenSource object that can be used to cancel the asynchronous transcoding operation.
  • O objeto MediaTranscoder que será usado para transcodificar arquivos de mídia.The MediaTranscoder object that will be used to transcode media files.
IBackgroundTaskInstance backgroundTaskInstance;
BackgroundTaskDeferral deferral;
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
MediaTranscoder transcoder;

O sistema chama o método Run de uma tarefa em segundo plano quando a tarefa é inicializada.The system calls Run method of a background task when the task is launched. Defina o objeto IBackgroundTask passado pelo método para a variável de membro correspondente.Set the IBackgroundTask object passed into the method to the corresponding member variable. Registre um manipulador para o evento Canceled, que será gerado se o sistema precisar desligar a tarefa em segundo plano.Register a handler for the Canceled event, which will be raised if the system needs to shut down the background task. Então, defina a propriedade Progress para zero.Then, set the Progress property to zero.

Em seguida, chame o método do objeto de tarefa de segundo plano GetDeferral para obter um adiamento.Next, call the background task object's GetDeferral method to obtain a deferral. Isso informa o sistema a não desligar sua tarefa porque você está executando operações assíncronas.This tells the system not to shut down your task because you are performing asynchronous operations.

Em seguida, chame o método auxiliar TranscodeFileAsync, que é definido na próxima seção.Next, call the helper method TranscodeFileAsync, which is defined in the next section. Se isso for concluído com êxito, um método auxiliar será chamado para inicializar uma notificação do sistema para alertar o usuário que a transcodificação foi concluída.If that completes successfully, a helper method is called to launch a toast notification to alert the user that transcoding is complete.

No fim do método Run, chame Complete no objeto de adiamento para informar ao sistema que você a sua tarefa em segundo plano foi concluída e pode ser encerrada.At the end of the Run method, call Complete on the deferral object to let the system know that your background task is complete and can be terminated.

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();
}

No método auxiliar TranscodeFileAsync, os nomes de arquivo para arquivos de saída e entrada para as operações de transcodificação são recuperados do LocalSettings para o seu aplicativo.In the TranscodeFileAsync helper method, the file names for the input and output files for the transcoding operations are retrieved from the LocalSettings for your app. Esses valores serão definidos pelo seu aplicativo em primeiro plano.These values will be set by your foreground app. Crie um objeto StorageFile para os arquivos de entrada e saída e, em seguida, crie um perfil de codificação para ser usado na transcodificação.Create a StorageFile object for the input and output files and then create an encoding profile to use for transcoding.

Chame PrepareFileTranscodeAsync, passando no arquivo de entrada, arquivo de saída e perfil de codificação.Call PrepareFileTranscodeAsync, passing in the input file, output file, and encoding profile. O objeto PrepareTranscodeResult devolvido dessa chamada informa a você se a transcodificação pode ser executada.The PrepareTranscodeResult object returned from this call lets you know if transcoding can be performed. Se a propriedade CanTranscode for verdadeira, chame TranscodeAsync para executar a operação de transcodificação.If the CanTranscode property is true, call TranscodeAsync to perform the transcoding operation.

O método AsTask permite que você rastreie o progresso da operação assíncrona ou a cancele.The AsTask method enables you to track the progress the asynchronous operation or cancel it. Crie um novo objeto Progress, especificando as unidades de progresso que você deseja e o nome do método que será chamado para avisar você sobre o progresso atual da tarefa.Create a new Progress object, specifying the units of progress you desire and the name of the method that will be called to notify you of the current progress of the task. Passe o objeto Progress no método AsTask juntamente com o token de cancelamento que permite que você cancele a tarefa.Pass the Progress object into the AsTask method along with the cancellation token that allows you to cancel the task.

  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;
      }
  }

No método que você usou para criar o objeto de Progresso na etapa anterior, Progress, defina o progresso da instância da tarefa em segundo plano.In the method you used to create the Progress object in the previous step, Progress, set the progress of the background task instance. Isso irá passar o progresso ao aplicativo em primeiro plano, se ele estiver sendo executado.This will pass the progress to the foreground app, if it is running.

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

O método auxiliar SendToastNotification cria uma nova notificação do sistema obtendo um documento XML de modelo para uma notificação que tenha apenas conteúdo de texto.The SendToastNotification helper method creates a new toast notification by getting a template XML document for a toast that only has text content. O elemento de texto da notificação do sistema é definido e, em seguida, um novo objeto ToastNotification é criado a partir do documento XML.The text element of the toast XML is set and then a new ToastNotification object is created from the XML document. Por fim, a notificação é exibida para o usuário chamando ToastNotifier.Show.Finally, the toast is shown to the user by calling ToastNotifier.Show.

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);
}

No manipulador do evento Canceled, chamado quando o sistema cancela a tarefa em segundo plano, é possível registrar em log o erro para fins de telemetria.In the handler for the Canceled event, which is called when the system cancels your background task, you can log the error for telemetry purposes.

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

Registrar e iniciar a tarefa em segundo planoRegister and launch the background task

Antes de poder iniciar a tarefa em segundo plano do seu aplicativo em primeiro plano, você deve atualizar o arquivo Package.appmanifest do aplicativo em primeiro plano para informar ao sistema que seu aplicativo usa uma tarefa em segundo plano.Before you can launch the background task from your foreground app, you must update your foreground app's Package.appmanifest file to let the system know that your app uses a background task.

  1. No Gerenciador de Soluções, clique duas vezes no ícone do arquivo Package.appmanifest para abrir o editor de manifesto.In Solution Explorer, double-click the Package.appmanifest file icon to open the manifest editor.
  2. Selecione a guia Declarações.Select the Declarations tab.
  3. Em Declarações Disponíveis, selecione Tarefas em Segundo Plano e clique em Adicionar.From Available Declarations, select Background Tasks and click Add.
  4. Em Declarações Duportadas verifique se o item Tarefas em Segundo Plano está selecionado.Under Supported Declarations make sure that the Background Tasks item is selected. Em Propriedades, marque a caixa de seleção Processamento de mídia.Under Properties, select the checkbox for Media processing.
  5. Na caixa de texto Ponto de Entrada, especifique o namespace e nome da classe para seu teste de em segundo plano, separado por um ponto.In the Entry Point text box, specify the namespace and class name for your background test, separated by a period. Para este exemplo, a entrada é:For this example, the entry is:
MediaProcessingBackgroundTask.MediaProcessingTask

Em seguida, você precisa adicionar uma referência à sua tarefa em segundo plano para seu aplicativo em primeiro plano.Next, you need to add a reference to your background task to your foreground app.

  1. No Gerenciador de Soluções, no seu projeto do aplicativo em primeiro plano, clique com botão direito na pasta Referências e selecione Adicionar Referência....In Solution Explorer, under your foreground app project, right-click the References folder and select Add Reference....
  2. Expanda o nó Projetos e selecione Solução.Expand the Projects node and select Solution.
  3. Marque a caixa ao lado do seu projeto de tarefa em segundo plano e clique em OK.Check the box next to your background task project and click OK.

O restante do código neste exemplo deve ser adicionado ao seu aplicativo em primeiro plano.The rest of the code in this example should be added to your foreground app. Primeiro, você precisará adicionar os namespaces a seguir ao seu projeto.First, you will need to add the following namespaces to your project.

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

Em seguida, adicione as seguintes variáveis de membro que são necessárias para registrar a tarefa em segundo plano.Next, add the following member variables that are needed to register the background task.

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

O método auxiliar PickFilesToTranscode usa um FileOpenPicker e um FileSavePicker para abrir arquivos de entrada e saída para transcodificação.The PickFilesToTranscode helper method uses a FileOpenPicker and a FileSavePicker to open the input and output files for transcoding. O usuário pode selecionar arquivos em uma localização a que seu aplicativo não tem acesso.The user may select files in a location that your app does not have access to. Para garantir que sua tarefa em segundo plano pode abrir os arquivos, adicione-os ao FutureAccessList do seu aplicativo.To make sure your background task can open the files, add them to the FutureAccessList for your app.

Por fim, defina entradas para nomes de arquivo de entrada e saída no LocalSettings do seu aplicativo.Finally, set entries for the input and output file names in the LocalSettings for your app. A tarefa em segundo plano recupera os nomes de arquivos dessa localização.The background task retrieves the file names from this location.

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;
}

Para registrar a tarefa em segundo plano, crie um novo MediaProcessingTrigger e um novo BackgroundTaskBuilder.To register the background task, create a new MediaProcessingTrigger and a new BackgroundTaskBuilder. Defina o nome do construtor de tarefa em segundo plano para que você possa identificá-lo mais tarde.Set the name of the background task builder so that you can identify it later. Defina o TaskEntryPoint para o mesmo namespace e cadeia de caracteres de nome de classe que você usou no arquivo de manifesto.Set the TaskEntryPoint to the same namespace and class name string you used in the manifest file. Defina a propriedade Trigger para a instância MediaProcessingTrigger.Set the Trigger property to the MediaProcessingTrigger instance.

Antes de registrar a tarefa, certifique de cancelar o registro de qualquer tarefa registrada anteriormente fazendo o looping pela coleção AllTasks e chamando Unregister em qualquer tarefa que tenha o nome que você especificou na propriedade BackgroundTaskBuilder.Name.Before registering the task, make sure you unregister any previously registered tasks by looping through the AllTasks collection and calling Unregister on any tasks that have the name you specified in the BackgroundTaskBuilder.Name property.

Registre a tarefa em segundo plano chamando Register.Register the background task by calling Register. Registre manipuladores para os eventos Completed e Progress.Register handlers for the Completed and Progress events.

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;
}

Um aplicativo típico registrará sua tarefa em segundo plano quando o aplicativo for iniciado inicialmente, como no evento OnNavigatedTo .A typical app will register their background task when the app is initially launched, such as in the OnNavigatedTo event.

Inicie a tarefa em segundo plano chamando o método RequestAsync do objeto MediaProcessingTrigger.Launch the background task by calling the MediaProcessingTrigger object's RequestAsync method. O objeto MediaProcessingTriggerResult devolvido por esse método informa se a tarefa em segundo plano foi iniciada com êxito ou se não foi iniciada.The MediaProcessingTriggerResult object returned by this method lets you know whether the background task was started successfully, and if not, lets you know why the background task wasn't launched.

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);
        }
    }

}

Um aplicativo típico iniciará a tarefa em segundo plano em resposta à interação do usuário, como no evento Click de um controle da interface do usuário.A typical app will launch the background task in response to user interaction, such as in the Click event of a UI control.

O manipulador de evento OnProgress é chamado quando a tarefa em segundo plano atualiza o progresso da operação.The OnProgress event handler is called when the background task updates the progress of the operation. Você pode aproveitar a oportunidade para atualizar sua interface do usuário com informações de progresso.You can use this opportunity to update your UI with progress information.

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

O manipulador de evento OnCompleted é chamado quando a tarefa em segundo plano conclui a execução.The OnCompleted event handler is called when the background task has finished running. Esta é outra oportunidade para atualizar sua interface do usuário para fornecer informações de status ao usuário.This is another opportunity to update your UI to give status information to the user.

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