// 读入json里指定的输入文件,加入到inputFile里 public static int LoadInputFiles(TaskProfile json, DirectoryInfo jsonDir, ObservableCollection <string> inputFile) { int fileCount = 0; if (json.InputFiles != null) { inputFile.Clear(); foreach (string file in json.InputFiles) { FileInfo input = new FileInfo(jsonDir.FullName + "\\" + file); if (inputFile.Contains(input.FullName)) { MessageBox.Show("指定的文件(" + input.FullName + ")重复了,请总监复查下输入文件列表?", "输入文件有重复", MessageBoxButton.OK, MessageBoxImage.Error); return(0); } if (input.Exists) { inputFile.Add(input.FullName); } else { MessageBox.Show("指定的文件(" + input.FullName + ")不存在啊,跟总监确认下json应该放哪?", "找不到输入文件啊", MessageBoxButton.OK, MessageBoxImage.Error); return(0); } } fileCount = json.InputFiles.Count; } return(fileCount); }
// 读入json文件,检查项目设置,并生成预览信息 private bool LoadJsonProfile(string filePath) { DirectoryInfo jsonDir = new DirectoryInfo(filePath).Parent; // 读入json文件 json = AddTaskService.LoadJsonAsProfile(filePath, jsonDir); if (json == null) { return(false); } // 读入json里指定的vs脚本,并检查#OKE:INPUTFILE 标签 vsScript = AddTaskService.LoadVsScript(json, jsonDir); if (string.IsNullOrEmpty(vsScript)) { return(false); } // 读入json里指定的输入文件,加入到inputFile里 int fileCount = AddTaskService.LoadInputFiles(json, jsonDir, wizardInfo.InputFile); SelectInputFile.CanFinish = fileCount > 0; // 预览 wizardInfo.ProjectPreview = json.ToString(); return(true); }
// 读入vs脚本,并检查OKE:INPUTFILE标签 public static string LoadVsScript(TaskProfile json, DirectoryInfo jsonDir) { FileInfo scriptFile = new FileInfo(jsonDir.FullName + "\\" + json.InputScript); if (scriptFile.Exists) { json.InputScript = scriptFile.FullName; string vsScript = File.ReadAllText(json.InputScript); if (json.Rpc && !vsScript.Contains(".set_output(1)")) { MessageBox.Show("请告诉技术总监给vpy里加上rpc的输出。", "vpy里没有准备rpc的输出", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } if (Constants.inputRegex.IsMatch(vsScript)) { return(vsScript); } else { MessageBox.Show("vpy里没有#OKE:INPUTFILE的标签。", "vpy没有为OKEGui设计", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } else { MessageBox.Show("指定的vpy文件没有找到,检查下json文件和vpy文件是不是放一起了?", "vpy文件找不到", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } }
private IMapper GetMapper() { var playerProfile = new PlayerProfile(); var houseProfile = new HouseProfile(); var taskProfile = new TaskProfile(); var mapperConfig = new MapperConfiguration(cfg => { cfg.AddProfile(playerProfile); cfg.AddProfile(houseProfile); cfg.AddProfile(taskProfile); }); return(mapperConfig.CreateMapper()); }
public TaskSettings(Task task, bool dbMode = true) : base() { _task = task; _profile = _task.Profile; _dbMode = dbMode; var fullName = _task.Profile.ConfigName(Config.App.UseDbSettings, true); var mode = ConfigurationManager.AppSettings[fullName]; if (!string.IsNullOrEmpty(mode)) { _dbMode = bool.Parse(mode); } }
public EACDemuxer(string eacPath, string fileName, TaskProfile jobProfile) { _eacPath = eacPath; sourceFile = fileName; JobAudio = new List <AudioInfo>(); if (jobProfile.AudioTracks != null) { JobAudio.AddRange(jobProfile.AudioTracks); } JobSub = new List <Info>(); if (jobProfile.SubtitleTracks != null) { JobSub.AddRange(jobProfile.SubtitleTracks); } extractVideo = jobProfile.ExtractVideo; }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); services.AddDbContext <NadrichnaDbConext>(options => options.UseSqlServer("Server=(local);Initial Catalog=Nadrichna;Trusted_Connection=True;MultipleActiveResultSets=true")); services.AddScoped <INadrichnaDbConext, NadrichnaDbConext>(); services.AddScoped <IPlayerRepository, PlayerRepository>(); services.AddScoped <IHouseRepository, HouseRepository>(); services.AddScoped <ITaskRepository, TaskRepository>(); var playerProfile = new PlayerProfile(); var houseProfile = new HouseProfile(); var taskProfile = new TaskProfile(); var mapperConfig = new MapperConfiguration(cfg => { cfg.AddProfile(playerProfile); cfg.AddProfile(houseProfile); cfg.AddProfile(taskProfile); }); var mapper = mapperConfig.CreateMapper(); services.AddSingleton(mapper); }
private void WorkerDoWork(object sender, DoWorkEventArgs e) { WorkerArgs args = (WorkerArgs)e.Argument; while (IsRunning) { TaskDetail task = args.taskManager.GetNextTask(); // 检查是否已经完成全部任务 if (task == null) { Logger.Debug("所有任务已经完成"); Action <MainWindow> disableButtonsAction = new Action <MainWindow>(DisableButtonsAfterFinish); MainWindow.Dispatcher.BeginInvoke(disableButtonsAction, MainWindow); lock (o) { bgworkerlist.TryRemove(args.Name, out BackgroundWorker v); if (bgworkerlist.Count == 0) { IsRunning = false; if (args.taskManager.AllSuccess()) { if (AfterFinish != null) { Logger.Info("全部任务正常结束;准备执行完结命令。"); MainWindow.Dispatcher.BeginInvoke(AfterFinish, MainWindow); } else { Logger.Info("全部任务正常结束;没有完结命令。"); } } else { Logger.Info("有些任务未正常结束,不执行完结命令。"); } } } return; } TaskProfile profile = task.Taskfile; try { task.WorkerName = args.Name; task.Progress = TaskStatus.TaskProgress.RUNNING; task.MediaOutFile = new MediaFile(); task.MkaOutFile = new MediaFile(); // 抽取音轨 profile.ExtractVideo = VideoService.ForceExtractVideo(task.InputFile); FileInfo eacInfo = new FileInfo(Constants.eac3toWrapperPath); MediaFile srcTracks = new EACDemuxer(eacInfo.FullName, task.InputFile, profile).Extract( (double progress, EACProgressType type) => { switch (type) { case EACProgressType.Analyze: task.CurrentStatus = "轨道分析中"; task.ProgressValue = progress; break; case EACProgressType.Process: task.CurrentStatus = "抽取音轨中"; task.ProgressValue = progress; break; case EACProgressType.Completed: task.CurrentStatus = "音轨抽取完毕"; task.ProgressValue = progress; break; default: return; } }); // 新建音频处理工作 for (int id = 0; id < srcTracks.AudioTracks.Count; id++) { AudioTrack track = srcTracks.AudioTracks[id]; OKEFile file = track.File; AudioInfo info = track.Info as AudioInfo; MuxOption option = info.MuxOption; switch (option) { case MuxOption.Default: case MuxOption.Mka: case MuxOption.External: AudioJob audioJob = new AudioJob(info); audioJob.SetUpdate(task); audioJob.Input = file.GetFullPath(); audioJob.Output = Path.ChangeExtension(audioJob.Input, "." + audioJob.CodecString.ToLower()); task.JobQueue.Enqueue(audioJob); break; default: break; } } // 如果必须抽取视频轨道,这里需要修改输入的vpy文件 if (profile.ExtractVideo) { VideoService.ReplaceVpyInputFile(profile.InputScript, task.InputFile, srcTracks.VideoTrack.File.GetFullPath()); } // 新建视频处理工作 VideoJob videoJob = new VideoJob(profile.VideoFormat); videoJob.SetUpdate(task); videoJob.Input = profile.InputScript; videoJob.EncoderPath = profile.Encoder; videoJob.EncodeParam = profile.EncoderParam; videoJob.Vfr = profile.TimeCode; videoJob.Fps = profile.Fps; 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") { videoJob.Output = task.Taskfile.WorkingPathPrefix + ".hevc"; if (!profile.EncoderParam.ToLower().Contains("--pools")) { videoJob.EncodeParam += " --pools " + NumaNode.X265PoolsParam(videoJob.NumaNode); } } else { videoJob.Output = task.Taskfile.WorkingPathPrefix; videoJob.Output += profile.ContainerFormat == "MKV" ? "_.mkv" : ".h264"; if (!profile.EncoderParam.ToLower().Contains("--threads") && NumaNode.UsableCoreCount > 10) { videoJob.EncodeParam += " --threads 16"; } } task.JobQueue.Enqueue(videoJob); // 添加字幕文件 foreach (SubtitleTrack track in srcTracks.SubtitleTracks) { OKEFile outputFile = track.File; Info info = track.Info; switch (info.MuxOption) { case MuxOption.Default: task.MediaOutFile.AddTrack(track); break; case MuxOption.Mka: task.MkaOutFile.AddTrack(track); break; case MuxOption.External: outputFile.AddCRC32(); break; default: break; } } while (task.JobQueue.Count != 0) { Job job = task.JobQueue.Dequeue(); switch (job) { case AudioJob aJob: { AudioInfo info = aJob.Info; string srcFmt = Path.GetExtension(aJob.Input).ToUpper().Remove(0, 1); if (srcFmt == "FLAC" && aJob.CodecString == "AAC") { task.CurrentStatus = "音频转码中"; QAACEncoder qaac = new QAACEncoder(aJob, (double progress) => { task.ProgressValue = progress; }, info.Bitrate); qaac.start(); qaac.waitForFinish(); } else if (srcFmt != aJob.CodecString) { OKETaskException ex = new OKETaskException(Constants.audioFormatMistachSmr); ex.Data["SRC_FMT"] = srcFmt; ex.Data["DST_FMT"] = aJob.CodecString; throw ex; } OKEFile outputFile = new OKEFile(aJob.Output); switch (info.MuxOption) { case MuxOption.Default: task.MediaOutFile.AddTrack(new AudioTrack(outputFile, info)); break; case MuxOption.Mka: task.MkaOutFile.AddTrack(new AudioTrack(outputFile, info)); break; case MuxOption.External: outputFile.AddCRC32(); break; default: break; } break; } case VideoJob vJob: { CommandlineVideoEncoder processor; task.CurrentStatus = "获取信息中"; task.IsUnKnowProgress = true; if (vJob.CodecString == "HEVC") { processor = new X265Encoder(vJob); } else { processor = new X264Encoder(vJob); } // 时间码文件 Timecode timecode = null; string timeCodeFile = null; if (vJob.Vfr) { timecode = new Timecode(Path.ChangeExtension(task.InputFile, ".tcfile"), (int)processor.NumberOfFrames); timeCodeFile = Path.ChangeExtension(task.InputFile, ".v2.tcfile"); try { timecode.SaveTimecode(timeCodeFile); } catch (IOException ex) { Logger.Info($"无法写入修正后timecode,将使用原文件\n{ex.Message}"); timeCodeFile = Path.ChangeExtension(task.InputFile, ".tcfile"); } task.LengthInMiliSec = (long)(timecode.TotalLength.Ticks / 1e4 + 0.5); } else { task.LengthInMiliSec = (long)((processor.NumberOfFrames - 1) / vJob.Fps * 1000 + 0.5); } // 添加章节文件 ChapterInfo chapterInfo = ChapterService.LoadChapter(task); if (chapterInfo != null) { if (task.ChapterStatus == ChapterStatus.Maybe || task.ChapterStatus == ChapterStatus.MKV) { task.ChapterStatus = ChapterStatus.Added; } FileInfo inputChapterFile = new FileInfo(Path.ChangeExtension(task.InputFile, ".txt")); FileInfo outputChapterFile = new FileInfo(Path.ChangeExtension(task.Taskfile.WorkingPathPrefix, ".txt")); if (inputChapterFile.Exists && !File.Exists(outputChapterFile.FullName)) { File.Copy(inputChapterFile.FullName, outputChapterFile.FullName); } chapterInfo.Save(ChapterTypeEnum.OGM, outputChapterFile.FullName); outputChapterFile.Refresh(); OKEFile chapterFile = new OKEFile(outputChapterFile); task.MediaOutFile.AddTrack(new ChapterTrack(chapterFile)); // 用章节文件生成qpfile string qpFileName = Path.ChangeExtension(task.Taskfile.WorkingPathPrefix, ".qpf"); string qpFile = vJob.Vfr ? ChapterService.GenerateQpFile(chapterInfo, timecode) : ChapterService.GenerateQpFile(chapterInfo, vJob.Fps); File.WriteAllText(qpFileName, qpFile); processor.AppendParameter($"--qpfile \"{qpFileName}\""); } else { task.ChapterStatus = ChapterStatus.No; } // 开始压制 task.CurrentStatus = "压制中"; task.ProgressValue = 0.0; processor.start(); processor.waitForFinish(); VideoInfo info = new VideoInfo(vJob.FpsNum, vJob.FpsDen, timeCodeFile); task.MediaOutFile.AddTrack(new VideoTrack(new OKEFile(vJob.Output), info)); break; } default: // 不支持的工作 break; } } // 封装 if (profile.ContainerFormat != "") { task.CurrentStatus = "封装中"; FileInfo mkvInfo = new FileInfo(".\\tools\\mkvtoolnix\\mkvmerge.exe"); if (!mkvInfo.Exists) { throw new Exception("mkvmerge不存在"); } FileInfo lsmash = new FileInfo(".\\tools\\l-smash\\muxer.exe"); if (!lsmash.Exists) { throw new Exception("l-smash 封装工具不存在"); } AutoMuxer muxer = new AutoMuxer(mkvInfo.FullName, lsmash.FullName); muxer.ProgressChanged += progress => task.ProgressValue = progress; OKEFile outFile = muxer.StartMuxing(Path.GetDirectoryName(task.Taskfile.OutputPathPrefix) + "\\" + task.OutputFile, task.MediaOutFile); task.OutputFile = outFile.GetFileName(); task.BitRate = CommandlineVideoEncoder.HumanReadableFilesize(outFile.GetFileSize(), 2); } if (task.MkaOutFile.Tracks.Count > 0) { task.CurrentStatus = "封装MKA中"; FileInfo mkvInfo = new FileInfo(".\\tools\\mkvtoolnix\\mkvmerge.exe"); FileInfo lsmash = new FileInfo(".\\tools\\l-smash\\muxer.exe"); AutoMuxer muxer = new AutoMuxer(mkvInfo.FullName, lsmash.FullName); muxer.ProgressChanged += progress => task.ProgressValue = progress; string mkaOutputFile = task.Taskfile.OutputPathPrefix + ".mka"; muxer.StartMuxing(mkaOutputFile, task.MkaOutFile); } //RP check if (profile.Rpc) { task.CurrentStatus = "RPC中"; RpcJob rpcJob = new RpcJob(profile.InputScript, videoJob); rpcJob.SetUpdate(task); RpChecker checker = new RpChecker(rpcJob); checker.start(); checker.waitForFinish(); task.RpcOutput = rpcJob.Output; } else { task.RpcStatus = RpcStatus.跳过.ToString(); } task.CurrentStatus = "完成"; task.Progress = TaskStatus.TaskProgress.FINISHED; task.ProgressValue = 100; } catch (OKETaskException ex) { ExceptionMsg msg = ExceptionParser.Parse(ex, task); Logger.Error(msg); new System.Threading.Tasks.Task(() => System.Windows.MessageBox.Show(msg.errorMsg, msg.fileName)).Start(); task.Progress = TaskStatus.TaskProgress.ERROR; task.CurrentStatus = ex.summary; task.ProgressValue = ex.progress.GetValueOrDefault(task.ProgressValue); continue; } catch (Exception ex) { FileInfo fileinfo = new FileInfo(task.InputFile); Logger.Error(ex.Message + ex.StackTrace); new System.Threading.Tasks.Task(() => System.Windows.MessageBox.Show(ex.Message, fileinfo.Name)).Start(); task.Progress = TaskStatus.TaskProgress.ERROR; task.CurrentStatus = "未知错误"; continue; } } }
// 依次检查json里各项输入是否正确 public static TaskProfile ProcessJsonProfile(TaskProfile json, DirectoryInfo projDir) { // 检查参数 if (json.Version != 2) { MessageBox.Show("你是不是把单个文件追加用的json当成一套任务用的json了?", "版本不对", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 编码器设置,目前只允许x264/x265 json.EncoderType = json.EncoderType.ToLower(); switch (json.EncoderType) { case "x264": json.VideoFormat = "AVC"; break; case "x265": json.VideoFormat = "HEVC"; break; default: MessageBox.Show("EncoderType请填写x264或者x265", "编码器版本错误", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 设置封装格式 json.ContainerFormat = json.ContainerFormat.ToUpper(); if (json.ContainerFormat != "MKV" && json.ContainerFormat != "MP4") { MessageBox.Show("MKV/MP4,只能这两种", "封装格式指定的有问题", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 如果是MP4则暂不支持指定时间码 if (json.ContainerFormat == "MP4" && json.TimeCode) { MessageBox.Show("MP4暂不支持VFR封装,请联系技术总监。", "MP4暂不支持VFR封装", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } if (json.Fps <= 0 && (json.FpsNum <= 0 || json.FpsDen <= 0)) { if (json.TimeCode) { json.Fps = 1; } else { MessageBox.Show("现在json文件中需要指定帧率,哪怕 Fps : 23.976", "帧率没有指定诶", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } if (json.FpsNum > 0 && json.FpsDen > 0) { json.Fps = ((double)json.FpsNum) / json.FpsDen; } else { switch (json.Fps) { case 1.0: json.FpsNum = 1; json.FpsDen = 1; break; case 23.976: json.FpsNum = 24000; json.FpsDen = 1001; break; case 24.000: json.FpsNum = 24; json.FpsDen = 1; break; case 25.000: json.FpsNum = 25; json.FpsDen = 1; break; case 29.970: json.FpsNum = 30000; json.FpsDen = 1001; break; case 50.000: json.FpsNum = 50; json.FpsDen = 1; break; case 59.940: json.FpsNum = 60000; json.FpsDen = 1001; break; default: MessageBox.Show("请通过FpsNum和FpsDen来指定", "不知道的帧率诶", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } if (json.AudioTracks != null && json.AudioTracks.Count > 0) { // 主音轨 json.AudioFormat = json.AudioTracks[0].OutputCodec; if (string.IsNullOrEmpty(json.AudioFormat)) { json.AudioFormat = "AAC"; } else { json.AudioFormat = json.AudioFormat.ToUpper(); } } else { json.AudioFormat = "AAC"; } if (json.AudioFormat != "FLAC" && json.AudioFormat != "AAC" && json.AudioFormat != "AC3" && json.AudioFormat != "DTS") { MessageBox.Show("音轨只能是FLAC/AAC/AC3/DTS", "音轨格式不支持", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } if (json.AudioFormat == "FLAC" && json.ContainerFormat == "MP4") { MessageBox.Show("MP4格式没法封FLAC", "音轨格式不支持", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 获取编码器全路径 FileInfo encoder = new FileInfo(projDir.FullName + "\\" + json.Encoder); if (encoder.Exists) { json.Encoder = encoder.FullName; } else { MessageBox.Show("编码器好像不在json指定的地方(文件名错误?还有记得放在json文件同目录下)", "找不到编码器啊", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } return(json); }
private void WorkerDoWork(object sender, DoWorkEventArgs e) { WorkerArgs args = (WorkerArgs)e.Argument; while (IsRunning) { TaskDetail task = args.taskManager.GetNextTask(); // 检查是否已经完成全部任务 if (task == null) { // 全部工作完成 lock (o) { bgworkerlist.TryRemove(args.Name, out BackgroundWorker v); if (bgworkerlist.Count == 0) { IsRunning = false; Debugger.Log(0, "", "Ready to call the after finish process\n"); AfterFinish?.Invoke(); } } return; } TaskProfile profile = task.Taskfile; try { task.WorkerName = args.Name; task.IsEnabled = false; task.IsRunning = true; task.MediaOutFile = new MediaFile(); task.MkaOutFile = new MediaFile(); // 抽取音轨 profile.ExtractVideo = VideoService.ForceExtractVideo(task.InputFile); FileInfo eacInfo = new FileInfo(".\\tools\\eac3to\\eac3to.exe"); MediaFile srcTracks = new EACDemuxer(eacInfo.FullName, task.InputFile, profile).Extract( (double progress, EACProgressType type) => { switch (type) { case EACProgressType.Analyze: task.CurrentStatus = "轨道分析中"; task.ProgressValue = progress; break; case EACProgressType.Process: task.CurrentStatus = "抽取音轨中"; task.ProgressValue = progress; break; case EACProgressType.Completed: task.CurrentStatus = "音轨抽取完毕"; task.ProgressValue = progress; break; default: return; } }); // 新建音频处理工作 for (int id = 0; id < srcTracks.AudioTracks.Count; id++) { AudioTrack track = srcTracks.AudioTracks[id]; OKEFile file = track.File; AudioInfo info = track.Info as AudioInfo; MuxOption option = info.MuxOption; switch (option) { case MuxOption.Default: case MuxOption.Mka: case MuxOption.External: AudioJob audioJob = new AudioJob(info); audioJob.SetUpdate(task); audioJob.Input = file.GetFullPath(); audioJob.Output = Path.ChangeExtension(audioJob.Input, "." + audioJob.CodecString.ToLower()); task.JobQueue.Enqueue(audioJob); break; default: break; } } // 如果必须抽取视频轨道,这里需要修改输入的vpy文件 if (profile.ExtractVideo) { VideoService.ReplaceVpyInputFile(profile.InputScript, task.InputFile, srcTracks.VideoTrack.File.GetFullPath()); } // 新建视频处理工作 VideoJob videoJob = new VideoJob(profile.VideoFormat); videoJob.SetUpdate(task); videoJob.Input = profile.InputScript; videoJob.EncoderPath = profile.Encoder; videoJob.EncodeParam = profile.EncoderParam; videoJob.Fps = profile.Fps; 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") { videoJob.Output = new FileInfo(task.InputFile).FullName + ".hevc"; if (!profile.EncoderParam.ToLower().Contains("--pools")) { videoJob.EncodeParam += " --pools " + NumaNode.X265PoolsParam(videoJob.NumaNode); } } else { videoJob.Output = new FileInfo(task.InputFile).FullName; videoJob.Output += profile.ContainerFormat == "MKV" ? "_.mkv" : ".h264"; if (!profile.EncoderParam.ToLower().Contains("--threads") && NumaNode.UsableCoreCount > 10) { videoJob.EncodeParam += " --threads 16"; } } task.JobQueue.Enqueue(videoJob); // 添加字幕文件 foreach (SubtitleTrack track in srcTracks.SubtitleTracks) { OKEFile outputFile = track.File; Info info = track.Info; switch (info.MuxOption) { case MuxOption.Default: task.MediaOutFile.AddTrack(track); break; case MuxOption.Mka: task.MkaOutFile.AddTrack(track); break; case MuxOption.External: outputFile.AddCRC32(); break; default: break; } } while (task.JobQueue.Count != 0) { Job job = task.JobQueue.Dequeue(); if (job is AudioJob) { AudioJob audioJob = job as AudioJob; AudioInfo info = audioJob.Info as AudioInfo; string srcFmt = Path.GetExtension(audioJob.Input).ToUpper().Remove(0, 1); if (srcFmt == "FLAC" && audioJob.CodecString == "AAC") { task.CurrentStatus = "音频转码中"; task.IsUnKnowProgress = true; QAACEncoder qaac = new QAACEncoder(audioJob, info.Bitrate); qaac.start(); qaac.waitForFinish(); } else if (srcFmt != audioJob.CodecString) { OKETaskException ex = new OKETaskException(Constants.audioFormatMistachSmr); ex.Data["SRC_FMT"] = srcFmt; ex.Data["DST_FMT"] = audioJob.CodecString; throw ex; } OKEFile outputFile = new OKEFile(job.Output); switch (info.MuxOption) { case MuxOption.Default: task.MediaOutFile.AddTrack(new AudioTrack(outputFile, info)); break; case MuxOption.Mka: task.MkaOutFile.AddTrack(new AudioTrack(outputFile, info)); break; case MuxOption.External: outputFile.AddCRC32(); break; default: break; } } else if (job is VideoJob) { videoJob = job as VideoJob; CommandlineVideoEncoder processor; task.CurrentStatus = "获取信息中"; task.IsUnKnowProgress = true; if (job.CodecString == "HEVC") { processor = new X265Encoder(videoJob); } else { processor = new X264Encoder(videoJob); } task.lengthInMiliSec = (long)((processor.NumberOfFrames - 1) / videoJob.Fps * 1000 + 0.5); // 添加章节文件 OKEFile chapterFile = ChapterService.AddChapter(task); if (chapterFile != null) { // 用章节文件生成qpfile string qpFileName = Path.ChangeExtension(task.InputFile, ".qpf"); string qpFile = ChapterService.GenerateQpFile(chapterFile, videoJob.Fps); File.WriteAllText(qpFileName, qpFile); processor.AppendParameter($"--qpfile \"{qpFileName}\""); } // 开始压制 task.CurrentStatus = "压制中"; task.ProgressValue = 0.0; processor.start(); processor.waitForFinish(); VideoInfo info = new VideoInfo(videoJob.FpsNum, videoJob.FpsDen); task.MediaOutFile.AddTrack(new VideoTrack(new OKEFile(job.Output), info)); } else { // 不支持的工作 } } // 封装 if (profile.ContainerFormat != "") { task.CurrentStatus = "封装中"; FileInfo mkvInfo = new FileInfo(".\\tools\\mkvtoolnix\\mkvmerge.exe"); if (!mkvInfo.Exists) { throw new Exception("mkvmerge不存在"); } FileInfo lsmash = new FileInfo(".\\tools\\l-smash\\muxer.exe"); if (!lsmash.Exists) { throw new Exception("l-smash 封装工具不存在"); } AutoMuxer muxer = new AutoMuxer(mkvInfo.FullName, lsmash.FullName); muxer.ProgressChanged += progress => task.ProgressValue = progress; muxer.StartMuxing(Path.GetDirectoryName(task.InputFile) + "\\" + task.OutputFile, task.MediaOutFile); } if (task.MkaOutFile.Tracks.Count > 0) { task.CurrentStatus = "封装MKA中"; FileInfo mkvInfo = new FileInfo(".\\tools\\mkvtoolnix\\mkvmerge.exe"); FileInfo lsmash = new FileInfo(".\\tools\\l-smash\\muxer.exe"); AutoMuxer muxer = new AutoMuxer(mkvInfo.FullName, lsmash.FullName); muxer.ProgressChanged += progress => task.ProgressValue = progress; string mkaOutputFile = task.InputFile + ".mka"; muxer.StartMuxing(mkaOutputFile, task.MkaOutFile); } task.CurrentStatus = "完成"; task.ProgressValue = 100; } catch (OKETaskException ex) { ExceptionMsg msg = ExceptionParser.Parse(ex, task); Logger.Error(msg); new System.Threading.Tasks.Task(() => System.Windows.MessageBox.Show(msg.errorMsg, msg.fileName)).Start(); task.IsRunning = false; task.CurrentStatus = ex.summary; task.ProgressValue = ex.progress.GetValueOrDefault(task.ProgressValue); continue; } catch (Exception ex) { FileInfo fileinfo = new FileInfo(task.InputFile); Logger.Error(ex.Message + ex.StackTrace); new System.Threading.Tasks.Task(() => System.Windows.MessageBox.Show(ex.Message, fileinfo.Name)).Start(); task.IsRunning = false; task.CurrentStatus = "未知错误"; continue; } } }
// 依次检查json里各项输入是否正确 public static TaskProfile ProcessJsonProfile(TaskProfile json, DirectoryInfo projDir) { // 检查参数 if (json.Version != 2 && json.Version != 3) { MessageBox.Show("你是不是把单个文件追加用的json当成一套任务用的json了?", "版本不对", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 检查VS版本 if (json.Version >= 3) { if (json.VSVersion == "") { MessageBox.Show("v3版的 JSON 中没有指定VS版本(VSVersion),请联系总监修改。", "JSON错误", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } string version; try { version = File.ReadAllText(Path.Combine(Directory.GetParent(Initializer.Config.vspipePath).FullName, "VERSION")).TrimEnd(); Logger.Debug("Detected VS Version: " + version); } catch { MessageBox.Show("无法获取VS版本,请检查VS安装。", "VS版本不对", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } if (version != json.VSVersion) { MessageBox.Show("总监指定的VS版本是" + json.VSVersion + ",但是OKEGui使用的版本是" + version, "VS版本不对", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } // 编码器设置,目前只允许x264/x265 json.EncoderType = json.EncoderType.ToLower(); switch (json.EncoderType) { case "x264": json.VideoFormat = "AVC"; break; case "x265": json.VideoFormat = "HEVC"; break; default: MessageBox.Show("EncoderType请填写x264或者x265", "编码器版本错误", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 设置封装格式 json.ContainerFormat = json.ContainerFormat.ToUpper(); if (json.ContainerFormat != "MKV" && json.ContainerFormat != "MP4") { MessageBox.Show("MKV/MP4,只能这两种", "封装格式指定的有问题", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 如果是MP4则暂不支持指定时间码 if (json.ContainerFormat == "MP4" && json.TimeCode) { MessageBox.Show("MP4暂不支持VFR封装,请联系技术总监。", "MP4暂不支持VFR封装", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } if (json.Fps <= 0 && (json.FpsNum <= 0 || json.FpsDen <= 0)) { if (json.TimeCode) { json.Fps = 1; } else { MessageBox.Show("现在json文件中需要指定帧率,哪怕 Fps : 23.976", "帧率没有指定诶", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } if (json.FpsNum > 0 && json.FpsDen > 0) { json.Fps = ((double)json.FpsNum) / json.FpsDen; } else { switch (json.Fps) { case 1.0: json.FpsNum = 1; json.FpsDen = 1; break; case 23.976: json.FpsNum = 24000; json.FpsDen = 1001; break; case 24.000: json.FpsNum = 24; json.FpsDen = 1; break; case 25.000: json.FpsNum = 25; json.FpsDen = 1; break; case 29.970: json.FpsNum = 30000; json.FpsDen = 1001; break; case 50.000: json.FpsNum = 50; json.FpsDen = 1; break; case 59.940: json.FpsNum = 60000; json.FpsDen = 1001; break; default: MessageBox.Show("请通过FpsNum和FpsDen来指定", "不知道的帧率诶", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } if (json.AudioTracks != null && json.AudioTracks.Count > 0) { foreach (AudioInfo ai in json.AudioTracks) { if (string.IsNullOrWhiteSpace(ai.OutputCodec)) { MessageBox.Show("音轨未设置 OutputCodec,请检查大小写", "音轨编码错误", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } // 主音轨 json.AudioFormat = json.AudioTracks[0].OutputCodec; if (string.IsNullOrEmpty(json.AudioFormat)) { json.AudioFormat = "AAC"; } else { json.AudioFormat = json.AudioFormat.ToUpper(); } } else { json.AudioFormat = "AAC"; } if (json.AudioFormat != "FLAC" && json.AudioFormat != "AAC" && json.AudioFormat != "AC3" && json.AudioFormat != "DTS") { MessageBox.Show("音轨只能是FLAC/AAC/AC3/DTS", "音轨格式不支持", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } if (json.AudioFormat == "FLAC" && json.ContainerFormat == "MP4") { MessageBox.Show("MP4格式没法封FLAC", "音轨格式不支持", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } // 获取编码器全路径 if (string.IsNullOrEmpty(json.Encoder)) { FileInfo encoder; switch (json.EncoderType) { case "x264": encoder = new FileInfo(Constants.x264Path); break; case "x265": encoder = new FileInfo(Constants.x265Path); break; default: // shouldn't happen. return(null); } json.Encoder = encoder.FullName; } else { FileInfo encoder = new FileInfo(projDir.FullName + "\\" + json.Encoder); if (encoder.Exists) { json.Encoder = encoder.FullName; } else { MessageBox.Show("编码器好像不在json指定的地方(文件名错误?还有记得放在json文件同目录下)", "找不到编码器啊", MessageBoxButton.OK, MessageBoxImage.Error); return(null); } } return(json); }