/// <summary> /// Saves the audio output of specified script into a WAV file. /// </summary> /// <param name="settings">An object containing the encoding settings.</param> /// <param name="destination">The WAV file to write.</param> /// <param name="options">The options that control the behaviors of the process.</param> public static void SaveAudioToWav(MediaEncoderSettings settings, string destination, ProcessStartOptions options) { string TempFile = settings.TempFile + ".avs"; AviSynthScriptBuilder Script = new AviSynthScriptBuilder(); if (settings.VideoAction != VideoAction.Copy) { // Read source script. Script.Script = File.ReadAllText(settings.ScriptFile); // Remote MT code. Script.RemoveMT(); Script.AppendLine("Trim(0,0)"); } else { // Read full video file. Script.AddPluginPath(); if (settings.ConvertToAvi || settings.InputFile.ToLower().EndsWith(".avi")) { Script.OpenAvi(settings.InputFile, !string.IsNullOrEmpty(settings.SourceAudioFormat)); } else { Script.OpenDirect(settings.InputFile, !string.IsNullOrEmpty(settings.SourceAudioFormat)); } Script.AppendLine("KillVideo()"); } Script.AppendLine(); // Add audio gain. if (settings.AudioGain.HasValue && settings.AudioGain != 0) { Script.AppendLine("AmplifydB({0})", settings.AudioGain.Value); } if (settings.ChangeAudioPitch) { // Change pitch to 432hz. Script.LoadPluginDll("TimeStretch.dll"); Script.AppendLine("ResampleAudio(48000)"); Script.AppendLine("TimeStretchPlugin(pitch = 100.0 * 0.98181819915771484)"); } // Add TWriteWAV. Script.AppendLine(); Script.LoadPluginDll("TWriteAVI.dll"); Script.AppendLine(@"TWriteWAV(""{0}"", true)", Script.GetAsciiPath(destination)); Script.AppendLine("ForceProcessWAV()"); // Write temp script. Script.WriteToFile(TempFile); // Execute. It aways returns an error but the file is generated. FFmpegProcess Worker = new FFmpegProcess(options); Worker.RunAvisynth(TempFile); File.Delete(TempFile); }
/// <summary> /// Returns whether the GPU supports the latest version of KNLMeans with OpenCL 1.2 /// </summary> /// <param name="supports11">If true, it will instead test whether the GPU supports OpenCL 1.1</param> /// <returns>True if OpenCL is supported.</returns> private static bool GpuSupportsOpenCL(bool version12) { string TempScript = Settings.TempFilesPath + "Temp.avs"; string TempResult = Settings.TempFilesPath + "Temp.txt"; string TempOut = Settings.TempFilesPath + "Temp.y4m"; AviSynthScriptBuilder Script = new AviSynthScriptBuilder(); Script.AddPluginPath(); Script.LoadPluginDll(string.Format("KNLMeansCL{0}.dll", version12 ? "" : "-6.11")); Script.AppendLine(@"colorbars(pixel_type = ""yv12"").killaudio().trim(1, 1)"); Script.AppendLine("Result = true"); Script.AppendLine("try {"); Script.AppendLine(@"KNLMeansCL(device_type=""GPU"")"); Script.AppendLine("} catch(error_msg) {"); Script.AppendLine("Result = false"); Script.AppendLine("}"); Script.AppendLine(@"WriteFileStart(""{0}"", string(Result))", TempResult); Script.WriteToFile(TempScript); // Run script. FfmpegBusiness.Run(@"Encoder\avs2yuv.exe", String.Format(@"""{0}"" -o ""{1}""", TempScript, TempOut), true); // Read frame count bool Result = false; if (File.Exists(TempResult)) { string FileString = File.ReadAllText(TempResult); try { Result = bool.Parse(FileString.TrimEnd()); } catch { Result = false; } } // Delete temp files. File.Delete(TempScript); File.Delete(TempResult); File.Delete(TempOut); // Dummy file that received avs2yuv output. return(Result); }
/// <summary> /// Generates a script for Deshaker prescan. This is a much simplified version of the full script that will execute faster. /// </summary> public static string GenerateDeshakerScript(MediaEncoderSettings settings, string inputFile, int segment, long frameStart, long frameEnd) { bool MultiProcesses = false; // Calculate encoding and final frame rates. double ChangeSpeedValue = settings.ChangeSpeed ? (double)settings.ChangeSpeedValue / 100 : 1; double FrameRateBefore = settings.SourceFrameRate.Value * ChangeSpeedValue; // Generate video script. AviSynthScriptBuilder Script = new AviSynthScriptBuilder(); Script.AddPluginPath(); Script.LoadPluginDll("VDubFilter.dll"); Script.AppendLine(@"LoadVirtualDubPlugin(P+""deshaker.vdf"", ""deshaker"", preroll=0)"); if (settings.ConvertToAvi || inputFile.ToLower().EndsWith(".avi")) { Script.OpenAvi(inputFile, false); } else { Script.OpenDirect(inputFile, false); } if (FrameRateBefore != settings.SourceFrameRate) { Script.AppendLine(CultureInfo.InvariantCulture, "AssumeFPS({0}, true)", FrameRateBefore); } if (settings.Trim) { Script.AppendLine("Trim({0}, {1})", (settings.TrimStart ?? 0) > 0 ? (int)(settings.TrimStart.Value * settings.SourceFrameRate.Value) : 0, (settings.TrimEnd ?? 0) > 0 ? (int)(settings.TrimEnd.Value * settings.SourceFrameRate.Value) : 0); } if (settings.CropSource.HasValue) { Script.AppendLine("Crop({0}, {1}, -{2}, -{3})", settings.CropSource.Left, settings.CropSource.Top, settings.CropSource.Right, settings.CropSource.Bottom); } // Generate script for a segment. if (frameStart > 0 || frameEnd > 0) { Script.AppendLine("Trim({0}, {1})", frameStart, frameEnd); } // Resize to the dimention deshaker will run at. if (settings.FrameDouble == 1) { int FinalWidth = settings.OutputWidth.Value + settings.CropAfter.Left + settings.CropAfter.Right; int FinalHeight = settings.OutputHeight + settings.CropAfter.Top + settings.CropAfter.Bottom; Script.AppendLine("BicubicResize({0}, {1})", FinalWidth, FinalHeight); } else if (settings.FrameDouble > 1) { Script.AppendLine("BicubicResize(Width*2, Height*2)"); } // Deshaker requires RGB input. Script.AppendLine(@"ConvertToRGB32(matrix=""{0}"")", settings.SourceColorMatrix == ColorMatrix.Rec601 ? "Rec601" : settings.SourceColorMatrix == ColorMatrix.Pc709 ? "Pc709" : settings.SourceColorMatrix == ColorMatrix.Pc601 ? "Pc601" : "Rec709"); // Generate log file Script.AppendLine(@"deshaker(""{0}"")", settings.DeshakerSettings.ToString(segment)); // FFMPEG will generate an AVI file; make it 8x8 to minimize processing. Script.AppendLine("ConvertToYV12()"); Script.AppendLine("PointResize(64,64)"); if (MultiProcesses) { Script.AppendLine("### prefetch: 0, 0"); Script.AppendLine("### branch: 2"); Script.AppendLine("### ###"); Script.ConvertToMultiProcesses(settings.SourceFrameRate.Value); } return(Script.Script); }
public static AviSynthScriptBuilder GenerateVideoScript(MediaEncoderSettings settings, string inputFile, bool preview, bool multiThreaded) { // int CPU = multiThreaded ? Environment.ProcessorCount : 1; int CPU = multiThreaded ? settings.Threads : 1; if (CPU <= 1) { multiThreaded = false; } bool RunMultiProcesses = false; if (settings.Deshaker && multiThreaded) { RunMultiProcesses = true; // Run through MP_Pipeline multiThreaded = false; // Deshaker doesn't work with MT CPU = 1; } //if (settings.Threads > 0) { // multiThreaded = false; // CPU = 1; //} settings.CalculateSize(); // Calculate encoding and final frame rates. double ChangeSpeedValue = (settings.ChangeSpeed && settings.CanAlterAudio) ? (double)settings.ChangeSpeedValue / 100 : 1; double FrameRateBefore = settings.SourceFrameRate.Value * ChangeSpeedValue; // Generate video script. AviSynthScriptBuilder Script = new AviSynthScriptBuilder(); bool IsYV24 = false; Script.AppendLine(); // After clean-up, this adds a line after LoadPlugin commands. Script.AddPluginPath(); if (multiThreaded) { Script.LoadPluginAvsi("AviSynthMT.avsi"); } if (settings.ConvertToAvi || inputFile.ToLower().EndsWith(".avi")) { Script.OpenAvi(inputFile, !string.IsNullOrEmpty(settings.SourceAudioFormat)); } else { Script.OpenDirect(inputFile, !string.IsNullOrEmpty(settings.SourceAudioFormat)); } if (FrameRateBefore != settings.SourceFrameRate) { Script.AppendLine(CultureInfo.InvariantCulture, "AssumeFPS({0}, true)", FrameRateBefore); } if (settings.Trim && settings.CanAlterAudio) { Script.AppendLine("Trim({0}, {1})", (settings.TrimStart ?? 0) > 0 ? (int)(settings.TrimStart.Value * settings.SourceFrameRate.Value) : 0, (settings.TrimEnd ?? 0) > 0 && !preview ? (int)(settings.TrimEnd.Value * settings.SourceFrameRate.Value) : 0); } if (settings.Denoise) { //Script.LoadPluginDll("MvTools2.dll"); //Script.LoadPluginDll("MaskTools2.dll"); //Script.LoadPluginDll("FFT3DFilter.dll"); //Script.LoadPluginDll("ModPlus.dll"); //Script.LoadPluginDll("RgTools.dll"); //Script.LoadPluginDll("DCTFilter.dll"); //Script.LoadPluginAvsi("mClean.avsi"); //Script.AppendLine("mClean(rn={0}{1})", 10, IsHD ? ", outbits=16" : ""); Script.AppendLine(@"MCTemporalDenoise(settings=""{0}""{1})", "medium", settings.Deblock ? ", deblock=true" : ""); } else if (settings.Deblock) { Script.LoadPluginDll("MaskTools2.dll"); Script.LoadPluginDll("DCTFilter.dll"); Script.LoadPluginDll("deblock.dll"); Script.LoadPluginAvsi("Deblock_QED.avsi"); Script.AppendLine("Deblock_QED()"); } if (settings.CropSource.HasValue) { Script.AppendLine("Crop({0}, {1}, -{2}, -{3})", settings.CropSource.Left, settings.CropSource.Top, settings.CropSource.Right, settings.CropSource.Bottom); } // If possible, KNLMeans will output 16-bit frames before upscaling. bool IsHD = (settings.Dering || settings.Deblock || settings.Degrain || settings.SourceColorMatrix != ColorMatrix.Rec709 || (settings.FrameDouble > 0 && (settings.SuperRes || settings.UpscaleMethod == UpscaleMethods.SuperXbr))); bool IsColorMatrixHD = IsHD; bool IsChromaFixed = settings.SourceChromaPlacement == ChromaPlacement.MPEG2; if (IsHD) { //if (!settings.Denoise) Script.AppendLine("ConvertBits(16)"); if (settings.SourceColorMatrix != ColorMatrix.Rec709) { Script.AppendLine("[ColorMatrixShader]"); // Placeholder that will be replaced after generating the rest. } } if (settings.FixDoubleFrames) { Script.LoadPluginDll("FrameRateConverter.dll"); Script.LoadPluginAvsi("FrameRateConverter.avsi"); Script.LoadPluginDll("MaskTools2.dll"); Script.LoadPluginDll("MvTools2.dll"); Script.AppendLine("InterpolateDoubles(.1)"); } if (settings.Dering) { Script.LoadPluginAvsi("HQDeringmod.avsi"); Script.LoadPluginDll("MedianBlur2.dll"); Script.LoadPluginDll("dfttest.dll"); Script.LoadPluginDll("RgTools.dll"); Script.LoadPluginDll("SmoothAdjust.dll"); Script.AppendLine("HQDeringmod({0})", IsHD ? "lsb_in=true, lsb=true" : ""); } if (settings.Degrain) { ApplyDegrain(Script, settings, ref IsHD, ref IsYV24); } if (settings.Deshaker) { ApplyDeshaker(Script, settings, ref IsHD, ref IsYV24, RunMultiProcesses); } if (settings.FrameDouble > 0) { Script.AppendLine(@"ConvertToYUV444({0})", !IsChromaFixed ? string.Format(@"ChromaInPlacement=""{0}""", settings.SourceChromaPlacement.ToString()) : ""); IsYV24 = true; IsChromaFixed = true; } string FinalSize = string.Format("fWidth={0}, fHeight={1}", settings.OutputWidth + settings.CropAfter.Left + settings.CropAfter.Right, settings.OutputHeight + settings.CropAfter.Top + settings.CropAfter.Bottom); string FinalResize = FinalSize; if (settings.DownscaleMethod == DownscaleMethods.SSim) { FinalResize += string.Format(@", fKernel=""SSim"", fB={0}{1}", settings.SSimStrength / 100, settings.SSimSoft ? ", fC=1" : ""); } else // DownscaleMethod == Bicubic { FinalResize += string.Format(@", fKernel=""Bicubic"", fB=0, fC=.75"); } if (settings.FrameDouble > 0) { if (settings.UpscaleMethod == UpscaleMethods.NNedi3) { bool IsLastDouble = false; DitherPost(Script, ref IsHD, ref IsYV24, true); Script.LoadPluginDll("nnedi3.dll"); Script.LoadPluginAvsi("edi_rpow2.avsi"); Script.LoadPluginAvsi("ResizeX.avsi"); for (int i = 0; i < settings.FrameDouble; i++) { IsLastDouble = i == settings.FrameDouble - 1; string DoubleScript = string.Format("edi_rpow2(2, nns=4, {0}, Threads=2)", IsLastDouble && settings.DownscaleMethod == DownscaleMethods.Bicubic ? @"cshift=""Bicubic"", a1=0, a2=.75, " + FinalSize : @"cshift=""Spline16Resize"""); if (settings.SuperRes) { Script.AppendLine(CultureInfo.InvariantCulture, @"SuperRes({0}, {1}, {2}, """"""{3}""""""{4}{5}{6})", settings.SuperRes3Passes ? (i == 0 && settings.FrameDouble > 1 ? 5 : 3) : 2, settings.SuperResStrength / 100f, settings.SuperResSoftness / 100f, DoubleScript, i == 0 ? GetMatrixIn(settings) : "", IsLastDouble && settings.DownscaleMethod == DownscaleMethods.SSim ? ", " + FinalResize : "", multiThreaded ? "" : ", Engines=1"); } else { Script.AppendLine(DoubleScript); if (IsLastDouble && settings.DownscaleMethod == DownscaleMethods.SSim) { Script.AppendLine("ResizeShader({0}{1})", FinalResize.Replace("fWidth=", "").Replace("fHeight=", "").Replace(" f", " "), // Use same string as FinalResize but remove 'f' parameter sufix. GetMatrixIn(settings)); } } } } else // UpscaleMethod == SuperXBR { if (settings.SuperRes) { Script.AppendLine(CultureInfo.InvariantCulture, @"SuperResXBR({0}, {1}, {2}{3}, XbrStr={4}, XbrSharp={5}{6}, {7}, FormatOut=""YV12""{8})", settings.SuperRes3Passes ? (settings.IncreaseFrameRate ? 5 : 3) : 2, settings.SuperResStrength / 100f, settings.SuperResSoftness / 100f, settings.FrameDouble > 1 ? ", Factor=" + (1 << settings.FrameDouble).ToString() : "", settings.SuperXbrStrength / 10f, settings.SuperXbrSharpness / 10f, GetMatrixIn(settings), FinalResize, multiThreaded ? "" : ", Engines=1"); } else { Script.AppendLine(@"SuperXBR(Str={0}, Sharp={1}{2}{3}, {4}, FormatOut=""YV12""{5})", settings.SuperXbrStrength / 10f, settings.SuperXbrSharpness / 10f, settings.FrameDouble > 1 ? ", Factor=" + (1 << settings.FrameDouble).ToString() : "", GetMatrixIn(settings), FinalResize, multiThreaded ? "" : ", Engines=1"); } IsHD = false; IsYV24 = false; } } if (settings.DownscaleMethod != DownscaleMethods.SSim) { DitherPost(Script, ref IsHD, ref IsYV24, settings.IncreaseFrameRate); } string[] ShaderCommands = new string[] { "SuperRes", "SuperXBR", "SuperResXBR", "ResizeShader" }; if (settings.CropAfter.HasValue || settings.FrameDouble == 0) { if (settings.CropAfter.HasValue || settings.SourceAspectRatio != 1 || settings.OutputWidth != settings.SourceWidth || settings.OutputHeight != settings.OutputHeight) { if (settings.DownscaleMethod == DownscaleMethods.SSim && settings.FrameDouble == 0) { Script.AppendLine("ResizeShader({0}{1})", FinalResize.Replace("fWidth=", "").Replace("fHeight=", "").Replace(" f", " "), // Use same string as FinalResize but remove 'f' parameter sufix. GetMatrixIn(settings)); } DitherPost(Script, ref IsHD, ref IsYV24, false); if (settings.CropAfter.HasValue || settings.DownscaleMethod == DownscaleMethods.Bicubic) { Script.LoadPluginAvsi("ResizeX.avsi"); bool ApplyResize = settings.FrameDouble == 0 || !Script.ContainsAny(ShaderCommands); string CropFormat = "ResizeX"; CropFormat += settings.CropAfter.HasValue ? "({0}, {1}, {2}, {3}, -{4}, -{5}{6})" : "({0}, {1}{6})"; Script.AppendLine(CropFormat, settings.OutputWidth, settings.OutputHeight, settings.CropAfter.Left, settings.CropAfter.Top, settings.CropAfter.Right, settings.CropAfter.Bottom, ApplyResize ? @", kernel=""Bicubic"", a1=0, a2=.75" : ""); } } } // Use ColorMatrixShader only if it wasn't already applied through any other shader. if (Script.ContainsAny(ShaderCommands)) { // ColorMatrix was applied though another shader. Script.Replace("[ColorMatrixShader]" + Environment.NewLine, ""); Script.LoadPluginDll("Shader.dll"); Script.LoadPluginAvsi("Shader.avsi"); } else { string ColorMatrixScript = ""; // Apply color matrix if (settings.SourceColorMatrix == ColorMatrix.Pc709) { Script.LoadPluginDll("SmoothAdjust.dll"); ColorMatrixScript = string.Format(@"ColorYUV(levels=""PC->TV"""); } else if (settings.SourceColorMatrix != ColorMatrix.Rec709) { Script.LoadPluginDll("Shader.dll"); Script.LoadPluginAvsi("Shader.avsi"); ColorMatrixScript = string.Format(@"ResizeShader(Kernel=""ColorMatrix""{0})", GetMatrixIn(settings)); } Script.Replace("[ColorMatrixShader]" + Environment.NewLine, ColorMatrixScript + Environment.NewLine); } if (settings.IncreaseFrameRate) { if (IsYV24) { Script.AppendLine(@"ConvertToYUV420()"); IsYV24 = false; } DitherPost(Script, ref IsHD, ref IsYV24, true); ApplyInterFrame(Script, settings, CPU); } if (preview) { if (settings.Crop) { Script.AppendLine("AddBorders(2, 2, 2, 2, $FFFFFF)"); } Script.AppendLine(@"ConvertToRGB32(matrix=""Rec709"")"); } if (multiThreaded) { Script.AppendLine("Prefetch({0})", CPU); } if (RunMultiProcesses) { Script.ConvertToMultiProcesses(settings.SourceFrameRate.Value); } else { Script.Cleanup(); } return(Script); }
/// <summary> /// Calculates auto-crop coordinates for specified video script. /// </summary> /// <param name="filePath">The script to analyze.</param> /// <param name="sourceWidth">The width of the source video.</param> /// <param name="sourceHeight">The height of the source video.</param> /// <param name="options">The options that control the behaviors of the process.</param> /// <returns>The auto-crop coordinates.</returns> public static Rect GetAutoCropRect(string filePath, int sourceWidth, int sourceHeight, ProcessStartOptions options) { string TempScript = PathManager.GetTempFile(".avs"); string TempResult = Path.ChangeExtension(TempScript, ".txt"); // Create script to get auto-crop coordinates AviSynthScriptBuilder Script = new AviSynthScriptBuilder(); Script.AddPluginPath(); Script.OpenDirect(filePath, false); Script.LoadPluginDll("RoboCrop26.dll"); Script.AppendLine(@"RoboCrop(LogFn=""{0}"")", Script.GetAsciiPath(TempResult)); Script.AppendLine("Trim(0,-1)"); Script.WriteToFile(TempScript); // Run script. FFmpegProcess Worker = new FFmpegProcess(options); Worker.RunAvisynth(TempScript); // Read auto crop coordinates Rect Result = new Rect(); if (File.Exists(TempResult)) { string[] Values = File.ReadAllText(TempResult).Split(' '); if (Values.Length >= 13) { Result.Left = Math.Max(int.Parse(Values[10]), 0); Result.Top = Math.Max(int.Parse(Values[11]), 0); Result.Right = Math.Max(sourceWidth - int.Parse(Values[12]), 0); Result.Bottom = Math.Max(sourceHeight - int.Parse(Values[13]), 0); // Make result conservative, we have to visually see a line of black border to know the right dimensions. if (Result.Left > 0) { Result.Left--; } if (Result.Top > 0) { Result.Top--; } if (Result.Right > 0) { Result.Right--; } if (Result.Bottom > 0) { Result.Bottom--; } } } // Delete temp files. Exception LastError = null; for (int i = 0; i < 10; i++) { try { File.Delete(TempScript); File.Delete(TempResult); break; } catch (Exception e) { LastError = e; System.Threading.Thread.Sleep(500); } } if (LastError != null) { throw LastError; } return(Result); }
public static Rect GetAutoCropRect(MediaEncoderSettings settings, bool silent) { string TempScript = settings.TempFile + ".avs"; string TempResult = settings.TempFile + ".txt"; string TempOut = settings.TempFile + ".y4m"; // Create script to get auto-crop coordinates AviSynthScriptBuilder Script = new AviSynthScriptBuilder(); Script.AddPluginPath(); Script.OpenDirect(settings.FilePath, false); Script.LoadPluginDll("RoboCrop26.dll"); Script.AppendLine(@"RoboCrop(LogFn=""{0}"")", Script.GetAsciiPath(TempResult)); Script.AppendLine("Trim(0,-1)"); Script.WriteToFile(TempScript); // Run script. Run(@"Encoder\avs2yuv.exe", String.Format(@"""{0}"" -o ""{1}""", TempScript, TempOut), true); // Read auto crop coordinates Rect Result = new Rect(); if (File.Exists(TempResult)) { string[] Values = File.ReadAllText(TempResult).Split(' '); if (Values.Length >= 13) { Result.Left = int.Parse(Values[10]); Result.Top = int.Parse(Values[11]); Result.Right = settings.SourceWidth.Value - int.Parse(Values[12]); Result.Bottom = settings.SourceHeight.Value - int.Parse(Values[13]); // Make result conservative, we have to visually see a line of black border to know the right dimensions. if (Result.Left > 0) { Result.Left--; } if (Result.Top > 0) { Result.Top--; } if (Result.Right > 0) { Result.Right--; } if (Result.Bottom > 0) { Result.Bottom--; } } } // Delete temp files. Exception LastError = null; for (int i = 0; i < 10; i++) { try { File.Delete(TempScript); File.Delete(TempResult); File.Delete(TempOut); // Dummy file that received avs2yuv output. break; } catch (Exception e) { LastError = e; System.Threading.Thread.Sleep(500); } } if (LastError != null) { throw LastError; } return(Result); }