/// <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); }
/// <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); } }
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; }