private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e) { object selectedItem = e.NewValue; if (selectedItem == null || selectedItem is PresetFolderViewModel) { // If it's a folder that got "selected" we ignore it and leave the previous preset selected for real return; } if (PresetComboBox.PresetComboOpen) { // If inside a combo box the combo box binding on close will handle it. return; } DispatchUtilities.BeginInvoke(() => { // This might be in the layout phase. Invoke on dispatcher to process cleanly. var newSelectedPreset = (PresetViewModel)selectedItem; if (this.presetsService.TryUpdateSelectedPreset(newSelectedPreset)) { StaticResolver.Resolve <Main>().ReadTextToScreenReader(newSelectedPreset.DisplayName); } }); }
public PresetTreeViewContainer() { this.InitializeComponent(); this.presetsService.PresetFolderManuallyExpanded += (sender, model) => { var item = UIUtilities.FindDescendant <TreeViewItem>(this.presetTreeView, viewItem => { return(viewItem.Header == model); }); //var item = this.presetTreeView.ContainerFromItem(model); // TODO: Find the TreeViewItem for the PresetFolderViewModel if (item != null) { DispatchUtilities.BeginInvoke( () => { UIUtilities.BringIntoView(item); }, DispatcherPriority.Background); } }; }
public void RestoreWindow() { DispatchUtilities.BeginInvoke(() => { this.Show(); this.WindowState = this.RestoredWindowState; }); }
public void Activate(string appUserModelId, string invokedArgs, NOTIFICATION_USER_INPUT_DATA[] data, uint dataCount) { StaticResolver.Resolve <Main>().RestoreWindow(); DispatchUtilities.BeginInvoke(() => { StaticResolver.Resolve <Main>().Activate(); }); }
public void Scan(string source) { var mainVM = StaticResolver.Resolve <MainViewModel>(); DispatchUtilities.Invoke(() => { mainVM.ScanFromAutoplay(source); }); }
public void Encode(string source, string destination, string preset, string picker) { var processingService = StaticResolver.Resolve <ProcessingService>(); DispatchUtilities.Invoke(() => { processingService.Process(source, destination, preset, picker); }); }
private void ScanNextJob() { SourcePath path = this.pathsToScan[this.currentJobIndex]; IScanProxy scanProxy = Utilities.CreateScanProxy(); scanProxy.ScanProgress += (sender, args) => { lock (this.currentJobIndexLock) { this.currentJobProgress = args.Value; this.RaisePropertyChanged(nameof(this.Progress)); } }; scanProxy.ScanCompleted += (sender, args) => { if (args.Value != null) { JsonScanObject scanObject = JsonConvert.DeserializeObject <JsonScanObject>(args.Value); this.ScanResults.Add(new ScanResult { SourcePath = path, VideoSource = scanObject.ToVideoSource() }); } else { this.ScanResults.Add(new ScanResult { SourcePath = path }); } lock (this.currentJobIndexLock) { this.currentJobIndex++; this.currentJobProgress = 0; this.RaisePropertyChanged(nameof(this.Progress)); if (this.ScanFinished) { DispatchUtilities.BeginInvoke(() => { this.Cancel.Execute(null); }); } else { this.ScanNextJob(); } } }; var scanLogger = StaticResolver.Resolve <AppLoggerFactory>().ResolveRemoteScanLogger(path.Path); scanProxy.StartScan(path.Path, scanLogger); }
private void ShowStatusMessage(string message) { DispatchUtilities.BeginInvoke(() => { this.statusTextBlock.Text = message; this.statusText.Visibility = Visibility.Visible; var storyboard = (Storyboard)this.FindResource("StatusTextStoryboard"); storyboard.Stop(); storyboard.Begin(); }); }
public void Encode(string source, string destination, string preset, string picker) { var processingService = StaticResolver.Resolve <ProcessingService>(); DispatchUtilities.Invoke(() => { try { processingService.Process(source, destination, preset, picker); } catch (Exception exception) { throw new FaultException <AutomationError>(new AutomationError { Message = exception.Message }); } }); }
public void Scan(string source) { var mainVM = StaticResolver.Resolve <MainViewModel>(); DispatchUtilities.Invoke(() => { try { mainVM.ScanFromAutoplay(source); } catch (Exception exception) { throw new FaultException <AutomationError>(new AutomationError { Message = exception.Message }); } }); }
public void ImportQueue(string filePath) { var queueImporter = StaticResolver.Resolve <IQueueImportExport>(); DispatchUtilities.Invoke(() => { try { queueImporter.Import(filePath); this.ShowMessage(MainRes.QueueImportSuccessMessage); } catch (Exception) { this.ShowMessage(MainRes.QueueImportErrorMessage); throw; } }); }
public void ImportPreset(string filePath) { var presetImporter = StaticResolver.Resolve <IPresetImportExport>(); DispatchUtilities.Invoke(() => { try { Preset preset = presetImporter.ImportPreset(filePath); this.ShowMessage(string.Format(MainRes.PresetImportSuccessMessage, preset.Name)); } catch (Exception) { this.ShowMessage(MainRes.PresetImportErrorMessage); throw; } }); }
private static void UpdateCornerImage(Image image, Grid imageHolder, BitmapSource bitmap, RegionChooser regionChooser, bool isRetry = false) { // Image dimensions int imageWidth = bitmap.PixelWidth; int imageHeight = bitmap.PixelHeight; double availableWidth = imageHolder.ActualWidth; double availableHeight = imageHolder.ActualHeight; if (availableWidth == 0 || availableHeight == 0) { // Intermittent bug causing this. In this case we queue it up to go again after a layout pass has been done. if (!isRetry) { DispatchUtilities.BeginInvoke(() => { UpdateCornerImage(image, imageHolder, bitmap, regionChooser, isRetry: true); }); } return; } int cornerWidthPixels = (int)(availableWidth / ZoomedPixelSize); int cornerHeightPixels = (int)(availableHeight / ZoomedPixelSize); // Make sure the subsection of the image is not larger than the image itself cornerWidthPixels = Math.Min(cornerWidthPixels, imageWidth); cornerHeightPixels = Math.Min(cornerHeightPixels, imageHeight); double cornerWidth = cornerWidthPixels * ZoomedPixelSize; double cornerHeight = cornerHeightPixels * ZoomedPixelSize; var croppedBitmap = new CroppedBitmap(); croppedBitmap.BeginInit(); croppedBitmap.SourceRect = regionChooser(imageWidth, imageHeight, cornerWidthPixels, cornerHeightPixels); croppedBitmap.Source = bitmap; croppedBitmap.EndInit(); image.Source = croppedBitmap; image.Width = cornerWidth; image.Height = cornerHeight; }
public LogWindow() { this.InitializeComponent(); this.PopulateLogColorBrushMapping(); this.listColumn.Width = new GridLength(Config.LogListPaneWidth); this.Loaded += (sender, e) => { this.logTextBox.ScrollToEnd(); }; this.logCoordinator.Logs .Connect() .OnItemAdded(addedLogViewModel => { DispatchUtilities.Invoke(() => { this.logCoordinator.SelectedLog = addedLogViewModel; this.logsListBox.ScrollIntoView(addedLogViewModel); }); }) .Subscribe(); this.logCoordinator.WhenAnyValue(x => x.SelectedLog).Subscribe(selectedLog => { if (selectedLog != null) { this.DisconnectFromLogger(); this.ConnectToLogger(selectedLog.Logger); } }); this.appThemeService.AppThemeObservable.Skip(1).Subscribe(_ => { this.Dispatcher.BeginInvoke(new Action(() => { this.PopulateLogColorBrushMapping(); this.logParagraph.Inlines.Clear(); this.AddExistingLogEntries(); })); }); }
public void ImportQueue(string filePath) { var queueImporter = Ioc.Get <IQueueImportExport>(); DispatchUtilities.Invoke(() => { try { queueImporter.Import(filePath); this.ShowMessage(MainRes.QueueImportSuccessMessage); } catch (Exception exception) { this.ShowMessage(MainRes.QueueImportErrorMessage); throw new FaultException <AutomationError>(new AutomationError { Message = exception.Message }); } }); }
public void ImportPreset(string filePath) { var presetImporter = Ioc.Get <IPresetImportExport>(); DispatchUtilities.Invoke(() => { try { Preset preset = presetImporter.ImportPreset(filePath); this.ShowMessage(string.Format(MainRes.PresetImportSuccessMessage, preset.Name)); } catch (Exception exception) { this.ShowMessage(MainRes.PresetImportErrorMessage); throw new FaultException <AutomationError>(new AutomationError { Message = exception.Message }); } }); }
public void SetChosenTracks(List <int> chosenAudioTracks, SourceTitle selectedTitle) { DispatchUtilities.Invoke(() => { int previousIndex = this.TargetStreamIndex; this.targetStreams.Clear(); this.targetStreams.Add(new TargetStreamViewModel { Text = CommonRes.All }); int shownStreams = Math.Max(previousIndex, chosenAudioTracks.Count); for (int i = 0; i < shownStreams; i++) { string details = null; if (i < chosenAudioTracks.Count && selectedTitle != null) { details = selectedTitle.AudioList[chosenAudioTracks[i] - 1].Description; } this.targetStreams.Add( new TargetStreamViewModel { Text = string.Format(CommonRes.StreamChoice, (i + 1)), TrackDetails = details }); } // Set to -1, then back to real index in order to force a refresh on the ComboBox this.targetStreamIndex = -1; this.RaisePropertyChanged(nameof(this.TargetStreamIndex)); this.targetStreamIndex = previousIndex; this.RaisePropertyChanged(nameof(this.TargetStreamIndex)); }); }
private async void StartBackgroundUpdate() { if (this.State != UpdateState.NotStarted && this.State != UpdateState.Failed && this.State != UpdateState.UpToDate) { // Can only start updates from certain states. return; } this.State = UpdateState.DownloadingInfo; this.updateDownloadCancellationTokenSource = new CancellationTokenSource(); await Task.Run(async() => { try { UpdateInfo updateInfo = await GetUpdateInfoAsync(CommonUtilities.Beta).ConfigureAwait(false); if (updateInfo == null) { this.State = UpdateState.Failed; this.logger.Log("Update download failed. Unable to get update info."); return; } Version updateVersion = updateInfo.LatestVersion; this.LatestVersion = updateVersion; if (updateVersion > Utilities.CurrentVersion) { // If an update is reported to be ready but the installer doesn't exist, clear out all the // installer info and redownload. string updateInstallerLocation = Config.UpdateInstallerLocation; if (updateInstallerLocation != string.Empty && !File.Exists(updateInstallerLocation)) { using (SQLiteTransaction transaction = Database.ThreadLocalConnection.BeginTransaction()) { ClearUpdateMetadata(); transaction.Commit(); } this.logger.Log("Downloaded update (" + updateInstallerLocation + ") could not be found. Re-downloading it."); } // If we have not finished the download update yet, start/resume the download. if (Config.UpdateInstallerLocation == string.Empty) { string updateVersionText = updateVersion.ToShortString(); if (CommonUtilities.Beta) { updateVersionText += " Beta"; } string newVersionStartedMessage = string.Format(MainRes.NewVersionDownloadStartedStatus, updateVersionText); this.logger.Log(newVersionStartedMessage); DispatchUtilities.BeginInvoke(() => { this.logger.ShowStatus(newVersionStartedMessage); }); this.State = UpdateState.DownloadingInstaller; this.UpdateDownloadProgressFraction = 0; string downloadLocation = updateInfo.DownloadUrl; string changelogLink = updateInfo.ChangelogUrl; string installerFileName = Path.GetFileName(downloadLocation); string installerFilePath = Path.Combine(Utilities.UpdatesFolder, installerFileName); Stream responseStream = null; FileStream fileStream = null; try { HttpClient client = new HttpClient(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, downloadLocation); long bytesProgressTotal = 0; if (File.Exists(installerFilePath)) { var fileInfo = new FileInfo(installerFilePath); request.Headers.Range = new RangeHeaderValue(fileInfo.Length, null); bytesProgressTotal = fileInfo.Length; fileStream = new FileStream(installerFilePath, FileMode.Append, FileAccess.Write, FileShare.None); } else { fileStream = new FileStream(installerFilePath, FileMode.Create, FileAccess.Write, FileShare.None); } var response = await client.SendAsync(request).ConfigureAwait(false); responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); byte[] downloadBuffer = new byte[2048]; int bytesRead; while ((bytesRead = await responseStream.ReadAsync(downloadBuffer, 0, downloadBuffer.Length).ConfigureAwait(false)) > 0 && !this.updateDownloadCancellationTokenSource.Token.IsCancellationRequested) { fileStream.Write(downloadBuffer, 0, bytesRead); bytesProgressTotal += bytesRead; this.UpdateDownloadProgressFraction = (double)bytesProgressTotal / response.Content.Headers.ContentLength.Value; } if (bytesRead == 0) { using (SQLiteTransaction transaction = Database.ThreadLocalConnection.BeginTransaction()) { Config.UpdateVersion = updateVersion.ToString(); Config.UpdateInstallerLocation = installerFilePath; Config.UpdateChangelogLocation = changelogLink; transaction.Commit(); } this.State = UpdateState.InstallerReady; this.UpdateDownloadProgressFraction = 1; string message = string.Format(MainRes.NewVersionDownloadFinishedStatus, updateVersionText); this.logger.Log(message); this.logger.ShowStatus(message); } else { // In this case the download must have been cancelled. this.State = UpdateState.NotStarted; } } finally { if (responseStream != null) { responseStream.Close(); } if (fileStream != null) { fileStream.Close(); } } } else { this.State = UpdateState.InstallerReady; } } else { this.State = UpdateState.UpToDate; } } catch (Exception exception) { this.State = UpdateState.Failed; this.logger.Log("Update download failed: " + exception.Message); } finally { this.updateDownloadCancellationTokenSource?.Dispose(); this.updateDownloadCancellationTokenSource = null; } }); }
public PickerWindowViewModel() { using (this.autoChangeTracker.TrackAutoChange()) { this.RegisterPickerProperties(); this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker) .Subscribe(x => { using (this.autoChangeTracker.TrackAutoChange()) { this.RaiseAllChanged(); // When we are swapping active pickers, update the local properties. if (!this.userModifyingOutputDirectory) { this.OutputDirectoryOverride = this.Picker.OutputDirectoryOverride; } if (!this.userModifyingNameFormat) { this.NameFormatOverride = this.Picker.NameFormatOverride; } if (!this.userModifyingEncodingPreset) { this.PopulateEncodingPreset(this.Picker.UseEncodingPreset); } } }); this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.AudioLanguageCodes).Subscribe(audioLanguageCodes => { using (this.autoChangeTracker.TrackAutoChange()) { this.audioLanguages.Edit(audioLanguagesInnerList => { audioLanguagesInnerList.Clear(); if (audioLanguageCodes == null) { audioLanguagesInnerList.Add(new LanguageViewModel(this) { Code = LanguageUtilities.GetDefaultLanguageCode() }); return; } audioLanguagesInnerList.AddRange(audioLanguageCodes.Select(l => new LanguageViewModel(this) { Code = l })); }); } }); var audioLanguagesObservable = this.audioLanguages.Connect(); audioLanguagesObservable.Bind(this.AudioLanguagesBindable).Subscribe(); audioLanguagesObservable.WhenAnyPropertyChanged().Subscribe(_ => { if (!this.autoChangeTracker.OperationInProgress) { this.HandleAudioLanguageUpdate(); } }); this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.SubtitleLanguageCodes).Subscribe(subtitleLanguageCodes => { using (this.autoChangeTracker.TrackAutoChange()) { this.subtitleLanguages.Edit(subtitleLanguagesInnerList => { subtitleLanguagesInnerList.Clear(); if (subtitleLanguageCodes == null) { subtitleLanguagesInnerList.Add(new LanguageViewModel(this) { Code = LanguageUtilities.GetDefaultLanguageCode() }); return; } subtitleLanguagesInnerList.AddRange(subtitleLanguageCodes.Select(l => new LanguageViewModel(this) { Code = l })); }); } }); var subtitleLanguagesObservable = this.subtitleLanguages.Connect(); subtitleLanguagesObservable.Bind(this.SubtitleLanguagesBindable).Subscribe(); subtitleLanguagesObservable.WhenAnyPropertyChanged().Subscribe(_ => { if (!this.autoChangeTracker.OperationInProgress) { this.HandleSubtitleLanguageUpdate(); } }); // HasMultipleAudioLanguages IObservable <int> audioLanguageCountObservable = audioLanguagesObservable .Count() .StartWith(this.audioLanguages.Count); IObservable <bool> hasMultipleAudioLanguagesObservable = audioLanguageCountObservable .Select(count => count > 1); hasMultipleAudioLanguagesObservable.ToProperty(this, x => x.HasMultipleAudioLanguages, out this.hasMultipleAudioLanguages); // AudioFirstTrackLabel hasMultipleAudioLanguagesObservable .Select(hasMultipleAudioLanguages => { return(hasMultipleAudioLanguages ? PickerRes.FirstTrackOfEachLanguageRadioButton : PickerRes.FirstTrackRadioButton); }) .ToProperty(this, x => x.AudioFirstTrackLabel, out this.audioFirstTrackLabel); // AudioAllTracksLabel hasMultipleAudioLanguagesObservable .Select(hasMultipleAudioLanguages => { return(hasMultipleAudioLanguages ? PickerRes.AllTracksForTheseLanguagesRadioButton : PickerRes.AllTracksForThisLanguageRadioButton); }) .ToProperty(this, x => x.AudioAllTracksLabel, out this.audioAllTracksLabel); // HasNoAudioLanguages audioLanguageCountObservable .Select(count => count == 0) .ToProperty(this, x => x.HasNoAudioLanguages, out this.hasNoAudioLanguages); // HasMultipleSubtitleLanguages IObservable <int> subtitleLanguageCountObservable = subtitleLanguagesObservable .Count() .StartWith(this.subtitleLanguages.Count); IObservable <bool> hasMultipleSubtitleLanguagesObservable = subtitleLanguageCountObservable .Select(count => count > 1); hasMultipleSubtitleLanguagesObservable.ToProperty(this, x => x.HasMultipleSubtitleLanguages, out this.hasMultipleSubtitleLanguages); // SubtitleFirstTrackLabel hasMultipleSubtitleLanguagesObservable .Select(hasMultipleSubtitleLanguages => { return(hasMultipleSubtitleLanguages ? PickerRes.FirstTrackOfEachLanguageRadioButton : PickerRes.FirstTrackRadioButton); }) .ToProperty(this, x => x.SubtitleFirstTrackLabel, out this.subtitleFirstTrackLabel); // SubtitleAllTracksLabel hasMultipleSubtitleLanguagesObservable .Select(hasMultipleSubtitleLanguages => { return(hasMultipleSubtitleLanguages ? PickerRes.AllTracksForTheseLanguagesRadioButton : PickerRes.AllTracksForThisLanguageRadioButton); }) .ToProperty(this, x => x.SubtitleAllTracksLabel, out this.subtitleAllTracksLabel); // HasNoSubtitleLanguages subtitleLanguageCountObservable .Select(count => count == 0) .ToProperty(this, x => x.HasNoSubtitleLanguages, out this.hasNoSubtitleLanguages); // SubtitleQuantityClass this.WhenAnyValue(x => x.SubtitleSelectionMode, x => x.SubtitleIndices, x => x.HasMultipleSubtitleLanguages, x => x.SubtitleLanguageAll, (selectionMode, subtitleIndices, hasMultipleLanguages, subtitleLanguageAll) => { switch (selectionMode) { case SubtitleSelectionMode.Disabled: case SubtitleSelectionMode.None: return(SubtitleQuantityClass.None); case SubtitleSelectionMode.First: case SubtitleSelectionMode.ForeignAudioSearch: return(SubtitleQuantityClass.Single); case SubtitleSelectionMode.ByIndex: return(ParseUtilities.ParseCommaSeparatedListToPositiveIntegers(subtitleIndices).Count > 1 ? SubtitleQuantityClass.Multiple : SubtitleQuantityClass.Single); case SubtitleSelectionMode.Language: if (hasMultipleLanguages) { return(SubtitleQuantityClass.Multiple); } return(subtitleLanguageAll ? SubtitleQuantityClass.Multiple : SubtitleQuantityClass.Single); case SubtitleSelectionMode.All: return(SubtitleQuantityClass.Multiple); default: throw new ArgumentOutOfRangeException(nameof(selectionMode), selectionMode, null); } }).ToProperty(this, x => x.SubtitleQuantityClass, out this.subtitleQuantityClass); // ShowMarkFirstAsDefaultCheckBox this.WhenAnyValue(x => x.SubtitleQuantityClass, x => x.SubtitleSelectionMode, (subtitleQuantityClass, selectionMode) => { return(subtitleQuantityClass == SubtitleQuantityClass.Multiple && selectionMode != SubtitleSelectionMode.ByIndex); }).ToProperty(this, x => x.ShowMarkFirstAsDefaultCheckBox, out this.showMarkFirstAsDefaultCheckBox); this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.IsDefault, x => x.SelectedPicker.Picker.IsModified, (isDefault, isModified) => !isDefault && !isModified).ToProperty(this, x => x.DeleteButtonVisible, out this.deleteButtonVisible); this.pickersService.WhenAnyValue(x => x.SelectedPicker.Picker.DisplayName, x => x.SelectedPicker.Picker.IsModified, (displayName, isModified) => { string windowTitle2 = string.Format(PickerRes.WindowTitle, displayName); if (isModified) { windowTitle2 += " *"; } return(windowTitle2); }).ToProperty(this, x => x.WindowTitle, out this.windowTitle); // Whenever the output directory override is disabled, used the config. this.WhenAnyValue(x => x.OutputDirectoryOverrideEnabled).Subscribe(directoryOverrideEnabled => { if (!directoryOverrideEnabled) { this.OutputDirectoryOverride = Config.AutoNameOutputFolder; } else { this.OutputDirectoryOverride = this.Picker.OutputDirectoryOverride; } }); // Whenever the name format override is disabled, used the config. this.WhenAnyValue(x => x.NameFormatOverrideEnabled).Subscribe(nameFormatOverrideEnabled => { if (!nameFormatOverrideEnabled) { this.NameFormatOverride = AutoNameCustomFormat; } else { this.NameFormatOverride = this.Picker.NameFormatOverride; } }); // Whenever UseEncodingPreset is false, set the selected VM to null. this.WhenAnyValue(x => x.UseEncodingPreset).Subscribe(useEncodingPreset => { this.PopulateEncodingPreset(useEncodingPreset); }); // Update the underlying picker when our local properties change. // Don't need to raise another changed event as our local property setter already raises it. this.WhenAnyValue(x => x.OutputDirectoryOverride).Skip(1).Subscribe(directoryOverride => { this.userModifyingOutputDirectory = true; this.UpdatePickerProperty(nameof(this.Picker.OutputDirectoryOverride), directoryOverride, raisePropertyChanged: false); this.outputPathService.GenerateOutputFileName(); this.userModifyingOutputDirectory = false; }); this.WhenAnyValue(x => x.NameFormatOverride).Skip(1).Subscribe(nameFormatOverride => { this.userModifyingNameFormat = true; this.UpdatePickerProperty(nameof(this.Picker.NameFormatOverride), nameFormatOverride, raisePropertyChanged: false); this.outputPathService.GenerateOutputFileName(); this.userModifyingNameFormat = false; }); this.WhenAnyValue(x => x.SelectedPreset).Subscribe(selectedPreset => { this.userModifyingEncodingPreset = true; string presetName = selectedPreset == null ? null : selectedPreset.Preset.Name; this.UpdatePickerProperty(nameof(this.Picker.EncodingPreset), presetName, raisePropertyChanged: false); if (this.UseEncodingPreset && selectedPreset != null) { if (!this.PresetsService.TryUpdateSelectedPreset(selectedPreset)) { DispatchUtilities.BeginInvoke(() => { this.SelectedPreset = this.PresetsService.SelectedPreset; }); } } this.userModifyingEncodingPreset = false; }); } }
public bool TryUpdateSelectedPreset(PresetViewModel value) { if (value == null || this.selectedPreset == value) { return(false); } PresetViewModel previouslySelectedPreset = this.selectedPreset; bool changeSelectedPreset = true; if (this.selectedPreset != null && this.selectedPreset.Preset.IsModified) { string dialogMessage; string dialogTitle; MessageBoxButton buttons; if (this.selectedPreset.Preset.IsBuiltIn) { dialogMessage = MainRes.PresetDiscardConfirmMessage; dialogTitle = MainRes.PresetDiscardConfirmTitle; buttons = MessageBoxButton.OKCancel; } else { dialogMessage = MainRes.SaveChangesPresetMessage; dialogTitle = MainRes.SaveChangesPresetTitle; buttons = MessageBoxButton.YesNoCancel; } MessageBoxResult dialogResult = Utilities.MessageBox.Show( this.main, dialogMessage, dialogTitle, buttons); if (dialogResult == MessageBoxResult.Yes) { // Yes, we wanted to save changes this.SavePreset(); } else if (dialogResult == MessageBoxResult.No || dialogResult == MessageBoxResult.OK) { // No, we didn't want to save changes or OK, we wanted to discard changes. this.RevertPreset(userInitiated: false); } else if (dialogResult == MessageBoxResult.Cancel) { // Queue up an action to switch back to this preset. int currentPresetIndex = this.AllPresets.IndexOf(this.selectedPreset); DispatchUtilities.BeginInvoke(() => { this.SelectedPreset = this.AllPresets[currentPresetIndex]; }); changeSelectedPreset = false; } } this.selectedPreset = value; this.selectedPreset.IsSelected = true; // For TreeView if (changeSelectedPreset) { this.NotifySelectedPresetChanged(); if (previouslySelectedPreset != null) { Config.LastPresetIndex = this.AllPresets.IndexOf(this.selectedPreset); } // If we're switching away from a temporary queue preset, remove it. if (previouslySelectedPreset != null && previouslySelectedPreset.Preset.IsQueue && previouslySelectedPreset != value) { this.AllPresets.Remove(previouslySelectedPreset); } } return(changeSelectedPreset); }
private void HandleDiscEvent(object sender, EventArrivedEventArgs e) { DispatchUtilities.BeginInvoke(() => this.mainViewModel.UpdateDriveCollection()); }
public static void SetVideo(this IPreviewFrame previewFrame, Action onCompleted, Action onFailed, IObservable <double> volume) { Grid holder = previewFrame.Holder; if (HasChild <MediaElement>(holder)) { // There is already a video in here. RemoveImage(holder); return; } // Close any video that was there before. RemoveVideo(holder); // Add on a new video var mediaElement = new MediaElement { Stretch = Stretch.Fill, Opacity = 0 }; var viewModel = (PreviewWindowViewModel)previewFrame.Holder.DataContext; mediaElement.SetBinding(MediaElement.SourceProperty, nameof(viewModel.PreviewFilePath)); mediaElement.LoadedBehavior = MediaState.Manual; mediaElement.ScrubbingEnabled = true; mediaElement.MediaOpened += (sender, args) => { if (mediaElement.NaturalDuration.HasTimeSpan) { viewModel.PreviewVideoDuration = mediaElement.NaturalDuration.TimeSpan; } else { viewModel.PreviewVideoDuration = TimeSpan.Zero; } // Video starts out black so we want to hold it at the start until it displays fully. mediaElement.Pause(); DispatchUtilities.BeginInvoke(() => { OnVideoPlaying(holder); mediaElement.Play(); }); }; mediaElement.MediaFailed += (sender, args) => { onFailed(); }; mediaElement.MediaEnded += (sender, args) => { onCompleted(); }; volume.Subscribe(v => { mediaElement.Volume = v; }); mediaElement.Play(); holder.Children.Add(mediaElement); }
public Main() { Ioc.Container.RegisterSingleton <Main>(() => this); this.InitializeComponent(); this.sourceRow.Height = new GridLength(Config.SourcePaneHeightStar, GridUnitType.Star); this.queueRow.Height = new GridLength(Config.QueuePaneHeightStar, GridUnitType.Star); this.Activated += (sender, args) => { DispatchUtilities.BeginInvoke(async() => { // Need to yield here for some reason, otherwise the activation is blocked. await Task.Yield(); this.toastNotificationService.Clear(); }); }; this.notifyIcon = new NotifyIcon { Visible = false }; this.notifyIcon.Click += (sender, args) => { this.RestoreWindow(); }; this.notifyIcon.DoubleClick += (sender, args) => { this.RestoreWindow(); }; StreamResourceInfo streamResourceInfo = System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/VidCoder_icon.ico")); if (streamResourceInfo != null) { Stream iconStream = streamResourceInfo.Stream; this.notifyIcon.Icon = new Icon(iconStream); } this.RefreshQueueColumns(); this.LoadCompletedColumnWidths(); #if DEBUG var debugDropDown = new DropDownButton { Header = "Debug" }; var loadScanFromJsonItem = new Fluent.MenuItem { Header = "Load scan from JSON..." }; loadScanFromJsonItem.Click += (sender, args) => { DebugJsonDialog dialog = new DebugJsonDialog("Debug Scan JSON"); dialog.ShowDialog(); if (!string.IsNullOrWhiteSpace(dialog.Json)) { try { var scanObject = JsonConvert.DeserializeObject <JsonScanObject>(dialog.Json); this.viewModel.UpdateFromNewVideoSource(new VideoSource { Titles = scanObject.TitleList, FeatureTitle = scanObject.MainFeature }); } catch (Exception exception) { MessageBox.Show(this, "Could not parse scan JSON:" + Environment.NewLine + Environment.NewLine + exception.ToString()); } } }; debugDropDown.Items.Add(loadScanFromJsonItem); var queueFromJsonItem = new Fluent.MenuItem { Header = "Queue job from JSON..." }; queueFromJsonItem.Click += (sender, args) => { if (!this.viewModel.HasVideoSource) { StaticResolver.Resolve <IMessageBoxService>().Show("Must open source before adding queue job from JSON"); return; } EncodeJobViewModel jobViewModel = this.viewModel.CreateEncodeJobVM(); DebugJsonDialog dialog = new DebugJsonDialog("Debug Encode JSON"); dialog.ShowDialog(); if (!string.IsNullOrWhiteSpace(dialog.Json)) { try { JsonEncodeObject encodeObject = JsonConvert.DeserializeObject <JsonEncodeObject>(dialog.Json); jobViewModel.DebugEncodeJsonOverride = dialog.Json; jobViewModel.Job.FinalOutputPath = encodeObject.Destination.File; jobViewModel.Job.SourcePath = encodeObject.Source.Path; this.processingService.Queue(jobViewModel); } catch (Exception exception) { MessageBox.Show(this, "Could not parse encode JSON:" + Environment.NewLine + Environment.NewLine + exception.ToString()); } } }; debugDropDown.Items.Add(queueFromJsonItem); var throwExceptionItem = new Fluent.MenuItem { Header = "Throw exception" }; throwExceptionItem.Click += (sender, args) => { throw new InvalidOperationException("Rats."); }; debugDropDown.Items.Add(throwExceptionItem); var addLogItem = new Fluent.MenuItem { Header = "Add 1 log item" }; addLogItem.Click += (sender, args) => { StaticResolver.Resolve <IAppLogger>().Log("This is a log item"); }; debugDropDown.Items.Add(addLogItem); var addTenLogItems = new Fluent.MenuItem { Header = "Add 10 log items" }; addTenLogItems.Click += (sender, args) => { for (int i = 0; i < 10; i++) { StaticResolver.Resolve <IAppLogger>().Log("This is a log item"); } }; debugDropDown.Items.Add(addTenLogItems); var addLongLogItem = new Fluent.MenuItem { Header = "Add long log item" }; addLongLogItem.Click += (sender, args) => { StaticResolver.Resolve <IAppLogger>().Log("This is a log item\r\nthat is split into multiple lines\r\nOh yes indeed"); }; debugDropDown.Items.Add(addLongLogItem); var doAnActionItem = new Fluent.MenuItem { Header = "Perform action" }; doAnActionItem.Click += (sender, args) => { var app = (App)System.Windows.Application.Current; app.ChangeTheme(new Uri("/Themes/Dark.xaml", UriKind.Relative)); }; debugDropDown.Items.Add(doAnActionItem); this.toolsRibbonGroupBox.Items.Add(debugDropDown); #endif this.DataContextChanged += this.OnDataContextChanged; TheDispatcher = this.Dispatcher; this.statusText.Opacity = 0.0; NameScope.SetNameScope(this, new NameScope()); this.RegisterName("StatusText", this.statusText); var storyboard = (Storyboard)this.FindResource("StatusTextStoryboard"); storyboard.Completed += (sender, args) => { this.statusText.Visibility = Visibility.Collapsed; }; this.presetTreeViewContainer.PresetTreeView.OnHierarchyMouseUp += (sender, args) => { this.presetButton.IsDropDownOpen = false; }; this.presetButton.DropDownOpened += (sender, args) => { var item = UIUtilities.FindDescendant <TreeViewItem>(this.presetTreeViewContainer.PresetTreeView, viewItem => { return(viewItem.Header == this.viewModel.PresetsService.SelectedPreset); }); if (item != null) { UIUtilities.BringIntoView(item); } }; this.Loaded += (e, o) => { this.RestoredWindowState = this.WindowState; }; this.statusService.MessageShown += (o, e) => { this.ShowStatusMessage(e.Value); }; this.queueView.SelectionChanged += this.QueueView_SelectionChanged; }
public OptionsDialogViewModel(IUpdater updateService) { this.updater = updateService; this.Tabs = new List <string> { OptionsRes.GeneralTab, // 0 OptionsRes.FileNamingTab, // 1 OptionsRes.ProcessTab, // 2 OptionsRes.AdvancedTab, // 3 }; if (Utilities.SupportsUpdates) { this.Tabs.Add(OptionsRes.UpdatesTab); // 4 } // UpdateStatus this.updater .WhenAnyValue(x => x.State) .Select(state => { switch (state) { case UpdateState.NotStarted: return(string.Empty); case UpdateState.DownloadingInfo: return(OptionsRes.DownloadingInfoStatus); case UpdateState.DownloadingInstaller: return(string.Format(OptionsRes.DownloadingStatus, this.updater.LatestVersion)); case UpdateState.UpToDate: return(OptionsRes.UpToDateStatus); case UpdateState.InstallerReady: return(string.Format(OptionsRes.UpdateReadyStatus, this.updater.LatestVersion)); case UpdateState.Failed: return(OptionsRes.UpdateFailedStatus); default: throw new ArgumentOutOfRangeException(); } }) .ToProperty(this, x => x.UpdateStatus, out this.updateStatus, scheduler: Scheduler.Immediate); // UpdateDownloading this.updater .WhenAnyValue(x => x.State) .Select(state => state == UpdateState.DownloadingInstaller) .ToProperty(this, x => x.UpdateDownloading, out this.updateDownloading); // UpdateProgressPercent this.updater .WhenAnyValue(x => x.UpdateDownloadProgressFraction) .Select(downloadFraction => downloadFraction * 100) .ToProperty(this, x => x.UpdateProgressPercent, out this.updateProgressPercent); // CpuThrottlingDisplay this.WhenAnyValue(x => x.CpuThrottlingCores, x => x.CpuThrottlingMaxCores, (cores, maxCores) => { double currentFraction = (double)cores / maxCores; return(currentFraction.ToString("p0")); }).ToProperty(this, x => x.CpuThrottlingDisplay, out this.cpuThrottlingDisplay, deferSubscription: true, scheduler: Scheduler.Immediate); this.updatesEnabledConfig = Config.UpdatesEnabled; this.updatePromptTiming = CustomConfig.UpdatePromptTiming; this.defaultPath = Config.AutoNameOutputFolder; this.customFormat = Config.AutoNameCustomFormat; this.customFormatString = Config.AutoNameCustomFormatString; this.outputToSourceDirectory = Config.OutputToSourceDirectory; this.preserveFolderStructureInBatch = Config.PreserveFolderStructureInBatch; this.useCustomPreviewFolder = Config.UseCustomPreviewFolder; this.previewOutputFolder = Config.PreviewOutputFolder; this.whenFileExists = CustomConfig.WhenFileExists; this.whenFileExistsBatch = CustomConfig.WhenFileExistsBatch; this.minimizeToTray = Config.MinimizeToTray; this.useCustomVideoPlayer = Config.UseCustomVideoPlayer; this.customVideoPlayer = Config.CustomVideoPlayer; this.useBuiltInPlayerForPreviews = Config.UseBuiltInPlayerForPreviews; this.playSoundOnCompletion = Config.PlaySoundOnCompletion; this.useCustomCompletionSound = Config.UseCustomCompletionSound; this.customCompletionSound = Config.CustomCompletionSound; this.workerProcessPriority = Config.WorkerProcessPriority; this.logVerbosity = Config.LogVerbosity; this.copyLogToOutputFolder = Config.CopyLogToOutputFolder; this.previewCount = Config.PreviewCount; this.rememberPreviousFiles = Config.RememberPreviousFiles; this.showAudioTrackNameField = Config.ShowAudioTrackNameField; this.enableLibDvdNav = Config.EnableLibDvdNav; this.deleteSourceFilesOnClearingCompleted = Config.DeleteSourceFilesOnClearingCompleted; this.preserveModifyTimeFiles = Config.PreserveModifyTimeFiles; this.resumeEncodingOnRestart = Config.ResumeEncodingOnRestart; this.useWorkerProcess = Config.UseWorkerProcess; this.minimumTitleLengthSeconds = Config.MinimumTitleLengthSeconds; this.AutoPauseProcesses = new ObservableCollection <string>(); this.videoFileExtensions = Config.VideoFileExtensions; this.cpuThrottlingCores = (int)Math.Round(this.CpuThrottlingMaxCores * Config.CpuThrottlingFraction); if (this.cpuThrottlingCores < 1) { this.cpuThrottlingCores = 1; } if (this.cpuThrottlingCores > this.CpuThrottlingMaxCores) { this.cpuThrottlingCores = this.CpuThrottlingMaxCores; } this.maxSimultaneousEncodes = Config.MaxSimultaneousEncodes; List <string> autoPauseList = CustomConfig.AutoPauseProcesses; if (autoPauseList != null) { foreach (string process in autoPauseList) { this.AutoPauseProcesses.Add(process); } } // List of language codes and names: http://msdn.microsoft.com/en-us/goglobal/bb896001.aspx this.LanguageChoices = new List <InterfaceLanguage> { new InterfaceLanguage { CultureCode = string.Empty, Display = OptionsRes.UseOSLanguage }, new InterfaceLanguage { CultureCode = "en-US", Display = "English" }, new InterfaceLanguage { CultureCode = "id-ID", Display = "Bahasa Indonesia / Indonesian" }, new InterfaceLanguage { CultureCode = "bs-Latn-BA", Display = "bosanski (Bosna i Hercegovina) / Bosnian (Latin)" }, new InterfaceLanguage { CultureCode = "cs-CZ", Display = "čeština / Czech" }, new InterfaceLanguage { CultureCode = "de-DE", Display = "Deutsch / German" }, new InterfaceLanguage { CultureCode = "es-ES", Display = "Español / Spanish" }, new InterfaceLanguage { CultureCode = "eu-ES", Display = "Euskara / Basque" }, new InterfaceLanguage { CultureCode = "fr-FR", Display = "Français / French" }, new InterfaceLanguage { CultureCode = "it-IT", Display = "italiano / Italian" }, new InterfaceLanguage { CultureCode = "hu-HU", Display = "Magyar / Hungarian" }, new InterfaceLanguage { CultureCode = "nl-BE", Display = "Nederlands / Dutch" }, new InterfaceLanguage { CultureCode = "pl-PL", Display = "polski / Polish" }, new InterfaceLanguage { CultureCode = "pt-PT", Display = "Português / Portuguese" }, new InterfaceLanguage { CultureCode = "pt-BR", Display = "Português (Brasil) / Portuguese (Brazil)" }, new InterfaceLanguage { CultureCode = "tr-TR", Display = "Türkçe / Turkish" }, new InterfaceLanguage { CultureCode = "ka-GE", Display = "ქართული / Georgian" }, new InterfaceLanguage { CultureCode = "ru-RU", Display = "русский / Russian" }, new InterfaceLanguage { CultureCode = "ko-KO", Display = "한국어 / Korean" }, new InterfaceLanguage { CultureCode = "zh-Hans", Display = "中文(简体) / Chinese (Simplified)" }, new InterfaceLanguage { CultureCode = "zh-Hant", Display = "中文(繁體) / Chinese (Traditional)" }, new InterfaceLanguage { CultureCode = "ja-JP", Display = "日本語 / Japanese" }, }; this.AppThemeChoices = new List <ComboChoice <AppThemeChoice> > { new ComboChoice <AppThemeChoice>(AppThemeChoice.Auto, EnumsRes.AppThemeChoice_Auto), new ComboChoice <AppThemeChoice>(AppThemeChoice.Light, EnumsRes.AppThemeChoice_Light), new ComboChoice <AppThemeChoice>(AppThemeChoice.Dark, EnumsRes.AppThemeChoice_Dark), }; this.appTheme = this.AppThemeChoices.FirstOrDefault(t => t.Value == CustomConfig.AppTheme); if (this.appTheme == null) { this.appTheme = this.AppThemeChoices[0]; } this.PriorityChoices = new List <ComboChoice> { new ComboChoice("High", OptionsRes.Priority_High), new ComboChoice("AboveNormal", OptionsRes.Priority_AboveNormal), new ComboChoice("Normal", OptionsRes.Priority_Normal), new ComboChoice("BelowNormal", OptionsRes.Priority_BelowNormal), new ComboChoice("Idle", OptionsRes.Priority_Idle), }; this.interfaceLanguage = this.LanguageChoices.FirstOrDefault(l => l.CultureCode == Config.InterfaceLanguageCode); if (this.interfaceLanguage == null) { this.interfaceLanguage = this.LanguageChoices[0]; } this.PlayerChoices = Players.All; if (this.PlayerChoices.Count > 0) { this.selectedPlayer = this.PlayerChoices[0]; foreach (IVideoPlayer player in this.PlayerChoices) { if (player.Id == Config.PreferredPlayer) { this.selectedPlayer = player; break; } } } if (!CommonUtilities.Beta) { Task.Run(async() => { this.betaInfo = await Updater.GetUpdateInfoAsync(beta: true); this.betaInfoAvailable = false; if (this.betaInfo != null) { if (this.betaInfo.LatestVersion.FillInWithZeroes() > Utilities.CurrentVersion) { this.betaInfoAvailable = true; } await DispatchUtilities.InvokeAsync(() => { this.RaisePropertyChanged(nameof(this.BetaChangelogUrl)); this.RaisePropertyChanged(nameof(this.BetaSectionVisible)); }); } }); } int tabIndex = Config.OptionsDialogLastTab; if (tabIndex >= this.Tabs.Count) { tabIndex = 0; } this.SelectedTabIndex = tabIndex; }
public VideoFiltersPanelViewModel(EncodingWindowViewModel encodingWindowViewModel) : base(encodingWindowViewModel) { this.AutomaticChange = true; this.RegisterProfileProperties(); this.DetelecineChoices = this.GetFilterPresetChoices(hb_filter_ids.HB_FILTER_DETELECINE); this.DeinterlaceChoices = new List <ComboChoice <VCDeinterlace> > { new ComboChoice <VCDeinterlace>(VCDeinterlace.Off, CommonRes.Off), new ComboChoice <VCDeinterlace>(VCDeinterlace.Yadif, EnumsRes.Deinterlace_Yadif), new ComboChoice <VCDeinterlace>(VCDeinterlace.Decomb, EnumsRes.Deinterlace_Decomb), }; this.CombDetectChoices = this.GetFilterPresetChoices(hb_filter_ids.HB_FILTER_COMB_DETECT, "CombDetect_"); this.DenoiseChoices = new List <ComboChoice <VCDenoise> > { new ComboChoice <VCDenoise>(VCDenoise.Off, CommonRes.Off), new ComboChoice <VCDenoise>(VCDenoise.hqdn3d, EnumsRes.Denoise_HQDN3D), new ComboChoice <VCDenoise>(VCDenoise.NLMeans, EnumsRes.Denoise_NLMeans), }; this.DenoiseTuneChoices = this.GetFilterTuneChoices(hb_filter_ids.HB_FILTER_NLMEANS, "DenoiseTune_"); // CustomDetelecineVisible this.WhenAnyValue(x => x.Detelecine, detelecine => { return(detelecine == "custom"); }).ToProperty(this, x => x.CustomDetelecineVisible, out this.customDetelecineVisible); // DeinterlacePresetChoices this.WhenAnyValue(x => x.DeinterlaceType) .Select(deinterlaceType => { if (deinterlaceType == VCDeinterlace.Off) { return(new List <ComboChoice>()); } return(this.GetFilterPresetChoices(GetDeinterlaceFilter(deinterlaceType), "DeinterlacePreset_")); }).ToProperty(this, x => x.DeinterlacePresetChoices, out this.deinterlacePresetChoices); // DeinterlacePresetVisible this.WhenAnyValue(x => x.DeinterlaceType) .Select(deinterlaceType => { return(deinterlaceType != VCDeinterlace.Off); }).ToProperty(this, x => x.DeinterlacePresetVisible, out this.deinterlacePresetVisible); // CustomDeinterlaceVisible this.WhenAnyValue(x => x.DeinterlaceType, x => x.DeinterlacePreset, (deinterlaceType, deinterlacePreset) => { return(deinterlaceType != VCDeinterlace.Off && deinterlacePreset == "custom"); }).ToProperty(this, x => x.CustomDeinterlaceVisible, out this.customDeinterlaceVisible); // CustomDeinterlaceToolTip this.WhenAnyValue(x => x.DeinterlaceType, deinterlaceType => { if (deinterlaceType == VCDeinterlace.Off) { return(string.Empty); } return(GetCustomFilterToolTip(GetDeinterlaceFilter(deinterlaceType))); }).ToProperty(this, x => x.CustomDeinterlaceToolTip, out this.customDeinterlaceToolTip); // CustomCombDetectVisible this.WhenAnyValue(x => x.CombDetect, combDetect => { return(combDetect == "custom"); }).ToProperty(this, x => x.CustomCombDetectVisible, out this.customCombDetectVisible); // DenoisePresetVisible this.WhenAnyValue(x => x.DenoiseType, denoise => { return(denoise != VCDenoise.Off); }).ToProperty(this, x => x.DenoisePresetVisible, out this.denoisePresetVisible); // DenoisePresetChoices this.WhenAnyValue(x => x.DenoiseType) .Select(denoiseType => { if (denoiseType == VCDenoise.Off) { return(new List <ComboChoice>()); } return(this.GetFilterPresetChoices(GetDenoiseFilter(denoiseType), "DenoisePreset_")); }).ToProperty(this, x => x.DenoisePresetChoices, out this.denoisePresetChoices); // DenoiseTuneVisible this.WhenAnyValue(x => x.DenoiseType, x => x.DenoisePreset, (denoiseType, denoisePreset) => { return(denoiseType == VCDenoise.NLMeans && denoisePreset != "custom"); }).ToProperty(this, x => x.DenoiseTuneVisible, out this.denoiseTuneVisible); // CustomDenoiseVisible this.WhenAnyValue(x => x.DenoiseType, x => x.DenoisePreset, (denoiseType, denoisePreset) => { return(denoiseType != VCDenoise.Off && denoisePreset == "custom"); }).ToProperty(this, x => x.CustomDenoiseVisible, out this.customDenoiseVisible); // CustomDenoiseToolTip this.WhenAnyValue(x => x.DenoiseType, denoiseType => { if (denoiseType == VCDenoise.Off) { return(string.Empty); } return(GetCustomFilterToolTip(GetDenoiseFilter(denoiseType))); }).ToProperty(this, x => x.CustomDenoiseToolTip, out this.customDenoiseToolTip); // DeblockText this.WhenAnyValue(x => x.Deblock, deblock => { if (deblock >= MinDeblock) { return(deblock.ToString(CultureInfo.CurrentCulture)); } return(CommonRes.Off); }).ToProperty(this, x => x.DeblockText, out this.deblockText); // The deinterlace and denoise presets need another nudge to change after the lists have changed. this.WhenAnyValue(x => x.DeinterlaceType) .Subscribe(_ => { DispatchUtilities.BeginInvoke(() => { this.RaisePropertyChanged(nameof(this.DeinterlacePreset)); }); }); this.WhenAnyValue(x => x.DenoiseType) .Subscribe(_ => { DispatchUtilities.BeginInvoke(() => { this.RaisePropertyChanged(nameof(this.DenoisePreset)); }); }); this.AutomaticChange = false; }
private void ProcessPreviewImageWork(object state) { PreviewImageJob imageJob; bool workLeft = true; while (workLeft) { lock (this.imageSync) { if (this.previewImageWorkQueue.Count == 0) { this.previewImageQueueProcessing = false; return; } imageJob = this.previewImageWorkQueue.Dequeue(); while (imageJob.UpdateVersion < updateVersion) { if (this.previewImageWorkQueue.Count == 0) { this.previewImageQueueProcessing = false; return; } imageJob = this.previewImageWorkQueue.Dequeue(); } } string imagePath = Path.Combine( Utilities.ImageCacheFolder, Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture), imageJob.UpdateVersion.ToString(CultureInfo.InvariantCulture), imageJob.PreviewIndex.ToString(CultureInfo.InvariantCulture) + ".bmp"); BitmapSource imageSource = null; // Check the disc cache for the image lock (imageJob.ImageFileSync) { if (File.Exists(imagePath)) { Uri imageUri; if (Uri.TryCreate(imagePath, UriKind.Absolute, out imageUri)) { // When we read from disc cache the image is already transformed. var bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.UriSource = imageUri; bitmapImage.EndInit(); bitmapImage.Freeze(); imageSource = bitmapImage; } else { StaticResolver.Resolve <IAppLogger>().LogError($"Could not load cached preview image from {imagePath} . Did not parse as a URI."); } } } if (imageSource == null && !imageJob.ScanInstance.IsDisposed) { // Make a HandBrake call to get the image imageSource = BitmapUtilities.ConvertToBitmapImage(BitmapUtilities.ConvertByteArrayToBitmap(imageJob.ScanInstance.GetPreview(imageJob.Profile.CreatePreviewSettings(imageJob.Title), imageJob.PreviewIndex, imageJob.Profile.DeinterlaceType != VCDeinterlace.Off))); // Transform the image as per rotation and reflection settings VCProfile profile = imageJob.Profile; if (profile.FlipHorizontal || profile.FlipVertical || profile.Rotation != VCPictureRotation.None) { imageSource = CreateTransformedBitmap(imageSource, profile); } // Start saving the image file in the background and continue to process the queue. ThreadPool.QueueUserWorkItem(this.BackgroundFileSave, new SaveImageJob { PreviewNumber = imageJob.PreviewIndex, UpdateVersion = imageJob.UpdateVersion, FilePath = imagePath, Image = imageSource, ImageFileSync = imageJob.ImageFileSync }); } lock (this.imageSync) { if (imageJob.UpdateVersion == updateVersion) { this.previewImageCache[imageJob.PreviewIndex] = imageSource; int previewIndex = imageJob.PreviewIndex; DispatchUtilities.BeginInvoke(() => { this.ImageLoaded?.Invoke(this, new PreviewImageLoadInfo { PreviewImage = imageSource, PreviewIndex = previewIndex }); //this.previewBitmapSource = imageSource; //this.RefreshFromBitmapImage(); }); //if (this.SelectedPreview == imageJob.PreviewIndex) // { // DispatchUtilities.BeginInvoke(() => // { // this.previewBitmapSource = imageSource; // this.RefreshFromBitmapImage(); // }); // } } if (this.previewImageWorkQueue.Count == 0) { workLeft = false; this.previewImageQueueProcessing = false; } } } }
private void previewImageRefreshTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { this.waitingOnRefresh = false; this.lastImageRefreshTime = DateTime.MinValue; DispatchUtilities.BeginInvoke(this.RefreshPreviews); }
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); }
private void ProcessPreviewImageWork(object state) { PreviewImageJob imageJob; bool workLeft = true; while (workLeft) { lock (this.imageSync) { if (this.previewImageWorkQueue.Count == 0) { this.previewImageQueueProcessing = false; return; } imageJob = this.previewImageWorkQueue.Dequeue(); while (imageJob.UpdateVersion < updateVersion) { if (this.previewImageWorkQueue.Count == 0) { this.previewImageQueueProcessing = false; return; } imageJob = this.previewImageWorkQueue.Dequeue(); } } string imagePath = Path.Combine(Utilities.ImageCacheFolder, Process.GetCurrentProcess().Id.ToString(CultureInfo.InvariantCulture), imageJob.UpdateVersion.ToString(CultureInfo.InvariantCulture), imageJob.PreviewNumber + ".bmp"); BitmapSource imageSource = null; // Check the disc cache for the image lock (imageJob.ImageFileSync) { if (File.Exists(imagePath)) { // When we read from disc cache the image is already transformed. var bitmapImage = new BitmapImage(); bitmapImage.BeginInit(); bitmapImage.CacheOption = BitmapCacheOption.OnLoad; bitmapImage.UriSource = new Uri(imagePath); bitmapImage.EndInit(); bitmapImage.Freeze(); imageSource = bitmapImage; } } if (imageSource == null && !imageJob.ScanInstance.IsDisposed) { // Make a HandBrake call to get the image imageSource = imageJob.ScanInstance.GetPreview(imageJob.Profile.CreatePreviewSettings(imageJob.Title), imageJob.PreviewNumber); // Transform the image as per rotation and reflection settings VCProfile profile = imageJob.Profile; if (profile.FlipHorizontal || profile.FlipVertical || profile.Rotation != VCPictureRotation.None) { imageSource = CreateTransformedBitmap(imageSource, profile); } // Start saving the image file in the background and continue to process the queue. ThreadPool.QueueUserWorkItem(this.BackgroundFileSave, new SaveImageJob { PreviewNumber = imageJob.PreviewNumber, UpdateVersion = imageJob.UpdateVersion, FilePath = imagePath, Image = imageSource, ImageFileSync = imageJob.ImageFileSync }); } lock (this.imageSync) { if (imageJob.UpdateVersion == updateVersion) { this.previewImageCache[imageJob.PreviewNumber] = imageSource; if (this.SelectedPreview == imageJob.PreviewNumber) { DispatchUtilities.BeginInvoke(() => { this.previewBitmapSource = imageSource; this.RefreshFromBitmapImage(); }); } } if (this.previewImageWorkQueue.Count == 0) { workLeft = false; this.previewImageQueueProcessing = false; } } } }