/// <summary> /// <para> ---- </para> /// <para>Establishes whether the data indicates the conversion is complete</para> /// </summary> /// <param name="data">Event data from the FFmpeg console.</param> /// <param name="conversionCompleted"> /// <para>If successful, outputs a <see cref="ConversionCompleted"/> which is </para> /// <para>generated from the data. </para> /// </param> internal static bool IsConvertCompleteData(string data, out ConversionCompleted conversionCompleted) { conversionCompleted = null; Match matchFrame = Index[Find.ConvertProgressFrame].Match(data); Match matchFps = Index[Find.ConvertProgressFps].Match(data); Match matchFinished = Index[Find.ConvertProgressFinished].Match(data); Match matchTime = Index[Find.ConvertProgressTime].Match(data); Match matchBitrate = Index[Find.ConvertProgressBitrate].Match(data); if (!matchFrame.Success || !matchFps.Success || !matchFinished.Success || !matchTime.Success || !matchBitrate.Success) { return(false); } TimeSpan processedDuration; TimeSpan.TryParse(matchTime.Groups[1].Value, out processedDuration); long frame = Convert.ToInt64(matchFrame.Groups[1].Value, CultureInfo.InvariantCulture); double fps = Convert.ToDouble(matchFps.Groups[1].Value, CultureInfo.InvariantCulture); int sizeKb = Convert.ToInt32(matchFinished.Groups[1].Value, CultureInfo.InvariantCulture); double bitrate = Convert.ToDouble(matchBitrate.Groups[1].Value, CultureInfo.InvariantCulture); conversionCompleted = new ConversionCompleted(processedDuration, TimeSpan.Zero, frame, fps, sizeKb, bitrate); return(true); }
private async void StartConversionProcess(string arguments) { convertProcess.StartInfo.Arguments = arguments; convertProcess.Start(); convertProcess.BeginErrorReadLine(); convertProcess.PriorityClass = ProcessPriorityClass.BelowNormal; stopped = false; await Task.Run(() => { convertProcess.WaitForExit(); }).ConfigureAwait(false); convertProcess.CancelErrorRead(); int exitCode = convertProcess.ExitCode; //0: success; -1: killed; 1: crashed synchronizationContext.Post(new SendOrPostCallback((o) => { if (exitCode != -1 && exitCode != 1) //Sometimes ffmpegs exits with weird numbers even if there were no errors { ConversionCompleted?.Invoke(progressData); } else if (!stopped) { progressData.ErrorMessage = outputLine; ConversionCompleted?.Invoke(progressData); } }), null); }
private void ReportCompletition(bool success) { if (!stopped) { synchronizationContext.Post(new SendOrPostCallback((o) => { if (!success) { ConversionAborted?.Invoke(errorLine); } else { ConversionCompleted?.Invoke(); } }), null); } }
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); } } } }