有一个简单的视频编辑器,将视频保存到文件后台实现,文档https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/process-media-files-in-the-Background的实现。该程序有效,但有一个细微差别 - 只有当主流处于非活动状态时,即当应用程序最小化到任务栏或关闭时,才会在后台保存视频。如果部署了应用程序,则暂停后台视频保存任务。告诉我如何在主应用程序处于活动状态时实现后台任务?谢谢!
课程后台任务:
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;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Media.Editing;
using Windows.Foundation;
using Windows.UI.Core;
using Lumia.Imaging;
using Lumia.Imaging.Adjustments;
using Lumia.Imaging.Artistic;
using System.Collections.Generic;
using Windows.Foundation.Collections;
using VideoEffectComponent;
namespace MediaProcessingBackgroundTask
{
public sealed class MediaProcessingTask : IBackgroundTask
{
IBackgroundTaskInstance backgroundTaskInstance;
BackgroundTaskDeferral deferral;
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
MediaTranscoder transcoder;
MediaComposition composition;
MediaClip clip;
EffectList effList = new EffectList();
PropertySet configurationPropertySet = new PropertySet();
PropertySet DustPropertySet = new PropertySet();
PropertySet ScretcchPropertySet = new PropertySet();
Windows.Media.Effects.VideoEffectDefinition videoEffect;
BrightnessEffect brightnessEff = new BrightnessEffect();
ContrastEffect contrastEff = new ContrastEffect();
HueSaturationEffect saturationEff = new HueSaturationEffect();
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();
}
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;
var redCurve = ApplicationData.Current.LocalSettings.Values["CurvRed"] as Point[];
var greenCurve = ApplicationData.Current.LocalSettings.Values["CurvGreen"] as Point[];
var blueCurve = ApplicationData.Current.LocalSettings.Values["CurvBlue"] as Point[];
var sat = ApplicationData.Current.LocalSettings.Values["SatVal"];
var brid = ApplicationData.Current.LocalSettings.Values["BridVal"];
var con = ApplicationData.Current.LocalSettings.Values["ContrVal"];
var dust = ApplicationData.Current.LocalSettings.Values["dustCVal"];
var scetch = ApplicationData.Current.LocalSettings.Values["scetchCVal"];
saturationEff.Saturation = (double)sat;
brightnessEff.Level = (double)brid;
contrastEff.Level = (double)con;
CurvesEffect curves = new CurvesEffect();
Curve RedC = new Curve();
Curve GreenC = new Curve();
Curve BlueC = new Curve();
RedC.Points = redCurve;
GreenC.Points = greenCurve;
BlueC.Points = blueCurve;
curves.Blue = BlueC;
curves.Green = GreenC;
curves.Red = RedC;
if (inputFileName == null || outputFileName == null)
{
return;
}
var inputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(inputFileName);
var outputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(outputFileName);
composition = await MediaComposition.LoadAsync(inputFile);
clip = composition.Clips[0];
effList.Add(saturationEff);
effList.Add(brightnessEff);
effList.Add(contrastEff);
effList.Add(curves);
configurationPropertySet.Add(new KeyValuePair<string, object>("Effect", effList));
DustPropertySet = new PropertySet();
DustPropertySet["DustCount"] = dust;
ScretcchPropertySet = new PropertySet();
ScretcchPropertySet["ScetchAmount"] = scetch;
videoEffect = new Windows.Media.Effects.VideoEffectDefinition("Lumia.Imaging.VideoEffect", configurationPropertySet);
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(Vignet).FullName, VignetPropertySet));
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(ExampleVideoEffect).FullName, ScretcchPropertySet));
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(Dust).FullName, DustPropertySet));
clip.VideoEffectDefinitions.Add(videoEffect);
MediaEncodingProfile mp = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD1080p);
Debug.WriteLine("PrepareFileTranscodeAsync");
settings.Values["TranscodingStatus"] = "Preparing to transcode ";
var startTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
Debug.WriteLine("Starting transcoding @" + startTime);
var progressT = new Progress<double>(TranscodeProgress);
settings.Values["TranscodingStatus"] = "Transcoding ";
settings.Values["ProcessingFileName"] = inputFileName;
var saveOperation = composition.RenderToFileAsync(outputFile, MediaTrimmingPreference.Precise, mp);// AsTask(cancelTokenSource.Token, progressT);
saveOperation.Completed = (info, status) =>
{
SendToastNotification("Video saved.");
clip.VideoEffectDefinitions.Clear();
composition = null;
deferral.Complete();
if (status != AsyncStatus.Completed)
{
// ShowErrorMessage("Error saving composition");
}
};
await saveOperation.AsTask(cancelTokenSource.Token, progressT);
Debug.WriteLine("Source content could not be transcoded.");
var endTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
Debug.WriteLine("End time = " + endTime);
}
catch (Exception e)
{
Debug.WriteLine("Exception type: {0}", e.ToString());
throw;
}
}
void TranscodeProgress(double percent)
{
Debug.WriteLine("Transcoding progress: " + percent.ToString().Split('.')[0] + "%");
backgroundTaskInstance.Progress = (uint)percent;
}
private void SendToastNotification(string toastMessage)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastText01;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode(toastMessage));
ToastNotification toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
Debug.WriteLine("Background " + sender.Task.Name + " Cancel Requested..." + reason.ToString());
}
}
}
注册并启动后台任务
MediaProcessingTrigger mediaProcessingTrigger;
string backgroundTaskBuilderName = "TranscodingBackgroundTask";
BackgroundTaskRegistration taskRegistration;
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;
}
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
{
string progress = "Progress: " + args.Progress + "%";
Debug.WriteLine(progress);
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
TextSave.Text = progress;
ProgressSave.Value = args.Progress;
});
}
private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine(" background task complete");
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
TasckCompleted();
});
}
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);
}
}
}
答案 0 :(得分:0)
仅在主流处于非活动状态时,即当应用程序最小化到任务栏或关闭时,才会在后台保存视频。
在上面的代码段中,后台任务由LaunchBackgroundTask()
方法触发。发生后台任务取决于您调用此方法的位置,而您没有显示相关的代码段。根据你的描述,后台任务仅在主流处于非活动状态时触发,我认为你在事件句柄中调用此方法,该句柄在应用程序处于非活动状态时被触发,例如,您在EnteredBackground
事件中调用了该方法。在这种情况下,您可能需要添加LaunchBackgroundTask()
方法调用前台以满足您的要求,例如,只需在按钮单击事件中调用它。
private void btnlaunch_Click(object sender, RoutedEventArgs e)
{
LaunchBackgroundTask();
}
MediaProcessingTask
为out-of-process background task,一旦后台任务被触发,无论应用处于活动状态还是非活动状态,它都将继续运行。但如果你的意思是重新部署,通过我的测试,这将首先卸载应用程序,这将取消注册后台任务并强制它停止。