将视频文件保存在UWP应用程序的后台

时间:2017-08-23 15:28:27

标签: c# uwp windows-10 background-task

有一个简单的视频编辑器,将视频保存到文件后台实现,文档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);
        }
    }

}

1 个答案:

答案 0 :(得分:0)

  

仅在主流处于非活动状态时,即当应用程序最小化到任务栏或关闭时,才会在后台保存视频。

在上面的代码段中,后台任务由LaunchBackgroundTask()方法触发。发生后台任务取决于您调用此方法的位置,而您没有显示相关的代码段。根据你的描述,后台任务仅在主流处于非活动状态时触发,我认为你在事件句柄中调用此方法,该句柄在应用程序处于非活动状态时被触发,例如,您在EnteredBackground事件中调用了该方法。在这种情况下,您可能需要添加LaunchBackgroundTask()方法调用前台以满足您的要求,例如,只需在按钮单击事件中调用它。

private void btnlaunch_Click(object sender, RoutedEventArgs e)
{
    LaunchBackgroundTask();
}

MediaProcessingTaskout-of-process background task,一旦后台任务被触发,无论应用处于活动状态还是非活动状态,它都将继续运行。但如果你的意思是重新部署,通过我的测试,这将首先卸载应用程序,这将取消注册后台任务并强制它停止。