이 문서에서는 MediaProcessingTrigger 및 백그라운드 작업을 사용하여 백그라운드에서 미디어 파일을 처리하는 방법을 보여 줍니다.
이 문서에 설명된 예제 앱을 사용하면 사용자가 코드 변환할 입력 미디어 파일을 선택하고 코드 변환 결과에 대한 출력 파일을 지정할 수 있습니다. 그런 다음, 코드 변환 작업을 수행하기 위해 백그라운드 작업이 시작됩니다. The MediaProcessingTrigger는 코드 변환 외에도 미디어 컴퍼지션을 디스크에 렌더링하는 것과, 처리가 완료된 후 처리된 미디어 파일을 업로드하는 것을 포함하여 다양한 미디어 처리 시나리오를 지원하기 위한 것입니다.
이 샘플에서 사용된 다양한 유니버설 Windows 앱 기능에 대한 자세한 내용은 다음을 참조하세요.
미디어 처리 백그라운드 작업 만들기
Microsoft Visual Studio에서 기존 솔루션에 백그라운드 작업을 추가하려면 comp의 이름을 입력합니다.
- 파일 메뉴에서 추가를 선택한 다음, 새 프로젝트....
- 프로젝트 유형 유니버설 Windows의 Windows 런타임 구성 요소을 선택합니다.
- 새 구성 요소 프로젝트의 이름을 입력합니다. 이 예제에서는 MediaProcessingBackgroundTask
프로젝트 이름을 사용합니다. - 확인을 클릭합니다.
솔루션 탐색기에서 기본적으로 생성된 "Class1.cs" 파일을 우클릭한 후, '이름 바꾸기'를 선택합니다. 파일 이름을 "MediaProcessingTask.cs"로 바꿉니다. Visual Studio에서 이 클래스에 대한 모든 참조의 이름을 바꿀 것인지 묻는 메시지가 표시되면 예클릭합니다.
이름이 바뀐 클래스 파일에서 지시문을 사용하여 다음
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 개체를 만듭니다. 작업을 취소할 수 있는 취소 토큰과 함께 Progress 개체를 AsTask 메서드에 전달합니다.
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 파일 아이콘을 두 번 클릭하여 매니페스트 편집기를 엽니다.
- Declarations 탭을 선택합니다.
- 사용 가능한 선언백그라운드 작업 선택하고 추가를 클릭합니다.
- 지원되는 선언에서 백그라운드 작업 항목이 선택되어 있는지 확인하세요. 속성아래에서 미디어 처리확인란을 선택합니다.
- 진입점 텍스트 상자에서 백그라운드 테스트의 네임스페이스 및 클래스 이름을 마침표로 구분하여 지정합니다. 이 예제의 항목은 다음과 같습니다.
MediaProcessingBackgroundTask.MediaProcessingTask
다음으로, 백그라운드 작업에 대한 참조를 포그라운드 앱에 추가해야 합니다.
- 솔루션 탐색기에서, 포그라운드 앱 프로젝트 아래의 참조 폴더를 마우스 오른쪽 버튼으로 클릭하고 참조 추가...를 선택합니다.
- 프로젝트 노드를 확장하고 솔루션선택합니다.
- 백그라운드 작업 프로젝트 옆의 확인란을 선택한 다음, 확인을 클릭하세요.
이 예제의 나머지 코드는 포그라운드 앱에 추가되어야 합니다. 먼저 프로젝트에 다음 네임스페이스를 추가해야 합니다.
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 매니페스트 파일에서 사용한 것과 동일한 네임스페이스 및 클래스 이름 문자열로 설정합니다. 트리거 속성을 MediaProcessingTrigger 인스턴스로 설정합니다.
작업을 등록하기 전에, AllTasks 컬렉션을 반복하면서 이전에 등록된 작업의 등록을 취소하는 것을 확실히 하기 위해, Unregister을 호출하여, BackgroundTaskBuilder.Name 속성에 지정한 이름이 있는 모든 작업을 등록 취소해야 합니다.
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를 업데이트할 수 있는 또 다른 기회입니다.
private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine(" background task complete");
}