/// <summary> /// Generates AviSynth script used for video encoding /// </summary> /// <param name="videoInfo">All video properties</param> /// <param name="changeFps">Defines whether framerate should be changed</param> /// <param name="targetFps">Sets target framerate</param> /// <param name="resizeTo">Sets target video resolution</param> /// <param name="stereoEncoding">Defines, which stereo encoding mode should be used</param> /// <param name="stereoVideoInfo">Sets all parameters for stereo encoding</param> /// <param name="isDvdResolution">Defines whether target resolution is used for DVD encoding</param> /// <param name="subtitleFile">Sets subtitle file for hardcoding into video</param> /// <param name="subtitleOnlyForced">Defines whether only forced captions should be hardcoded</param> /// <param name="skipScaling"></param> /// <returns>Path to AviSynth script</returns> public string Generate(VideoInfo videoInfo, bool changeFps, float targetFps, Size resizeTo, StereoEncoding stereoEncoding, StereoVideoInfo stereoVideoInfo, bool isDvdResolution, string subtitleFile, bool subtitleOnlyForced, bool skipScaling) { var sb = new StringBuilder(); var mtUseful = (videoInfo.Interlaced && _appConfig.UseHQDeinterlace) || changeFps; var useStereo = stereoEncoding != StereoEncoding.None && stereoVideoInfo.RightStreamId > -1; // support for multithreaded AviSynth if (_appConfig.UseAviSynthMT && mtUseful) { sb.AppendLine("SetMTMode(2,0)"); sb.AppendLine("SetMemoryMax(512)"); } var pluginList = new List <string> { "ffms2.dll" }; var scriptList = new List <string>(); //loading plugins if (changeFps || (videoInfo.Interlaced && _appConfig.UseHQDeinterlace)) { pluginList.Add("mvtools2.dll"); } if (videoInfo.Interlaced && _appConfig.UseHQDeinterlace) { pluginList.Add(_appConfig.LastAviSynthVer.StartsWith("2.5") ? "mt_masktools-25.dll" : "mt_masktools-26.dll"); pluginList.Add("nnedi3.dll"); pluginList.Add("RemoveGrainSSE2.dll"); pluginList.Add("RepairSSE2.dll"); scriptList.Add("QTGMC-3.32.avsi"); } else if (videoInfo.Interlaced) { pluginList.Add("Decomb.dll"); } if (useStereo) { pluginList.Add("H264StereoSource.dll"); } if (!string.IsNullOrEmpty(subtitleFile) && File.Exists(subtitleFile)) { switch (Path.GetExtension(subtitleFile)) { case "sup": pluginList.Add("SupTitle.dll"); break; case "ass": case "ssa": case "srt": pluginList.Add("VSFilter.dll"); break; } } // generate plugin and script loading foreach (var plugin in pluginList) { sb.AppendLine($"LoadPlugin(\"{Path.Combine(_appConfig.AvsPluginsPath, plugin)}\")"); } foreach (var script in scriptList) { sb.AppendLine($"Import(\"{Path.Combine(_appConfig.AvsPluginsPath, script)}\")"); } //generate rest of the script // calculate framerate numerator & denominator if (videoInfo.Fps <= 0) { var mi = new MediaInfoContainer(); try { mi = GenHelper.GetMediaInfo(videoInfo.TempFile); } catch (TimeoutException ex) { Log.Error(ex); mi = new MediaInfoContainer(); } finally { if (mi.Video.Count > 0) { videoInfo.Fps = mi.Video[0].FrameRate; VideoHelper.GetFpsNumDenom(videoInfo.Fps, out videoInfo.FrameRateEnumerator, out videoInfo.FrameRateDenominator); if (videoInfo.FrameRateEnumerator == 0) { videoInfo.FrameRateEnumerator = (int)Math.Round(videoInfo.Fps) * 1000; videoInfo.FrameRateDenominator = (int)(Math.Round(Math.Ceiling(videoInfo.Fps) - Math.Floor(videoInfo.Fps)) + 1000); } } } } sb.Append($"FFVideoSource(\"{videoInfo.TempFile}\","); if (videoInfo.FrameRateEnumerator > 0 && videoInfo.FrameRateDenominator > 0) { sb.Append($"fpsnum={videoInfo.FrameRateEnumerator:0},fpsden={videoInfo.FrameRateDenominator:0},"); } var threadCount = _appConfig.LimitDecoderThreads ? 1 : 0; sb.Append($"threads={threadCount:0})"); sb.AppendLine(); var stereoVar = string.Empty; if (useStereo) { var configFile = GenerateStereoSourceConfig(stereoVideoInfo); sb.AppendLine($"VideoRight = H264StereoSource(\"{configFile}\",{videoInfo.FrameCount - 50:0})"); StereoConfigFile = configFile; stereoVar = "VideoRight"; } // deinterlace video source if (videoInfo.Interlaced) { if (_appConfig.UseHQDeinterlace) { sb.AppendLine("QTGMC(Preset=\"Slower\")"); } else { sb.AppendLine("ConvertToYUY2(interlaced=true)"); sb.AppendLine("Telecide(post=4)"); sb.AppendLine("Crop(4, 0, -4, 0)"); sb.AppendLine("AddBorders(4, 0, 4, 0)"); sb.AppendLine("ConvertToYV12()"); } } // hardcode subtitles if (!string.IsNullOrEmpty(subtitleFile) && File.Exists(subtitleFile)) { switch (Path.GetExtension(subtitleFile)) { case "sup": var subForced = subtitleOnlyForced ? "true" : "false"; sb.Append($"SupTitle(\"{subtitleFile}\", forcedOnly={subForced})"); break; case "ass": case "ssa": case "srt": sb.Append($"TextSub(\"{subtitleFile}\")"); break; } sb.AppendLine(); } // video cropping if (!videoInfo.CropRect.IsEmpty && !skipScaling) { int temp; Math.DivRem(videoInfo.CropRect.X, 2, out temp); videoInfo.CropRect.X += temp; Math.DivRem(videoInfo.CropRect.Y, 2, out temp); videoInfo.CropRect.Y += temp; Math.DivRem(videoInfo.CropRect.Width, 2, out temp); videoInfo.CropRect.Width += temp; Math.DivRem(videoInfo.CropRect.Height, 2, out temp); videoInfo.CropRect.Height += temp; videoInfo.Height = videoInfo.CropRect.Height; videoInfo.Width = videoInfo.CropRect.Width; if ((videoInfo.CropRect.X > 0) || (videoInfo.CropRect.Y > 0) || (videoInfo.CropRect.Width < videoInfo.Width) || (videoInfo.CropRect.Height < videoInfo.Height)) { sb.Append(useStereo ? "CroppedVideoRight = Crop(VideoRight," : "Crop("); sb.Append($"{videoInfo.CropRect.Left:0},{videoInfo.CropRect.Top:0},"); sb.Append($"{videoInfo.CropRect.Width:0},{videoInfo.CropRect.Height:0})"); sb.AppendLine(); if (useStereo) { stereoVar = "CroppedVideoRight"; } } } // Side-By-Side stereo encoding if (!string.IsNullOrEmpty(stereoVar)) { switch (stereoEncoding) { case StereoEncoding.FullSideBySideLeft: case StereoEncoding.HalfSideBySideLeft: sb.AppendLine($"StackHorizontal(last,{stereoVar})"); break; case StereoEncoding.FullSideBySideRight: case StereoEncoding.HalfSideBySideRight: sb.AppendLine($"StackHorizontal({stereoVar},last)"); break; } sb.AppendLine("ConvertToYV12()"); } var calculatedHeight = videoInfo.Height; var calculatedWidth = videoInfo.Width; var borderRight = 0; var borderLeft = 0; var borderBottom = 0; var borderTop = 0; var addBorders = false; // video resizing if (!resizeTo.IsEmpty && (resizeTo.Height != videoInfo.Height || resizeTo.Width != videoInfo.Width) && !skipScaling) { // aspect ratios var toAr = (float)Math.Round(resizeTo.Width / (float)resizeTo.Height, 3); var fromAr = videoInfo.AspectRatio; var mod = 1f; calculatedWidth = resizeTo.Width; if (fromAr > toAr) // source aspectratio higher than target aspectratio { if (isDvdResolution) { calculatedHeight = (int)(calculatedWidth / fromAr); if (calculatedHeight > resizeTo.Height) { calculatedHeight = resizeTo.Height; } calculatedWidth = 720; } else { calculatedWidth = resizeTo.Width; calculatedHeight = (int)(calculatedWidth / fromAr); } int temp; Math.DivRem(calculatedWidth, 2, out temp); calculatedWidth += temp; Math.DivRem(calculatedHeight, 2, out temp); calculatedHeight += temp; if (calculatedHeight != resizeTo.Height) { addBorders = true; var borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight / 2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; } } else if (Math.Abs(fromAr - toAr) <= 0) // source and target aspectratio equals { if (isDvdResolution) { calculatedHeight = (int)(calculatedWidth / fromAr); calculatedWidth = 720; if (calculatedHeight > resizeTo.Height) { calculatedHeight = resizeTo.Height; } } else { calculatedWidth = resizeTo.Width; calculatedHeight = (int)(calculatedWidth / toAr); } int temp; Math.DivRem(calculatedWidth, 2, out temp); calculatedWidth += temp; Math.DivRem(calculatedHeight, 2, out temp); calculatedHeight += temp; if (calculatedHeight != resizeTo.Height) { addBorders = true; var borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight / 2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; } } else { if (fromAr > 1.4f && isDvdResolution) // source aspectratio not 4:3, encoding for dvd resolution { mod = 720f / resizeTo.Width; calculatedHeight = (int)(calculatedWidth / fromAr); if (calculatedHeight > resizeTo.Height) { calculatedHeight = resizeTo.Height; calculatedWidth = (int)(calculatedHeight * fromAr * mod); } else { calculatedWidth = 720; } } else if (isDvdResolution) { calculatedHeight = resizeTo.Height; calculatedWidth = (int)(calculatedHeight * fromAr); } else { calculatedHeight = resizeTo.Height; } int temp; Math.DivRem(calculatedWidth, 2, out temp); calculatedWidth += temp; Math.DivRem(calculatedHeight, 2, out temp); calculatedHeight += temp; if (Math.Abs(toAr - 1.778f) <= 0) // aspectratio 16:9 { addBorders = true; var borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight / 2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; var borderWidth = (int)((resizeTo.Width * mod) - calculatedWidth); borderLeft = borderWidth / 2; Math.DivRem(borderLeft, 2, out temp); borderLeft += temp; borderRight = borderWidth - borderLeft; } else if (calculatedWidth != resizeTo.Width) { addBorders = true; var borderWidth = resizeTo.Width - calculatedWidth; borderLeft = borderWidth / 2; Math.DivRem(borderLeft, 2, out temp); borderLeft += temp; borderRight = borderWidth - borderLeft; var borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight / 2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; } } } // apply resize filter if (calculatedHeight != videoInfo.Height || calculatedWidth != videoInfo.Width || (stereoEncoding == StereoEncoding.HalfSideBySideLeft || stereoEncoding == StereoEncoding.HalfSideBySideRight && useStereo) && !skipScaling) { if (calculatedHeight < videoInfo.Height || calculatedWidth < videoInfo.Width || (stereoEncoding == StereoEncoding.HalfSideBySideLeft || stereoEncoding == StereoEncoding.HalfSideBySideRight && useStereo)) { sb.Append("BicubicResize"); } else { sb.Append("Lanczos4Resize"); } sb.Append($"({calculatedWidth:0},{calculatedHeight:0})"); sb.AppendLine(); } // add borders if needed if (addBorders && (borderLeft > 0 || borderRight > 0 || borderTop > 0 || borderBottom > 0) && !skipScaling) { sb.AppendLine($"AddBorders({borderLeft:0},{borderTop:0},{borderRight:0},{borderBottom:0})"); } // change framerate if (changeFps) { int fpsnum; int fpsden; // get framerate numerator & denominator for target framerate VideoHelper.GetFpsNumDenom(targetFps, out fpsnum, out fpsden); // source is 23.976 or 24 fps if (videoInfo.FrameRateEnumerator == 24000 && (videoInfo.FrameRateDenominator == 1001 || videoInfo.FrameRateDenominator == 1000)) { if (fpsnum == 30000 && fpsden == 1001) { // 3:2 pulldown / telecine sb.AppendLine("AssumeFrameBased()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEvery(8, 0, 1, 2, 3, 2, 5, 4, 7, 6, 7)"); sb.AppendLine("Weave()"); } else if (fpsnum == 25000 && fpsden == 1000) { // convert to 25 fps sb.AppendLine("ConvertToYUY2()"); sb.AppendLine("ConvertFPS(50)"); sb.AppendLine("AssumeTFF()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEvery(4,0,3)"); sb.AppendLine("Weave()"); sb.AppendLine("ConvertToYV12()"); } } // source is 30fps else if (videoInfo.FrameRateEnumerator == 30000) { sb.AppendLine("ConvertToYUY2()"); sb.AppendLine("DoubleWeave()"); sb.AppendLine($"ConvertFPS(numerator={fpsnum * 2:0},denominator={fpsden:0})"); sb.AppendLine("SelectEven()"); sb.AppendLine("ConvertToYV12()"); } // source is 25fps else if (videoInfo.FrameRateEnumerator == 25000 && videoInfo.FrameRateDenominator == 1000) { if ((fpsnum == 30000 || fpsnum == 24000) && fpsden == 1001) { sb.AppendLine("ConvertToYUY2()"); sb.AppendLine("ConvertFPS(numerator=48000,denominator=1001"); if (fpsnum == 30000) { sb.AppendLine("AssumeFrameBased()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEvery(8, 0, 1, 2, 3, 2, 5, 4, 7, 6, 7)"); } else { sb.AppendLine("AssumeTFF()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEven()"); } sb.AppendLine("Weave()"); sb.AppendLine("ConvertToYV12()"); } } // every other framerate else { // very slow framerate interpolation sb.AppendLine("super = MSuper(pel=2)"); sb.AppendLine("backward_vec = MAnalyse(super, overlap=4, isb = true, search=3)"); sb.AppendLine("forward_vec = MAnalyse(super, overlap=4, isb = false, search=3)"); sb.Append($"MFlowFps(super, backward_vec, forward_vec, num={fpsnum:0}, den={fpsden:0})"); } sb.AppendLine(); } // multithreaded avisynth if (!_appConfig.UseAviSynthMT || !mtUseful) { return(WriteScript(sb.ToString())); } sb.AppendLine("SetMTMode(1)"); sb.AppendLine("GetMTMode(false) > 0 ? distributor() : last"); return(WriteScript(sb.ToString())); }
/// <summary> /// Generates commandline arguments used for encoding an video stream to h.264 format. /// Input is either stdin or file/avisynth script. /// </summary> /// <param name="inProfile">Encoding profile</param> /// <param name="bitrate">Target bitrate</param> /// <param name="hRes">Video width</param> /// <param name="vRes">Video height</param> /// <param name="pass">Encoding pass</param> /// <param name="fpsN">Framerate numerator</param> /// <param name="fpsD">Framerate denominator</param> /// <param name="stereo">Defines, which stereo encoding mode should be used</param> /// <param name="format">Image format</param> /// <param name="inFile">Path to input file</param> /// <param name="outFile">Path to output file</param> /// <returns>Commandline arguments</returns> public static string Generate(X264Profile inProfile, int bitrate, int hRes, int vRes, int pass, int fpsN, int fpsD, StereoEncoding stereo = StereoEncoding.None, VideoFormat format = VideoFormat.Unknown, string inFile = "input", string outFile = "output") { StringBuilder sb = new StringBuilder(); if (inProfile != null) { bool display; X264Device device = X264Device.CreateDeviceList()[inProfile.TuneDevice]; // AVC Profiles switch (inProfile.AVCProfile) { case 0: sb.Append("--profile baseline "); break; case 1: sb.Append("--profile main "); break; default: sb.Append("--profile high "); break; } // AVC Levels if (inProfile.AVCLevel != 15) // unrestricted sb.AppendFormat("--level {0} ", CLILevelNames[inProfile.AVCLevel]); // Blu-Ray compatibility if (inProfile.UseBluRayCompatibility) sb.Append("--bluray-compat "); // x264 Presets if (!inProfile.CustomCommandLine.Contains("--preset")) { switch (inProfile.Preset) { case 0: sb.Append("--preset ultrafast "); break; case 1: sb.Append("--preset superfast "); break; case 2: sb.Append("--preset veryfast "); break; case 3: sb.Append("--preset faster "); break; case 4: sb.Append("--preset fast "); break; //case 5: sb.Append("--preset medium "); break; // default value case 6: sb.Append("--preset slow "); break; case 7: sb.Append("--preset slower "); break; case 8: sb.Append("--preset veryslow "); break; case 9: sb.Append("--preset placebo "); break; } } // x264 Tunings if (!inProfile.CustomCommandLine.Contains("--tune")) { switch (inProfile.Tuning) { case 1: sb.Append("--tune film "); break; case 2: sb.Append("--tune animation "); break; case 3: sb.Append("--tune grain "); break; case 4: sb.Append("--tune psnr "); break; case 5: sb.Append("--tune ssim "); break; case 6: sb.Append("--tune fastdecode "); break; } } // Encoding Modes int tempPass = pass; int tempBitrate = bitrate; int vbvBuf = GetVBVMaxrate(inProfile, device); if (tempBitrate <= 0) tempBitrate = inProfile.VBRSetting; if (vbvBuf > 0 && tempBitrate > vbvBuf) // limit Bitrate to max vbvbuf size tempBitrate = vbvBuf; switch (inProfile.EncodingMode) { case 0: // ABR if (!inProfile.CustomCommandLine.Contains("--bitrate")) sb.AppendFormat(AppSettings.CInfo, "--bitrate {0:0} ", tempBitrate); break; case 1: // Constant Quantizer if (!inProfile.CustomCommandLine.Contains("--qp")) sb.AppendFormat(AppSettings.CInfo, "--qp {0:0}", inProfile.QuantizerSetting); break; case 2: // automated 2 pass case 3: // automated 3 pass sb.AppendFormat(AppSettings.CInfo, "--pass {0:0} --bitrate {1:0} ", tempPass, tempBitrate); break; default: if (!inProfile.CustomCommandLine.Contains("--crf") && inProfile.QualitySetting != 23) sb.AppendFormat(AppSettings.CInfo, "--crf {0:0} ", inProfile.QualitySetting); break; } // Slow 1st Pass if (!inProfile.CustomCommandLine.Contains("--slow-firstpass")) if ((inProfile.UseSlowFirstPass) && inProfile.Preset < 9 && // 9 = placebo ((inProfile.EncodingMode == 2) || // automated twopass (inProfile.EncodingMode == 3))) // automated threepass sb.Append("--slow-firstpass "); // Threads if (!inProfile.CustomCommandLine.Contains("--thread-input")) if (inProfile.UseThreadInput && inProfile.NumThreads == 1) sb.Append("--thread-input "); if (!inProfile.CustomCommandLine.Contains("--threads")) if (inProfile.NumThreads > 0) sb.AppendFormat(AppSettings.CInfo, "--threads {0:0} ", inProfile.NumThreads); #region frame-type tab // H.264 Features if (inProfile.UseDeblocking) { display = false; switch (inProfile.Tuning) { case 1: if (inProfile.DeblockingStrength != -1 || inProfile.DeblockingThreshold != -1) display = true; break; // film case 2: if (inProfile.DeblockingStrength != 1 || inProfile.DeblockingThreshold != 1) display = true; break; // animation case 3: if (inProfile.DeblockingStrength != -2 || inProfile.DeblockingThreshold != -2) display = true; break; // grain default: if (inProfile.DeblockingStrength != 0 || inProfile.DeblockingThreshold != 0) display = true; break; } if (!inProfile.CustomCommandLine.Contains("--deblock ")) if (display) sb.AppendFormat(AppSettings.CInfo, "--deblock {0:0}:{1:0} ", inProfile.DeblockingStrength, inProfile.DeblockingThreshold); } else { if (!inProfile.CustomCommandLine.Contains("--no-deblock")) if (inProfile.Preset != 0 && inProfile.Tuning != 7) // ultrafast preset and not fast decode tuning sb.Append("--no-deblock "); } if (inProfile.AVCProfile > 0 && !inProfile.CustomCommandLine.Contains("--no-cabac")) { if (!inProfile.UseCabac) { if (inProfile.Preset != 0 && inProfile.Tuning != 7) // ultrafast preset and not fast decode tuning sb.Append("--no-cabac "); } } // GOP Size int backupMaxGopSize = inProfile.MaxGopSize; int backupMinGopSize = inProfile.MinGopSize; inProfile.MaxGopSize = GetKeyInt(fpsN, fpsD, backupMaxGopSize, device, inProfile.GopCalculation); if (inProfile.MaxGopSize != 250) // default size { if (inProfile.MaxGopSize == 0) sb.Append("--keyint infinite "); else sb.AppendFormat(AppSettings.CInfo, "--keyint {0:0} ", inProfile.MaxGopSize); } if (!inProfile.UseBluRayCompatibility) { inProfile.MinGopSize = GetMinKeyInt(fpsN, fpsD, backupMinGopSize, inProfile.MaxGopSize, device, inProfile.GopCalculation); if (inProfile.MinGopSize > (inProfile.MaxGopSize / 2 + 1)) { inProfile.MinGopSize = inProfile.MaxGopSize / 2 + 1; } int Default = Math.Min(inProfile.MaxGopSize / 10, fpsN / fpsD); if (inProfile.MinGopSize != Default) // (MIN(--keyint / 10,--fps)) is default sb.AppendFormat(AppSettings.CInfo, "--min-keyint {0:0} ", inProfile.MinGopSize); } inProfile.MaxGopSize = backupMaxGopSize; inProfile.MinGopSize = backupMinGopSize; if (!inProfile.CustomCommandLine.Contains("--open-gop") && (inProfile.UseOpenGop || inProfile.UseBluRayCompatibility)) sb.Append("--open-gop "); // B-Frames inProfile.NumBFrames = GetBFrames(inProfile, device); if (inProfile.AVCProfile > 0 && inProfile.NumBFrames != X264Settings.GetDefaultNumberOfBFrames(inProfile.AVCLevel, inProfile.Tuning, inProfile.AVCProfile, device)) sb.AppendFormat(AppSettings.CInfo, "--bframes {0:0} ", inProfile.NumBFrames); if (inProfile.NumBFrames > 0) { if (!inProfile.CustomCommandLine.Contains("--b-adapt")) { display = false; if (inProfile.Preset > 5) // medium { if (inProfile.AdaptiveBFrames != 2) display = true; } else if (inProfile.Preset > 0) // ultrafast { if (inProfile.AdaptiveBFrames != 1) display = true; } else { if (inProfile.AdaptiveBFrames != 0) display = true; } if (display) sb.AppendFormat(AppSettings.CInfo, "--b-adapt {0:0} ", inProfile.AdaptiveBFrames); } inProfile.BPyramid = GetBPyramid(inProfile, device); if (inProfile.NumBFrames > 1 && (inProfile.BPyramid != 2 && !inProfile.UseBluRayCompatibility || inProfile.BPyramid != 1 && inProfile.UseBluRayCompatibility)) { switch (inProfile.BPyramid) // pyramid needs a minimum of 2 b frames { case 1: sb.Append("--b-pyramid strict "); break; case 0: sb.Append("--b-pyramid none "); break; } } if (!inProfile.CustomCommandLine.Contains("--no-weightb")) if (!inProfile.UseWeightedPred && inProfile.Tuning != 7 && inProfile.Preset != 0) // no weightpredb + tuning != fastdecode + preset != ultrafast sb.Append("--no-weightb "); } // B-Frames bias if (!inProfile.CustomCommandLine.Contains("--b-bias ")) if (inProfile.BFrameBias != 0) sb.AppendFormat(AppSettings.CInfo, "--b-bias {0:0} ", inProfile.BFrameBias); // Other if (inProfile.UseAdaptiveIFrameDecision) { if (!inProfile.CustomCommandLine.Contains("--scenecut ")) if (inProfile.NumExtraIFrames != 40 && inProfile.Preset != 0 || inProfile.NumExtraIFrames != 0 && inProfile.Preset == 0) sb.AppendFormat(AppSettings.CInfo, "--scenecut {0:0} ", inProfile.NumExtraIFrames); } else { if (!inProfile.CustomCommandLine.Contains("--no-scenecut")) if (inProfile.Preset != 0) sb.Append("--no-scenecut "); } // reference frames int iRefFrames = GetRefFrames(hRes, vRes, inProfile, device); if (iRefFrames != X264Settings.GetDefaultNumberOfRefFrames(inProfile.Preset, inProfile.Tuning, null, inProfile.AVCLevel, hRes, vRes)) sb.AppendFormat(AppSettings.CInfo, "--ref {0:0} ", iRefFrames); // WeightedPPrediction inProfile.PFrameWeightedPrediction = GetWeightp(inProfile, device); if (inProfile.PFrameWeightedPrediction != X264Settings.GetDefaultNumberOfWeightp(inProfile.Preset, inProfile.Tuning, inProfile.AVCProfile, inProfile.UseBluRayCompatibility)) sb.AppendFormat(AppSettings.CInfo, "--weightp {0:0} ", inProfile.PFrameWeightedPrediction); // Slicing inProfile.NumSlices = GetSlices(inProfile, device); if (inProfile.NumSlices != 0) sb.AppendFormat(AppSettings.CInfo, "--slices {0:0} ", inProfile.NumSlices); if (!inProfile.CustomCommandLine.Contains("--slice-max-size ")) if (inProfile.MaxSliceSizeBytes != 0) sb.AppendFormat(AppSettings.CInfo, "--slice-max-size {0:0} ", inProfile.MaxSliceSizeBytes); if (!inProfile.CustomCommandLine.Contains("--slice-max-mbs ")) if (inProfile.MaxSliceSizeBlocks != 0) sb.AppendFormat(AppSettings.CInfo, "--slice-max-mbs {0:0} ", inProfile.MaxSliceSizeBlocks); #endregion #region rc tab if (!inProfile.CustomCommandLine.Contains("--qpmin")) if (inProfile.QuantizerMin != 0) sb.AppendFormat(AppSettings.CInfo, "--qpmin {0:0} ", inProfile.QuantizerMin); if (!inProfile.CustomCommandLine.Contains("--qpmax")) if (inProfile.QuantizerMax != 69) sb.AppendFormat(AppSettings.CInfo, "--qpmax {0:0} ", inProfile.QuantizerMax); if (!inProfile.CustomCommandLine.Contains("--qpstep")) if (inProfile.QuantizerDelta != 4) sb.AppendFormat(AppSettings.CInfo, "--qpstep {0:0} ", inProfile.QuantizerDelta); if (Math.Abs(inProfile.QuantizerRatioIP - 1.4F) > 0) { display = true; if (inProfile.Tuning == 3 && Math.Abs(inProfile.QuantizerRatioIP - 1.1F) <= 0) display = false; if (!inProfile.CustomCommandLine.Contains("--ipratio")) if (display) sb.AppendFormat(AppSettings.CInfo, "--ipratio {0:0} ", inProfile.QuantizerRatioIP); } if (Math.Abs(inProfile.QuantizerRatioPB - 1.3F) > 0) { display = true; if (inProfile.Tuning == 3 && Math.Abs(inProfile.QuantizerRatioPB - 1.1F) <= 0) display = false; if (!inProfile.CustomCommandLine.Contains("--pbratio")) if (display) sb.AppendFormat(AppSettings.CInfo, "--pbratio {0:0} ", inProfile.QuantizerRatioPB); } if (!inProfile.CustomCommandLine.Contains("--chroma-qp-offset")) if (inProfile.ChromaQPOffset != 0) sb.AppendFormat(AppSettings.CInfo, "--chroma-qp-offset {0:0} ", inProfile.ChromaQPOffset); if (inProfile.EncodingMode != 1) // doesn't apply to CQ mode { inProfile.VBVBufSize = GetVBVBufsize(inProfile, device); if (inProfile.VBVBufSize > 0) sb.AppendFormat(AppSettings.CInfo, "--vbv-bufsize {0:0} ", inProfile.VBVBufSize); inProfile.VBVMaxRate = GetVBVMaxrate(inProfile, device); if (inProfile.VBVMaxRate > 0) sb.AppendFormat(AppSettings.CInfo, "--vbv-maxrate {0:0} ", inProfile.VBVMaxRate); if (!inProfile.CustomCommandLine.Contains("--vbv-init")) if (Math.Abs(inProfile.VBVInitialBuffer - 0.9F) > 0) sb.AppendFormat(AppSettings.CInfo, "--vbv-init {0:0.0} ", inProfile.VBVInitialBuffer); if (!inProfile.CustomCommandLine.Contains("--ratetol")) if (Math.Abs(inProfile.BitrateVariance - 1.0F) > 0) sb.AppendFormat(AppSettings.CInfo, "--ratetol {0:0.0} ", inProfile.BitrateVariance); if (!inProfile.CustomCommandLine.Contains("--qcomp")) { display = true; if ((inProfile.Tuning == 3 && Math.Abs(inProfile.QuantizerCompression - 0.8F) <= 0) || (inProfile.Tuning != 3 && Math.Abs(inProfile.QuantizerCompression - 0.6F) <= 0)) display = false; if (display) sb.AppendFormat(AppSettings.CInfo, "--qcomp {0:0.0} ", inProfile.QuantizerCompression); } if (inProfile.EncodingMode > 1) // applies only to twopass { if (!inProfile.CustomCommandLine.Contains("--cplxblur")) if (inProfile.TempBlurFrameComplexity != 20) sb.AppendFormat(AppSettings.CInfo, "--cplxblur {0:0} ", inProfile.TempBlurFrameComplexity); if (!inProfile.CustomCommandLine.Contains("--qblur")) if (Math.Abs(inProfile.TempBlurQuant - 0.5F) > 0) sb.AppendFormat(AppSettings.CInfo, "--qblur {0:0.0} ", inProfile.TempBlurQuant); } } // Dead Zones if (!inProfile.CustomCommandLine.Contains("--deadzone-inter")) { display = true; if ((inProfile.Tuning != 3 && inProfile.DeadZoneInter == 21 && inProfile.DeadZoneIntra == 11) || (inProfile.Tuning == 3 && inProfile.DeadZoneInter == 6 && inProfile.DeadZoneIntra == 6)) display = false; if (display) sb.AppendFormat(AppSettings.CInfo, "--deadzone-inter {0:0} ", inProfile.DeadZoneInter); } if (!inProfile.CustomCommandLine.Contains("--deadzone-intra")) { display = true; if ((inProfile.Tuning != 3 && inProfile.DeadZoneIntra == 11) || (inProfile.Tuning == 3 && inProfile.DeadZoneIntra == 6)) display = false; if (display) sb.AppendFormat(AppSettings.CInfo, "--deadzone-intra {0:0} ", inProfile.DeadZoneIntra); } // Disable Macroblok Tree if (!inProfile.UseMBTree) { if (!inProfile.CustomCommandLine.Contains("--no-mbtree")) if (inProfile.Preset > 0) // preset veryfast sb.Append("--no-mbtree "); } else { // RC Lookahead if (!inProfile.CustomCommandLine.Contains("--rc-lookahead")) { display = false; switch (inProfile.Preset) { case 0: case 1: if (inProfile.NumFramesLookahead != 0) display = true; break; case 2: if (inProfile.NumFramesLookahead != 10) display = true; break; case 3: if (inProfile.NumFramesLookahead != 20) display = true; break; case 4: if (inProfile.NumFramesLookahead != 30) display = true; break; case 5: if (inProfile.NumFramesLookahead != 40) display = true; break; case 6: if (inProfile.NumFramesLookahead != 50) display = true; break; case 7: case 8: case 9: if (inProfile.NumFramesLookahead != 60) display = true; break; } if (display) sb.AppendFormat("--rc-lookahead {0:0} ", inProfile.NumFramesLookahead); } } // AQ-Mode if (inProfile.EncodingMode != 1) { if (!inProfile.CustomCommandLine.Contains("--aq-mode")) { if (inProfile.AdaptiveQuantizersMode != X264Settings.GetDefaultAQMode(inProfile.Preset, inProfile.Tuning)) sb.AppendFormat("--aq-mode {0:0} ", inProfile.AdaptiveQuantizersMode); } if (inProfile.AdaptiveQuantizersMode > 0) { display = false; switch (inProfile.Tuning) { case 2: if (Math.Abs(inProfile.AdaptiveQuantizersStrength - 0.6F) > 0) display = true; break; case 3: if (Math.Abs(inProfile.AdaptiveQuantizersStrength - 0.5F) > 0) display = true; break; case 7: if (Math.Abs(inProfile.AdaptiveQuantizersStrength - 1.3F) > 0) display = true; break; default: if (Math.Abs(inProfile.AdaptiveQuantizersStrength - 1.0F) > 0) display = true; break; } if (!inProfile.CustomCommandLine.Contains("--aq-strength")) if (display) sb.AppendFormat(AppSettings.CInfo, "--aq-strength {0:0.0} ", inProfile.AdaptiveQuantizersStrength); } } // custom matrices if (inProfile.AVCProfile > 1 && inProfile.QuantizerMatrix > 0) { switch (inProfile.QuantizerMatrix) { case 1: if (!inProfile.CustomCommandLine.Contains("--cqm")) sb.Append("--cqm \"jvt\" "); break; } } #endregion #region analysis tab // Disable Chroma Motion Estimation if (!inProfile.CustomCommandLine.Contains("--no-chroma-me")) if (!inProfile.UseChromaMotionEstimation) sb.Append("--no-chroma-me "); // Motion Estimation Range if (!inProfile.CustomCommandLine.Contains("--merange")) { if ((inProfile.Preset <= 7 && inProfile.MotionEstimationRange != 16) || (inProfile.Preset >= 8 && inProfile.MotionEstimationRange != 24)) sb.AppendFormat("--merange {0:0} ", inProfile.MotionEstimationRange); } // ME Type if (!inProfile.CustomCommandLine.Contains("--me ")) { display = false; switch (inProfile.Preset) { case 0: case 1: if (inProfile.MotionEstimationAlgorithm != 0) display = true; break; case 2: case 3: case 4: case 5: if (inProfile.MotionEstimationAlgorithm != 1) display = true; break; case 6: case 7: case 8: if (inProfile.MotionEstimationAlgorithm != 2) display = true; break; case 9: if (inProfile.MotionEstimationAlgorithm != 4) display = true; break; } if (display) { switch (inProfile.MotionEstimationAlgorithm) { case 0: sb.Append("--me dia "); break; case 1: sb.Append("--me hex "); break; case 2: sb.Append("--me umh "); break; case 3: sb.Append("--me esa "); break; case 4: sb.Append("--me tesa "); break; } } } if (!inProfile.CustomCommandLine.Contains("--direct ")) { display = false; if (inProfile.Preset > 5) // preset medium { if (inProfile.MVPredictionMod != 3) display = true; } else if (inProfile.MVPredictionMod != 1) display = true; if (display) { switch (inProfile.MVPredictionMod) { case 0: sb.Append("--direct none "); break; case 1: sb.Append("--direct spatial "); break; case 2: sb.Append("--direct temporal "); break; case 3: sb.Append("--direct auto "); break; } } } if (!inProfile.CustomCommandLine.Contains("--nr ")) if (inProfile.NoiseReduction > 0) sb.AppendFormat("--nr {0:0} ", inProfile.NoiseReduction); // subpel refinement if (!inProfile.CustomCommandLine.Contains("--subme ")) { display = false; switch (inProfile.Preset) { case 0: if (inProfile.SubPixelRefinement != 0) display = true; break; case 1: if (inProfile.SubPixelRefinement != 1) display = true; break; case 2: if (inProfile.SubPixelRefinement != 2) display = true; break; case 3: if (inProfile.SubPixelRefinement != 4) display = true; break; case 4: if (inProfile.SubPixelRefinement != 6) display = true; break; case 5: if (inProfile.SubPixelRefinement != 7) display = true; break; case 6: if (inProfile.SubPixelRefinement != 8) display = true; break; case 7: if (inProfile.SubPixelRefinement != 9) display = true; break; case 8: if (inProfile.SubPixelRefinement != 10) display = true; break; case 9: if (inProfile.SubPixelRefinement != 11) display = true; break; } if (display) sb.AppendFormat("--subme {0:0} ", inProfile.SubPixelRefinement); } // macroblock types if (!inProfile.CustomCommandLine.Contains("--partitions ")) { bool bExpectedP8X8Mv = true; bool bExpectedB8X8Mv = true; bool bExpectedI4X4Mv = true; bool bExpectedI8X8Mv = true; bool bExpectedP4X4Mv = true; switch (inProfile.Preset) { case 0: bExpectedP8X8Mv = false; bExpectedB8X8Mv = false; bExpectedI4X4Mv = false; bExpectedI8X8Mv = false; bExpectedP4X4Mv = false; break; case 1: bExpectedP8X8Mv = false; bExpectedB8X8Mv = false; bExpectedP4X4Mv = false; break; case 2: case 3: case 4: case 5: case 6: bExpectedP4X4Mv = false; break; } if (inProfile.Tuning == 7 && bExpectedP8X8Mv) bExpectedP4X4Mv = true; if (inProfile.AVCProfile < 2) bExpectedI8X8Mv = false; if (bExpectedP8X8Mv != inProfile.MacroBlocksPartitionsP8X8 || bExpectedB8X8Mv != inProfile.MacroBlocksPartitionsB8X8 || bExpectedI4X4Mv != inProfile.MacroBlocksPartitionsI4X4 || bExpectedI8X8Mv != inProfile.MacroBlocksPartitionsI8X8 || bExpectedP4X4Mv != inProfile.MacroBlocksPartitionsP4X4) { if (inProfile.MacroBlocksPartitionsP8X8 || inProfile.MacroBlocksPartitionsB8X8 || inProfile.MacroBlocksPartitionsI4X4 || inProfile.MacroBlocksPartitionsI8X8 || inProfile.MacroBlocksPartitionsP4X4) { sb.Append("--partitions "); if (inProfile.MacroBlocksPartitionsI4X4 && inProfile.MacroBlocksPartitionsI8X8 && inProfile.MacroBlocksPartitionsP4X4 && inProfile.MacroBlocksPartitionsP8X8 && inProfile.MacroBlocksPartitionsB8X8) sb.Append("all "); else { if (inProfile.MacroBlocksPartitionsP8X8) // default is checked sb.Append("p8x8,"); if (inProfile.MacroBlocksPartitionsB8X8) // default is checked sb.Append("b8x8,"); if (inProfile.MacroBlocksPartitionsI4X4) // default is checked sb.Append("i4x4,"); if (inProfile.MacroBlocksPartitionsP4X4) // default is unchecked sb.Append("p4x4,"); if (inProfile.MacroBlocksPartitionsI8X8) // default is checked sb.Append("i8x8"); if (sb.ToString().EndsWith(",")) sb.Remove(sb.Length - 1, 1); } if (!sb.ToString().EndsWith(" ")) sb.Append(" "); } else sb.Append("--partitions none "); } } if (inProfile.AVCProfile > 1 && !inProfile.CustomCommandLine.Contains("--no-8x8dct")) if (!inProfile.MacroBlocksPartitionsAdaptiveDCT) if (inProfile.Preset > 0) sb.Append("--no-8x8dct "); // Trellis if (!inProfile.CustomCommandLine.Contains("--trellis ")) { display = false; switch (inProfile.Preset) { case 0: case 1: case 2: if (inProfile.Trellis != 0) display = true; break; case 3: case 4: case 5: case 6: if (inProfile.Trellis != 1) display = true; break; case 7: case 8: case 9: if (inProfile.Trellis != 2) display = true; break; } if (display) sb.AppendFormat("--trellis {0:0} ", inProfile.Trellis); } if (!inProfile.CustomCommandLine.Contains("--psy-rd ")) { if (inProfile.SubPixelRefinement > 5) { display = false; switch (inProfile.Tuning) { case 1: if ((Math.Abs(inProfile.PsyRDStrength - 1.0F) > 0) || (Math.Abs(inProfile.PsyTrellisStrength - 0.15F) > 0)) display = true; break; case 2: if ((Math.Abs(inProfile.PsyRDStrength - 0.4F) > 0) || (Math.Abs(inProfile.PsyTrellisStrength - 0.0F) > 0)) display = true; break; case 3: if ((Math.Abs(inProfile.PsyRDStrength - 1.0F) > 0) || (Math.Abs(inProfile.PsyTrellisStrength - 0.25F) > 0)) display = true; break; case 7: if ((Math.Abs(inProfile.PsyRDStrength - 1.0F) > 0) || (Math.Abs(inProfile.PsyTrellisStrength - 0.2F) > 0)) display = true; break; default: if ((Math.Abs(inProfile.PsyRDStrength - 1.0F) > 0) || (Math.Abs(inProfile.PsyTrellisStrength - 0.0F) > 0)) display = true; break; } if (display) sb.AppendFormat(AppSettings.CInfo, "--psy-rd {0:0.00}:{1:0.00} ", inProfile.PsyRDStrength, inProfile.PsyTrellisStrength); } } if (!inProfile.CustomCommandLine.Contains("--no-mixed-refs")) if (inProfile.UseNoMixedReferenceFrames) if (inProfile.Preset >= 4) // preset fast sb.Append("--no-mixed-refs "); if (!inProfile.CustomCommandLine.Contains("--no-dct-decimate")) if (inProfile.UseNoDCTDecimation) if (inProfile.Tuning != 3) // tune grain sb.Append("--no-dct-decimate "); if (!inProfile.CustomCommandLine.Contains("--no-fast-pskip")) if (inProfile.UseNoFastPSkip) if (inProfile.Preset != 9) // preset placebo sb.Append("--no-fast-pskip "); if (!inProfile.CustomCommandLine.Contains("--no-psy")) if (inProfile.UseNoPsychovisualEnhancements && (inProfile.Tuning != 5 && inProfile.Tuning != 6)) sb.Append("--no-psy "); inProfile.UseAccessUnitDelimiters = GetAud(inProfile, device); if (inProfile.UseAccessUnitDelimiters && !inProfile.UseBluRayCompatibility) sb.Append("--aud "); inProfile.HRDInfo = GetNalHrd(inProfile, device); switch (inProfile.HRDInfo) { case 1: if (!inProfile.UseBluRayCompatibility) sb.Append("--nal-hrd vbr "); break; case 2: sb.Append("--nal-hrd cbr "); break; } if (!inProfile.CustomCommandLine.Contains("--non-deterministic")) if (inProfile.UseNonDeterministic) sb.Append("--non-deterministic "); #endregion #region misc tab if (!inProfile.CustomCommandLine.Contains("--psnr")) if (inProfile.UsePSNRCalculation) sb.Append("--psnr "); if (!inProfile.CustomCommandLine.Contains("--ssim")) if (inProfile.UseSSIMCalculation) sb.Append("--ssim "); if (!inProfile.CustomCommandLine.Contains("--range ")) switch (inProfile.VUIRange) { case 1: sb.AppendFormat("--range tv "); break; case 2: sb.Append("--range pc "); break; } #endregion #region input / ouput / custom string customSarValue = string.Empty; Dar? d = new Dar((ulong)hRes, (ulong)vRes); if (inProfile.UseAutoSelectSAR) { int tempValue = GetSar(inProfile, d, hRes, vRes, out customSarValue, String.Empty); inProfile.ForceSAR = tempValue; } if (inProfile.UseAutoSelectColorSettings) { inProfile.ColorPrimaries = GetColorprim(inProfile, format); inProfile.Transfer = GetTransfer(inProfile, format); inProfile.ColorMatrix = GetColorMatrix(inProfile, format); } if (device.BluRay) { if (inProfile.InterlaceMode < 2) inProfile.InterlaceMode = GetInterlacedMode(format); inProfile.UseFakeInterlaced = GetFakeInterlaced(inProfile, format, fpsN, fpsD); inProfile.UseForcePicStruct = GetPicStruct(inProfile, format); inProfile.Pulldown = GetPulldown(inProfile, format, fpsN, fpsD); } else { if (inProfile.InterlaceMode == 0) inProfile.InterlaceMode = GetInterlacedMode(format); if (inProfile.Pulldown == 0) inProfile.Pulldown = GetPulldown(inProfile, format, fpsN, fpsD); } if (!inProfile.CustomCommandLine.Contains("--bff") && !inProfile.CustomCommandLine.Contains("--tff")) { switch (inProfile.InterlaceMode) { case 2: sb.Append("--bff "); break; case 3: sb.Append("--tff "); break; } } if (!inProfile.CustomCommandLine.Contains("--fake-interlaced")) { if (inProfile.UseFakeInterlaced && inProfile.InterlaceMode == 1) sb.Append("--fake-interlaced "); } if (!inProfile.CustomCommandLine.Contains("--pic-struct")) { if (inProfile.UseForcePicStruct && inProfile.InterlaceMode == 1 && inProfile.Pulldown == 0) sb.Append("--pic-struct "); } if (!inProfile.CustomCommandLine.Contains("--colorprim")) { switch (inProfile.ColorPrimaries) { case 0: break; case 1: sb.Append("--colorprim bt709 "); break; case 2: sb.Append("--colorprim bt470m "); break; case 3: sb.Append("--colorprim bt470bg "); break; case 4: sb.Append("--colorprim smpte170m "); break; case 5: sb.Append("--colorprim smpte240m "); break; case 6: sb.Append("--colorprim film "); break; } } if (!inProfile.CustomCommandLine.Contains("--transfer")) { switch (inProfile.Transfer) { case 0: break; case 1: sb.Append("--transfer bt709 "); break; case 2: sb.Append("--transfer bt470m "); break; case 3: sb.Append("--transfer bt470bg "); break; case 4: sb.Append("--transfer linear "); break; case 5: sb.Append("--transfer log100 "); break; case 6: sb.Append("--transfer log316 "); break; case 7: sb.Append("--transfer smpte170m "); break; case 8: sb.Append("--transfer smpte240m "); break; } } if (!inProfile.CustomCommandLine.Contains("--colormatrix")) { switch (inProfile.ColorMatrix) { case 0: break; case 1: sb.Append("--colormatrix bt709 "); break; case 2: sb.Append("--colormatrix fcc "); break; case 3: sb.Append("--colormatrix bt470bg "); break; case 4: sb.Append("--colormatrix smpte170m "); break; case 5: sb.Append("--colormatrix smpte240m "); break; case 6: sb.Append("--colormatrix GBR "); break; case 7: sb.Append("--colormatrix YCgCo "); break; } } if (!inProfile.CustomCommandLine.Contains("--pulldown")) { switch (inProfile.Pulldown) { case 0: break; case 1: break; case 2: sb.Append("--pulldown 22 "); break; case 3: sb.Append("--pulldown 32 "); break; case 4: sb.Append("--pulldown 64 "); break; case 5: sb.Append("--pulldown double "); break; case 6: sb.Append("--pulldown triple "); break; case 7: sb.Append("--pulldown euro "); break; } } if (!String.IsNullOrEmpty(inProfile.CustomCommandLine)) // add custom encoder options sb.Append(Regex.Replace(inProfile.CustomCommandLine, @"\r\n?|\n", string.Empty).Trim() + " "); if (!inProfile.CustomCommandLine.Contains("--sar")) { switch (inProfile.ForceSAR) { case 0: { if (!String.IsNullOrEmpty(customSarValue)) sb.Append("--sar " + customSarValue + " "); break; } case 1: sb.Append("--sar 1:1 "); break; case 2: sb.Append("--sar 4:3 "); break; case 3: sb.Append("--sar 8:9 "); break; case 4: sb.Append("--sar 10:11 "); break; case 5: sb.Append("--sar 12:11 "); break; case 6: sb.Append("--sar 16:11 "); break; case 7: sb.Append("--sar 32:27 "); break; case 8: sb.Append("--sar 40:33 "); break; case 9: sb.Append("--sar 64:45 "); break; } } if (!inProfile.CustomCommandLine.Contains("--frame-packing")) { if (stereo != StereoEncoding.None) sb.Append("--frame-packing 3 "); } //add the rest of the commandline regarding the output if ((inProfile.EncodingMode == 2 || inProfile.EncodingMode == 3) && (tempPass == 1)) sb.Append("--output NUL "); else if (!String.IsNullOrEmpty(outFile)) sb.AppendFormat("--output \"{0}\" ", outFile); if (!String.IsNullOrEmpty(inFile)) { if (String.CompareOrdinal(inFile, "-") == 0) sb.AppendFormat("--demuxer y4m - "); else sb.AppendFormat("\"{0}\" ", inFile); } #endregion } return sb.ToString(); }
/// <summary> /// Generates AviSynth script used for video encoding /// </summary> /// <param name="videoInfo">All video properties</param> /// <param name="changeFps">Defines whether framerate should be changed</param> /// <param name="targetFps">Sets target framerate</param> /// <param name="resizeTo">Sets target video resolution</param> /// <param name="stereoEncoding">Defines, which stereo encoding mode should be used</param> /// <param name="stereoVideoInfo">Sets all parameters for stereo encoding</param> /// <param name="isDvdResolution">Defines whether target resolution is used for DVD encoding</param> /// <param name="subtitleFile">Sets subtitle file for hardcoding into video</param> /// <param name="subtitleOnlyForced">Defines whether only forced captions should be hardcoded</param> /// <returns>Path to AviSynth script</returns> public static string Generate(VideoInfo videoInfo, bool changeFps, float targetFps, Size resizeTo, StereoEncoding stereoEncoding, StereoVideoInfo stereoVideoInfo, bool isDvdResolution, string subtitleFile, bool subtitleOnlyForced) { StringBuilder sb = new StringBuilder(); bool mtUseful = (videoInfo.Interlaced && AppSettings.UseHQDeinterlace) || changeFps; bool useStereo = stereoEncoding != StereoEncoding.None && stereoVideoInfo.RightStreamId > -1; // support for multithreaded AviSynth if (AppSettings.UseAviSynthMT && mtUseful) { sb.AppendLine("SetMTMode(2,0)"); sb.AppendLine("SetMemoryMax(512)"); } //loading plugins sb.AppendLine(ImportFFMPEGSource()); // ffms2 if (changeFps || (videoInfo.Interlaced && AppSettings.UseHQDeinterlace)) sb.AppendLine(string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "mvtools2.dll"))); if (videoInfo.Interlaced && AppSettings.UseHQDeinterlace) { sb.AppendLine(AppSettings.LastAviSynthVer.StartsWith("2.5") ? string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "mt_masktools-25.dll")) : string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "mt_masktools-26.dll"))); sb.AppendLine(string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "nnedi3.dll"))); sb.AppendLine(string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "RemoveGrainSSE2.dll"))); sb.AppendLine(string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "RepairSSE2.dll"))); sb.AppendLine(string.Format(AppSettings.CInfo, "Import(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "QTGMC-3.32.avsi"))); } else if (videoInfo.Interlaced) { sb.AppendLine(string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "Decomb.dll"))); } if (useStereo) sb.AppendLine(string.Format(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "H264StereoSource.dll"))); if (!string.IsNullOrEmpty(subtitleFile) && File.Exists(subtitleFile)) { switch (Path.GetExtension(subtitleFile)) { case "sup": sb.AppendFormat(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "SupTitle.dll")); break; case "ass": case "ssa": case "srt": sb.AppendFormat(AppSettings.CInfo, "LoadPlugin(\"{0:s}\")", Path.Combine(AppSettings.AppPath, "AvsPlugins", "VSFilter.dll")); break; } sb.AppendLine(); } //generate rest of the script // calculate framerate numerator & denominator if (videoInfo.FPS <= 0) { MediaInfoContainer mi = new MediaInfoContainer(); try { mi = Processing.GetMediaInfo(videoInfo.TempFile); } catch (TimeoutException ex) { Log.Error(ex); mi = new MediaInfoContainer(); } finally { if (mi.Video.Count > 0) { videoInfo.FPS = mi.Video[0].FrameRate; Processing.GetFPSNumDenom(videoInfo.FPS, out videoInfo.FrameRateEnumerator, out videoInfo.FrameRateDenominator); if (videoInfo.FrameRateEnumerator == 0) { videoInfo.FrameRateEnumerator = (int)Math.Round(videoInfo.FPS) * 1000; videoInfo.FrameRateDenominator = (int)(Math.Round(Math.Ceiling(videoInfo.FPS) - Math.Floor(videoInfo.FPS)) + 1000); } } } } if (videoInfo.FrameRateEnumerator > 0 && videoInfo.FrameRateDenominator > 0) sb.AppendLine(string.Format(AppSettings.CInfo, "FFVideoSource(\"{0:s}\",fpsnum={1:0},fpsden={2:0},threads=1)", videoInfo.TempFile, videoInfo.FrameRateEnumerator, videoInfo.FrameRateDenominator)); else sb.AppendLine(string.Format(AppSettings.CInfo, "FFVideoSource(\"{0:s}\",threads=1)", videoInfo.TempFile)); string stereoVar = string.Empty; if (useStereo) { string configFile = GenerateStereoSourceConfig(stereoVideoInfo); sb.AppendLine(string.Format(AppSettings.CInfo, "VideoRight = H264StereoSource(\"{0:s}\",{1:g})", configFile, videoInfo.FrameCount - 50)); StereoConfigFile = configFile; stereoVar = "VideoRight"; } // deinterlace video source if (videoInfo.Interlaced) { if (AppSettings.UseHQDeinterlace) sb.AppendLine("QTGMC(Preset=\"Slower\")"); else { sb.AppendLine("ConvertToYUY2(interlaced=true)"); sb.AppendLine("Telecide(post=4)"); sb.AppendLine("Crop(4, 0, -4, 0)"); sb.AppendLine("AddBorders(4, 0, 4, 0)"); sb.AppendLine("ConvertToYV12()"); } } // hardcode subtitles if (!string.IsNullOrEmpty(subtitleFile) && File.Exists(subtitleFile)) { switch (Path.GetExtension(subtitleFile)) { case "sup": sb.AppendFormat(AppSettings.CInfo, "SupTitle(\"{0}\", forcedOnly={1})", subtitleFile, subtitleOnlyForced ? "true" : "false"); break; case "ass": case "ssa": case "srt": sb.AppendFormat(AppSettings.CInfo, "TextSub(\"{0}\")", subtitleFile); break; } sb.AppendLine(); } // video cropping if (!videoInfo.CropRect.IsEmpty) { int temp; Math.DivRem(videoInfo.CropRect.X, 2, out temp); videoInfo.CropRect.X += temp; Math.DivRem(videoInfo.CropRect.Y, 2, out temp); videoInfo.CropRect.Y += temp; Math.DivRem(videoInfo.CropRect.Width, 2, out temp); videoInfo.CropRect.Width += temp; Math.DivRem(videoInfo.CropRect.Height, 2, out temp); videoInfo.CropRect.Height += temp; videoInfo.Height = videoInfo.CropRect.Height; videoInfo.Width = videoInfo.CropRect.Width; if ((videoInfo.CropRect.X > 0) || (videoInfo.CropRect.Y > 0) || (videoInfo.CropRect.Width < videoInfo.Width) || (videoInfo.CropRect.Height < videoInfo.Height)) { sb.AppendLine(string.Format(AppSettings.CInfo, "Crop({0:g},{1:g},{2:g},{3:g})", videoInfo.CropRect.Left, videoInfo.CropRect.Top, videoInfo.CropRect.Width, videoInfo.CropRect.Height)); if (useStereo) { sb.AppendLine(string.Format(AppSettings.CInfo, "CroppedVideoRight = Crop(VideoRight,{0:g},{1:g},{2:g},{3:g})", videoInfo.CropRect.Left, videoInfo.CropRect.Top, videoInfo.CropRect.Width, videoInfo.CropRect.Height)); stereoVar = "CroppedVideoRight"; } } } // Side-By-Side stereo encoding if (!string.IsNullOrEmpty(stereoVar)) { switch(stereoEncoding) { case StereoEncoding.FullSideBySideLeft: case StereoEncoding.HalfSideBySideLeft: sb.AppendLine(string.Format("StackHorizontal(last,{0})", stereoVar)); break; case StereoEncoding.FullSideBySideRight: case StereoEncoding.HalfSideBySideRight: sb.AppendLine(string.Format("StackHorizontal({0},last)", stereoVar)); break; } sb.AppendLine("ConvertToYV12()"); } int calculatedHeight = videoInfo.Height; int calculatedWidth = videoInfo.Width; int borderRight = 0; int borderLeft = 0; int borderBottom = 0; int borderTop = 0; bool addBorders = false; // video resizing if (!resizeTo.IsEmpty && (resizeTo.Height != videoInfo.Height || resizeTo.Width != videoInfo.Width)) { // aspect ratios float toAr = (float) Math.Round(resizeTo.Width / (float)resizeTo.Height, 3); calculatedWidth = resizeTo.Width; float mod = 1f; if (videoInfo.AspectRatio > toAr) // source aspectratio higher than target aspectratio { if (isDvdResolution) { calculatedHeight = (int)(calculatedWidth / videoInfo.AspectRatio); if (calculatedHeight > resizeTo.Height) calculatedHeight = resizeTo.Height; calculatedWidth = 720; } else { calculatedWidth = resizeTo.Width; calculatedHeight = (int)(calculatedWidth / videoInfo.AspectRatio); } int temp; Math.DivRem(calculatedWidth, 2, out temp); calculatedWidth += temp; Math.DivRem(calculatedHeight, 2, out temp); calculatedHeight += temp; if (calculatedHeight != resizeTo.Height) { addBorders = true; int borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight/2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; } } else if (Math.Abs(videoInfo.AspectRatio - toAr) <= 0) // source and target aspectratio equals { if (isDvdResolution) { calculatedHeight = (int)(calculatedWidth / videoInfo.AspectRatio); calculatedWidth = 720; if (calculatedHeight > resizeTo.Height) calculatedHeight = resizeTo.Height; } else { calculatedWidth = resizeTo.Width; calculatedHeight = (int) (calculatedWidth/toAr); } int temp; Math.DivRem(calculatedWidth, 2, out temp); calculatedWidth += temp; Math.DivRem(calculatedHeight, 2, out temp); calculatedHeight += temp; if (calculatedHeight != resizeTo.Height) { addBorders = true; int borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight/2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; } } else { if (videoInfo.AspectRatio > 1.4f && isDvdResolution) // source aspectratio not 4:3, encoding for dvd resolution { mod = 720f/resizeTo.Width; calculatedHeight = (int)(calculatedWidth / videoInfo.AspectRatio); if (calculatedHeight > resizeTo.Height) { calculatedHeight = resizeTo.Height; calculatedWidth = (int)(calculatedHeight * videoInfo.AspectRatio * mod); } else calculatedWidth = 720; } else if (isDvdResolution) { calculatedHeight = resizeTo.Height; calculatedWidth = (int) (calculatedHeight*videoInfo.AspectRatio); } else calculatedHeight = resizeTo.Height; int temp; Math.DivRem(calculatedWidth, 2, out temp); calculatedWidth += temp; Math.DivRem(calculatedHeight, 2, out temp); calculatedHeight += temp; if (Math.Abs(toAr - 1.778f) <= 0) // aspectratio 16:9 { addBorders = true; int borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight/2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; int borderWidth = (int) ((resizeTo.Width*mod) - calculatedWidth); borderLeft = borderWidth/2; Math.DivRem(borderLeft, 2, out temp); borderLeft += temp; borderRight = borderWidth - borderLeft; } else if (calculatedWidth != resizeTo.Width) { addBorders = true; int borderWidth = resizeTo.Width - calculatedWidth; borderLeft = borderWidth/2; Math.DivRem(borderLeft, 2, out temp); borderLeft += temp; borderRight = borderWidth - borderLeft; int borderHeight = resizeTo.Height - calculatedHeight; borderTop = borderHeight/2; Math.DivRem(borderTop, 2, out temp); borderTop += temp; borderBottom = borderHeight - borderTop; } } } // apply resize filter if (calculatedHeight != videoInfo.Height || calculatedWidth != videoInfo.Width || (stereoEncoding == StereoEncoding.HalfSideBySideLeft || stereoEncoding == StereoEncoding.HalfSideBySideRight && useStereo)) { if (calculatedHeight < videoInfo.Height || calculatedWidth < videoInfo.Width || (stereoEncoding == StereoEncoding.HalfSideBySideLeft || stereoEncoding == StereoEncoding.HalfSideBySideRight && useStereo)) sb.AppendLine(string.Format(AppSettings.CInfo, "BicubicResize({0:g},{1:g})", calculatedWidth, calculatedHeight)); else sb.AppendLine(string.Format(AppSettings.CInfo, "Lanczos4Resize({0:g},{1:g})", calculatedWidth, calculatedHeight)); } // add borders if needed if (addBorders && (borderLeft > 0 || borderRight > 0 || borderTop > 0 || borderBottom > 0)) sb.AppendLine(string.Format(AppSettings.CInfo, "AddBorders({0:g},{1:g},{2:g},{3:g})", borderLeft, borderTop, borderRight, borderBottom)); // change framerate if (changeFps) { int fpsnum; int fpsden; // get framerate numerator & denominator for target framerate Processing.GetFPSNumDenom(targetFps, out fpsnum, out fpsden); // source is 23.976 or 24 fps if (videoInfo.FrameRateEnumerator == 24000 && (videoInfo.FrameRateDenominator == 1001 || videoInfo.FrameRateDenominator == 1000)) { if (fpsnum == 30000 && fpsden == 1001) { // 3:2 pulldown / telecine sb.AppendLine("AssumeFrameBased()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEvery(8, 0, 1, 2, 3, 2, 5, 4, 7, 6, 7)"); sb.AppendLine("Weave()"); } else if (fpsnum == 25000 && fpsden == 1000) { // convert to 25 fps sb.AppendLine("ConvertToYUY2()"); sb.AppendLine("ConvertFPS(50)"); sb.AppendLine("AssumeTFF()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEvery(4,0,3)"); sb.AppendLine("Weave()"); sb.AppendLine("ConvertToYV12()"); } } // source is 30fps else if (videoInfo.FrameRateEnumerator == 30000) { sb.AppendLine("ConvertToYUY2()"); sb.AppendLine("DoubleWeave()"); sb.AppendLine(string.Format(AppSettings.CInfo, "ConvertFPS({0:0.000})", targetFps*2)); sb.AppendLine("SelectEven()"); sb.AppendLine("ConvertToYV12()"); } // source is 25fps else if (videoInfo.FrameRateEnumerator == 25000 && videoInfo.FrameRateDenominator == 1000) { if ((fpsnum == 30000 || fpsnum == 24000) && fpsden == 1001) { sb.AppendLine("ConvertToYUY2()"); sb.AppendLine(string.Format(AppSettings.CInfo, "ConvertFPS({0:0.000}*2)", 23.976)); if (fpsnum == 30000) { sb.AppendLine("AssumeFrameBased()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEvery(8, 0, 1, 2, 3, 2, 5, 4, 7, 6, 7)"); } else { sb.AppendLine("AssumeTFF()"); sb.AppendLine("SeparateFields()"); sb.AppendLine("SelectEven()"); } sb.AppendLine("Weave()"); sb.AppendLine("ConvertToYV12()"); } } // every other framerate else { // very slow framerate interpolation sb.AppendLine("super = MSuper(pel=2)"); sb.AppendLine("backward_vec = MAnalyse(super, overlap=4, isb = true, search=3)"); sb.AppendLine("forward_vec = MAnalyse(super, overlap=4, isb = false, search=3)"); sb.AppendFormat("MFlowFps(super, backward_vec, forward_vec, num={0:0}, den={1:0})", fpsnum, fpsden); } sb.AppendLine(); } // multithreaded avisynth if (AppSettings.UseAviSynthMT && mtUseful) { sb.AppendLine("SetMTMode(1)"); sb.AppendLine("GetMTMode(false) > 0 ? distributor() : last"); } return WriteScript(sb.ToString()); }