Пример #1
0
        /// <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);
                }
            };
        }
Пример #3
0
        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;
            }
        }
Пример #4
0
        /// <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);
                }
            });
        }
Пример #5
0
        public EncodeJobViewModel(VCJob job)
        {
            this.job = job;

            Messenger.Default.Register <ScanningChangedMessage>(
                this,
                message =>
            {
                this.EditQueueJobCommand.RaiseCanExecuteChanged();
            });
        }
Пример #6
0
        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());
        }
Пример #7
0
        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)
                                         );
        }
Пример #8
0
        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);
            });
        }
Пример #9
0
        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);
        }
Пример #10
0
        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);
        }
Пример #11
0
        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();
            }
        }
Пример #12
0
        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);
        }
Пример #13
0
        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);
            }
        }
Пример #14
0
        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;
        }
Пример #15
0
        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));
                }
            };
        }
Пример #17
0
        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();
        }