/// <summary> /// Prepares the files of an existing job. /// </summary> /// <returns>A MediaEncoderSegments object containing the segments analysis.</returns> public MediaEncoderSegments PrepareExistingJob(MediaEncoderSettings settings) { settings.ResumePos = 0; settings.CompletionStatus = CompletionStatus.Success; if (File.Exists(settings.FinalFile)) { // Merging was completed. return null; } else { MediaEncoderSegments SegBusiness = new MediaEncoderSegments(); SegBusiness.Analyze(settings); return SegBusiness; } }
/// <summary> /// For files encoded in various segments (stop/resume), merge the various segments. /// </summary> private CompletionStatus MergeSegments(MediaEncoderSettings settings, string destination) { MediaEncoderSegments segBusiness = new MediaEncoderSegments(); segBusiness.Analyze(settings); if (segBusiness.SegLeft.Count() > 0) return CompletionStatus.Error; List<string> SegmentList = new List<string>(); foreach (SegmentInfo seg in segBusiness.SegDone) { SegmentList.Add(PathManager.GetOutputFile(settings.JobIndex, seg.Start, settings.Container)); } CompletionStatus Result = CompletionStatus.Success; File.Delete(destination); if (SegmentList.Count == 1) File.Move(SegmentList[0], destination); else if (SegmentList.Count > 1) { Result = MediaMuxer.Concatenate(SegmentList, destination, new ProcessStartOptions(settings.JobIndex, "Merging Files", false)); } settings.CompletionStatus = Result; return Result; }
private void EncoderThread(object obj) { MediaEncoderSettings settings = obj as MediaEncoderSettings; settings.CompletionStatus = CompletionStatus.Success; DateTime StartTime = DateTime.Now; FFmpegConfig.UserInterfaceManager.Start(settings.JobIndex, "Processing Video"); MediaEncoderSegments SegBusiness = PrepareExistingJob(settings); // If merging is completed, SegBusiness==null. If work is completed but not merged, SegBusiness.SegLeft = empty list. if (SegBusiness != null && SegBusiness.SegLeft.Count() > 0) { if (settings.Deshaker && (settings.DeshakerSettings.PrescanAction != PrescanType.Full || !settings.DeshakerSettings.PrescanCompleted)) { settings.DeshakerSettings.PrescanAction = PrescanType.Full; settings.CompletionStatus = GenerateDeshakerLog(settings, settings.InputFile); } if (settings.CompletionStatus == CompletionStatus.Success) { // Encode audio stream Task EncAudio = null; if (settings.HasAudioOptions) EncAudio = Task.Run(() => EncoderBusiness.EncodeAudio(settings)); // Encode video stream in segments List<Task<CompletionStatus>> EncTasks = new List<Task<CompletionStatus>>(); if (settings.VideoAction != VideoAction.Copy) { bool Cancel = false; foreach (SegmentInfo seg in SegBusiness.SegLeft) { MediaEncoderSettings EncSettings = settings.Clone(); EncSettings.ResumePos = seg.Start; File.Delete(EncSettings.OutputFile); EncTasks.Add(Task.Run(() => EncoderBusiness.EncodeVideo(EncSettings, seg.Length, SegBusiness.TotalFrames))); // If there are more segments than max parallel instances, wait until some threads finish if (EncTasks.Count >= settings.ParallelProcessing) { Task.WaitAny(EncTasks.ToArray()); foreach (var item in EncTasks.ToArray()) { if (item.IsCompleted) { if (item.Result == CompletionStatus.Success) EncTasks.Remove(item); else { settings.CompletionStatus = item.Result; Cancel = true; } } } } if (Cancel) break; } } EncAudio?.Wait(); Task.WaitAll(EncTasks.ToArray()); } } else if (settings.CompletionStatus == CompletionStatus.None) settings.CompletionStatus = CompletionStatus.Success; if (FFmpegConfig.UserInterfaceManager.AppExited) return; // Check if encode is completed. EncodingCompletedEventArgs CompletedArgs = null; if (settings.CompletionStatus == CompletionStatus.Success) { CompletedArgs = FinalizeEncoding(settings, StartTime); if (settings.CompletionStatus == CompletionStatus.Success && CompletedArgs != null) EncodingCompleted?.Invoke(this, CompletedArgs); } if (settings.CompletionStatus != CompletionStatus.Success) { CompletedArgs = GetEncodingResults(settings, null, StartTime); if (IsEncoding) EncodingFailed?.Invoke(this, CompletedArgs); } if (IsEncoding || settings.CompletionStatus == CompletionStatus.Success) Application.Current.Dispatcher.Invoke(() => ProcessingQueue.Remove(settings)); FFmpegConfig.UserInterfaceManager.Stop(settings.JobIndex); // Start next job. if (IsEncoding && ProcessingQueue.Count > 0) EncoderThread(ProcessingQueue.First()); JobThread = null; }