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); }