Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        /// <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);
        }
Esempio n. 6
0
        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;
                }
            }
        }
Esempio n. 7
0
        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;
                }
            }
        }
Esempio n. 8
0
 public ChapterChecker(OKEFile chapterFile, long lengthInMiliSec)
 {
     ChapterFile     = chapterFile;
     LengthInMiliSec = lengthInMiliSec;
     Chapters        = ChapterService.ReadChapters(chapterFile);
 }