// -------------------------------------------------------------------------------------------------------------------- // // 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 HandBrake.ApplicationServices.Services { using System; using System.Collections.Generic; using System.Text; using System.Threading; using HandBrake.ApplicationServices.EventArgs; using HandBrake.ApplicationServices.Model.Encoding; using HandBrake.ApplicationServices.Parsing; using HandBrake.ApplicationServices.Services.Interfaces; using HandBrake.ApplicationServices.Utilities; using HandBrake.Interop; using HandBrake.Interop.EventArgs; using HandBrake.Interop.Interfaces; using AudioTrack = HandBrake.ApplicationServices.Parsing.Audio; using ScanProgressEventArgs = HandBrake.Interop.EventArgs.ScanProgressEventArgs; using Size = System.Drawing.Size; /// /// Scan a Source /// public class LibScan : IScan { /* * TODO * 1. Expose the Previews code. * 2. Expose the Logging. * */ #region Private Variables /// /// Lock for the log file /// static readonly object LogLock = new object(); /// /// LibHB Instance /// private readonly IHandBrakeInstance instance; /// /// Log data from HandBrakeInstance /// private readonly StringBuilder logging; /// /// The Log File Header /// private readonly StringBuilder header; /// /// The Current source scan path. /// private string currentSourceScanPath; #endregion /// /// Initializes a new instance of the class. /// /// /// The hand Brake Instance. /// public LibScan(IHandBrakeInstance handBrakeInstance) { logging = new StringBuilder(); header = GeneralUtilities.CreateCliLogHeader(); instance = handBrakeInstance; instance.Initialize(1); instance.ScanProgress += this.InstanceScanProgress; instance.ScanCompleted += this.InstanceScanCompleted; HandBrakeUtils.MessageLogged += this.HandBrakeInstanceMessageLogged; HandBrakeUtils.ErrorLogged += this.HandBrakeInstanceErrorLogged; } #region Events /// /// Scan has Started /// public event EventHandler ScanStared; /// /// Scan has completed /// public event ScanCompletedStatus ScanCompleted; /// /// Encode process has progressed /// public event ScanProgessStatus ScanStatusChanged; #endregion #region Properties /// /// Gets a value indicating whether IsScanning. /// public bool IsScanning { get; private set; } /// /// Gets the Souce Data. /// public Source SouceData { get; private set; } /// /// Gets ActivityLog. /// public string ActivityLog { get { return string.IsNullOrEmpty(this.logging.ToString()) ? this.header + "No log data available..." : this.header + this.logging.ToString(); } } #endregion #region Public Methods /// /// Scan a Source Path. /// Title 0: scan all /// /// /// Path to the file to scan /// /// /// int title number. 0 for scan all /// /// /// The preview Count. /// /// /// The post Action. /// public void Scan(string sourcePath, int title, int previewCount, Action postAction) { Thread t = new Thread(unused => this.ScanSource(sourcePath, title, previewCount)); t.Start(); } /// /// Kill the scan /// public void Stop() { instance.StopScan(); } /// /// Debug a Scan Log (Only Available for CLI Mode, not LIBHB) /// /// /// The path. /// /// /// (Only Available for CLI Mode, not LIBHB) /// public void DebugScanLog(string path) { throw new NotImplementedException("Only Available when using the CLI mode. Not LibHB"); } /// /// Shutdown the service. /// public void Shutdown() { // Nothing to do for this implementation. } #endregion #region Private Methods /// /// 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 { this.logging.Clear(); string source = sourcePath.ToString().EndsWith("\\") ? string.Format("\"{0}\\\\\"", sourcePath.ToString().TrimEnd('\\')) : "\"" + sourcePath + "\""; currentSourceScanPath = source; IsScanning = true; if (this.ScanStared != null) this.ScanStared(this, new EventArgs()); if (title != 0) instance.StartScan(sourcePath.ToString(), previewCount, title); else instance.StartScan(sourcePath.ToString(), previewCount); } catch (Exception exc) { this.Stop(); if (this.ScanCompleted != null) this.ScanCompleted(this, new ScanCompletedEventArgs(false, exc, "An Error has occured in ScanService.ScanSource()")); } } #endregion #region HandBrakeInstance Event Handlers /// /// Scan Completed Event Handler /// /// /// The sender. /// /// /// The EventArgs. /// private void InstanceScanCompleted(object sender, EventArgs e) { // TODO -> Might be a better place to fix this. string path = currentSourceScanPath; if (currentSourceScanPath.Contains("\"")) { path = currentSourceScanPath.Trim('\"'); } this.SouceData = new Source { Titles = ConvertTitles(this.instance.Titles), ScanPath = path }; IsScanning = false; if (this.ScanCompleted != null) this.ScanCompleted(this, new ScanCompletedEventArgs(false, null, string.Empty)); } /// /// Scan Progress Event Handler /// /// /// The sender. /// /// /// The EventArgs. /// private void InstanceScanProgress(object sender, ScanProgressEventArgs e) { if (this.ScanStatusChanged != null) { ApplicationServices.EventArgs.ScanProgressEventArgs eventArgs = new ApplicationServices.EventArgs.ScanProgressEventArgs { CurrentTitle = e.CurrentTitle, Titles = e.Titles }; this.ScanStatusChanged(this, eventArgs); } } /// /// Log a message /// /// /// The sender. /// /// /// The MessageLoggedEventArgs. /// private void HandBrakeInstanceErrorLogged(object sender, MessageLoggedEventArgs e) { lock (LogLock) { this.logging.AppendLine(e.Message); } } /// /// Log a message /// /// /// The sender. /// /// /// The MessageLoggedEventArgs. /// private void HandBrakeInstanceMessageLogged(object sender, MessageLoggedEventArgs e) { lock (LogLock) { this.logging.AppendLine(e.Message); } } /// /// Convert Interop Title objects to App Services Title object /// /// /// The titles. /// /// /// The convert titles. /// private static List ConvertTitles(IEnumerable<Interop.SourceData.Title> titles) { List<Title> titleList = new List<Title>(); foreach (Interop.SourceData.Title title in titles) { Title converted = new Title { TitleNumber = title.TitleNumber, Duration = title.Duration, Resolution = new Size(title.Resolution.Width, title.Resolution.Height), AspectRatio = title.AspectRatio, AngleCount = title.AngleCount, ParVal = new Size(title.ParVal.Width, title.ParVal.Height), AutoCropDimensions = title.AutoCropDimensions, Fps = title.Framerate }; foreach (Interop.SourceData.Chapter chapter in title.Chapters) { converted.Chapters.Add(new Chapter(chapter.ChapterNumber, string.Empty, chapter.Duration)); } foreach (Interop.SourceData.AudioTrack track in title.AudioTracks) { converted.AudioTracks.Add(new AudioTrack(track.TrackNumber, track.Language, track.LanguageCode, track.Description, string.Empty, track.SampleRate, track.Bitrate)); } foreach (Interop.SourceData.Subtitle track in title.Subtitles) { SubtitleType convertedType = new SubtitleType(); switch (track.SubtitleSource) { case Interop.SourceData.SubtitleSource.VobSub: convertedType = SubtitleType.VobSub; break; case Interop.SourceData.SubtitleSource.UTF8: convertedType = SubtitleType.UTF8Sub; break; case Interop.SourceData.SubtitleSource.TX3G: convertedType = SubtitleType.TX3G; break; case Interop.SourceData.SubtitleSource.SSA: convertedType = SubtitleType.SSA; break; case Interop.SourceData.SubtitleSource.SRT: convertedType = SubtitleType.SRT; break; case Interop.SourceData.SubtitleSource.CC608: convertedType = SubtitleType.CC; break; case Interop.SourceData.SubtitleSource.CC708: convertedType = SubtitleType.CC; break; } converted.Subtitles.Add(new Subtitle(track.TrackNumber, track.Language, track.LanguageCode, convertedType)); } titleList.Add(converted); } return titleList; } #endregion } }