public static void GetSourceFrameCount(string source) { // Skip Framecount Calculation if it already "exists" (Resume Mode) if (File.Exists(Path.Combine(Global.temp_path, Global.temp_path_folder, "framecount.log")) == false) { // This function calculates the total number of frames Process process = new Process { StartInfo = new ProcessStartInfo() { UseShellExecute = false, CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, FileName = "cmd.exe", WorkingDirectory = Global.FFmpeg_Path, Arguments = "/C ffmpeg.exe -i " + '\u0022' + source + '\u0022' + " -hide_banner -loglevel 32 -map 0:v:0 -f null -", RedirectStandardError = true, RedirectStandardOutput = true } }; process.Start(); string stream = process.StandardError.ReadToEnd(); process.WaitForExit(); string tempStream = stream.Substring(stream.LastIndexOf("frame=")); string data = GetBetween(tempStream, "frame=", "fps="); MainWindow.TotalFrames = int.Parse(data); Helpers.WriteToFileThreadSafe(data, Path.Combine(Global.temp_path, Global.temp_path_folder, "framecount.log")); } else { // Reads the first line of the framecount file MainWindow.TotalFrames = int.Parse(File.ReadLines(Path.Combine(Global.temp_path, Global.temp_path_folder, "framecount.log")).First()); } }
public static void Encode() { // Main Encoding Function // Creates a new Thread Pool using (SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(Worker_Count)) { // Creates a tasks list List <Task> tasks = new List <Task>(); // Iterates over all args in VideoChunks list foreach (var command in Global.Video_Chunks) { concurrencySemaphore.Wait(); var task = Task.Factory.StartNew(() => { try { if (!SmallFunctions.Cancel.CancelAll) { // We need the index of the command in the array var index = Array.FindIndex(Global.Video_Chunks, row => row.Contains(command)); // Logic for resume mode - skips already encoded files if (File.Exists(Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + ".ivf" + "_finished.log")) == false) { // One Pass Encoding Process ffmpegProcess = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.UseShellExecute = true; startInfo.FileName = "cmd.exe"; startInfo.WorkingDirectory = Global.FFmpeg_Path; if (!Show_Terminal) { startInfo.WindowStyle = ProcessWindowStyle.Hidden; } string InputVideo = ""; if (Splitting.split_type >= 1) { // FFmpeg Scene Detect or PySceneDetect InputVideo = " -i " + '\u0022' + Global.Video_Path + '\u0022' + " " + command; } else if (Splitting.split_type == 0) { // Chunk based splitting InputVideo = " -i " + '\u0022' + Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", command) + '\u0022'; } // Saves encoder progress to log file string ffmpeg_progress = " -progress " + '\u0022' + Path.Combine(Global.temp_path, Global.temp_path_folder, "Progress", "split" + index.ToString("D5") + "_progress.log") + '\u0022'; string ffmpeg_input = InputVideo + " " + MainWindow.FilterCommand + Pixel_Format + " " + MainWindow.VSYNC + " "; // Process Exit Code int exit_code = 0; // Logic to skip first pass encoding if "_finished" log file exists if (File.Exists(Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + "_stats.log" + "_finished.log")) == false) { string encoderCMD = ""; if (MainWindow.OnePass) { // One Pass Encoding encoderCMD = " -y " + Final_Encoder_Command + " "; encoderCMD += '\u0022' + Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + ".webm") + '\u0022'; } else { // Two Pass Encoding - First Pass encoderCMD = " -y " + Final_Encoder_Command + " -pass 1 -passlogfile "; encoderCMD += '\u0022' + Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + "_stats.log") + '\u0022' + " -f webm NUL"; } startInfo.Arguments = "/C ffmpeg.exe " + ffmpeg_progress + ffmpeg_input + encoderCMD; Helpers.Logging("Encoding Video: " + startInfo.Arguments); ffmpegProcess.StartInfo = startInfo; ffmpegProcess.Start(); // Sets the process priority if (!Process_Priority) { ffmpegProcess.PriorityClass = ProcessPriorityClass.BelowNormal; } // Get launched Process ID int temp_pid = ffmpegProcess.Id; // Add Process ID to Array, inorder to keep track / kill the instances Global.Launched_PIDs.Add(temp_pid); ffmpegProcess.WaitForExit(); // Get Exit Code exit_code = ffmpegProcess.ExitCode; if (exit_code != 0) { Helpers.Logging("Chunk " + command + " Failed with Exit Code: " + exit_code.ToString()); } // Remove PID from Array after Exit Global.Launched_PIDs.RemoveAll(i => i == temp_pid); if (MainWindow.OnePass == false && SmallFunctions.Cancel.CancelAll == false && exit_code == 0) { // Writes log file if first pass is finished, to be able to skip them later if in resume mode Helpers.WriteToFileThreadSafe("", Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + "_stats.log" + "_finished.log")); } } if (!MainWindow.OnePass) { // Creates a different progress file for the second pass (avoids negative frame progressbar) ffmpeg_progress = " -progress " + '\u0022' + Path.Combine(Global.temp_path, Global.temp_path_folder, "Progress", "split" + index.ToString("D5") + "_progress_2nd.log") + '\u0022'; string encoderCMD = " -pass 2 " + Final_Encoder_Command; encoderCMD += " -passlogfile " + '\u0022' + Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + "_stats.log") + '\u0022'; encoderCMD += " " + '\u0022' + Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + ".webm") + '\u0022'; startInfo.Arguments = "/C ffmpeg.exe " + ffmpeg_progress + ffmpeg_input + encoderCMD; Helpers.Logging("Encoding Video: " + startInfo.Arguments); ffmpegProcess.StartInfo = startInfo; ffmpegProcess.Start(); // Sets the process priority if (!Process_Priority) { ffmpegProcess.PriorityClass = ProcessPriorityClass.BelowNormal; } // Get launched Process ID int temp_pid = ffmpegProcess.Id; // Add Process ID to Array, inorder to keep track / kill the instances Global.Launched_PIDs.Add(temp_pid); ffmpegProcess.WaitForExit(); // Get Exit Code exit_code = ffmpegProcess.ExitCode; if (exit_code != 0) { Helpers.Logging("Chunk " + command + " Failed with Exit Code: " + exit_code.ToString()); } // Remove PID from Array after Exit Global.Launched_PIDs.RemoveAll(i => i == temp_pid); } if (SmallFunctions.Cancel.CancelAll == false && exit_code == 0) { // This function will write finished encodes to a log file, to be able to skip them if in resume mode Helpers.WriteToFileThreadSafe("", Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split" + index.ToString("D5") + ".ivf" + "_finished.log")); } } } } finally { concurrencySemaphore.Release(); } }); tasks.Add(task); } Task.WaitAll(tasks.ToArray()); } }
private static void FFmpegChunking() { // Skips Splitting of already existent if (!File.Exists(Path.Combine(Global.temp_path, Global.temp_path_folder, "splitting.log"))) { // Create Chunks Folder Helpers.Create_Temp_Folder(Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks")); // Generate Command string ffmpeg_command = "/C ffmpeg.exe"; ffmpeg_command += " -y -i " + '\u0022' + Global.Video_Path + '\u0022'; // Video Input ffmpeg_command += " -reset_timestamps 1 -map_metadata -1 -sn -an"; // Remove unnecessary metadata etc if (skip_reencode) { ffmpeg_command += " -c:v copy"; } else { if (encode_method == 0) { ffmpeg_command += " -c:v libx264 -preset ultrafast -crf 0"; // Re-Encoding - Needed because else it WILL loose frames } else if (encode_method == 1) { ffmpeg_command += " -c:v ffv1 -level 3 -threads 4 -coder 1 -context 1 -slicecrc 0 -slices 4"; // Re-Encoding - Needed because else it WILL loose frames } else if (encode_method == 2) { ffmpeg_command += " -c:v utvideo"; // Re-Encoding - Needed because else it WILL loose frames } // Hardsub if (MainWindow.subHardSubEnabled) { ffmpeg_command += " " + MainWindow.hardsub_command; } // Filters ffmpeg_command += MainWindow.FilterCommand; // Reset Filter Command so it is not being used later by encoders MainWindow.FilterCommand = ""; ffmpeg_command += " -sc_threshold 0 -g " + chunking_length; // Make Splitting more accurate ffmpeg_command += " -force_key_frames " + '\u0022' + "expr:gte(t, n_forced * " + chunking_length + ")" + '\u0022'; // Make Splitting more accurate } ffmpeg_command += " -segment_time " + chunking_length + " -f segment " + '\u0022'; // Segmenting ffmpeg_command += Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks", "split%6d.mkv") + '\u0022'; // Video Output Helpers.Logging("Equal Chunking: " + ffmpeg_command); // Start Splitting Process chunking_process = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo { WindowStyle = ProcessWindowStyle.Hidden, FileName = "cmd.exe", WorkingDirectory = Global.FFmpeg_Path, Arguments = ffmpeg_command }; chunking_process.StartInfo = startInfo; // Start Process chunking_process.Start(); // Get launched Process ID int temp_pid = chunking_process.Id; // Add Process ID to Array, inorder to keep track / kill the instances Global.Launched_PIDs.Add(temp_pid); // Wait for Exit chunking_process.WaitForExit(); // Get Exit Code int exit_code = chunking_process.ExitCode; // Remove PID from Array after Exit Global.Launched_PIDs.RemoveAll(i => i == temp_pid); // Write Save Point Helpers.WriteToFileThreadSafe("", Path.Combine(Global.temp_path, Global.temp_path_folder, "splitting.log")); } // Add Chunks to Array Global.Video_Chunks = Directory.GetFiles(Path.Combine(Global.temp_path, Global.temp_path_folder, "Chunks"), "*mkv", SearchOption.AllDirectories).Select(x => Path.GetFileName(x)).ToArray(); }