バックグラウンドでのメディア ファイルの処理Process media files in the background

この記事では、MediaProcessingTrigger とバックグラウンド タスクを使って、バックグラウンドでメディア ファイルを処理する方法について説明します。This article shows you how to use the MediaProcessingTrigger and a background task to process media files in the background.

この記事で説明するサンプル アプリを使うと、ユーザーは入力メディア ファイルを選んでコード変換し、コード変換結果の出力ファイルを指定できます。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. 次に、バックグラウンド タスクが起動してコード変換操作が実行されます。Then, a background task is launched to perform the transcoding operation. MediaProcessingTrigger は、コード変換だけでなくさまざまなメディア処理シナリオ (ディスクへのメディア コンポジションのレンダリング、処理の完了後の処理済みメディア ファイルのアップロードなど) をサポートすることを目的としています。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.

このサンプルで利用されているさまざまなユニバーサル Windows アプリ機能について詳しくは、次をご覧ください。For more detailed information on the different Universal Windows app features utilized in this sample, see:

メディア処理のバックグラウンド タスクの作成Create a media processing background task

Microsoft Visual Studio で既存のソリューションにバックグラウンド タスクを追加するには、コンポーネントの名前を入力します。To add a background task to your existing solution in Microsoft Visual Studio, Enter a name for your comp

  1. [ファイル] メニューの [追加] をクリックし、 [新しいプロジェクト] をクリックします。From the File menu, select Add and then New Project....
  2. プロジェクトの種類として [Windows ランタイム コンポーネント (ユニバーサル アプリ)] を選びます。Select the project type Windows Runtime Component (Universal Windows).
  3. 新しいコンポーネント プロジェクトの名前を入力します。Enter a name for your new component project. この例では、プロジェクト名として MediaProcessingBackgroundTask を使います。This example uses the project name MediaProcessingBackgroundTask.
  4. [OK] をクリックします。Click OK.

ソリューション エクスプ ローラーで、既定で作成された "Class1.cs" ファイルのアイコンを右クリックし、 [名前の変更] をクリックします。In Solution Explorer, right-click the icon for the "Class1.cs" file that is created by default and select Rename. ファイル名を "MediaProcessingTask.cs" に変更します。Rename the file to "MediaProcessingTask.cs". Visual Studio に、このクラスへのすべての参照の名前を変更するかどうかを確認するメッセージが表示されたら、 [はい] をクリックします。When Visual Studio asks if you want to rename all of the references to this class, click Yes.

名前が変更されたクラス ファイルで、次の using ディレクティブを追加してこれらの名前空間をプロジェクトに含めます。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;

クラスの宣言を更新して、クラスを IBackgroundTask から継承します。Update your class declaration to make your class inherit from IBackgroundTask.

public sealed class MediaProcessingTask : IBackgroundTask
{

次のメンバー変数をクラスに追加します。Add the following member variables to your class:

  • IBackgroundTaskInstance。バックグラウンド タスクの進行状況によってフォアグラウンド アプリを更新するために使われます。An IBackgroundTaskInstance that will be used to update the foreground app with the progress of the background task.
  • BackgroundTaskDeferral。メディアのコード変換が非同期的に実行されている間も、システムがバックグラウンド タスクをシャットダウンしないようにします。A BackgroundTaskDeferral that keeps the system from shutting down your background task while media transcoding is being performed asynchronously.
  • CancellationTokenSource オブジェクト。非同期コード変換操作を取り消すために使うことができます。A CancellationTokenSource object that can be used to cancel the asynchronous transcoding operation.
  • MediaTranscoder オブジェクト。メディア ファイルのコード変換に使われます。The MediaTranscoder object that will be used to transcode media files.
IBackgroundTaskInstance backgroundTaskInstance;
BackgroundTaskDeferral deferral;
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
MediaTranscoder transcoder;

タスクが起動すると、システムはバックグラウンド タスクの Run メソッドを呼び出します。The system calls Run method of a background task when the task is launched. メソッドに渡される IBackgroundTask オブジェクトを、対応するメンバー変数に設定します。Set the IBackgroundTask object passed into the method to the corresponding member variable. システムがバックグラウンド タスクをシャットダウンする必要がある場合に発生する Canceled イベントのハンドラーを登録します。Register a handler for the Canceled event, which will be raised if the system needs to shut down the background task. 次に、Progress プロパティを 0 に設定します。Then, set the Progress property to zero.

次に、バックグラウンド タスク オブジェクトの GetDeferral メソッドを呼び出して保留を取得します。Next, call the background task object's GetDeferral method to obtain a deferral. 非同期操作の実行中のため、タスクをシャットダウンしないようにシステムに指示されます。This tells the system not to shut down your task because you are performing asynchronous operations.

次に、次のセクションで定義するヘルパー メソッド TranscodeFileAsync を呼び出します。Next, call the helper method TranscodeFileAsync, which is defined in the next section. 正常に完了した場合、ヘルパー メソッドが呼び出され、コード変換が完了したことをユーザーに通知するトースト通知が起動されます。If that completes successfully, a helper method is called to launch a toast notification to alert the user that transcoding is complete.

Run メソッドの最後に、保留オブジェクトで Complete を呼び出して、バックグラウンド タスクが完了したため終了できることをシステムが認識できるようにします。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();
}

TranscodeFileAsync ヘルパー メソッドで、コード変換操作の入力ファイルと出力ファイルのファイル名がアプリの LocalSettings から取得されます。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. これらの値は、フォアグラウンド アプリによって設定されます。These values will be set by your foreground app. 入力ファイルと出力ファイルの StorageFile オブジェクトを作成し、コード変換に使うエンコード プロファイルを作成します。Create a StorageFile object for the input and output files and then create an encoding profile to use for transcoding.

入力ファイル、出力ファイル、エンコード プロファイルを渡して PrepareFileTranscodeAsync を呼び出します。Call PrepareFileTranscodeAsync, passing in the input file, output file, and encoding profile. この呼び出しから返される PrepareTranscodeResult オブジェクトにより、コード変換を実行できるかどうかを把握できます。The PrepareTranscodeResult object returned from this call lets you know if transcoding can be performed. CanTranscode プロパティが true の場合、TranscodeAsync を呼び出してコード変換操作を実行します。If the CanTranscode property is true, call TranscodeAsync to perform the transcoding operation.

AsTask メソッドを使うと、非同期操作の進行状況を追跡したり、取り消したりできます。The AsTask method enables you to track the progress the asynchronous operation or cancel it. 必要な進行状況の単位と、タスクの現在の進行状況について通知するために呼び出されるメソッドの名前を指定して、新しい Progress オブジェクトを作成します。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. タスクの取り消しを可能にするキャンセル トークンと共に、Progress オブジェクトを AsTask メソッドに渡します。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;
      }
  }

前の手順で Progress オブジェクトを作成するために使ったメソッド Progress で、バックグラウンド タスク インスタンスの進行状況を設定します。In the method you used to create the Progress object in the previous step, Progress, set the progress of the background task instance. これにより、進行状況がフォアグラウンド アプリ (実行されている場合) に渡されます。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;
}

SendToastNotification ヘルパー メソッドは、テキスト コンテンツしかないトーストのテンプレート XML ドキュメントを取得することによって新しいトースト通知を作成します。The SendToastNotification helper method creates a new toast notification by getting a template XML document for a toast that only has text content. トースト XML のテキスト要素が設定された後、XML ドキュメントから新しい ToastNotification オブジェクトが作成されます。The text element of the toast XML is set and then a new ToastNotification object is created from the XML document. 最後に、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);
}

システムがバック グラウンド タスクをキャンセルしたときに呼び出される Canceled イベントのハンドラーでは、利用統計情報を取集するためにログにエラーを記録することができます。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());
}

バックグラウンド タスクの登録と起動Register and launch the background task

フォアグラウンド アプリからバックグラウンド タスクを起動するには、フォアグラウンド アプリの Package.appmanifest ファイルを更新して、アプリがバックグラウンド タスクを使っていることをシステムが認識できるようにする必要があります。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. ソリューション エクスプローラーで、Package.appmanifest アイコンをダブルクリックしてマニフェスト エディターを開きます。In Solution Explorer, double-click the Package.appmanifest file icon to open the manifest editor.
  2. [宣言] タブをクリックします。Select the Declarations tab.
  3. [使用可能な宣言] で、 [バックグラウンド タスク] を選び、 [追加] をクリックします。From Available Declarations, select Background Tasks and click Add.
  4. [サポートされる宣言] で、 [バックグラウンド タスク] 項目が選択されていることを確認します。Under Supported Declarations make sure that the Background Tasks item is selected. [プロパティ] で、 [Media processing] (メディア処理) チェック ボックスをオンにします。Under Properties, select the checkbox for Media processing.
  5. [エントリ ポイント] ボックスで、バックグラウンド テストの名前空間とクラス名を、ピリオドで区切って指定します。In the Entry Point text box, specify the namespace and class name for your background test, separated by a period. この例では、エントリは次のとおりです。For this example, the entry is:
MediaProcessingBackgroundTask.MediaProcessingTask

次に、フォアグラウンド アプリにバックグラウンド タスクへの参照を追加する必要があります。Next, you need to add a reference to your background task to your foreground app.

  1. ソリューション エクスプローラーのフォアグラウンド アプリ プロジェクトで、 [参照] フォルダーを右クリックし、 [参照の追加] を選択します。In Solution Explorer, under your foreground app project, right-click the References folder and select Add Reference....
  2. [プロジェクト] ノードを展開し、 [ソリューション] を選択します。Expand the Projects node and select Solution.
  3. バックグラウンド プロジェクトの横のボックスをオンにし、 [OK] をクリックします。Check the box next to your background task project and click OK.

この例のコードの残りの部分をフォアグラウンド アプリに追加する必要があります。The rest of the code in this example should be added to your foreground app. まず、次の名前空間をプロジェクトに追加する必要があります。First, you will need to add the following namespaces to your project.

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

次に、バックグラウンド タスクの登録に必要な次のメンバー変数を追加します。Next, add the following member variables that are needed to register the background task.

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

PickFilesToTranscode ヘルパー メソッドは、FileOpenPickerFileSavePicker を使ってコード変換用の入力ファイルと出力ファイルを開きます。The PickFilesToTranscode helper method uses a FileOpenPicker and a FileSavePicker to open the input and output files for transcoding. アプリがアクセスできない場所にあるファイルをユーザーが選ぶ可能性があります。The user may select files in a location that your app does not have access to. バックグラウンド タスクがファイルを開けるようにするには、ファイルをアプリの FutureAccessList に追加します。To make sure your background task can open the files, add them to the FutureAccessList for your app.

最後に、アプリの LocalSettings で入力ファイルと出力ファイルの名前のエントリを設定します。Finally, set entries for the input and output file names in the LocalSettings for your app. バックグラウンド タスクは、この場所からファイル名を取得します。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;
}

バックグラウンド タスクを登録するには、新しい MediaProcessingTrigger と新しい BackgroundTaskBuilder を作成します。To register the background task, create a new MediaProcessingTrigger and a new BackgroundTaskBuilder. 後で識別できるようにバックグラウンド タスク ビルダーの名前を設定します。Set the name of the background task builder so that you can identify it later. TaskEntryPoint を、マニフェスト ファイルで使ったのと同じ名前空間とクラス名文字列に設定します。Set the TaskEntryPoint to the same namespace and class name string you used in the manifest file. Trigger プロパティを MediaProcessingTrigger インスタンスに設定します。Set the Trigger property to the MediaProcessingTrigger instance.

タスクを登録する前に、AllTasks コレクションをループ処理し、BackgroundTaskBuilder.Name プロパティで指定した名前を持つすべてのタスクで Unregister を呼び出すことにより、以前に登録したタスクを必ず登録解除してください。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.

Register を呼び出してバックグラウンド タスクを登録します。Register the background task by calling Register. Completed イベントと 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;
}

アプリがなどで、最初に起動したときに一般的なアプリが、バック グラウンド タスクを登録、 OnNavigatedToイベント。A typical app will register their background task when the app is initially launched, such as in the OnNavigatedTo event.

MediaProcessingTrigger オブジェクトの RequestAsync メソッドを呼び出してバックグラウンド タスクを起動します。Launch the background task by calling the MediaProcessingTrigger object's RequestAsync method. このメソッドによって返される MediaProcessingTriggerResult オブジェクトにより、バックグラウンド タスクが正常に起動されたかどうかを把握することができます。正常に起動されなかった場合は、バックグラウンド タスクが起動しなかった理由を把握できます。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);
        }
    }

}

一般的なアプリは起動し、ユーザーの操作への応答でバック グラウンド タスクなど、クリックしてUI コントロールのイベント。A typical app will launch the background task in response to user interaction, such as in the Click event of a UI control.

バックグラウンド タスクが操作の進行状況を更新すると、OnProgress イベント ハンドラーが呼び出されます。The OnProgress event handler is called when the background task updates the progress of the operation. この機会を使って、進行状況情報によって UI を更新することができます。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);
}

バックグラウンド タスクの実行が完了すると、OnCompleted イベント ハンドラーが呼び出されます。The OnCompleted event handler is called when the background task has finished running. ここでも、UI を更新してユーザーに状態情報を示すことができます。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");
}