From f31cef6ed54cef055f0171f55fabd8c185907b43 Mon Sep 17 00:00:00 2001 From: LittlePox Date: Wed, 11 Sep 2019 00:13:28 +0800 Subject: [PATCH] 1. Allow disabling numa node 2. Allow episode specific settings. --- OKEGui/OKEGui/00001.m2ts.json | 6 +++ OKEGui/OKEGui/Gui/WizardWindow.xaml.cs | 27 ++++++++++++- OKEGui/OKEGui/Job/VideoJob/VideoInfoJob.cs | 10 +++-- OKEGui/OKEGui/Job/VideoJob/VideoJob.cs | 5 ++- .../Video/CommandlineVideoEncoder.cs | 2 +- .../JobProcessor/Video/VSPipeProcessor.cs | 38 ++++++++---------- .../OKEGui/JobProcessor/Video/X264Encoder.cs | 25 +++++++----- .../OKEGui/JobProcessor/Video/x265Encoder.cs | 25 +++++++----- OKEGui/OKEGui/OKEGui.csproj | 1 + OKEGui/OKEGui/Properties/AssemblyInfo.cs | 2 +- OKEGui/OKEGui/Task/EpisodeProfile.cs | 40 +++++++++++++++++++ OKEGui/OKEGui/Task/TaskProfile.cs | 4 +- OKEGui/OKEGui/Utils/Initializer.cs | 1 + OKEGui/OKEGui/Utils/VapourSynthHelper.cs | 10 ++--- OKEGui/OKEGui/Worker/ExecuteTaskService.cs | 12 ++++-- OKEGui/OKEGui/Worker/NumaNode.cs | 17 ++++++-- OKEGui/OKEGui/demo.json | 8 +++- 17 files changed, 169 insertions(+), 64 deletions(-) create mode 100644 OKEGui/OKEGui/00001.m2ts.json create mode 100644 OKEGui/OKEGui/Task/EpisodeProfile.cs diff --git a/OKEGui/OKEGui/00001.m2ts.json b/OKEGui/OKEGui/00001.m2ts.json new file mode 100644 index 00000000..989c9d69 --- /dev/null +++ b/OKEGui/OKEGui/00001.m2ts.json @@ -0,0 +1,6 @@ +{ + "VspipeArgs" : [ + "op_start=8000", + "op_end=16000" + ] +} \ No newline at end of file diff --git a/OKEGui/OKEGui/Gui/WizardWindow.xaml.cs b/OKEGui/OKEGui/Gui/WizardWindow.xaml.cs index f6c85d76..116fcbb2 100644 --- a/OKEGui/OKEGui/Gui/WizardWindow.xaml.cs +++ b/OKEGui/OKEGui/Gui/WizardWindow.xaml.cs @@ -9,6 +9,8 @@ using OKEGui.Utils; using OKEGui.Model; using OKEGui.Worker; +using OKEGui.Task; +using Newtonsoft.Json; namespace OKEGui { @@ -19,6 +21,7 @@ namespace OKEGui /// public partial class WizardWindow : Window { + private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); // Wizard里需要显示的内容。 private class NewTask : INotifyPropertyChanged { @@ -196,6 +199,23 @@ private void WizardFinish(object sender, RoutedEventArgs e) // 清理文件 cleaner.Clean(inputFile, new List { json.InputScript }); + EpisodeConfig config = null; + string cfgPath = inputFile + ".json"; + FileInfo cfgFile = new FileInfo(cfgPath); + if (cfgFile.Exists) + { + try + { + string configStr = File.ReadAllText(cfgPath); + config = JsonConvert.DeserializeObject(configStr); + } + catch (Exception ex) + { + System.Windows.MessageBox.Show(ex.ToString(), cfgFile.Name + "文件写错了诶", MessageBoxButton.OK, MessageBoxImage.Error); + continue; + } + } + // 新建vpy文件(inputname.m2ts-mmddHHMM.vpy) string vpy = inputTemplate[0] + inputTemplate[1] + "r'" + inputFile + "'" + inputTemplate[3]; @@ -204,7 +224,7 @@ private void WizardFinish(object sender, RoutedEventArgs e) string fileName = inputFile + "-" + time.ToString("MMddHHmm") + ".vpy"; File.WriteAllText(fileName, vpy); - var finfo = new FileInfo(inputFile); + FileInfo finfo = new FileInfo(inputFile); TaskDetail td = new TaskDetail { TaskName = string.IsNullOrEmpty(json.ProjectName) ? finfo.Name : json.ProjectName + "-" + finfo.Name, @@ -214,8 +234,11 @@ private void WizardFinish(object sender, RoutedEventArgs e) // 更新输入脚本和输出文件拓展名 td.Taskfile.InputScript = fileName; + if (config != null) + { + td.Taskfile.Config = config.Clone() as EpisodeConfig; + } td.UpdateOutputFileName(); - workerManager.AddTask(td); } } diff --git a/OKEGui/OKEGui/Job/VideoJob/VideoInfoJob.cs b/OKEGui/OKEGui/Job/VideoJob/VideoInfoJob.cs index 2c428be6..4b6dde75 100644 --- a/OKEGui/OKEGui/Job/VideoJob/VideoInfoJob.cs +++ b/OKEGui/OKEGui/Job/VideoJob/VideoInfoJob.cs @@ -1,10 +1,14 @@ -namespace OKEGui +using System.Collections.Generic; + +namespace OKEGui { public class VideoInfoJob : Job { - public VideoInfoJob(string input) : base() + public List Args = new List(); + public VideoInfoJob(string input, List args) : base() { - this.Input = input; + Input = input; + Args.AddRange(args); } public override JobType GetJobType() diff --git a/OKEGui/OKEGui/Job/VideoJob/VideoJob.cs b/OKEGui/OKEGui/Job/VideoJob/VideoJob.cs index 9799d346..e8612829 100644 --- a/OKEGui/OKEGui/Job/VideoJob/VideoJob.cs +++ b/OKEGui/OKEGui/Job/VideoJob/VideoJob.cs @@ -1,9 +1,12 @@ -namespace OKEGui +using System.Collections.Generic; + +namespace OKEGui { public class VideoJob : Job { public string EncoderPath; public string EncodeParam; + public List VspipeArgs = new List(); public double Fps; public uint FpsNum; public uint FpsDen; diff --git a/OKEGui/OKEGui/JobProcessor/Video/CommandlineVideoEncoder.cs b/OKEGui/OKEGui/JobProcessor/Video/CommandlineVideoEncoder.cs index 76c0a7cb..cde35954 100644 --- a/OKEGui/OKEGui/JobProcessor/Video/CommandlineVideoEncoder.cs +++ b/OKEGui/OKEGui/JobProcessor/Video/CommandlineVideoEncoder.cs @@ -38,7 +38,7 @@ protected void getInputProperties(VideoJob job) { //VapourSynthHelper vsHelper = new VapourSynthHelper(); //vsHelper.LoadScriptFile(job.Input); - VSPipeInfo vsHelper = new VSPipeInfo(job.Input); + VSPipeInfo vsHelper = new VSPipeInfo(job.Input, job.VspipeArgs); fps_n = vsHelper.FpsNum; fps_d = vsHelper.FpsDen; numberOfFrames = (ulong)vsHelper.TotalFreams; diff --git a/OKEGui/OKEGui/JobProcessor/Video/VSPipeProcessor.cs b/OKEGui/OKEGui/JobProcessor/Video/VSPipeProcessor.cs index 19dd4274..24359dfd 100644 --- a/OKEGui/OKEGui/JobProcessor/Video/VSPipeProcessor.cs +++ b/OKEGui/OKEGui/JobProcessor/Video/VSPipeProcessor.cs @@ -12,28 +12,24 @@ namespace OKEGui { public class VSPipeProcessor : CommandlineJobProcessor { - public static IJobProcessor NewVSPipeProcessor(Job j) - { - if (j is VideoInfoJob) { - return new VSPipeProcessor(j as VideoInfoJob); - } - return null; - } - private VSVideoInfo videoInfo; private ManualResetEvent retrieved = new ManualResetEvent(false); public VSPipeProcessor(VideoInfoJob j) : base() { // 获取VSPipe路径 - this.executable = Initializer.Config.vspipePath; + executable = Initializer.Config.vspipePath; videoInfo = new VSVideoInfo(); StringBuilder sb = new StringBuilder(); - sb.Append("--info "); - sb.Append("\"" + j.Input + "\" "); - sb.Append("-"); + sb.Append("--info"); + foreach (string arg in j.Args) + { + sb.Append($" --arg \"{arg}\""); + } + sb.Append(" \"" + j.Input + "\""); + sb.Append(" -"); commandLine = sb.ToString(); } @@ -49,7 +45,14 @@ public override void ProcessLine(string line, StreamType stream) Regex rColorFamily = new Regex("Color Family: ([a-zA-Z]+)"); Regex rBits = new Regex("Bits: ([0-9]+)"); - if (line.Contains("Width")) + if (line.Contains("Python exception: ")) + { + OKETaskException ex = new OKETaskException(Constants.vpyErrorSmr); + ex.progress = 0.0; + ex.Data["VPY_ERROR"] = line.Substring(18); + throw ex; + } + else if (line.Contains("Width")) { var s = rWidth.Split(line); int w; @@ -129,14 +132,7 @@ public override void ProcessLine(string line, StreamType stream) else if (line.Contains("SubSampling")) { //目前还没有要处理subsampling的 - } - else if (line.Contains("Python exception: ")) - { - OKETaskException ex = new OKETaskException(Constants.vpyErrorSmr); - ex.progress = 0.0; - ex.Data["VPY_ERROR"] = line.Substring(18); - throw ex; - } + } } public override void waitForFinish() diff --git a/OKEGui/OKEGui/JobProcessor/Video/X264Encoder.cs b/OKEGui/OKEGui/JobProcessor/Video/X264Encoder.cs index cc490f4f..53150f4f 100644 --- a/OKEGui/OKEGui/JobProcessor/Video/X264Encoder.cs +++ b/OKEGui/OKEGui/JobProcessor/Video/X264Encoder.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using OKEGui.Utils; using OKEGui.JobProcessor; +using System.Collections.Generic; namespace OKEGui { @@ -14,9 +15,9 @@ public class X264Encoder : CommandlineVideoEncoder private readonly string X264Path = ""; private readonly string VspipePath = ""; - public X264Encoder(Job j) : base() + public X264Encoder(VideoJob job) : base() { - job = j as VideoJob; + this.job = job; getInputProperties(job); executable = Path.Combine(Environment.SystemDirectory, "cmd.exe"); @@ -29,7 +30,7 @@ public X264Encoder(Job j) : base() // 获取VSPipe路径 this.VspipePath = Initializer.Config.vspipePath; - commandLine = BuildCommandline(job.EncodeParam, job.NumaNode); + commandLine = BuildCommandline(job.EncodeParam, job.NumaNode, job.VspipeArgs); } public override void ProcessLine(string line, StreamType stream) @@ -90,7 +91,7 @@ public override void ProcessLine(string line, StreamType stream) } } - private string BuildCommandline(string extractParam, int numaNode) + private string BuildCommandline(string extractParam, int numaNode, List vspipeArgs) { StringBuilder sb = new StringBuilder(); @@ -98,14 +99,18 @@ private string BuildCommandline(string extractParam, int numaNode) sb.Append(numaNode.ToString()); // 构建vspipe参数 sb.Append(" \"" + VspipePath + "\""); - sb.Append(" --y4m "); - sb.Append("\"" + job.Input + "\""); - sb.Append(" - | "); + sb.Append(" --y4m"); + foreach (string arg in vspipeArgs) + { + sb.Append($" --arg \"{arg}\""); + } + sb.Append(" \"" + job.Input + "\""); + sb.Append(" - |"); // 构建X264参数 - sb.Append("\"" + X264Path + "\""); - sb.Append(" --demuxer y4m " + extractParam + " -o "); - sb.Append("\"" + job.Output + "\" -"); + sb.Append(" \"" + X264Path + "\""); + sb.Append(" --demuxer y4m " + extractParam + " -o"); + sb.Append(" \"" + job.Output + "\" -"); sb.Append("\""); return sb.ToString(); diff --git a/OKEGui/OKEGui/JobProcessor/Video/x265Encoder.cs b/OKEGui/OKEGui/JobProcessor/Video/x265Encoder.cs index 851f33b9..a5bd2d8e 100644 --- a/OKEGui/OKEGui/JobProcessor/Video/x265Encoder.cs +++ b/OKEGui/OKEGui/JobProcessor/Video/x265Encoder.cs @@ -5,6 +5,7 @@ using System.Text.RegularExpressions; using OKEGui.Utils; using OKEGui.JobProcessor; +using System.Collections.Generic; namespace OKEGui { @@ -13,9 +14,9 @@ public class X265Encoder : CommandlineVideoEncoder private readonly string X265Path = ""; private readonly string vspipePath = ""; - public X265Encoder(Job j) : base() + public X265Encoder(VideoJob job) : base() { - job = j as VideoJob; + this.job = job; getInputProperties(job); executable = Path.Combine(Environment.SystemDirectory, "cmd.exe"); @@ -28,7 +29,7 @@ public X265Encoder(Job j) : base() // 获取VSPipe路径 this.vspipePath = Initializer.Config.vspipePath; - commandLine = BuildCommandline(job.EncodeParam, job.NumaNode); + commandLine = BuildCommandline(job.EncodeParam, job.NumaNode, job.VspipeArgs); } public override void ProcessLine(string line, StreamType stream) @@ -89,7 +90,7 @@ public override void ProcessLine(string line, StreamType stream) } } - private string BuildCommandline(string extractParam, int numaNode) + private string BuildCommandline(string extractParam, int numaNode, List vspipeArgs) { StringBuilder sb = new StringBuilder(); @@ -97,14 +98,18 @@ private string BuildCommandline(string extractParam, int numaNode) sb.Append(numaNode.ToString()); // 构建vspipe参数 sb.Append(" \"" + vspipePath + "\""); - sb.Append(" --y4m "); - sb.Append("\"" + job.Input + "\""); - sb.Append(" - | "); + sb.Append(" --y4m"); + foreach (string arg in vspipeArgs) + { + sb.Append($" --arg \"{arg}\""); + } + sb.Append(" \"" + job.Input + "\""); + sb.Append(" - |"); // 构建x265参数 - sb.Append("\"" + X265Path + "\""); - sb.Append(" --y4m " + extractParam + " -o "); - sb.Append("\"" + job.Output + "\" -"); + sb.Append(" \"" + X265Path + "\""); + sb.Append(" --y4m " + extractParam + " -o"); + sb.Append(" \"" + job.Output + "\" -"); sb.Append("\""); return sb.ToString(); diff --git a/OKEGui/OKEGui/OKEGui.csproj b/OKEGui/OKEGui/OKEGui.csproj index 2e791437..2abd6ec6 100644 --- a/OKEGui/OKEGui/OKEGui.csproj +++ b/OKEGui/OKEGui/OKEGui.csproj @@ -103,6 +103,7 @@ + diff --git a/OKEGui/OKEGui/Properties/AssemblyInfo.cs b/OKEGui/OKEGui/Properties/AssemblyInfo.cs index 2777cb24..553daefe 100644 --- a/OKEGui/OKEGui/Properties/AssemblyInfo.cs +++ b/OKEGui/OKEGui/Properties/AssemblyInfo.cs @@ -47,4 +47,4 @@ //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, // 方法是按如下所示使用“*”: : // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("4.8.*")] +[assembly: AssemblyVersion("4.9.*")] diff --git a/OKEGui/OKEGui/Task/EpisodeProfile.cs b/OKEGui/OKEGui/Task/EpisodeProfile.cs new file mode 100644 index 00000000..db441907 --- /dev/null +++ b/OKEGui/OKEGui/Task/EpisodeProfile.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; + +namespace OKEGui.Task +{ + public class EpisodeConfig : ICloneable + { + public List VspipeArgs = new List(); + + public object Clone() + { + EpisodeConfig clone = MemberwiseClone() as EpisodeConfig; + if (VspipeArgs != null) + { + clone.VspipeArgs = new List(); + foreach (string arg in VspipeArgs) + { + clone.VspipeArgs.Add(arg); + } + } + return clone; + } + + public override string ToString() + { + string str = "EpisodeConfig{"; + str += "VspipeArgs: "; + if (VspipeArgs == null) + { + str += "null"; + } + else + { + str += "[" + string.Join(",", VspipeArgs) + "]"; + } + str += "]"; + return str; + } + } +} diff --git a/OKEGui/OKEGui/Task/TaskProfile.cs b/OKEGui/OKEGui/Task/TaskProfile.cs index 86b30600..dc5ebcb9 100644 --- a/OKEGui/OKEGui/Task/TaskProfile.cs +++ b/OKEGui/OKEGui/Task/TaskProfile.cs @@ -1,4 +1,5 @@ -using System; +using OKEGui.Task; +using System; using System.Collections.Generic; /// @@ -27,6 +28,7 @@ public class TaskProfile : ICloneable public string SubtitleLanguage; public List SubtitleTracks; public List InputFiles; + public EpisodeConfig Config; public Object Clone() { diff --git a/OKEGui/OKEGui/Utils/Initializer.cs b/OKEGui/OKEGui/Utils/Initializer.cs index 220d312d..c8923a78 100644 --- a/OKEGui/OKEGui/Utils/Initializer.cs +++ b/OKEGui/OKEGui/Utils/Initializer.cs @@ -13,6 +13,7 @@ class OKEGuiConfig { public string vspipePath; public string logLevel = "DEBUG"; + public bool noNuma = false; } static class Initializer diff --git a/OKEGui/OKEGui/Utils/VapourSynthHelper.cs b/OKEGui/OKEGui/Utils/VapourSynthHelper.cs index 386aaeb5..56f76285 100644 --- a/OKEGui/OKEGui/Utils/VapourSynthHelper.cs +++ b/OKEGui/OKEGui/Utils/VapourSynthHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; @@ -214,15 +215,14 @@ public class VSPipeInfo private int height; private VSVideoInfo videoInfo; - public VSPipeInfo(string vsScriptPath) + public VSPipeInfo(string vsScriptPath, List args) { - VideoInfoJob j = new VideoInfoJob(vsScriptPath); + VideoInfoJob j = new VideoInfoJob(vsScriptPath, args); - IJobProcessor processor = VSPipeProcessor.NewVSPipeProcessor(j); + VSPipeProcessor processor = new VSPipeProcessor(j); processor.start(); - videoInfo = (processor as VSPipeProcessor).VideoInfo; - + videoInfo = processor.VideoInfo; UpdateVideoInfo(); } diff --git a/OKEGui/OKEGui/Worker/ExecuteTaskService.cs b/OKEGui/OKEGui/Worker/ExecuteTaskService.cs index 06da3c24..6cdeda3f 100644 --- a/OKEGui/OKEGui/Worker/ExecuteTaskService.cs +++ b/OKEGui/OKEGui/Worker/ExecuteTaskService.cs @@ -109,6 +109,10 @@ private void WorkerDoWork(object sender, DoWorkEventArgs e) videoJob.FpsNum = profile.FpsNum; videoJob.FpsDen = profile.FpsDen; videoJob.NumaNode = args.numaNode; + if (profile.Config != null) + { + videoJob.VspipeArgs.AddRange(profile.Config.VspipeArgs); + } if (profile.VideoFormat == "HEVC") { @@ -196,23 +200,23 @@ private void WorkerDoWork(object sender, DoWorkEventArgs e) } else if (job is VideoJob) { + videoJob = job as VideoJob; CommandlineVideoEncoder processor; task.CurrentStatus = "获取信息中"; task.IsUnKnowProgress = true; if (job.CodecString == "HEVC") { - processor = new X265Encoder(job); + processor = new X265Encoder(videoJob); } else { - processor = new X264Encoder(job); + processor = new X264Encoder(videoJob); } task.CurrentStatus = "压制中"; task.ProgressValue = 0.0; processor.start(); processor.waitForFinish(); - videoJob = job as VideoJob; VideoInfo info = new VideoInfo(videoJob.FpsNum, videoJob.FpsDen); task.MediaOutFile.AddTrack(new VideoTrack(new OKEFile(job.Output), info)); @@ -281,7 +285,7 @@ private void WorkerDoWork(object sender, DoWorkEventArgs e) catch (Exception ex) { FileInfo fileinfo = new FileInfo(task.InputFile); - Logger.Error(ex.StackTrace); + Logger.Error(ex.Message + ex.StackTrace); new System.Threading.Tasks.Task(() => System.Windows.MessageBox.Show(ex.Message, fileinfo.Name)).Start(); task.IsRunning = false; diff --git a/OKEGui/OKEGui/Worker/NumaNode.cs b/OKEGui/OKEGui/Worker/NumaNode.cs index 03aad148..269decd1 100644 --- a/OKEGui/OKEGui/Worker/NumaNode.cs +++ b/OKEGui/OKEGui/Worker/NumaNode.cs @@ -1,4 +1,5 @@ -using System; +using OKEGui.Utils; +using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; @@ -19,9 +20,17 @@ static class NumaNode static NumaNode() { - GetNumaHighestNodeNumber(out uint temp); - CurrentNuma = (int)temp; - NumaCount = CurrentNuma + 1; + if (Initializer.Config.noNuma) + { + CurrentNuma = 0; + NumaCount = 1; + } + else + { + GetNumaHighestNodeNumber(out uint temp); + CurrentNuma = (int)temp; + NumaCount = CurrentNuma + 1; + } UsableCoreCount = Environment.ProcessorCount; } diff --git a/OKEGui/OKEGui/demo.json b/OKEGui/OKEGui/demo.json index 84cbf5b2..71d27106 100644 --- a/OKEGui/OKEGui/demo.json +++ b/OKEGui/OKEGui/demo.json @@ -21,5 +21,11 @@ "Main_Disc\\BDMV\\STREAM\\00000.m2ts", "Main_Disc\\BDMV\\STREAM\\00001.m2ts", "Main_Disc\\BDMV\\STREAM\\00002.m2ts", - ] + ], + "Config" : { + "VspipeArgs" : [ + "op_start = 10000", + "op_end = 15000" + ] + } }