Exemple #1
0
 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();
        }