/// <summary> /// Replace arguments with the given job information. /// </summary> /// <param name="nameFormat">The name format to use.</param> /// <param name="picker">The picker.</param> /// <param name="jobViewModel">The job to pick information from.</param> /// <returns>The string with arguments replaced.</returns> public string ReplaceArguments(string nameFormat, Picker picker, EncodeJobViewModel jobViewModel) { // The jobViewModel might have null VideoSource and VideoSourceMetadata from an earlier version < 4.17. VCJob job = jobViewModel.Job; SourceTitle title = jobViewModel.VideoSource?.Titles.Single(t => t.Index == job.Title); string sourceName = jobViewModel.VideoSourceMetadata != null ? jobViewModel.VideoSourceMetadata.Name : string.Empty; TimeSpan titleDuration = title?.Duration.ToSpan() ?? TimeSpan.Zero; int chapterCount = title?.ChapterList.Count ?? 0; bool hasMultipleTitles = jobViewModel.VideoSource != null && jobViewModel.VideoSource.Titles.Count > 1; return(this.ReplaceArguments( job.SourcePath, sourceName, job.Title, titleDuration, job.RangeType, job.ChapterStart, job.ChapterEnd, chapterCount, TimeSpan.FromSeconds(job.SecondsStart), TimeSpan.FromSeconds(job.SecondsEnd), job.FramesStart, job.FramesEnd, nameFormat, hasMultipleTitles, picker)); }
public QueueTitlesDialogViewModel(List <Title> allTitles) { this.main = Ioc.Container.GetInstance <MainViewModel>(); this.selectedTitles = new ObservableCollection <TitleSelectionViewModel>(); this.selectRange = Config.QueueTitlesUseRange; this.startRange = Config.QueueTitlesStartTime; this.endRange = Config.QueueTitlesEndTime; this.titleStartOverrideEnabled = Config.QueueTitlesUseTitleOverride; this.titleStartOverride = Config.QueueTitlesTitleOverride; this.directoryOverrideEnabled = Config.QueueTitlesUseDirectoryOverride; this.directoryOverride = Config.QueueTitlesDirectoryOverride; this.nameOverrideEnabled = Config.QueueTitlesUseNameOverride; this.nameOverride = Config.QueueTitlesNameOverride; this.titles = new List <TitleSelectionViewModel>(); foreach (Title title in allTitles) { var titleVM = new TitleSelectionViewModel(title, this); this.titles.Add(titleVM); } // Perform range selection if enabled. if (this.selectRange) { this.SetSelectedFromRange(); } this.selectedTitles.CollectionChanged += (sender, args) => { this.RaisePropertyChanged(() => this.TitleDetailsVisible); if (this.selectedTitles.Count == 1) { Title title = this.selectedTitles[0].Title; // Do preview var previewProfile = new VCProfile { CustomCropping = true, Cropping = new Cropping(), VideoEncoder = "x264", AudioEncodings = new List <AudioEncoding>() }; var previewJob = new VCJob { RangeType = VideoRangeType.All, Title = title.TitleNumber, EncodingProfile = previewProfile }; this.PreviewImage = this.main.ScanInstance.GetPreview(previewJob.HbJob, 2); this.RaisePropertyChanged(() => this.TitleText); } }; }
public void RefreshOutputSize() { if (this.HasSourceData) { VCJob job = this.MainViewModel.EncodeJob; job.EncodingProfile = this.Profile; int width, height, parWidth, parHeight; this.MainViewModel.ScanInstance.GetSize(job.HbJob, out width, out height, out parWidth, out parHeight); if (this.Profile.Rotation == VCPictureRotation.Clockwise90 || this.Profile.Rotation == VCPictureRotation.Clockwise270) { int temp = width; width = height; height = temp; temp = parWidth; parWidth = parHeight; parHeight = temp; } this.StorageWidth = width; this.StorageHeight = height; Messenger.Default.Send(new OutputSizeChangedMessage()); this.OutputSourceResolution = width + " x " + height; this.OutputPixelAspectRatio = parWidth + "/" + parHeight; this.OutputDisplayResolution = Math.Round(width * (((double)parWidth) / parHeight)) + " x " + height; } }
/// <summary> /// Starts an encode, given a VidCoder job and some extra data. /// </summary> /// <param name="job">The VidCoder job to run.</param> /// <param name="previewNumber">The preview number to run.</param> /// <param name="previewSeconds">The number of seconds the preview should be.</param> /// <param name="defaultChapterNameFormat">The default format for chapter names.</param> public void StartEncode( VCJob job, int previewNumber, int previewSeconds, string defaultChapterNameFormat) { this.StartEncodeInternal( job.SourcePath, job.Title, scanObject => { SourceTitle encodeTitle = scanObject.TitleList.FirstOrDefault(title => title.Index == job.Title); if (encodeTitle != null) { JsonEncodeFactory factory = new JsonEncodeFactory(ServiceLocator.Current.GetInstance <ILogger>()); JsonEncodeObject encodeObject = factory.CreateJsonObject( job, encodeTitle, defaultChapterNameFormat, previewNumber, previewSeconds, this.passedPreviewCount); return(JsonConvert.SerializeObject(encodeObject, JsonSettings.HandBrakeJsonSerializerSettings)); } else { return(null); } }); }
public EncodeJobViewModel(VCJob job) { this.job = job; Messenger.Default.Register <ScanningChangedMessage>( this, message => { this.EditQueueJobCommand.RaiseCanExecuteChanged(); }); }
public EncodeJobViewModel(VCJob job) { this.job = job; // ShowProgressBar this.WhenAnyValue(x => x.Encoding, x => x.IsOnlyItem, (encoding, isOnlyItem) => { return(encoding && !isOnlyItem); }).ToProperty(this, x => x.ShowProgressBar, out this.showProgressBar); // ProgressToolTip this.WhenAnyValue(x => x.Eta, eta => { if (eta == TimeSpan.Zero) { return(null); } return("Job ETA: " + Utilities.FormatTimeSpan(eta)); }).ToProperty(this, x => x.ProgressToolTip, out this.progressToolTip); // ShowQueueEditButtons this.WhenAnyValue(x => x.Encoding, encoding => !encoding) .ToProperty(this, x => x.ShowQueueEditButtons, out this.showQueueEditButtons); // ProgressBarColor this.WhenAnyValue(x => x.IsPaused, isPaused => { if (isPaused) { return(new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(255, 230, 0))); } else { return(new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(0, 200, 0))); } }).ToProperty(this, x => x.ProgressBarColor, out this.progressBarColor); this.EditQueueJob = ReactiveCommand.Create(this.WhenAnyValue( x => x.Encoding, x => x.MainViewModel.VideoSourceState, (isEncoding, videoSourceState) => { return(!isEncoding && videoSourceState != VideoSourceState.Scanning); })); this.EditQueueJob.Subscribe(_ => this.EditQueueJobImpl()); this.RemoveQueueJob = ReactiveCommand.Create(this.WhenAnyValue(x => x.Encoding, encoding => { return(!encoding); })); this.RemoveQueueJob.Subscribe(_ => this.RemoveQueueJobImpl()); }
public async Task StartEncodeAsync( VCJob job, IAppLogger logger, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds) { this.Logger = logger; this.encodeStartEvent = new SemaphoreSlim(0, 1); this.encodeEndEvent = new SemaphoreSlim(0, 1); await this.RunOperationAsync(worker => worker.StartEncode( job, preview ? previewNumber : -1, previewSeconds, EncodingRes.DefaultChapterName) ); }
public void StartEncode( VCJob job, IAppLogger logger, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds) { this.Logger = logger; this.encodeStartEvent = new ManualResetEventSlim(false); this.encodeEndEvent = new ManualResetEventSlim(false); this.StartOperation(channel => { channel.StartEncode( job, preview ? previewNumber : -1, previewSeconds, EncodingRes.DefaultChapterName); }); }
public Task StartEncodeAsync( VCJob job, IAppLogger logger, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds) { this.logger = logger; this.StartEncodeInternal( job.SourcePath, job.Title, scanObject => { SourceTitle encodeTitle = scanObject.TitleList.FirstOrDefault(title => title.Index == job.Title); if (encodeTitle != null) { JsonEncodeFactory factory = new JsonEncodeFactory(logger); JsonEncodeObject jsonEncodeObject = factory.CreateJsonObject( job, encodeTitle, EncodingRes.DefaultChapterName, preview ? previewNumber : -1, previewSeconds, Config.PreviewCount); return(JsonConvert.SerializeObject(jsonEncodeObject, JsonSettings.HandBrakeJsonSerializerSettings)); } else { return(null); } }); return(Task.CompletedTask); }
public EncodeJobViewModel(VCJob job) { this.job = job; // ShowProgressBar Observable.CombineLatest( this.WhenAnyValue(x => x.Encoding), this.ProcessingService.QueueCountObservable, (encoding, queueCount) => { return(encoding && queueCount != 1); }).ToProperty(this, x => x.ShowProgressBar, out this.showProgressBar); // ProgressToolTip this.WhenAnyValue(x => x.Eta, eta => { if (eta == TimeSpan.Zero) { return(null); } return("Job ETA: " + Utilities.FormatTimeSpan(eta)); }).ToProperty(this, x => x.ProgressToolTip, out this.progressToolTip); // ShowQueueEditButtons this.WhenAnyValue(x => x.Encoding, encoding => !encoding) .ToProperty(this, x => x.ShowQueueEditButtons, out this.showQueueEditButtons); // PercentComplete this.WhenAnyValue(x => x.FractionComplete).Select(fractionComplete => { return(this.fractionComplete * 100.0); }).ToProperty(this, x => x.PercentComplete, out this.percentComplete); // PassProgressPercent this.WhenAnyValue(x => x.PassProgressFraction).Select(passProgressFraction => { return(this.passProgressFraction * 100.0); }).ToProperty(this, x => x.PassProgressPercent, out this.passProgressPercent); // FileSizeDisplay this.WhenAnyValue(x => x.FileSizeBytes).Select(fileSizeBytes => { return(Utilities.FormatFileSize(fileSizeBytes)); }).ToProperty(this, x => x.FileSizeDisplay, out this.fileSizeDisplay); // EncodeTimeDisplay this.WhenAnyValue(x => x.EncodeTime).Select(encodeTime => { return(Utilities.FormatTimeSpan(encodeTime)); }).ToProperty(this, x => x.EncodeTimeDisplay, out this.encodeTimeDisplay); // EtaDisplay this.WhenAnyValue(x => x.Eta).Select(eta => { return(Utilities.FormatTimeSpan(eta)); }).ToProperty(this, x => x.EtaDisplay, out this.etaDisplay); // PassProgressDisplay this.WhenAnyValue(x => x.CurrentPassId).Select(passId => { switch (passId) { case -1: return(EncodeDetailsRes.ScanPassLabel); case 0: return(EncodeDetailsRes.EncodePassLabel); case 1: return(EncodeDetailsRes.FirstPassLabel); case 2: return(EncodeDetailsRes.SecondPassLabel); default: return(null); } }).ToProperty(this, x => x.PassProgressDisplay, out this.passProgressDisplay); }
private void RefreshPreviews() { this.job = this.mainViewModel.EncodeJob; OutputSizeInfo newOutputSizeInfo = this.outputSizeService.Size; int width = newOutputSizeInfo.OutputWidth; int height = newOutputSizeInfo.OutputHeight; int parWidth = newOutputSizeInfo.Par.Num; int parHeight = newOutputSizeInfo.Par.Den; if (parWidth <= 0 || parHeight <= 0) { this.HasPreview = false; StaticResolver.Resolve <IAppLogger>().LogError("HandBrake returned a negative pixel aspect ratio. Cannot show preview."); return; } if (width < 100 || height < 100) { this.HasPreview = false; return; } this.OutputSizeInfo = newOutputSizeInfo; var profile = this.PresetsService.SelectedPreset.Preset.EncodingProfile; this.PadColor = ColorUtilities.ToWindowsColor(profile.PadColor); // Update the number of previews. this.previewCount = this.ScanInstance.PreviewCount; foreach (PreviewImageServiceClient client in this.clients.Items) { if (client.PreviewIndex >= this.previewCount) { client.PreviewIndex = this.previewCount - 1; } } this.RaisePropertyChanged(nameof(this.PreviewCount)); this.HasPreview = true; lock (this.imageSync) { this.previewImageCache = new BitmapSource[this.previewCount]; updateVersion++; // Clear main work queue. this.previewImageWorkQueue.Clear(); // Clear old images out of the file cache. this.ClearImageFileCache(); this.imageFileSync = new List <object>(this.previewCount); for (int i = 0; i < this.previewCount; i++) { this.imageFileSync.Add(new object()); } this.BeginBackgroundImageLoad(); } }
private void RefreshPreviews() { this.originalScanInstance = this.ScanInstance; this.job = this.mainViewModel.EncodeJob; OutputSizeInfo newOutputSizeInfo = this.outputSizeService.Size; int width = newOutputSizeInfo.OutputWidth; int height = newOutputSizeInfo.OutputHeight; int parWidth = newOutputSizeInfo.Par.Num; int parHeight = newOutputSizeInfo.Par.Den; if (parWidth <= 0 || parHeight <= 0) { this.HasPreview = false; this.Title = PreviewRes.NoVideoSourceTitle; Ioc.Get <IAppLogger>().LogError("HandBrake returned a negative pixel aspect ratio. Cannot show preview."); return; } if (width < 100 || height < 100) { this.HasPreview = false; this.UpdateTitle(newOutputSizeInfo); return; } this.PreviewDisplayHeight = height; this.PreviewDisplayWidth = width * ((double)parWidth / parHeight); this.OutputSizeInfo = newOutputSizeInfo; var profile = this.PresetsService.SelectedPreset.Preset.EncodingProfile; this.PadColor = ColorUtilities.ToWindowsColor(profile.PadColor); // Update the number of previews. this.previewCount = this.ScanInstance.PreviewCount; if (this.selectedPreview >= this.previewCount) { this.selectedPreview = this.previewCount - 1; this.RaisePropertyChanged(nameof(this.SelectedPreview)); } this.RaisePropertyChanged(nameof(this.PreviewCount)); this.HasPreview = true; lock (this.imageSync) { this.previewImageCache = new BitmapSource[this.previewCount]; updateVersion++; // Clear main work queue. this.previewImageWorkQueue.Clear(); this.imageFileCacheFolder = Path.Combine( Utilities.ImageCacheFolder, Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture), updateVersion.ToString(CultureInfo.InvariantCulture)); if (!Directory.Exists(this.imageFileCacheFolder)) { Directory.CreateDirectory(this.imageFileCacheFolder); } // Clear old images out of the file cache. this.ClearImageFileCache(); this.imageFileSync = new List <object>(this.previewCount); for (int i = 0; i < this.previewCount; i++) { this.imageFileSync.Add(new object()); } this.BeginBackgroundImageLoad(); this.View?.RefreshImageSize(); } this.UpdateTitle(newOutputSizeInfo); }
private void RefreshPreviews() { this.originalScanInstance = this.ScanInstance; this.job = this.mainViewModel.EncodeJob; VCProfile profile = this.job.EncodingProfile; int width, height, parWidth, parHeight; this.ScanInstance.GetSize(this.job.HbJob, out width, out height, out parWidth, out parHeight); // If we're rotating by 90 degrees, swap width and height for sizing purposes. if (profile.Rotation == VCPictureRotation.Clockwise90 || profile.Rotation == VCPictureRotation.Clockwise270) { int temp = width; width = height; height = temp; temp = parWidth; parWidth = parHeight; parHeight = temp; } if (parWidth <= 0 || parHeight <= 0) { this.HasPreview = false; this.Title = PreviewRes.NoVideoSourceTitle; Ioc.Container.GetInstance <ILogger>().LogError("HandBrake returned a negative pixel aspect ratio. Cannot show preview."); return; } this.PreviewDisplayHeight = height; this.PreviewDisplayWidth = width * ((double)parWidth / parHeight); // Update the number of previews. this.previewCount = this.ScanInstance.PreviewCount; if (this.selectedPreview >= this.previewCount) { this.selectedPreview = this.previewCount - 1; this.RaisePropertyChanged(() => this.SelectedPreview); } this.RaisePropertyChanged(() => this.PreviewCount); this.HasPreview = true; lock (this.imageSync) { this.previewImageCache = new BitmapSource[this.previewCount]; updateVersion++; // Clear main work queue. this.previewImageWorkQueue.Clear(); this.imageFileCacheFolder = Path.Combine(Utilities.ImageCacheFolder, Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture), updateVersion.ToString(CultureInfo.InvariantCulture)); if (!Directory.Exists(this.imageFileCacheFolder)) { Directory.CreateDirectory(this.imageFileCacheFolder); } // Clear old images out of the file cache. this.ClearImageFileCache(); this.imageFileSync = new List <object>(this.previewCount); for (int i = 0; i < this.previewCount; i++) { this.imageFileSync.Add(new object()); } this.BeginBackgroundImageLoad(); } if (parWidth == parHeight) { this.Title = string.Format(PreviewRes.PreviewWindowTitleSimple, width, height); } else { this.Title = string.Format( PreviewRes.PreviewWindowTitleComplex, Math.Round(this.PreviewDisplayWidth), Math.Round(this.PreviewDisplayHeight), width, height); } }
public void StartEncode(VCJob job, ILogger logger, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds) { this.logger = logger; this.logger.Log("Starting encode in-process"); this.encoding = true; this.encodeStartEvent = new ManualResetEventSlim(false); this.encodeEndEvent = new ManualResetEventSlim(false); this.instance = new HandBrakeInstance(); this.instance.Initialize(Config.LogVerbosity); this.instance.ScanCompleted += (o, e) => { try { Title encodeTitle = this.instance.Titles.FirstOrDefault(title => title.TitleNumber == job.Title); if (encodeTitle != null) { lock (this.encoderLock) { this.instance.StartEncode(job.HbJob, preview, previewNumber, previewSeconds, overallSelectedLengthSeconds, Config.PreviewCount); this.IsEncodeStarted = true; if (this.EncodeStarted != null) { this.EncodeStarted(this, new EventArgs()); } this.encodeStartEvent.Set(); } } else { if (this.EncodeCompleted != null) { this.EncodeCompleted(this, new EncodeCompletedEventArgs { Error = true }); } this.encodeStartEvent.Set(); this.encodeEndEvent.Set(); } } catch (Exception exception) { this.logger.LogError("Encoding failed. Please report this error so it can be fixed in the future:" + Environment.NewLine + exception); } }; this.instance.EncodeProgress += (o, e) => { // Dispatch to avoid deadlocks on callbacks DispatchService.BeginInvoke(() => { lock (this.encoderLock) { if (this.encoding && this.EncodeProgress != null) { this.EncodeProgress(this, e); } } }); }; this.instance.EncodeCompleted += (o, e) => { if (this.encoding) { if (this.EncodeCompleted != null) { this.EncodeCompleted(this, e); } this.encoding = false; } this.encodeEndEvent.Set(); this.instance.Dispose(); }; this.instance.StartScan(job.SourcePath, Config.PreviewCount, job.Title); this.encoding = true; }
private void GeneratePreviewImpl() { this.job = this.mainViewModel.EncodeJob; this.PreviewPercentComplete = 0; this.EncodeState = PreviewEncodeState.EncodeStarting; this.cancelPending = false; this.encodeCancelled = false; this.SetPreviewFilePath(); this.job.OutputPath = this.previewFilePath; if (this.job.Subtitles?.SourceSubtitles != null) { SourceSubtitle scanTrack = this.job.Subtitles.SourceSubtitles.FirstOrDefault(s => s.TrackNumber == 0); if (scanTrack != null) { this.job.Subtitles.SourceSubtitles.Remove(scanTrack); } } this.encodeProxy = Utilities.CreateEncodeProxy(); this.encodeProxy.EncodeStarted += (o, e) => { DispatchUtilities.BeginInvoke(() => { this.EncodeState = PreviewEncodeState.Encoding; if (this.cancelPending) { this.CancelPreviewImpl(); } }); }; this.encodeProxy.EncodeProgress += (o, e) => { double totalWeight; double completeWeight; if (e.PassCount == 1) { // Single pass, no subtitle scan totalWeight = 1; completeWeight = e.FractionComplete; } else if (e.PassCount == 2 && e.PassId <= 0) { // Single pass with subtitle scan totalWeight = 1 + SubtitleScanCost; if (e.PassId == -1) { // In subtitle scan completeWeight = e.FractionComplete * SubtitleScanCost; } else { // In normal pass completeWeight = SubtitleScanCost + e.FractionComplete; } } else if (e.PassCount == 2 && e.PassId >= 1) { // Two normal passes totalWeight = 2; if (e.PassId == 1) { // First pass completeWeight = e.FractionComplete; } else { // Second pass completeWeight = 1 + e.FractionComplete; } } else { // Two normal passes with subtitle scan totalWeight = 2 + SubtitleScanCost; if (e.PassId == -1) { // In subtitle scan completeWeight = e.FractionComplete * SubtitleScanCost; } else if (e.PassId == 1) { // First normal pass completeWeight = SubtitleScanCost + e.FractionComplete; } else { // Second normal pass completeWeight = SubtitleScanCost + 1 + e.FractionComplete; } } double fractionComplete = completeWeight / totalWeight; this.PreviewPercentComplete = fractionComplete * 100; }; this.encodeProxy.EncodeCompleted += (o, e) => { DispatchUtilities.BeginInvoke(() => { this.EncodeState = PreviewEncodeState.NotEncoding; if (this.encodeCancelled) { this.logger.Log("Cancelled preview clip generation"); } else { if (e.Error) { this.logger.Log(PreviewRes.PreviewClipGenerationFailedTitle); Utilities.MessageBox.Show(PreviewRes.PreviewClipGenerationFailedMessage); } else { var previewFileInfo = new FileInfo(this.previewFilePath); this.logger.Log("Finished preview clip generation. Size: " + Utilities.FormatFileSize(previewFileInfo.Length)); this.PlayPreview(); } } }); }; this.logger.Log("Generating preview clip"); this.logger.Log(" Path: " + this.job.OutputPath); this.logger.Log(" Title: " + this.job.Title); this.logger.Log(" Preview #: " + this.SelectedPreview); this.encodeProxy.StartEncode(this.job, this.logger, true, this.SelectedPreview, this.PreviewSeconds, this.job.Length.TotalSeconds); }
public QueueTitlesWindowViewModel() { this.main = Ioc.Get <MainViewModel>(); this.PickersService = Ioc.Get <PickersService>(); this.windowManager = Ioc.Get <IWindowManager>(); this.selectedTitles = new ReactiveList <TitleSelectionViewModel>(); this.titleStartOverrideEnabled = Config.QueueTitlesUseTitleOverride; this.titleStartOverride = Config.QueueTitlesTitleOverride; this.nameOverrideEnabled = Config.QueueTitlesUseNameOverride; this.nameOverride = Config.QueueTitlesNameOverride; this.titles = new ReactiveList <TitleSelectionViewModel>(); this.RefreshTitles(); this.Play = ReactiveCommand.Create(MvvmUtilities.CreateConstantObservable(Players.Installed.Count > 0)); this.Play.Subscribe(_ => this.PlayImpl()); this.AddToQueue = ReactiveCommand.Create(); this.AddToQueue.Subscribe(_ => this.AddToQueueImpl()); this.main.WhenAnyValue(x => x.SourceData) .Skip(1) .Subscribe(_ => { this.RefreshTitles(); }); this.PickersService.WhenAnyValue(x => x.SelectedPicker.Picker.TitleRangeSelectEnabled) .Skip(1) .Subscribe(_ => { this.SetSelectedFromRange(); }); this.PickersService.WhenAnyValue(x => x.SelectedPicker.Picker.TitleRangeSelectStartMinutes) .Skip(1) .Subscribe(_ => { this.SetSelectedFromRange(); }); this.PickersService.WhenAnyValue(x => x.SelectedPicker.Picker.TitleRangeSelectEndMinutes) .Skip(1) .Subscribe(_ => { this.SetSelectedFromRange(); }); this.selectedTitles.CountChanged .Select(count => count == 1) .ToProperty(this, x => x.TitleDetailsVisible, out this.titleDetailsVisible, initialValue: false); this.selectedTitles.CollectionChanged += (sender, args) => { if (this.selectedTitles.Count == 1) { SourceTitle title = this.selectedTitles[0].Title; // Do preview var previewProfile = new VCProfile { CustomCropping = true, Cropping = new VCCropping(), VideoEncoder = "x264", AudioEncodings = new List <AudioEncoding>() }; var previewJob = new VCJob { RangeType = VideoRangeType.All, Title = title.Index, EncodingProfile = previewProfile }; this.PreviewImage = this.main.ScanInstance.GetPreview(previewProfile.CreatePreviewSettings(title), 2); this.RaisePropertyChanged(nameof(this.TitleText)); } }; }
public void StartEncode(VCJob job, ILogger logger, bool preview, int previewNumber, int previewSeconds, double overallSelectedLengthSeconds) { this.logger = logger; this.encodeStartEvent = new ManualResetEventSlim(false); this.encodeEndEvent = new ManualResetEventSlim(false); var task = new Task(() => { this.lastWorkerCommunication = DateTimeOffset.UtcNow; this.pipeName = PipeNamePrefix + Guid.NewGuid().ToString(); var startInfo = new ProcessStartInfo( "VidCoderWorker.exe", Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture) + " " + this.pipeName); startInfo.RedirectStandardOutput = true; startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; this.worker = Process.Start(startInfo); // We don't set this any more because the thread priority inside the worker process sets them to lower priority. this.worker.PriorityClass = CustomConfig.WorkerProcessPriority; // When the process writes out a line, its pipe server is ready and can be contacted for // work. Reading line blocks until this happens. this.logger.Log("Worker ready: " + this.worker.StandardOutput.ReadLine()); bool connectionSucceeded = false; this.logger.Log("Connecting to process " + this.worker.Id + " on pipe " + this.pipeName); lock (this.encoderLock) { this.ExecuteProxyOperation(() => { connectionSucceeded = this.ConnectToPipe(); if (!connectionSucceeded) { return; } this.channel.StartEncode( job.HbJob, preview, previewNumber, previewSeconds, overallSelectedLengthSeconds, Config.LogVerbosity, Config.PreviewCount, Config.EnableLibDvdNav); // After we do StartEncode (which can take a while), switch the timeout down to normal level to do pings var contextChannel = (IContextChannel)this.channel; contextChannel.OperationTimeout = TimeSpan.FromSeconds(PipeTimeoutSeconds); }); } if (!connectionSucceeded) { this.EndEncode(error: true); return; } this.pingTimer = new Timer { AutoReset = true, Interval = PingTimerIntervalMs }; this.pingTimer.Elapsed += (o, e) => { lock (this.encoderLock) { if (!this.encoding) { return; } } if (this.encoding) { try { this.channel.Ping(); lock (this.encoderLock) { this.lastWorkerCommunication = DateTimeOffset.UtcNow; } } catch (CommunicationException exception) { this.HandlePingError(exception); } catch (TimeoutException exception) { this.HandlePingError(exception); } } }; this.pingTimer.Start(); }); this.encoding = true; task.Start(); }