private async void ConversionCompleted(ProgressData progressData) { DoubleAnimation progressAnimation = new DoubleAnimation(100, TimeSpan.FromSeconds(0)); progressBarConvertProgress.BeginAnimation(ProgressBar.ValueProperty, progressAnimation); textBlockProgress.Text = progressData.IsFastCut ? "Video cut!" : "Video converted!"; string outputSize = GetBytesReadable(new FileInfo(currentOutputPath).Length); textBlockSize.Text = "Output size: " + outputSize; TaskbarItemInfo.ProgressState = TaskbarItemProgressState.None; Storyboard storyboard = FindResource("ProgressAnimationOut") as Storyboard; storyboard.Begin(); buttonConvert.IsEnabled = true; buttonPreview.IsEnabled = true; buttonOpenFile.IsEnabled = true; buttonOpenStream.IsEnabled = true; buttonPauseResume.IsEnabled = false; buttonCancel.IsEnabled = false; checkBoxCrop.IsEnabled = true; checkBoxCut.IsEnabled = true; gridSourceMedia.IsEnabled = true; buttonOpenOutput.Visibility = Visibility.Visible; Title = "AVC to HEVC Converter"; MediaInfo outputFile = await MediaInfo.Open(currentOutputPath); textBlockDuration.Text += $" ⟶ {outputFile.Duration.ToString(@"hh\:mm\:ss\.ff")}"; textBlockCodec.Text += $" ⟶ {outputFile.Codec} / {outputFile.AudioCodec}"; textBlockFramerate.Text += $" ⟶ {outputFile.Framerate} fps"; textBlockBitrate.Text += $" ⟶ {outputFile.Bitrate} Kbps"; textBlockResolution.Text += $" ⟶ {outputFile.Width + "x" + outputFile.Height}"; textBlockInputSize.Text += $" ⟶ {outputSize}"; if (!String.IsNullOrEmpty(outputFile.AspectRatio) && outputFile.AspectRatio != "N/A") { textBlockResolution.Text += $" ({outputFile.AspectRatio})"; } }
public async void FastCut(string source, string destination, string start, string end) { progressData = new ProgressData(); progressData.IsFastCut = true; progressData.TotalTime = TimeSpan.Parse(end) - TimeSpan.Parse(start); convertProcess.StartInfo.Arguments = $"-y -ss {start} -to {end} -i \"{source}\" -c copy -avoid_negative_ts 1 \"{destination}\""; convertProcess.Start(); convertProcess.BeginErrorReadLine(); await Task.Run(() => { convertProcess.WaitForExit(); errorWaitHandle.WaitOne(); }); convertProcess.CancelErrorRead(); int exitCode = convertProcess.ExitCode; if (exitCode == 0) //conversion not aborted { ConversionCompleted?.Invoke(progressData); } }
public async void Convert(MediaInfo sourceInfo, string destination, ConversionOptions conversionOptions) { progressData = new ProgressData(); progressData.IsFastCut = false; if (conversionOptions.End != TimeSpan.Zero) { progressData.TotalTime = conversionOptions.End - conversionOptions.Start; } else { progressData.TotalTime = sourceInfo.Duration - conversionOptions.Start; } string filters = ""; if (conversionOptions.Resolution.HasValue() && conversionOptions.CropData.HasValue()) { filters = $" -vf \"scale={conversionOptions.Resolution.Width}:{conversionOptions.Resolution.Height}," + $" crop=in_w-{conversionOptions.CropData.Left + conversionOptions.CropData.Right}:in_h-{conversionOptions.CropData.Top + conversionOptions.CropData.Bottom}:{conversionOptions.CropData.Left}:{conversionOptions.CropData.Top}\""; } else if (conversionOptions.Resolution.HasValue()) { filters = $" -vf \"scale={conversionOptions.Resolution.Width}:{conversionOptions.Resolution.Height}\""; } else if (conversionOptions.CropData.HasValue()) { filters = $" -vf \"crop=in_w-{conversionOptions.CropData.Left + conversionOptions.CropData.Right}:in_h-{conversionOptions.CropData.Top + conversionOptions.CropData.Bottom}:{conversionOptions.CropData.Left}:{conversionOptions.CropData.Top}\""; } StringBuilder sb = new StringBuilder("-y"); sb.Append($" -ss {conversionOptions.Start} "); sb.Append($" -i \"{sourceInfo.Source}\""); if (!String.IsNullOrEmpty(sourceInfo.AudioSource)) { sb.Append($" -i \"{sourceInfo.AudioSource}\""); } if (conversionOptions.End != TimeSpan.Zero) { sb.Append($" -t {conversionOptions.End - conversionOptions.Start}"); } sb.Append(" -c:v " + (conversionOptions.Encoder == Encoder.H264 ? "libx264" : "libx265")); sb.Append(" -movflags faststart -preset " + PRESETS[conversionOptions.Preset]); sb.Append(" -crf " + conversionOptions.Crf); if (conversionOptions.Framerate > 0) { sb.Append(" -r" + conversionOptions.Framerate); } sb.Append(filters); sb.Append(conversionOptions.SkipAudio ? " -an" : " -c:a copy"); sb.Append($" \"{destination}\" -hide_banner"); convertProcess.StartInfo.Arguments = sb.ToString(); convertProcess.Start(); convertProcess.BeginErrorReadLine(); await Task.Run(() => { convertProcess.WaitForExit(); errorWaitHandle.WaitOne(); }); convertProcess.CancelErrorRead(); int exitCode = convertProcess.ExitCode; if (exitCode == 0) //conversion not aborted { ConversionCompleted?.Invoke(progressData); } }
public async void Convert(MediaInfo sourceInfo, string outputPath, ConversionOptions conversionOptions) { progressData = new ProgressData(); previousProgressData = new ProgressData(); //Capture the Synchronization Context of the caller, in order to invoke the events in its original thread synchronizationContext = SynchronizationContext.Current; //Duration if (conversionOptions.EncodeSections.Count > 0) { progressData.TotalTime = conversionOptions.EncodeSections.TotalDuration; } else { progressData.TotalTime = sourceInfo.Duration; } progressData.EncodingMode = conversionOptions.EncodingMode; partialProgress = false; //2-pass mode if (conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass) { await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions), false).ConfigureAwait(false); if (!stopped) { progressData.EncodingMode = EncodingMode.AverageBitrate_SecondPass; conversionOptions.EncodingMode = EncodingMode.AverageBitrate_SecondPass; await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions)).ConfigureAwait(false); } //Remove 2pass log files foreach (var file in Directory.GetFiles(Environment.CurrentDirectory).Where(x => x.Contains("log"))) { File.Delete(file); } } //Single pass mode else { if (conversionOptions.EncodeSections.Count == 0) { await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions)).ConfigureAwait(false); } else if (conversionOptions.EncodeSections.Count == 1) { await RunConversionProcess(BuildArgumentsString(sourceInfo, outputPath, conversionOptions, conversionOptions.EncodeSections.ActualStart, conversionOptions.EncodeSections.ActualEnd, conversionOptions.FadeEffect, conversionOptions.FadeEffect)).ConfigureAwait(false); } else { partialProgress = true; string outputDirectory = Path.GetDirectoryName(outputPath); string outputFileName = Path.GetFileNameWithoutExtension(outputPath); for (int i = 0; i < conversionOptions.EncodeSections.Count; i++) { bool fadeStart = conversionOptions.FadeEffect && i != 0; bool fadeEnd = conversionOptions.FadeEffect && i < conversionOptions.EncodeSections.Count - 1; string destination = $"{outputDirectory}\\{outputFileName}_part_{i}.mp4"; string arguments = BuildArgumentsString(sourceInfo, destination, conversionOptions, conversionOptions.EncodeSections[i].Start, conversionOptions.EncodeSections[i].End, fadeStart, fadeEnd); await RunConversionProcess(arguments, false).ConfigureAwait(false); if (stopped) { break; } previousProgressData = progressData; File.AppendAllText("concat.txt", $"file '{destination}'\n"); } if (!stopped) { await RunConversionProcess($"-y -f concat -safe 0 -i concat.txt -c copy \"{outputPath}\"", false).ConfigureAwait(false); } File.Delete("concat.txt"); for (int i = 0; i < conversionOptions.EncodeSections.Count; i++) { File.Delete($"{outputDirectory}\\{outputFileName}_part_{i}.mp4"); } if (!stopped) { synchronizationContext.Post(new SendOrPostCallback((o) => { ConversionCompleted?.Invoke(progressData); }), null); } } } }
public async void Convert(MediaInfo sourceInfo, string destination, ConversionOptions conversionOptions) { progressData = new ProgressData(); //Captures the Synchronization Context of the caller, in order to invoke the events on its original thread synchronizationContext = SynchronizationContext.Current; //Duration if (conversionOptions.End != TimeSpan.Zero) { progressData.TotalTime = conversionOptions.End - conversionOptions.Start; } else { progressData.TotalTime = sourceInfo.Duration - conversionOptions.Start; } //Filters string filters = ""; if (conversionOptions.Resolution.HasValue() || conversionOptions.CropData.HasValue() || conversionOptions.Rotation.HasValue()) { filters = " -vf " + ConcatFilters(conversionOptions.Resolution.FilterString, conversionOptions.CropData.FilterString, conversionOptions.Rotation.FilterString); } //Get nearest before keyframe var keyframes = await sourceInfo.GetNearestBeforeAndAfterKeyFrames(conversionOptions.Start.TotalSeconds).ConfigureAwait(false); TimeSpan startTime = TimeSpan.FromSeconds(keyframes.before); //FFMpeg command string StringBuilder sb = new StringBuilder("-y"); sb.Append($" -ss {startTime}"); sb.Append($" -i \"{sourceInfo.Source}\""); if (sourceInfo.HasExternalAudio) { sb.Append($" -ss {startTime}"); sb.Append($" -i \"{sourceInfo.ExternalAudioSource}\""); } if (conversionOptions.End != TimeSpan.Zero) { sb.Append($" -t {conversionOptions.End - conversionOptions.Start}"); } sb.Append($" -map 0:v:0"); if (!conversionOptions.SkipAudio) { foreach (var audioTrack in sourceInfo.AudioTracks) { if (audioTrack.Enabled) { sb.Append($" -map {(sourceInfo.HasExternalAudio ? "1" : "0")}:{audioTrack.StreamIndex}"); sb.Append($" -disposition:{audioTrack.StreamIndex} {(audioTrack.Default ? "default" : "none")}"); } } } sb.Append(" -map 0:s?"); sb.Append(" -movflags faststart -c:v " + conversionOptions.Encoder.GetFFMpegCommand()); if (conversionOptions.Framerate > 0) { sb.Append(" -r " + conversionOptions.Framerate); } sb.Append(filters); sb.Append(conversionOptions.SkipAudio ? " -an" : " -c:a copy"); sb.Append($" -ss {conversionOptions.Start - startTime}"); sb.Append($" -avoid_negative_ts 1 \"{destination}\" -hide_banner"); StartConversionProcess(sb.ToString()); }
public void Convert(MediaInfo sourceInfo, string outputPath, ConversionOptions conversionOptions) { progressData = new ProgressData(); previousProgressData = new ProgressData(); errorLine = ""; // Capture the Synchronization Context of the caller, in order to invoke the events in its original thread synchronizationContext = SynchronizationContext.Current; // Duration if (conversionOptions.EncodeSections.Count > 0) { progressData.TotalTime = conversionOptions.EncodeSections.TotalDuration; } else { progressData.TotalTime = sourceInfo.Duration; } // Gets the total number of output frames Filters.FpsFilter fpsFilter = conversionOptions.Filters.FirstOrDefault(f => f is Filters.FpsFilter) as Filters.FpsFilter; double outputFps = fpsFilter?.Framerate ?? sourceInfo.Framerate; progressData.TotalFrames = System.Convert.ToInt32(progressData.TotalTime.TotalSeconds * outputFps); // Get the total output file size (if using constant bitrate) if (conversionOptions.EncodingMode == EncodingMode.AverageBitrate_FirstPass || conversionOptions.EncodingMode == EncodingMode.AverageBitrate_SinglePass) { progressData.TotalByteSize = conversionOptions.Encoder.Bitrate.Bps / 8 * System.Convert.ToInt64(progressData.TotalTime.TotalSeconds); foreach (var audioTrack in sourceInfo.AudioTracks) { if (conversionOptions.AudioConversionOptions.ContainsKey(audioTrack.StreamIndex)) { progressData.TotalByteSize += conversionOptions.AudioConversionOptions[audioTrack.StreamIndex].Encoder.Bitrate.Bps / 8 * System.Convert.ToInt64(progressData.TotalTime.TotalSeconds); } else { progressData.TotalByteSize += audioTrack.Bitrate.Bps / 8 * System.Convert.ToInt64(progressData.TotalTime.TotalSeconds); } } } partialProgress = false; progressData.EncodingMode = conversionOptions.EncodingMode; stopped = false; // Starts the conversion task Task <bool> conversionTask; if (conversionOptions.EncodeSections.Count == 0) { conversionTask = Convert_SingleSegment(sourceInfo, outputPath, conversionOptions, TimeSpan.Zero, TimeSpan.Zero); } else if (conversionOptions.EncodeSections.Count == 1) { conversionTask = Convert_SingleSegment(sourceInfo, outputPath, conversionOptions, conversionOptions.EncodeSections.ActualStart, conversionOptions.EncodeSections.ActualEnd); } else { conversionTask = Convert_MultipleSegments(sourceInfo, outputPath, conversionOptions); } // Reports the conversion result to the original caller conversionTask.ContinueWith(result => ReportCompletition(result.Result)); }