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 an installer downloaded, but there's a newer one out, clear out the downloaded update metadata if (Config.UpdateInstallerLocation != string.Empty && Version.TryParse(Config.UpdateVersion, out Version downloadedUpdateVersion) && downloadedUpdateVersion.FillInWithZeroes() < updateVersion.FillInWithZeroes()) { using (SQLiteTransaction transaction = Database.ThreadLocalConnection.BeginTransaction()) { ClearUpdateMetadata(); transaction.Commit(); } } // 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 { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; 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 downloadFinishedFormat = CustomConfig.UpdatePromptTiming == UpdatePromptTiming.OnExit ? MainRes.NewVersionDownloadFinishedStatus : MainRes.NewVersionDownloadFinishedOnLaunchStatus; string message = string.Format(downloadFinishedFormat, updateVersionText); this.logger.Log(message); this.logger.ShowStatus(message); } else { // In this case the download must have been cancelled. this.State = UpdateState.NotStarted; } } finally { responseStream?.Close(); 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." + Environment.NewLine + exception); } finally { this.updateDownloadCancellationTokenSource?.Dispose(); this.updateDownloadCancellationTokenSource = null; } if (this.State == UpdateState.InstallerReady && CustomConfig.UpdatePromptTiming == UpdatePromptTiming.OnLaunch) { DispatchUtilities.BeginInvoke(() => { if (this.PromptToApplyUpdate(relaunchWhenComplete: true)) { StaticResolver.Resolve <MainViewModel>().Exit.Execute(null); } }); } }); }
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 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 }); }); } if (this.previewImageWorkQueue.Count == 0) { workLeft = false; this.previewImageQueueProcessing = false; } } } }
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 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 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(); DebugEncodeJsonDialog dialog = new DebugEncodeJsonDialog(); dialog.ShowDialog(); if (!string.IsNullOrWhiteSpace(dialog.EncodeJson)) { try { JsonEncodeObject encodeObject = JsonConvert.DeserializeObject <JsonEncodeObject>(dialog.EncodeJson); jobViewModel.DebugEncodeJsonOverride = dialog.EncodeJson; 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 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); }; }
private void previewImageRefreshTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { this.waitingOnRefresh = false; this.lastImageRefreshTime = DateTime.MinValue; DispatchUtilities.BeginInvoke(this.RefreshPreviews); }
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 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_"); this.SharpenChoices = new List <ComboChoice <VCSharpen> > { new ComboChoice <VCSharpen>(VCSharpen.Off, CommonRes.Off), new ComboChoice <VCSharpen>(VCSharpen.UnSharp, EnumsRes.Sharpen_UnSharp), new ComboChoice <VCSharpen>(VCSharpen.LapSharp, EnumsRes.Sharpen_LapSharp), }; // 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); // SharpenPresetChoices this.WhenAnyValue(x => x.SharpenType) .Select(sharpenType => { if (sharpenType == VCSharpen.Off) { return(new List <ComboChoice>()); } return(this.GetFilterPresetChoices(GetSharpenFilter(sharpenType))); }).ToProperty(this, x => x.SharpenPresetChoices, out this.sharpenPresetChoices); // SharpenPresetVisible this.WhenAnyValue(x => x.SharpenType) .Select(sharpenType => { return(sharpenType != VCSharpen.Off); }).ToProperty(this, x => x.SharpenPresetVisible, out this.sharpenPresetVisible); // SharpenTuneChoices this.WhenAnyValue(x => x.SharpenType) .Select(sharpenType => { if (sharpenType == VCSharpen.Off) { return(new List <ComboChoice>()); } return(this.GetFilterTuneChoices(GetSharpenFilter(sharpenType))); }).ToProperty(this, x => x.SharpenTuneChoices, out this.sharpenTuneChoices); // SharpenTuneVisible this.WhenAnyValue(x => x.SharpenType, x => x.SharpenPreset, (sharpenType, sharpenPreset) => { return(sharpenType != VCSharpen.Off && sharpenPreset != "custom"); }).ToProperty(this, x => x.SharpenTuneVisible, out this.sharpenTuneVisible); // CustomSharpenVisible this.WhenAnyValue(x => x.SharpenType, x => x.SharpenPreset, (sharpenType, sharpenPreset) => { return(sharpenType != VCSharpen.Off && sharpenPreset == "custom"); }).ToProperty(this, x => x.CustomSharpenVisible, out this.customSharpenVisible); // CustomSharpenToolTip this.WhenAnyValue(x => x.SharpenType) .Select(sharpenType => { if (sharpenType == VCSharpen.Off) { return(string.Empty); } return(GetCustomFilterToolTip(GetSharpenFilter(sharpenType))); }).ToProperty(this, x => x.CustomSharpenToolTip, out this.customSharpenToolTip); // 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 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; 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; } } } }
private void HandleDiscEvent(object sender, EventArrivedEventArgs e) { DispatchUtilities.BeginInvoke(() => this.mainViewModel.UpdateDriveCollection()); }