// --------------------------------------------------------------------------------------------------------------------
//
// 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 titles)
{
List titleList = new List();
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
}
}