public OKEFile StartMuxing(string path, MediaFile mediaFile) { List <string> input = new List <string>(); string videoFps = ""; string videoName = ""; string timeCodeFile = null; List <string> audioLanguages = new List <string>(); List <string> audioNames = new List <string>(); List <string> subtitleLanguages = new List <string>(); List <string> subtitleNames = new List <string>(); foreach (var track in mediaFile.Tracks) { if (track.Info.MuxOption != MuxOption.Default && track.Info.MuxOption != MuxOption.Mka) { continue; } switch (track.TrackType) { case TrackType.Audio: AudioTrack audioTrack = track as AudioTrack; audioLanguages.Add(audioTrack.Info.Language); audioNames.Add(audioTrack.Info.Name); break; case TrackType.Video: VideoTrack videoTrack = track as VideoTrack; VideoInfo videoInfo = track.Info as VideoInfo; videoFps = $"{videoInfo.FpsNum}/{videoInfo.FpsDen}"; videoName = videoInfo.Name; timeCodeFile = videoInfo.TimeCodeFile; break; case TrackType.Subtitle: SubtitleTrack subtitleTrack = track as SubtitleTrack; subtitleLanguages.Add(subtitleTrack.Info.Language); subtitleNames.Add(subtitleTrack.Info.Name); break; } input.Add(track.File.GetFullPath()); } this.StartMerge(input, path, videoFps, videoName, timeCodeFile, audioLanguages, audioNames, subtitleLanguages, subtitleNames); OKEFile outFile = new OKEFile(path); outFile.AddCRC32(); return(outFile.Exists() ? outFile : null); }
public static string GenerateQpFile(OKEFile chapterFile, double fps) { string qpFile = ""; SortedDictionary <string, string> chapters = ReadChapters(chapterFile); foreach (string strTimeStamp in chapters.Keys) { long miliSec = StrToMilisec(strTimeStamp); int frameNo = (int)(miliSec / 1000.0 * fps + 0.5); qpFile += frameNo.ToString() + " I" + Environment.NewLine; } return(qpFile); }
public static SortedDictionary <string, string> ReadChapters(OKEFile file) { SortedDictionary <string, string> chapters = new SortedDictionary <string, string>(); string fileContent = File.ReadAllText(file.GetFullPath()); string[] chapterLinesArr = fileContent.Split(new string[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); List <string> chapterLines = new List <string>(chapterLinesArr); chapterLines.RemoveAll(i => string.IsNullOrWhiteSpace(i)); for (int i = 0; i < chapterLines.Count / 2; i++) { string strTime = chapterLines[i + i].Split(new char[] { '=' })[1]; string name = chapterLines[i + i + 1].Split(new char[] { '=' })[1]; chapters.Add(strTime, name); } return(chapters); }
public static OKEFile AddChapter(TaskDetail task) { FileInfo txtChapter = new FileInfo(Path.ChangeExtension(task.InputFile, ".txt")); if (txtChapter.Exists) { OKEFile chapterFile = new OKEFile(txtChapter); ChapterChecker checker = new ChapterChecker(chapterFile, task.lengthInMiliSec); checker.RemoveUnnecessaryEnd(); if (checker.IsEmpty()) { Logger.Info(txtChapter.Name + "为空,跳过封装。"); return(null); } else { task.MediaOutFile.AddTrack(new ChapterTrack(chapterFile)); return(chapterFile); } } return(null); }
/// <summary> /// /// </summary> /// <param name="fileName"></param> /// <param name="completedCallback">抽取的轨道,不包含重复轨道;重复轨道文件名带有.bak</param> public MediaFile Extract(Action <double, EACProgressType> progressCallback) { if (!new FileInfo(sourceFile).Exists) { return(null); } _progressCallback = progressCallback; state = ProcessState.FetchStream; StartEac($"\"{sourceFile}\"", false); var args = new List <string>(); var extractResult = new List <TrackInfo>(); List <TrackInfo> srcAudio = new List <TrackInfo>(); List <TrackInfo> srcSub = new List <TrackInfo>(); foreach (TrackInfo track in tracks) { switch (track.Type) { case TrackType.Audio: srcAudio.Add(track); break; case TrackType.Subtitle: srcSub.Add(track); break; default: break; } } if (srcAudio.Count != JobAudio.Count) { OKETaskException ex = new OKETaskException(Constants.audioNumMismatchSmr); ex.progress = 0.0; ex.Data["SRC_TRACK"] = srcAudio.Count; ex.Data["DST_TRACK"] = JobAudio.Count; throw ex; } if (srcSub.Count != JobSub.Count) { OKETaskException ex = new OKETaskException(Constants.subNumMismatchSmr); ex.progress = 0.0; ex.Data["SRC_TRACK"] = srcSub.Count; ex.Data["DST_TRACK"] = JobSub.Count; throw ex; } int audioId = 0, subId = 0; foreach (TrackInfo track in tracks) { EacOutputTrackType trackType = s_eacOutputs.Find(val => val.Codec == track.Codec); if (!(trackType.Extract || trackType.Type == TrackType.Video && extractVideo)) { continue; } ; if (track.Type == TrackType.Audio) { AudioInfo jobAudioInfo = JobAudio[audioId++]; if (jobAudioInfo.MuxOption == MuxOption.Skip) { continue; } } if (track.Type == TrackType.Subtitle) { Info jobSubInfo = JobSub[subId++]; if (jobSubInfo.MuxOption == MuxOption.Skip) { continue; } } args.Add($"{track.Index}:\"{track.OutFileName}\""); extractResult.Add(track); } JobAudio.RemoveAll(info => info.MuxOption == MuxOption.Skip); JobSub.RemoveAll(info => info.MuxOption == MuxOption.Skip); state = ProcessState.ExtractStream; StartEac($"\"{sourceFile}\" {string.Join(" ", args)}", true); foreach (TrackInfo track in extractResult) { FileInfo finfo = new FileInfo(track.OutFileName); if (!finfo.Exists || finfo.Length == 0) { throw new Exception("文件输出失败: " + track.OutFileName); } else { track.FileSize = finfo.Length; } if (track.Type == TrackType.Audio) { FFmpegVolumeChecker checker = new FFmpegVolumeChecker(track.OutFileName); checker.start(); checker.waitForFinish(); track.MaxVolume = checker.MaxVolume; track.MeanVolume = checker.MeanVolume; } } List <int> removeList = new List <int>(); for (int i = 0; i < extractResult.Count; i++) { TrackInfo track = extractResult[i]; if (removeList.Contains(track.Index)) { continue; } if (track.IsEmpty()) { Logger.Warn(track.OutFileName + "被检测为空轨道。"); removeList.Add(track.Index); track.MarkSkipping(); continue; } for (int j = i + 1; j < extractResult.Count; j++) { TrackInfo other = extractResult[j]; if (track.IsDuplicate(other)) { Logger.Warn(track.OutFileName + "被检测为与" + other.OutFileName + "重复。"); removeList.Add(other.Index); other.MarkSkipping(); } } } MediaFile mf = new MediaFile(); audioId = 0; subId = 0; foreach (var item in extractResult) { OKEFile file = new OKEFile(item.OutFileName); switch (item.Type) { case TrackType.Audio: AudioInfo audioInfo = JobAudio[audioId++]; audioInfo.DupOrEmpty = item.DupOrEmpty; mf.AddTrack(new AudioTrack(file, audioInfo)); break; case TrackType.Subtitle: Info subInfo = JobSub[subId++]; subInfo.DupOrEmpty = item.DupOrEmpty; mf.AddTrack(new SubtitleTrack(file, subInfo)); break; case TrackType.Chapter: FileInfo txtChapter = new FileInfo(Path.ChangeExtension(sourceFile, ".txt")); if (txtChapter.Exists) { Logger.Info("检测到单独准备的章节,不予添加"); } else { file.Rename(txtChapter.FullName); } break; case TrackType.Video: mf.AddTrack(new VideoTrack(file, new VideoInfo())); break; default: System.Windows.MessageBox.Show(item.OutFileName, "不认识的轨道呢"); break; } } return(mf); }
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; } } }
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; } } }
public ChapterChecker(OKEFile chapterFile, long lengthInMiliSec) { ChapterFile = chapterFile; LengthInMiliSec = lengthInMiliSec; Chapters = ChapterService.ReadChapters(chapterFile); }