/// <summary> /// Prepares the files of an existing job that we resume. /// </summary> /// <returns>Whether job still needs to execute.</returns> //private bool PrepareResumeJob(MediaEncoderSettings settings) { // AvisynthTools.EditStartPosition(settings.ScriptFile, 0); // // At least one segment has been processed. Check if the entire file has been processed. // ProcessStartOptions Options = new ProcessStartOptions(settings.JobIndex, "Resuming...", false).TrackProcess(settings); // Task<long> TaskCount = Task.Run(() => AvisynthTools.GetFrameCount(settings.ScriptFile, Options)); // int Segment = 0; // List<Task<long>> TaskList = new List<Task<long>>(); // while (File.Exists(PathManager.GetOutputFile(settings.JobIndex, ++Segment, settings.VideoCodec)) && settings.CompletionStatus != CompletionStatus.Cancelled) { // string SegmentFile = PathManager.GetOutputFile(settings.JobIndex, Segment, settings.VideoCodec); // // Discard segments of less than 10kb. // if (new FileInfo(SegmentFile).Length > 10000) { // int SegmentLocal = Segment; // TaskList.Add(Task.Run(() => AvisynthTools.GetFrameCount(PathManager.GetOutputFile(settings.JobIndex, SegmentLocal, settings.VideoCodec), null))); // } else { // // There shouldn't be any resumed job following a segment that is being deleted. // File.Delete(SegmentFile); // break; // } // } // long OutputFrames = 0; // Task.WaitAll(TaskList.ToArray()); // foreach (Task<long> item in TaskList) { // OutputFrames += item.Result; // } // TaskCount.Wait(); // if (settings.CompletionStatus == CompletionStatus.Cancelled) // return false; // long ScriptFrames = TaskCount.Result; // if (OutputFrames >= ScriptFrames) { // // Job completed. // //EncodingCompletedEventArgs EncodeResult = FinalizeEncoding(settings, null); // //if (EncodeResult != null) // // EncodingCompleted(this, EncodeResult); // //else { // // PathManager.DeleteJobFiles(settings.JobIndex); // //} // return false; // } else { // // Resume with new segment. // AvisynthTools.EditStartPosition(settings.ScriptFile, OutputFrames); // settings.ResumeSegment = Segment; // settings.ResumePos = OutputFrames; // File.Delete(settings.OutputFile); // return true; // } //} private async Task GetMediaInfo(string previewFile, MediaEncoderSettings settings) { FFmpegProcess FInfo = await Task.Run(() => MediaInfo.GetFileInfo(previewFile)); FFmpegVideoStreamInfo VInfo = FInfo.VideoStream; FFmpegAudioStreamInfo AInfo = settings.ConvertToAvi ? await Task.Run(() => MediaInfo.GetFileInfo(settings.FilePath).AudioStream) : FInfo.AudioStream; settings.SourceWidth = FInfo.VideoStream.Width; settings.SourceHeight = FInfo.VideoStream.Height; if (settings.SourceHeight > 768) { settings.OutputHeight = settings.SourceHeight.Value; } settings.SourceAspectRatio = (float)(VInfo?.PixelAspectRatio ?? 1); // Fix last track of VCDs that is widescreen. if (settings.SourceHeight == 288 && settings.SourceWidth == 352 && settings.SourceAspectRatio == 1.485f) { settings.SourceAspectRatio = 1.092f; } settings.SourceFrameRate = VInfo?.FrameRate; settings.SourceAudioFormat = AInfo?.Format; settings.SourceVideoFormat = VInfo?.Format; bool IsTvRange = VInfo?.ColorRange != "pc"; if (!string.IsNullOrEmpty(VInfo?.ColorMatrix)) { settings.SourceColorMatrix = VInfo.ColorMatrix.EndsWith("601") ? (IsTvRange ? ColorMatrix.Rec601 : ColorMatrix.Pc601) : (IsTvRange ? ColorMatrix.Rec709 : ColorMatrix.Pc709); } else { settings.SourceColorMatrix = VInfo?.Height < 600 ? (IsTvRange ? ColorMatrix.Rec601 : ColorMatrix.Pc601) : (IsTvRange ? ColorMatrix.Rec709 : ColorMatrix.Pc709); } settings.SourceChromaPlacement = string.Compare(VInfo?.Format, "mpeg1video", true) == 0 ? ChromaPlacement.MPEG1 : ChromaPlacement.MPEG2; settings.DegrainPrefilter = VInfo?.Height < 600 ? DegrainPrefilters.SD : DegrainPrefilters.HD; settings.SourceVideoBitrate = (int)(new FileInfo(previewFile).Length / FInfo.FileDuration.TotalSeconds / 1024 * 8); settings.SourceAudioBitrate = AInfo?.Bitrate; if (!settings.HasAudioOptions) { settings.AudioQuality = AInfo?.Bitrate > 0 ? AInfo.Bitrate : 256; } if (settings.AudioQuality > 384) { settings.AudioQuality = 384; } settings.SourceBitDepth = 8; // VInfo.BitDepth; //settings.DenoiseD = 2; //settings.DenoiseA = settings.SourceHeight < 720 ? 2 : 1; settings.Position = FInfo.FileDuration.TotalSeconds / 2; settings.VideoAction = settings.SourceHeight >= 1080 ? VideoAction.x264 : VideoAction.x265; settings.EncodeQuality = settings.SourceHeight >= 1080 ? 23 : 22; settings.EncodePreset = settings.SourceHeight >= 1080 ? EncodePresets.veryslow : EncodePresets.medium; // Use Cache to open file when file is over 500MB settings.CalculateSize(); }
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); }
public CompletionStatus GenerateDeshakerLog(MediaEncoderSettings settings, string inputFile) { // Prepare Deshaker settings. settings.DeshakerSettings.Pass = 1; settings.DeshakerSettings.LogFile = settings.DeshakerTempLog; settings.DeshakerSettings.SourcePixelAspectRatio = settings.SourceAspectRatio.Value; // settings.DeshakerSettings.AppendToFile = true; File.Delete(settings.DeshakerLog); // Start UI. CompletionStatus Result = CompletionStatus.Success; object JobId = "Deshaker"; FFmpegConfig.UserInterfaceManager.Start(JobId, "Running Deshaker Prescan"); ProcessStartOptions JobOptions = new ProcessStartOptions(JobId, "Getting Frame Count", false); // Get frame count. settings.CalculateSize(); int FrameStart = (int)((settings.DeshakerSettings.PrescanStart ?? 0) * settings.SourceFrameRate.Value); int FrameEnd = (int)((settings.DeshakerSettings.PrescanEnd ?? 0) * settings.SourceFrameRate.Value); string Script = MediaEncoderScript.GenerateDeshakerScript(settings, inputFile, 0, FrameStart, FrameEnd); File.WriteAllText(settings.DeshakerScript, Script); JobOptions.FrameCount = AvisynthTools.GetFrameCount(settings.DeshakerScript, JobOptions); // Pad file start. using (StreamWriter sw = new StreamWriter(File.Open(settings.DeshakerLog, FileMode.Create), Encoding.ASCII)) { for (int i = 0; i < FrameStart; i++) { sw.WriteLine((i + 1).ToString().PadLeft(7) + " skipped # 0.00 0.00 "); } } // Run segments. var Segments = settings.DeshakerSettings.Segments; if (JobOptions.FrameCount > 0) { for (int i = 0; i < Segments.Count; i++) { // Get start position of next segment. long NextSegmentStart = i < Segments.Count - 1 ? Segments[i + 1].FrameStart : 0; if (NextSegmentStart == 0 || NextSegmentStart > FrameStart) // Enforce PrescanStart for preview { long SegmentStart = Segments[i].FrameStart; long SegmentEnd = NextSegmentStart > 0 ? NextSegmentStart - 1 : 0; // Enforce PrescanEnd for preview if ((FrameEnd > 0 && SegmentStart > FrameEnd) || (SegmentEnd > 0 && SegmentStart > SegmentEnd)) { break; } if ((FrameStart > 0 && FrameStart > SegmentStart) || SegmentStart == 0) { SegmentStart = FrameStart; } if ((FrameEnd > 0 && FrameEnd < SegmentEnd) || SegmentEnd == 0) { SegmentEnd = FrameEnd; } Result = GenerateDeshakerLogSegment(settings, inputFile, i, FrameStart, SegmentStart, SegmentEnd, JobOptions); if (Result != CompletionStatus.Success) { break; } // Merge log segment into log file and set right frame numbers. using (StreamWriter sw = new StreamWriter(File.Open(settings.DeshakerLog, FileMode.Append), Encoding.ASCII)) { using (StreamReader sr = new StreamReader(File.OpenRead(settings.DeshakerTempLog), Encoding.ASCII)) { string LogLine, LogNum, LogNumField, LineOut; long NewLineNum = SegmentStart; LogLine = sr.ReadLine(); while (LogLine != null) { if (LogLine.Length > 7) { LogNum = LogLine.Substring(0, 7).Trim(); if (LogNum.Length > 0) { LogNumField = LogNum[LogNum.Length - 1].ToString(); if (LogNumField != "A" && LogNumField != "B") // For interlaced videos { LogNumField = ""; } NewLineNum++; // Log file starts at 1, not 0. LineOut = (NewLineNum.ToString() + LogNumField).PadLeft(7) + LogLine.Substring(7, LogLine.Length - 8); sw.WriteLine(LineOut); } } LogLine = sr.ReadLine(); } } } File.Delete(settings.DeshakerTempLog); } } } else { Result = CompletionStatus.Error; } // End UI. FFmpegConfig.UserInterfaceManager.Stop(JobId); return(Result); }