/// <summary> /// 提供音视频转码 /// </summary> /// <param name="SourceFile">源文件</param> /// <param name="DestinationFile">目标文件</param> /// <param name="MediaTranscodeEncodingProfile">转码编码</param> /// <param name="MediaTranscodeQuality">转码质量</param> /// <param name="SpeedUp">是否启用硬件加速</param> /// <returns></returns> public static Task TranscodeFromAudioOrVideoAsync(StorageFile SourceFile, StorageFile DestinationFile, string MediaTranscodeEncodingProfile, string MediaTranscodeQuality, bool SpeedUp) { return(Task.Factory.StartNew((obj) => { if (obj is ValueTuple <StorageFile, StorageFile, string, string, bool> Para) { using (ExtendedExecutionController ExtExecution = ExtendedExecutionController.TryCreateExtendedExecution().Result) { IsAnyTransformTaskRunning = true; AVTranscodeCancellation = new CancellationTokenSource(); MediaTranscoder Transcoder = new MediaTranscoder { HardwareAccelerationEnabled = true, VideoProcessingAlgorithm = Para.Item5 ? MediaVideoProcessingAlgorithm.Default : MediaVideoProcessingAlgorithm.MrfCrf444 }; try { MediaEncodingProfile Profile = null; VideoEncodingQuality VideoQuality = default; AudioEncodingQuality AudioQuality = default; switch (Para.Item4) { case "UHD2160p": VideoQuality = VideoEncodingQuality.Uhd2160p; break; case "QVGA": VideoQuality = VideoEncodingQuality.Qvga; break; case "HD1080p": VideoQuality = VideoEncodingQuality.HD1080p; break; case "HD720p": VideoQuality = VideoEncodingQuality.HD720p; break; case "WVGA": VideoQuality = VideoEncodingQuality.Wvga; break; case "VGA": VideoQuality = VideoEncodingQuality.Vga; break; case "High": AudioQuality = AudioEncodingQuality.High; break; case "Medium": AudioQuality = AudioEncodingQuality.Medium; break; case "Low": AudioQuality = AudioEncodingQuality.Low; break; } switch (Para.Item3) { case "MKV": Profile = MediaEncodingProfile.CreateHevc(VideoQuality); break; case "MP4": Profile = MediaEncodingProfile.CreateMp4(VideoQuality); break; case "WMV": Profile = MediaEncodingProfile.CreateWmv(VideoQuality); break; case "AVI": Profile = MediaEncodingProfile.CreateAvi(VideoQuality); break; case "MP3": Profile = MediaEncodingProfile.CreateMp3(AudioQuality); break; case "ALAC": Profile = MediaEncodingProfile.CreateAlac(AudioQuality); break; case "WMA": Profile = MediaEncodingProfile.CreateWma(AudioQuality); break; case "M4A": Profile = MediaEncodingProfile.CreateM4a(AudioQuality); break; } PrepareTranscodeResult Result = Transcoder.PrepareFileTranscodeAsync(Para.Item1, Para.Item2, Profile).AsTask().Result; if (Result.CanTranscode) { SendUpdatableToastWithProgressForTranscode(Para.Item1, Para.Item2); Progress <double> TranscodeProgress = new Progress <double>((CurrentValue) => { try { NotificationData Data = new NotificationData { SequenceNumber = 0 }; Data.Values["ProgressValue"] = (Math.Ceiling(CurrentValue) / 100).ToString(); Data.Values["ProgressValueString"] = Convert.ToInt32(CurrentValue) + "%"; ToastNotificationManager.CreateToastNotifier().Update(Data, "TranscodeNotification"); } catch (Exception ex) { LogTracer.Log(ex, "Toast notification could not be sent"); } }); Result.TranscodeAsync().AsTask(AVTranscodeCancellation.Token, TranscodeProgress).Wait(); CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { ShowTranscodeCompleteNotification(Para.Item1, Para.Item2); }).AsTask().Wait(); } else { LogTracer.Log("Transcode format is not supported"); Para.Item2.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask().Wait(); } } catch (AggregateException) { Para.Item2.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask().Wait(); } catch (Exception ex) { LogTracer.Log(ex, "Transcode failed"); Para.Item2.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask().Wait(); } finally { AVTranscodeCancellation.Dispose(); AVTranscodeCancellation = null; IsAnyTransformTaskRunning = false; } } } }, (SourceFile, DestinationFile, MediaTranscodeEncodingProfile, MediaTranscodeQuality, SpeedUp), TaskCreationOptions.LongRunning)); }
/// <summary> /// 将指定的视频文件合并并产生新文件 /// </summary> /// <param name="DestinationFile">新文件</param> /// <param name="Composition">片段</param> /// <param name="EncodingProfile">编码</param> /// <returns></returns> public static Task GenerateMergeVideoFromOriginAsync(StorageFile DestinationFile, MediaComposition Composition, MediaEncodingProfile EncodingProfile) { return(Task.Factory.StartNew((obj) => { if (obj is ValueTuple <StorageFile, MediaComposition, MediaEncodingProfile> Para) { IsAnyTransformTaskRunning = true; using (ExtendedExecutionController ExtExecution = ExtendedExecutionController.TryCreateExtendedExecution().Result) { AVTranscodeCancellation = new CancellationTokenSource(); SendUpdatableToastWithProgressForMergeVideo(); Progress <double> CropVideoProgress = new Progress <double>((CurrentValue) => { try { string Tag = "MergeVideoNotification"; NotificationData data = new NotificationData { SequenceNumber = 0 }; data.Values["ProgressValue"] = Math.Round(CurrentValue / 100, 2, MidpointRounding.AwayFromZero).ToString(); data.Values["ProgressValueString"] = Convert.ToInt32(CurrentValue) + "%"; ToastNotificationManager.CreateToastNotifier().Update(data, Tag); } catch (Exception ex) { LogTracer.Log(ex, "Toast notification could not be sent"); } }); try { Para.Item2.RenderToFileAsync(Para.Item1, MediaTrimmingPreference.Precise, Para.Item3).AsTask(AVTranscodeCancellation.Token, CropVideoProgress).Wait(); CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { ShowMergeCompleteNotification(); }).AsTask().Wait(); } catch (AggregateException) { CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { ShowMergeCancelNotification(); }).AsTask().Wait(); Para.Item1.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask().Wait(); } catch (Exception) { Para.Item1.DeleteAsync(StorageDeleteOption.PermanentDelete).AsTask().Wait(); LogTracer.Log("Merge video failed"); } finally { AVTranscodeCancellation?.Dispose(); AVTranscodeCancellation = null; IsAnyTransformTaskRunning = false; } } } }, (DestinationFile, Composition, EncodingProfile), TaskCreationOptions.LongRunning)); }
/// <summary> /// 提供图片转码 /// </summary> /// <param name="SourceFile">源文件</param> /// <param name="DestinationFile">目标文件</param> /// <param name="IsEnableScale">是否启用缩放</param> /// <param name="ScaleWidth">缩放宽度</param> /// <param name="ScaleHeight">缩放高度</param> /// <param name="InterpolationMode">插值模式</param> /// <returns></returns> public static async Task TranscodeFromImageAsync(FileSystemStorageFile SourceFile, FileSystemStorageFile DestinationFile, bool IsEnableScale = false, uint ScaleWidth = default, uint ScaleHeight = default, BitmapInterpolationMode InterpolationMode = default) { try { IsAnyTransformTaskRunning = true; using (ExtendedExecutionController ExtExecution = await ExtendedExecutionController.TryCreateExtendedExecution()) using (IRandomAccessStream OriginStream = await SourceFile.GetRandomAccessStreamFromFileAsync(FileAccessMode.Read).ConfigureAwait(false)) { try { BitmapDecoder Decoder = await BitmapDecoder.CreateAsync(OriginStream); using (SoftwareBitmap TranscodeImage = await Decoder.GetSoftwareBitmapAsync()) using (IRandomAccessStream TargetStream = await DestinationFile.GetRandomAccessStreamFromFileAsync(FileAccessMode.ReadWrite).ConfigureAwait(false)) { BitmapEncoder Encoder = DestinationFile.Type.ToLower() switch { ".png" => await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, TargetStream), ".jpg" => await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, TargetStream), ".bmp" => await BitmapEncoder.CreateAsync(BitmapEncoder.BmpEncoderId, TargetStream), ".heic" => await BitmapEncoder.CreateAsync(BitmapEncoder.HeifEncoderId, TargetStream), ".tiff" => await BitmapEncoder.CreateAsync(BitmapEncoder.TiffEncoderId, TargetStream), _ => throw new InvalidOperationException("Unsupport image format"), }; if (IsEnableScale) { Encoder.BitmapTransform.ScaledWidth = ScaleWidth; Encoder.BitmapTransform.ScaledHeight = ScaleHeight; Encoder.BitmapTransform.InterpolationMode = InterpolationMode; } Encoder.SetSoftwareBitmap(TranscodeImage); await Encoder.FlushAsync(); } } catch (Exception) { await DestinationFile.DeleteAsync(true); await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async() => { QueueContentDialog dialog = new QueueContentDialog { Title = Globalization.GetString("Common_Dialog_ErrorTitle"), Content = Globalization.GetString("EnDecode_Dialog_Content"), CloseButtonText = Globalization.GetString("Common_Dialog_CloseButton") }; _ = await dialog.ShowAsync(); }); } } } catch (Exception ex) { LogTracer.Log(ex); } finally { IsAnyTransformTaskRunning = false; } }