この記事では、 MediaProcessingTrigger とバックグラウンド タスクを使用して、バックグラウンドでメディア ファイルを処理する方法について説明します。
この記事で説明するサンプル アプリを使用すると、ユーザーは入力メディア ファイルを選択してトランスコードし、コード変換結果の出力ファイルを指定できます。 次に、トランスコード操作を実行するバックグラウンド タスクが起動されます。 MediaProcessingTrigger は、メディアコンポジションのディスクへのレンダリングや処理完了後の処理済みメディア ファイルのアップロードなど、コード変換以外にも多くの異なるメディア処理シナリオをサポートすることを目的としています。
このサンプルで使用されるさまざまなユニバーサル Windows アプリ機能の詳細については、次を参照してください。
メディア処理のバックグラウンド タスクを作成する
Microsoft Visual Studio で既存のソリューションにバックグラウンド タスクを追加するには、comp の名前を入力します
- [ファイル] メニューの [ 追加] を選択し、[新しいプロジェクト... ]を追加します。
- プロジェクトの種類 として Windows ランタイム コンポーネント (ユニバーサル Windows) を選択します。
- 新しいコンポーネント プロジェクトの名前を入力します。 この例では、プロジェクト名 MediaProcessingBackgroundTaskを使用します。
- OKをクリックしてください。
ソリューション エクスプローラーで、既定で作成された "Class1.cs" ファイルのアイコンを右クリックし、[名前の変更] を選択します。 ファイルの名前を "MediaProcessingTask.cs" に変更します。 Visual Studio で、このクラスへのすべての参照の名前を変更するかどうかを確認するメッセージが表示されたら、[ はい] をクリックします。
名前が変更されたクラス ファイルに、次の using ディレクティブを追加して、これらの名前空間をプロジェクトに含めます。
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から継承するようにします。
public sealed class MediaProcessingTask : IBackgroundTask
{
クラスに次のメンバー変数を追加します。
- バックグラウンド タスクの進行状況をフォアグラウンド アプリに反映させるために使用される IBackgroundTaskInstance。
- BackgroundTaskDeferral は、メディア トランスコードが非同期的に実行されている間、システムがバックグラウンド タスクをシャットダウンするのを防ぎます。
- 非同期コード変換操作を取り消すために使用できる CancellationTokenSource オブジェクト。
- メディア ファイルのトランスコードに使用される MediaTranscoder オブジェクト。
IBackgroundTaskInstance backgroundTaskInstance;
BackgroundTaskDeferral deferral;
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
MediaTranscoder transcoder;
タスクの起動時に、バックグラウンド タスクの Run メソッドが呼び出されます。 メソッドに渡された IBackgroundTask オブジェクトを、対応するメンバー変数に設定します。 Canceled イベントのハンドラーを登録します。これは、システムがバックグラウンド タスクをシャットダウンする必要がある場合に発生します。 次に、 Progress プロパティを 0 に設定します。
次に、バックグラウンド タスク オブジェクトの GetDeferral メソッドを呼び出して遅延を取得します。 これにより、非同期操作を実行しているため、タスクをシャットダウンしないようにシステムに指示されます。
次に、次のセクションで定義されているヘルパー メソッド TranscodeFileAsync を呼び出します。 これが正常に完了すると、ヘルパー メソッドが呼び出されてトースト通知が起動され、コード変換が完了したことをユーザーに通知します。
Run メソッドの最後に、遅延オブジェクトに対して Complete を呼び出して、バックグラウンド タスクが完了し、終了できることをシステムに通知します。
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 から取得されます。 これらの値は、フォアグラウンド アプリによって設定されます。 入力ファイルと出力ファイルの StorageFile オブジェクトを作成し、コード変換に使用するエンコード プロファイルを作成します。
PrepareFileTranscodeAsync を呼び出し、入力ファイル、出力ファイル、エンコード プロファイルを渡します。 この呼び出しから返される PrepareTranscodeResult オブジェクトを使用すると、コード変換を実行できるかどうかを確認できます。 CanTranscode プロパティが true の場合は、TranscodeAsync を呼び出してコード変換操作を実行します。
AsTask メソッドを使用すると、非同期操作の進行状況を追跡したり、キャンセルしたりできます。 必要な進行状況の単位と、タスクの現在の進行状況を通知するために呼び出されるメソッドの名前を指定して、新しい Progress オブジェクトを作成します。 タスクを取り消すことのできるキャンセル トークンと共に、AsTask メソッドに Progress オブジェクトを渡します。
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 で、バックグラウンド タスク インスタンスの進行状況を設定します。 これにより、フォアグラウンド アプリが実行されている場合、進行状況がフォアグラウンド アプリに渡されます。
void TranscodeProgress(double percent)
{
Debug.WriteLine("Transcoding progress: " + percent.ToString().Split('.')[0] + "%");
backgroundTaskInstance.Progress = (uint)percent;
}
SendToastNotification ヘルパー メソッドは、テキスト コンテンツのみを含むトーストのテンプレート XML ドキュメントを取得することで、新しいトースト通知を作成します。 トースト XML のテキスト要素が設定され、XML ドキュメントから新しい ToastNotification オブジェクトが作成されます。 最後に、 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 イベントのハンドラーでは、テレメトリのためにエラーをログに記録できます。
private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
Debug.WriteLine("Background " + sender.Task.Name + " Cancel Requested..." + reason.ToString());
}
バックグラウンド タスクを登録して起動する
フォアグラウンド アプリからバックグラウンド タスクを起動する前に、フォアグラウンド アプリの Package.appmanifest ファイルを更新して、アプリがバックグラウンド タスクを使用していることをシステムに通知する必要があります。
- ソリューション エクスプローラーで、Package.appmanifest ファイル アイコンをダブルクリックしてマニフェスト エディターを開きます。
- [宣言] タブを選択します。
- 使用可能な宣言から、[バックグラウンド タスク] を選択し、[追加]をクリックします。
- サポートされている宣言 の下で、バックグラウンド タスク 項目が選択されていることを確認します。 [プロパティ]で、[メディア処理]のチェック ボックスをオンにします。
- [ エントリ ポイント ] テキスト ボックスで、バックグラウンド テストの名前空間とクラス名をピリオドで区切って指定します。 この例では、エントリは次のようになります。
MediaProcessingBackgroundTask.MediaProcessingTask
次に、バックグラウンド タスクへの参照をフォアグラウンド アプリに追加する必要があります。
- ソリューション エクスプローラーのフォアグラウンド アプリ プロジェクトで、[参照] フォルダーを右クリックし、[参照の追加] を選択します。...
- [ プロジェクト ] ノードを展開し、[ソリューション] を選択 します。
- バックグラウンド タスク プロジェクトの横にあるチェック ボックスをオンにし、[OK] をクリック します。
この例の残りのコードは、フォアグラウンド アプリに追加する必要があります。 まず、次の名前空間をプロジェクトに追加する必要があります。
using Windows.ApplicationModel.Background;
using Windows.Storage;
次に、バックグラウンド タスクを登録するために必要な次のメンバー変数を追加します。
MediaProcessingTrigger mediaProcessingTrigger;
string backgroundTaskBuilderName = "TranscodingBackgroundTask";
BackgroundTaskRegistration taskRegistration;
PickFilesToTranscode ヘルパー メソッドは、FileOpenPicker と FileSavePicker を使用して、トランスコード用の入力ファイルと出力ファイルを開きます。 ユーザーは、アプリがアクセスできない場所にあるファイルを選択できます。 バックグラウンド タスクでファイルを開くことができるようにするには、アプリの FutureAccessList にファイルを追加します。
最後に、アプリの LocalSettings で入力ファイル名と出力ファイル名のエントリを設定します。 バックグラウンド タスクは、この場所からファイル名を取得します。
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 を作成します。 バックグラウンド タスク ビルダーの名前を設定して、後で識別できるようにします。 TaskEntryPoint を、マニフェスト ファイルで使用したのと同じ名前空間とクラス名の文字列に設定します。 Trigger プロパティを MediaProcessingTrigger インスタンスに設定します。
タスクを登録する前に、AllTasks コレクションをループ処理し、BackgroundTaskBuilder.Name プロパティで指定した名前を持つタスクに対して Unregister を呼び出して、以前に登録したタスクの登録を解除してください。
Register を呼び出してバックグラウンド タスクを 登録します。 Completed イベントと Progress イベントのハンドラーを登録します。
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 イベントなど、アプリが最初に起動されたときにバックグラウンド タスクを登録します。
MediaProcessingTrigger オブジェクトの RequestAsync メソッドを呼び出して、バックグラウンド タスクを起動します。 このメソッドによって返される MediaProcessingTriggerResult オブジェクトを使用すると、バックグラウンド タスクが正常に開始されたかどうかを確認できます。開始されていない場合は、バックグラウンド タスクが起動されなかった理由を確認できます。
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 コントロールの Click イベントなど、ユーザーの操作に応じてバックグラウンド タスクを起動します。
OnProgress イベント ハンドラーは、バックグラウンド タスクが操作の進行状況を更新するときに呼び出されます。 この機会を使用して、UI を進行状況情報で更新できます。
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
{
string progress = "Progress: " + args.Progress + "%";
Debug.WriteLine(progress);
}
OnCompleted イベント ハンドラーは、バックグラウンド タスクの実行が完了したときに呼び出されます。 これは、ユーザーに状態情報を提供するために UI を更新するもう 1 つの機会です。
private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine(" background task complete");
}