private int GetTotalEncodingSteps() { int encodingSteps = 0; foreach (EncodeInfo job in JobList) { if (!string.IsNullOrEmpty(job.TempInput)) { encodingSteps++; // create temp file with ascii filename } encodingSteps++; // demux encodingSteps += job.AudioStreams.Count( aud => job.AudioProfile.Type == ProfileType.AC3 || job.AudioProfile.Type == ProfileType.OGG || job.AudioProfile.Type == ProfileType.MP3 || job.AudioProfile.Type == ProfileType.AAC || job.AudioProfile.Type == ProfileType.FLAC); // demux subtitles encodingSteps += job.SubtitleStreams.Count(sub => sub.RawStream == false); // process subtitles encodingSteps += job.SubtitleStreams.Count(sub => sub.NeedConversion); if (job.VideoStream != null) { if (job.VideoProfile.Type != ProfileType.Copy) { encodingSteps++; // index switch (job.VideoProfile.Type) { case ProfileType.X264: X264Profile videoProfile = (X264Profile)job.VideoProfile; switch (videoProfile.EncodingMode) { case 2: encodingSteps += 2; // 2 pass encoding break; case 3: encodingSteps += 3; // 3 pass encoding break; default: encodingSteps++; break; } if (job.EncodingProfile.AutoCropResize && !job.EncodingProfile.KeepInputResolution) { encodingSteps++; // search croprect } break; case ProfileType.HcEnc: encodingSteps += 2; break; case ProfileType.VP8: VP8Profile vp8Profile = (VP8Profile)job.VideoProfile; if (vp8Profile.EncodingMode == 0) { encodingSteps++; } else { encodingSteps += 2; } if (job.EncodingProfile.AutoCropResize && !job.EncodingProfile.KeepInputResolution) { encodingSteps++; // search croprect } break; } } // end if videoprofile != copy if (job.EncodingProfile.OutFormat == OutputType.OutputDvd) { encodingSteps++; // premux streams for dvdauthor if (job.SubtitleStreams.Count > 0) { encodingSteps += job.SubtitleStreams.Count; // premux subtitles } } } // end if videostream != null encodingSteps++; // mux streams if (!string.IsNullOrEmpty(job.TempOutput)) { encodingSteps++; // move finished file to output destination } if (AppSettings.CreateXbmcInfoFile && (job.MovieInfo != null || job.EpisodeInfo != null)) { encodingSteps++; // create xbmc info files } } // foreach job return(encodingSteps); }
public void DoEncode(object sender, DoWorkEventArgs e) { _bw = (BackgroundWorker)sender; string passStr = Processing.GetResourceString("vp8_pass"); string status = Processing.GetResourceString("vp8_encoding_status"); VP8Profile encProfile = (VP8Profile)_jobInfo.VideoProfile; if (!_jobInfo.EncodingProfile.Deinterlace && _jobInfo.VideoStream.Interlaced) { _jobInfo.VideoStream.Interlaced = false; } Size resizeTo = VideoHelper.GetTargetSize(_jobInfo); if (string.IsNullOrEmpty(_jobInfo.AviSynthScript)) { GenerateAviSynthScript(resizeTo); } string inputFile = _jobInfo.AviSynthScript; string outFile = Processing.CreateTempFile( string.IsNullOrEmpty(_jobInfo.TempOutput) ? _jobInfo.BaseName : _jobInfo.TempOutput, "encoded.webm"); _frameCount = _jobInfo.VideoStream.FrameCount; int targetBitrate = 0; if (_jobInfo.EncodingProfile.TargetFileSize > 0) { targetBitrate = Processing.CalculateVideoBitrate(_jobInfo); } int encodeMode = encProfile.EncodingMode; if (encodeMode == 1) { _pass = string.Format(" {1} {0:0}; ", _jobInfo.StreamId, passStr); } _bw.ReportProgress(-10, status + _pass.Replace("; ", string.Empty)); _bw.ReportProgress(0, status); string argument = VP8CommandLineGenerator.Generate(encProfile, targetBitrate, resizeTo.Width, resizeTo.Height, _jobInfo.StreamId, _jobInfo.VideoStream.FrameRateEnumerator, _jobInfo.VideoStream.FrameRateDenominator, outFile); string localExecutable = Path.Combine(AppSettings.ToolsPath, Executable); using (Process encoder = new Process(), decoder = FfMpeg.GenerateDecodeProcess(inputFile, AppSettings.Use64BitEncoders && AppSettings.UseFfmpegScaling, new Size(_jobInfo.VideoStream.Width, _jobInfo.VideoStream.Height), _jobInfo.VideoStream.AspectRatio, _jobInfo.VideoStream.CropRect, resizeTo)) { ProcessStartInfo parameter = new ProcessStartInfo(localExecutable) { WorkingDirectory = AppSettings.DemuxLocation, Arguments = argument, CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true, RedirectStandardInput = true }; encoder.StartInfo = parameter; encoder.ErrorDataReceived += OnDataReceived; Log.InfoFormat("start parameter: vpxenc {0:s}", argument); bool started; bool decStarted; try { started = encoder.Start(); } catch (Exception ex) { started = false; Log.ErrorFormat("vpxenc exception: {0}", ex); _jobInfo.ExitCode = -1; } NamedPipeServerStream decodePipe = new NamedPipeServerStream(AppSettings.DecodeNamedPipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.None); try { decStarted = decoder.Start(); } catch (Exception ex) { decStarted = false; Log.ErrorFormat("avconv exception: {0}", ex); _jobInfo.ExitCode = -1; } _startTime = DateTime.Now; if (started && decStarted) { encoder.PriorityClass = AppSettings.GetProcessPriority(); encoder.BeginErrorReadLine(); decoder.PriorityClass = AppSettings.GetProcessPriority(); decoder.BeginErrorReadLine(); Thread pipeReadThread = new Thread(() => { try { ReadThreadStart(decodePipe, encoder); } catch (Exception ex) { Log.Error(ex); } }); pipeReadThread.Start(); pipeReadThread.Priority = ThreadPriority.BelowNormal; encoder.Exited += (o, args) => pipeReadThread.Abort(); while (!encoder.HasExited) { if (_bw.CancellationPending) { encoder.Kill(); decoder.Kill(); } Thread.Sleep(200); } encoder.WaitForExit(10000); encoder.CancelErrorRead(); if (decodePipe.IsConnected) { try { decodePipe.Disconnect(); } catch (Exception ex) { Log.Error(ex); } } try { decodePipe.Close(); decodePipe.Dispose(); } catch (Exception ex) { Log.Error(ex); } decoder.WaitForExit(10000); decoder.CancelErrorRead(); _jobInfo.ExitCode = encoder.ExitCode; Log.InfoFormat("Exit Code: {0:g}", _jobInfo.ExitCode); } } if (_jobInfo.ExitCode == 0) { if ((encProfile.EncodingMode == 1 && _jobInfo.StreamId == 2) || encProfile.EncodingMode == 0) { _jobInfo.VideoStream.Encoded = true; _jobInfo.VideoStream.IsRawStream = false; _jobInfo.TempFiles.Add(_jobInfo.VideoStream.TempFile); _jobInfo.VideoStream.TempFile = outFile; try { _jobInfo.MediaInfo = Processing.GetMediaInfo(_jobInfo.VideoStream.TempFile); } catch (TimeoutException ex) { Log.Error(ex); } _jobInfo.VideoStream = VideoHelper.GetStreamInfo(_jobInfo.MediaInfo, _jobInfo.VideoStream, _jobInfo.EncodingProfile.OutFormat == OutputType.OutputBluRay); string statsFile = Processing.CreateTempFile(outFile, "stats"); _jobInfo.TempFiles.Add(statsFile); _jobInfo.TempFiles.Add(_jobInfo.AviSynthScript); _jobInfo.TempFiles.Add(_jobInfo.FfIndexFile); _jobInfo.TempFiles.Add(_jobInfo.AviSynthStereoConfig); } } _bw.ReportProgress(100); _jobInfo.CompletedStep = _jobInfo.NextStep; e.Result = _jobInfo; }
/// <summary> /// Generates commandline arguments used for encoding an video stream to VP8 format. /// Input is always stdin. /// </summary> /// <param name="inProfile">Encoding profile</param> /// <param name="bitrate">Target bitrate</param> /// <param name="hRes">Video width</param> /// <param name="vRes">Video height</param> /// <param name="pass">Encoding pass</param> /// <param name="fpsN">Framerate numerator</param> /// <param name="fpsD">Framerate denominator</param> /// <param name="outFile">Path to output file</param> /// <returns>Commandline arguments</returns> public static string Generate(VP8Profile inProfile, int bitrate, int hRes, int vRes, int pass, int fpsN, int fpsD, string outFile = "output") { StringBuilder sb = new StringBuilder(); if (inProfile != null) { int tempPass = pass; sb.Append("--debug --codec="); sb.Append(inProfile.Encoder == 0 ? "vp8 " : "vp9 "); sb.AppendFormat(AppSettings.CInfo, "--width={0:g} --height={1:g} ", hRes, vRes); sb.AppendFormat(AppSettings.CInfo, " --deadline={0:g} ", inProfile.DeadlinePerFrame); sb.Append("--passes="); switch (inProfile.EncodingMode) { case 0: sb.Append("1 "); break; case 1: sb.Append("2 "); sb.AppendFormat(AppSettings.CInfo, "--pass={0:g} ", tempPass); break; } int tempBitrate = bitrate; if (tempBitrate <= 0) { tempBitrate = inProfile.Bitrate; } sb.AppendFormat(AppSettings.CInfo, "--target-bitrate={0:g} ", tempBitrate); sb.AppendFormat(AppSettings.CInfo, "--end-usage={0:g} ", inProfile.BitrateMode); if (inProfile.EncodingMode == 1) { string fpfFile = Processing.CreateTempFile(outFile, "stats"); sb.AppendFormat("--fpf=\"{0}\" ", fpfFile); } sb.AppendFormat(AppSettings.CInfo, "--profile={0:g} ", inProfile.Profile); switch (inProfile.SpeedControl) { case 0: sb.Append("--rt "); break; case 1: sb.Append("--good "); break; case 2: sb.Append("--best "); break; } sb.AppendFormat(AppSettings.CInfo, "--cpu-used={0:g} ", inProfile.CPUModifier); sb.AppendFormat(AppSettings.CInfo, "--token-parts={0:g} ", inProfile.TokenPart); sb.AppendFormat(AppSettings.CInfo, "--noise-sensitivity={0:g} ", inProfile.NoiseFiltering); sb.AppendFormat(AppSettings.CInfo, "--sharpness={0:g} ", inProfile.Sharpness); int tempThreads = inProfile.Threads; if (tempThreads == 0) { tempThreads = Environment.ProcessorCount * 2; } sb.AppendFormat(AppSettings.CInfo, "--threads={0:g} ", tempThreads); sb.AppendFormat(AppSettings.CInfo, "--static-thresh={0:g} ", inProfile.StaticThreshold); sb.Append("--error-resilient="); sb.Append(inProfile.UseErrorResilience ? "1 " : "0 "); sb.AppendFormat(AppSettings.CInfo, "--kf-min-dist={0:g} --kf-max-dist={1:g} ", inProfile.GopMin, inProfile.GopMax); sb.AppendFormat(AppSettings.CInfo, "--lag-in-frames={0:g} ", inProfile.MaxFramesLag); sb.AppendFormat(AppSettings.CInfo, "--drop-frame={0:g} ", inProfile.FrameDrop); if (inProfile.UseSpatialResampling) { sb.AppendFormat(AppSettings.CInfo, "--resize-allowed=1 --resize-up={0:g} --resize-down={1:g} ", inProfile.UpscaleThreshold, inProfile.DownscaleThreshold); } else { sb.Append("--resize-allowed=0 "); } if (inProfile.UseArnrFrameDecision) { sb.AppendFormat(AppSettings.CInfo, "--auto-alt-ref=1 --arnr-maxframes={0:g} --arnr-strength={1:g} ", inProfile.ArnrMaxFrames, inProfile.ArnrStrength); } else { sb.Append("--auto-alt-ref=0 "); } sb.AppendFormat(AppSettings.CInfo, "--buf-initial-sz={0:g} ", inProfile.InitialBufferSize); sb.AppendFormat(AppSettings.CInfo, "--buf-optimal-sz={0:g} ", inProfile.OptimalBufferSize); sb.AppendFormat(AppSettings.CInfo, "--buf-sz={0:g} ", inProfile.BufferSize); sb.AppendFormat(AppSettings.CInfo, "--undershoot-pct={0:g} ", inProfile.UndershootDataRate); sb.AppendFormat(AppSettings.CInfo, "--min-q={0:g} --max-q={1:g} ", inProfile.QuantizerMin, inProfile.QuantizerMax); sb.AppendFormat(AppSettings.CInfo, "--bias-pct={0:g} ", inProfile.BiasFrameAdjust); sb.AppendFormat(AppSettings.CInfo, "--minsection-pct={0:g} --maxsection-pct={1:g} ", inProfile.SectionMin, inProfile.SectionMax); // in 2-pass encoding mode use null output for first pass if (inProfile.EncodingMode == 1 && tempPass == 1) { sb.Append("-o NUL "); } else if (!String.IsNullOrEmpty(outFile)) { sb.AppendFormat("-o \"{0}\" ", outFile); } sb.Append("- "); } return(sb.ToString()); }