public static void CheckStreamLimit(EncodeInfo encodingJob) { // rearrange default audio stream AudioInfo defaultAudioItem = encodingJob.AudioStreams.Find(info => info.MkvDefault); if (defaultAudioItem != null) { encodingJob.AudioStreams.Remove(defaultAudioItem); encodingJob.AudioStreams.Insert(0, defaultAudioItem); } // rearrange default subtitle stream SubtitleInfo defaultSubtitleItem = encodingJob.SubtitleStreams.Find(info => info.MkvDefault); if (defaultSubtitleItem != null) { encodingJob.SubtitleStreams.Remove(defaultSubtitleItem); encodingJob.SubtitleStreams.Insert(0, defaultSubtitleItem); } switch (encodingJob.EncodingProfile.OutFormat) { case OutputType.OutputWebM: // WebM has no support for subtitles encodingJob.SubtitleStreams.Clear(); // WebM supports max one audio stream per file AudioInfo firstIndex = encodingJob.AudioStreams.First(); if (firstIndex != null) { encodingJob.AudioStreams.RemoveAll(info => info != firstIndex); } break; case OutputType.OutputDvd: int audioCount = encodingJob.AudioStreams.Count; int subtitleCount = encodingJob.SubtitleStreams.Count; int chapterCount = encodingJob.Chapters.Count; // DVD supports max 8 audio streams if (audioCount > 8) { encodingJob.AudioStreams.RemoveRange(8, audioCount - 8); } // DVD supports max 32 subtitle streams if (subtitleCount > 32) { encodingJob.SubtitleStreams.RemoveRange(32, subtitleCount - 32); } // DVD supports max 99 chapter markers if (chapterCount > 99) { encodingJob.Chapters.RemoveRange(99, chapterCount - 99); } break; } }
public static void CheckSubtitles(EncodeInfo encodingJob) { // WebM Format has no support for subtitles if (encodingJob.EncodingProfile.OutFormat == OutputType.OutputWebM) { encodingJob.SubtitleStreams.Clear(); } foreach (SubtitleInfo info in encodingJob.SubtitleStreams) { info.NeedConversion = SubtitleNeedConversion(encodingJob.EncodingProfile.OutFormat, info.Format) || (info.KeepOnlyForcedCaptions && !info.HardSubIntoVideo); info.FormatSupported = SubtitleConversionSupported(encodingJob.EncodingProfile.OutFormat, info.Format); } encodingJob.SubtitleStreams.RemoveAll(info => !info.FormatSupported); }
private void DoDump(EncodeInfo job) { switch (job.Input) { case InputType.InputDvd: MPlayer mplayer = new MPlayer(); mplayer.SetJob(job); _worker.DoWork += mplayer.DoDump; Log.Info("MPlayer.DoDump()"); break; } }
private void DoDemux(EncodeInfo job) { Eac3To eac3Toenc = new Eac3To(); FfMpeg ffmpeg = new FfMpeg(); switch (job.Input) { case InputType.InputBluRay: case InputType.InputAvchd: case InputType.InputHddvd: case InputType.InputDvd: eac3Toenc.SetJob(job); _worker.DoWork += eac3Toenc.DoDemux; Log.Info("eac3toEncoder.DoDemux()"); break; case InputType.InputAvi: case InputType.InputFlash: case InputType.InputMp4: case InputType.InputWm: case InputType.InputMatroska: case InputType.InputMpegps: case InputType.InputTs: case InputType.InputOgg: case InputType.InputWebM: ffmpeg.SetJob(job); _worker.DoWork += ffmpeg.DoDemux; Log.Info("ffmpegEncoder.DoDemux()"); break; } }
/// <summary> /// sets output filename based on output type /// </summary> /// <param name="input"></param> /// <returns></returns> private static EncodeInfo SetOutput(EncodeInfo input) { input.OutputFile = Path.Combine(AppSettings.OutputLocation, input.JobName); string inputFilePath = Path.GetDirectoryName(input.InputFile); if (string.IsNullOrEmpty(inputFilePath)) inputFilePath = input.InputFile; string inFile = Path.Combine(inputFilePath, // ReSharper disable AssignNullToNotNullAttribute Path.GetFileNameWithoutExtension(input.InputFile)); // ReSharper restore AssignNullToNotNullAttribute if (inFile == input.OutputFile) { input.OutputFile += ".new"; } switch (input.EncodingProfile.OutFormat) { case OutputType.OutputMatroska: input.OutputFile += ".mkv"; break; case OutputType.OutputWebM: input.OutputFile += ".webm"; break; case OutputType.OutputMp4: input.OutputFile += ".mp4"; break; case OutputType.OutputTs: input.OutputFile += ".ts"; break; case OutputType.OutputM2Ts: input.OutputFile += ".m2ts"; break; case OutputType.OutputBluRay: break; case OutputType.OutputAvchd: break; case OutputType.OutputDvd: break; } Log.InfoFormat("Add Input File: {0:s}", input.InputFile); Log.InfoFormat("Input Format {0}", input.Input); Log.InfoFormat("Output File: {0:s}", input.OutputFile); Log.InfoFormat("Output Format {0}", input.EncodingProfile.OutFormatStr); Log.Info("Job Details"); Log.Info(Environment.NewLine + input); return input; }
private void DoWriteInfoFile(EncodeInfo job) { InfoWriter writer = new InfoWriter(); writer.SetJob(job); _worker.DoWork += writer.DoWrite; Log.Info("InfoWriter.DoWrite()"); }
private void DoPremuxSubtitle(EncodeInfo job) { SpuMux subMux = new SpuMux(); subMux.SetJob(job); _worker.DoWork += subMux.Process; Log.Info("SpuMux.Process()"); }
private void DoMuxResult(EncodeInfo job) { switch (job.EncodingProfile.OutFormat) { case OutputType.OutputTs: case OutputType.OutputM2Ts: case OutputType.OutputAvchd: case OutputType.OutputBluRay: TsMuxeR tsmuxer = new TsMuxeR(); tsmuxer.SetJob(job); _worker.DoWork += tsmuxer.DoEncode; Log.Info("TSMuxer.DoEncode()"); break; case OutputType.OutputMatroska: case OutputType.OutputWebM: MkvMerge mkvmerge = new MkvMerge(); mkvmerge.SetJob(job); _worker.DoWork += mkvmerge.DoEncode; Log.Info("MKVmergeEncoder.DoEncode()"); break; case OutputType.OutputDvd: DvdAuthor dvdauthor = new DvdAuthor(); dvdauthor.SetJob(job); _worker.DoWork += dvdauthor.DoEncode; Log.Info("DVDAuthor.DoEncode()"); break; case OutputType.OutputMp4: MP4Box box = new MP4Box(); box.SetJob(job); _worker.DoWork += box.DoEncode; Log.Info("MP4Box.DoEncode()"); break; } }
private void DoIndexVideo(EncodeInfo job) { FfmsIndex fIndex = new FfmsIndex(); fIndex.SetJob(job); _worker.DoWork += fIndex.DoIndex; Log.Info("ffindex.DoIndex()"); }
/// <summary> /// reserved for future development /// </summary> /// <param name="job"></param> /// <returns></returns> public static bool CheckDvdCompatible(EncodeInfo job) { return true; }
// TODO: check overhead calculation public static int CalculateVideoBitrate(EncodeInfo jobInfo) { const double tsOverhead = 0.1D; // 10% const double mkvOverhead = 0.005D; // 0.5% const double dvdOverhead = 0.04D; // 4% ulong targetSize = jobInfo.EncodingProfile.TargetFileSize; double overhead = 0D; switch (jobInfo.EncodingProfile.OutFormat) { case OutputType.OutputBluRay: overhead = tsOverhead; break; case OutputType.OutputAvchd: overhead = tsOverhead; break; case OutputType.OutputMatroska: case OutputType.OutputWebM: overhead = mkvOverhead; break; case OutputType.OutputMp4: break; case OutputType.OutputTs: case OutputType.OutputM2Ts: overhead = tsOverhead; break; case OutputType.OutputDvd: overhead = dvdOverhead; break; } ulong streamSizes = 0; int maxRate = -1; if (jobInfo.VideoProfile.Type == ProfileType.X264) { maxRate = CalculateMaxRatex264((X264Profile)jobInfo.VideoProfile, jobInfo.EncodingProfile.OutFormat); } foreach (AudioInfo item in jobInfo.AudioStreams) { streamSizes += item.StreamSize + (ulong)Math.Floor(item.StreamSize * overhead); if ((item.IsHdStream) && (Math.Abs(overhead - tsOverhead) <= 0)) { streamSizes += (ulong)Math.Floor(item.StreamSize * 0.03D); } } streamSizes = jobInfo.SubtitleStreams.Aggregate(streamSizes, (current, item) => current + (item.StreamSize + (ulong)Math.Floor(item.StreamSize * overhead))); ulong sizeRemains = targetSize - streamSizes; sizeRemains -= (ulong)Math.Floor(sizeRemains * overhead); int bitrateCalc = (int)Math.Floor(sizeRemains / jobInfo.VideoStream.Length / 1000 * 8); if (jobInfo.EncodingProfile.OutFormat == OutputType.OutputDvd) { bitrateCalc = Math.Min(bitrateCalc, 8000); } if (maxRate > -1) { bitrateCalc = Math.Min(bitrateCalc, maxRate); } return(bitrateCalc); }
/// <summary> /// reserved for future development /// </summary> /// <param name="job"></param> /// <returns></returns> public static bool CheckBluRayCompatible(EncodeInfo job) { return(true); }
private void CreateJob(string fileName) { EncodeInfo inJob = new EncodeInfo {InputFile = fileName, Input = Processing.DetectInputType(fileName)}; if ((string.IsNullOrEmpty(inJob.InputFile)) || (inJob.Input == InputType.InputUndefined)) return; StreamSelect streamSelection = new StreamSelect {JobInfo = inJob, Owner = this}; bool? retValue = streamSelection.ShowDialog(); if (retValue != true) return; inJob = SetOutput(inJob); inJob = SetInOutTemp(inJob); JobCollection.Add(inJob); }
private void DoEncodeAudio(EncodeInfo job) { FfMpeg ffmpeg = new FfMpeg(); OggEnc oggEnc = new OggEnc(); Lame lame = new Lame(); NeroAACEnc aacEnc = new NeroAACEnc(); switch (job.AudioProfile.Type) { case ProfileType.AC3: ffmpeg.SetJob(job); _worker.DoWork += ffmpeg.DoEncodeAc3; Log.Info("ffmpeg.DoEncodeAC3()"); break; case ProfileType.OGG: oggEnc.SetJob(job); _worker.DoWork += oggEnc.DoEncode; Log.Info("oggenc.DoEncode()"); break; case ProfileType.AAC: aacEnc.SetJob(job); _worker.DoWork += aacEnc.DoEncode; Log.Info("NeroAacEnc.DoEncode()"); break; case ProfileType.MP3: lame.SetJob(job); _worker.DoWork += lame.DoEncode; Log.Info("lame.DoEncode()"); break; case ProfileType.Copy: if (job.EncodingProfile.OutFormat == OutputType.OutputDvd && !Processing.CheckAudioDvdCompatible(job.AudioStreams[job.StreamId])) { ffmpeg.SetJob(job); _worker.DoWork += ffmpeg.DoEncodeAc3; Log.Info("ffmpeg.DoEncodeAC3()"); } break; } }
// TODO: check overhead calculation public static int CalculateVideoBitrate(EncodeInfo jobInfo) { const double tsOverhead = 0.1D; // 10% const double mkvOverhead = 0.005D; // 0.5% const double dvdOverhead = 0.04D; // 4% ulong targetSize = jobInfo.EncodingProfile.TargetFileSize; double overhead = 0D; switch (jobInfo.EncodingProfile.OutFormat) { case OutputType.OutputBluRay: overhead = tsOverhead; break; case OutputType.OutputAvchd: overhead = tsOverhead; break; case OutputType.OutputMatroska: case OutputType.OutputWebM: overhead = mkvOverhead; break; case OutputType.OutputMp4: break; case OutputType.OutputTs: case OutputType.OutputM2Ts: overhead = tsOverhead; break; case OutputType.OutputDvd: overhead = dvdOverhead; break; } ulong streamSizes = 0; int maxRate = -1; if (jobInfo.VideoProfile.Type == ProfileType.X264) maxRate = CalculateMaxRatex264((X264Profile)jobInfo.VideoProfile, jobInfo.EncodingProfile.OutFormat); foreach (AudioInfo item in jobInfo.AudioStreams) { streamSizes += item.StreamSize + (ulong)Math.Floor(item.StreamSize * overhead); if ((item.IsHdStream) && (Math.Abs(overhead - tsOverhead) <= 0)) streamSizes += (ulong)Math.Floor(item.StreamSize * 0.03D); } streamSizes = jobInfo.SubtitleStreams.Aggregate(streamSizes, (current, item) => current + (item.StreamSize + (ulong) Math.Floor(item.StreamSize*overhead))); ulong sizeRemains = targetSize - streamSizes; sizeRemains -= (ulong)Math.Floor(sizeRemains * overhead); int bitrateCalc = (int)Math.Floor(sizeRemains / jobInfo.VideoStream.Length / 1000 * 8); if (jobInfo.EncodingProfile.OutFormat == OutputType.OutputDvd) bitrateCalc = Math.Min(bitrateCalc, 8000); if (maxRate > -1) bitrateCalc = Math.Min(bitrateCalc, maxRate); return bitrateCalc; }
private void DoEncodeVideo(EncodeInfo job) { switch (job.VideoProfile.Type) { case ProfileType.X264: { X264 x264Enc = new X264(); x264Enc.SetJob(job); _worker.DoWork += x264Enc.DoEncode; Log.Info("x264Encoder.DoEncode()"); } break; case ProfileType.HcEnc: { HcEnc hcEnc = new HcEnc(); hcEnc.SetJob(job); _worker.DoWork += hcEnc.DoEncodeDvd; Log.Info("HCEnc.DoEncodeDVD()"); } break; case ProfileType.VP8: { VpxEnc vpxEnc = new VpxEnc(); vpxEnc.SetJob(job); _worker.DoWork += vpxEnc.DoEncode; Log.Info("VpxEnc.DoEncode()"); } break; } }
private static void DeleteTempFiles(ref EncodeInfo job) { if (!AppSettings.DeleteTemporaryFiles) return; foreach (string tempFile in job.TempFiles) { if (tempFile == job.InputFile || tempFile == job.OutputFile || string.IsNullOrEmpty(tempFile)) continue; FileAttributes fi = new FileInfo(tempFile).Attributes; try { Log.InfoFormat("Deleting \"{0:s}\"", tempFile); if (fi == FileAttributes.Directory) Directory.Delete(tempFile); else File.Delete(tempFile); } catch (Exception exc) { Log.ErrorFormat("Could not delete File \"{0:s}\" -> {1:s}", tempFile, exc.Message); } } job.TempFiles.Clear(); }
private void DoMoveOutFile(EncodeInfo job) { FileWorker fw = new FileWorker(); fw.SetFiles(job.TempOutput, job.OutputFile); _worker.DoWork += fw.MoveFile; Log.Info("FileWorker.MoveFile()"); }
private static void DetermineNextStep(ref EncodeInfo job) { switch (job.NextStep) { case EncodingStep.NotSet: switch (job.Input) { case InputType.InputAvi: case InputType.InputMp4: case InputType.InputMatroska: case InputType.InputTs: case InputType.InputWm: case InputType.InputFlash: case InputType.InputMpegps: case InputType.InputWebM: case InputType.InputOgg: job.NextStep = !string.IsNullOrEmpty(job.TempInput) ? EncodingStep.CopyTempFile : EncodingStep.Demux; break; case InputType.InputDvd: job.NextStep = EncodingStep.Dump; break; default: job.NextStep = EncodingStep.Demux; break; } job.ExitCode = 0; break; case EncodingStep.CopyTempFile: case EncodingStep.Dump: job.NextStep = EncodingStep.Demux; break; case EncodingStep.Demux: // if output format for audio is other than copy or // output is set to copy but the encoding profile is set to output dvd // // and if there are actually some audio streams // // then the next step is to encode the audio streams if ((job.AudioProfile.Type != ProfileType.Copy || (job.AudioProfile.Type == ProfileType.Copy && job.EncodingProfile.OutFormat == OutputType.OutputDvd)) && job.AudioStreams.Count > 0) { job.NextStep = EncodingStep.EncodeAudio; job.StreamId = 0; } else GetSubOrVideoStep(job); break; case EncodingStep.EncodeAudio: if (job.AudioStreams.Count - 1 > job.StreamId) job.StreamId++; else GetSubOrVideoStep(job); break; case EncodingStep.ProcessSubtitle: if (job.SubtitleStreams.Count - 1 > job.StreamId && job.EncodingProfile.OutFormat == OutputType.OutputDvd && AppSettings.JavaInstalled) job.StreamId++; else GetSubOrVideoStep(job); break; case EncodingStep.IndexVideo: if (job.EncodingProfile.AutoCropResize && !job.EncodingProfile.KeepInputResolution && job.EncodingProfile.OutFormat != OutputType.OutputDvd) job.NextStep = EncodingStep.GetCropRect; else { job.NextStep = EncodingStep.EncodeVideo; job.StreamId = 1; } break; case EncodingStep.GetCropRect: job.NextStep = EncodingStep.EncodeVideo; job.StreamId = 1; break; case EncodingStep.EncodeVideo: int encodingPasses = 1; switch (job.VideoProfile.Type) { case ProfileType.X264: switch (((X264Profile)job.VideoProfile).EncodingMode) { case 2: encodingPasses = 2; break; case 3: encodingPasses = 3; break; } break; case ProfileType.VP8: encodingPasses += ((VP8Profile) job.VideoProfile).EncodingMode; break; } if (job.StreamId < encodingPasses) job.StreamId++; else if (job.EncodingProfile.OutFormat == OutputType.OutputDvd) job.NextStep = EncodingStep.PreMuxResult; else job.NextStep = EncodingStep.MuxResult; break; case EncodingStep.PreMuxResult: if (job.SubtitleStreams.Count > 0) { job.NextStep = EncodingStep.PremuxSubtitle; job.StreamId = 0; } else job.NextStep = EncodingStep.MuxResult; break; case EncodingStep.PremuxSubtitle: if (job.StreamId < job.SubtitleStreams.Count - 1) job.StreamId++; else job.NextStep = EncodingStep.MuxResult; break; case EncodingStep.MuxResult: if (string.IsNullOrEmpty(job.TempOutput)) if (AppSettings.CreateXbmcInfoFile && job.MovieInfo != null) job.NextStep = EncodingStep.WriteInfoFile; else job.NextStep = EncodingStep.Done; else job.NextStep = EncodingStep.MoveOutFile; break; case EncodingStep.MoveOutFile: if (AppSettings.CreateXbmcInfoFile && job.MovieInfo != null) job.NextStep = EncodingStep.WriteInfoFile; else job.NextStep = EncodingStep.Done; break; case EncodingStep.WriteInfoFile: job.NextStep = EncodingStep.Done; break; } }
private void DoPreMuxResult(EncodeInfo job) { MJpeg mplex = new MJpeg(); mplex.SetJob(job); _worker.DoWork += mplex.DoEncode; Log.Info("mjpeg.DoEncode()"); }
private static void GetSubOrVideoStep(EncodeInfo job) { if (job.VideoStream != null) { switch (job.NextStep) { case EncodingStep.Demux: case EncodingStep.EncodeAudio: SubtitleInfo sub = job.SubtitleStreams.FirstOrDefault( subInfo => !subInfo.HardSubIntoVideo && subInfo.KeepOnlyForcedCaptions && (subInfo.Format.Equals("VobSub") || subInfo.Format.Equals("PGS"))); if (job.EncodingProfile.OutFormat == OutputType.OutputDvd && AppSettings.JavaInstalled && job.SubtitleStreams.Count > 0) { job.NextStep = EncodingStep.ProcessSubtitle; job.StreamId = 0; } else if (AppSettings.JavaInstalled && sub != null) { job.NextStep = EncodingStep.ProcessSubtitle; job.StreamId = job.SubtitleStreams.IndexOf(sub); } else if (job.VideoProfile.Type != ProfileType.Copy) job.NextStep = EncodingStep.IndexVideo; else if (job.EncodingProfile.OutFormat == OutputType.OutputDvd) job.NextStep = EncodingStep.PreMuxResult; else job.NextStep = EncodingStep.MuxResult; break; case EncodingStep.ProcessSubtitle: if (job.VideoProfile.Type != ProfileType.Copy) job.NextStep = EncodingStep.IndexVideo; else if (job.EncodingProfile.OutFormat == OutputType.OutputDvd) job.NextStep = EncodingStep.PreMuxResult; else job.NextStep = EncodingStep.MuxResult; break; } } else { job.NextStep = job.EncodingProfile.OutFormat == OutputType.OutputDvd ? EncodingStep.PreMuxResult : EncodingStep.MuxResult; } }
private void DoProcessSubtitle(EncodeInfo job) { BdSup2SubTool subtool = new BdSup2SubTool(); subtool.SetJob(job); _worker.DoWork += subtool.DoProcess; Log.Info("BDSup2SubTool.DoProcess()"); }
private void DoCopyTempFile(EncodeInfo job) { FileWorker fw = new FileWorker(); fw.SetFiles(job.InputFile, job.TempInput); _worker.DoWork += fw.CopyFile; Log.Info("FileWorker.CopyFile()"); }
private void GetCropRect(EncodeInfo job) { FfMpeg ffmpeg = new FfMpeg(); ffmpeg.SetJob(job); _worker.DoWork += ffmpeg.GetCrop; Log.Info("ffmpegEncoder.GetCropRect()"); }
private static EncodeInfo SetInOutTemp(EncodeInfo inJob) { string asciiFile = Processing.GetAsciiFileName(inJob.InputFile); if (string.CompareOrdinal(inJob.InputFile, asciiFile) != 0) inJob.TempInput = Processing.CreateTempFile(Path.GetExtension(inJob.InputFile)); asciiFile = Processing.GetAsciiFileName(inJob.OutputFile); if (string.CompareOrdinal(inJob.OutputFile, asciiFile) != 0) { string fExt; if ((inJob.EncodingProfile.OutFormat == OutputType.OutputAvchd) || (inJob.EncodingProfile.OutFormat == OutputType.OutputBluRay) || (inJob.EncodingProfile.OutFormat == OutputType.OutputDvd)) fExt = string.Empty; else fExt = Path.GetExtension(inJob.OutputFile); inJob.TempOutput = Processing.CreateTempFile(string.IsNullOrEmpty(inJob.TempInput) ? asciiFile : inJob.TempInput, fExt); } return inJob; }