// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // Scan a Source // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.Services.Scan { using System; using System.Collections.Generic; using System.Diagnostics; using System.Windows.Media.Imaging; using HandBrake.Interop.Interop; using HandBrake.Interop.Interop.Interfaces; using HandBrake.Interop.Interop.Json.Scan; using HandBrake.Interop.Interop.Model; using HandBrake.Interop.Interop.Model.Encoding; using HandBrake.Interop.Interop.Model.Preview; using HandBrake.Interop.Model; using HandBrakeWPF.Instance; using HandBrakeWPF.Services.Encode.Model; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.Services.Scan.EventArgs; using HandBrakeWPF.Services.Scan.Factories; using HandBrakeWPF.Services.Scan.Interfaces; using HandBrakeWPF.Services.Scan.Model; using HandBrakeWPF.Utilities; using ILog = Logging.Interfaces.ILog; using LogService = Logging.LogService; using ScanProgressEventArgs = HandBrake.Interop.Interop.EventArgs.ScanProgressEventArgs; using Title = Model.Title; /// /// Scan a Source /// public class LibScan : IScan, IDisposable { private readonly ILog log = null; private readonly IUserSettingService userSettingService; private TitleFactory titleFactory = new TitleFactory(); private string currentSourceScanPath; private IHandBrakeInstance instance; private Action postScanOperation; private bool isCancelled = false; public LibScan(ILog logService, IUserSettingService userSettingService) { this.log = logService; this.userSettingService = userSettingService; this.IsScanning = false; } public event EventHandler ScanStarted; public event ScanCompletedStatus ScanCompleted; public event ScanProgessStatus ScanStatusChanged; public bool IsScanning { get; private set; } /// /// Scan a Source Path. /// Title 0: scan all /// /// /// Path to the file to scan /// /// /// int title number. 0 for scan all /// /// /// The post Action. /// public void Scan(string sourcePath, int title, Action postAction) { // Try to cleanup any previous scan instances. if (this.instance != null) { try { this.instance.Dispose(); } catch (Exception) { // Do Nothing } } this.isCancelled = false; // Handle the post scan operation. this.postScanOperation = postAction; // Create a new HandBrake Instance. this.instance = HandBrakeInstanceManager.GetScanInstance(this.userSettingService.GetUserSetting(UserSettingConstants.Verbosity)); this.instance.ScanProgress += this.InstanceScanProgress; this.instance.ScanCompleted += this.InstanceScanCompleted; // Start the scan on a back this.ScanSource(sourcePath, title, this.userSettingService.GetUserSetting(UserSettingConstants.PreviewScanCount)); } /// /// Kill the scan /// public void Stop() { try { this.ServiceLogMessage("Manually Stopping Scan ..."); this.IsScanning = false; var handBrakeInstance = this.instance; if (handBrakeInstance != null) { handBrakeInstance.StopScan(); handBrakeInstance.ScanProgress -= this.InstanceScanProgress; handBrakeInstance.ScanCompleted -= this.InstanceScanCompleted; handBrakeInstance.Dispose(); this.instance = null; } } catch (Exception exc) { this.ServiceLogMessage(exc.ToString()); } finally { this.ScanCompleted?.Invoke(this, new ScanCompletedEventArgs(this.isCancelled, null, null, null)); this.instance = null; this.ServiceLogMessage("Scan Stopped ..."); } } /// /// Cancel the current scan. /// public void Cancel() { this.isCancelled = true; this.Stop(); } /// /// Get a Preview image for the current job and preview number. /// /// /// The job. /// /// /// The preview. /// /// /// The . /// public BitmapImage GetPreview(EncodeTask job, int preview) { if (this.instance == null) { return null; } BitmapImage bitmapImage = null; try { PreviewSettings settings = new PreviewSettings { Cropping = new Cropping(job.Cropping), MaxWidth = job.MaxWidth ?? 0, MaxHeight = job.MaxHeight ?? 0, KeepDisplayAspect = job.KeepDisplayAspect, TitleNumber = job.Title, Anamorphic = job.Anamorphic, Modulus = job.Modulus, Width = job.Width ?? 0, Height = job.Height ?? 0, PixelAspectX = job.PixelAspectX, PixelAspectY = job.PixelAspectY }; RawPreviewData bitmapData = this.instance.GetPreview(settings, preview, job.DeinterlaceFilter != DeinterlaceFilter.Off); bitmapImage = BitmapUtilities.ConvertToBitmapImage(BitmapUtilities.ConvertByteArrayToBitmap(bitmapData)); } catch (AccessViolationException e) { Debug.WriteLine(e); } return bitmapImage; } /// /// The service log message. /// /// /// The message. /// protected void ServiceLogMessage(string message) { this.log.LogMessage(string.Format("{0} # {1}{0}", Environment.NewLine, message)); } /// /// Start a scan for a given source path and title /// /// /// Path to the source file /// /// /// the title number to look at /// /// /// The preview Count. /// private void ScanSource(object sourcePath, int title, int previewCount) { try { string source = sourcePath.ToString().EndsWith("\\") ? string.Format("\"{0}\\\\\"", sourcePath.ToString().TrimEnd('\\')) : "\"" + sourcePath + "\""; this.currentSourceScanPath = source; this.IsScanning = true; TimeSpan minDuration = TimeSpan.FromSeconds(this.userSettingService.GetUserSetting(UserSettingConstants.MinScanDuration)); HandBrakeUtils.SetDvdNav(!this.userSettingService.GetUserSetting(UserSettingConstants.DisableLibDvdNav)); this.ServiceLogMessage("Starting Scan ..."); this.instance.StartScan(sourcePath.ToString(), previewCount, minDuration, title != 0 ? title : 0); this.ScanStarted?.Invoke(this, System.EventArgs.Empty); } catch (Exception exc) { this.ServiceLogMessage("Scan Failed ..." + Environment.NewLine + exc); this.Stop(); } } /// /// Scan Completed Event Handler /// /// /// The sender. /// /// /// The EventArgs. /// private void InstanceScanCompleted(object sender, System.EventArgs e) { try { this.ServiceLogMessage("Processing Scan Information ..."); bool cancelled = this.isCancelled; this.isCancelled = false; // TODO -> Might be a better place to fix this. string path = this.currentSourceScanPath; if (this.currentSourceScanPath.Contains("\"")) { path = this.currentSourceScanPath.Trim('\"'); } // Process into internal structures. Source sourceData = null; if (this.instance?.Titles != null) { sourceData = new Source { Titles = this.ConvertTitles(this.instance.Titles), ScanPath = path }; } this.IsScanning = false; if (this.postScanOperation != null) { try { this.postScanOperation(true, sourceData); } catch (Exception exc) { Debug.WriteLine(exc); } this.postScanOperation = null; // Reset this.ServiceLogMessage("Scan Finished for Queue Edit ..."); } else { this.ScanCompleted?.Invoke( this, new ScanCompletedEventArgs(cancelled, null, string.Empty, sourceData)); this.ServiceLogMessage("Scan Finished ..."); } } finally { var handBrakeInstance = this.instance; if (handBrakeInstance != null) { handBrakeInstance.ScanProgress -= this.InstanceScanProgress; handBrakeInstance.ScanCompleted -= this.InstanceScanCompleted; } } } /// /// Scan Progress Event Handler /// /// /// The sender. /// /// /// The EventArgs. /// private void InstanceScanProgress(object sender, ScanProgressEventArgs e) { if (this.ScanStatusChanged != null) { EventArgs.ScanProgressEventArgs eventArgs = new EventArgs.ScanProgressEventArgs { CurrentTitle = e.CurrentTitle, Titles = e.Titles, Percentage = Math.Round((decimal)e.Progress * 100, 0) }; this.ScanStatusChanged(this, eventArgs); } } /// /// Convert Interop Title objects to App Services Title object /// /// /// The titles. /// /// /// The convert titles. /// private List ConvertTitles(JsonScanObject titles) { List<Title> titleList = new List<Title>(); foreach (SourceTitle title in titles.TitleList) { Title converted = this.titleFactory.CreateTitle(title, titles.MainFeature); titleList.Add(converted); } return titleList; } public void Dispose() { if (this.instance != null) { try { this.instance.Dispose(); this.instance = null; } catch (Exception e) { this.ServiceLogMessage("Unable to Dispose of LibScan: " + e); } } } } }