summaryrefslogtreecommitdiffstats
path: root/win/C#/HandBrake.ApplicationServices/Parsing
diff options
context:
space:
mode:
authorsr55 <[email protected]>2010-06-06 18:22:39 +0000
committersr55 <[email protected]>2010-06-06 18:22:39 +0000
commit0c9a71f626e0e552cf670103b8dad8e61de1fb69 (patch)
tree8bda1188ea4fd4f15700b5c997c491bbe37f9f4e /win/C#/HandBrake.ApplicationServices/Parsing
parent21edb5248c8d25d334e3225e2f52ff9e8d9782dd (diff)
WinGui:
- Moved all the services that handle parsing, scanning, encodes and the queue out into a separate library. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@3362 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'win/C#/HandBrake.ApplicationServices/Parsing')
-rw-r--r--win/C#/HandBrake.ApplicationServices/Parsing/AudioTrack.cs171
-rw-r--r--win/C#/HandBrake.ApplicationServices/Parsing/Chapter.cs110
-rw-r--r--win/C#/HandBrake.ApplicationServices/Parsing/DVD.cs53
-rw-r--r--win/C#/HandBrake.ApplicationServices/Parsing/Parser.cs159
-rw-r--r--win/C#/HandBrake.ApplicationServices/Parsing/Subtitle.cs134
-rw-r--r--win/C#/HandBrake.ApplicationServices/Parsing/Title.cs291
6 files changed, 918 insertions, 0 deletions
diff --git a/win/C#/HandBrake.ApplicationServices/Parsing/AudioTrack.cs b/win/C#/HandBrake.ApplicationServices/Parsing/AudioTrack.cs
new file mode 100644
index 000000000..f83660bb8
--- /dev/null
+++ b/win/C#/HandBrake.ApplicationServices/Parsing/AudioTrack.cs
@@ -0,0 +1,171 @@
+/* AudioTrack.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+namespace HandBrake.ApplicationServices.Parsing
+{
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text.RegularExpressions;
+
+ /// <summary>
+ /// An object represending an AudioTrack associated with a Title, in a DVD
+ /// </summary>
+ public class AudioTrack
+ {
+ /// <summary>
+ /// Gets The track number of this Audio Track
+ /// </summary>
+ public int TrackNumber { get; private set; }
+
+ /// <summary>
+ /// Gets The language (if detected) of this Audio Track
+ /// </summary>
+ public string Language { get; private set; }
+
+ /// <summary>
+ /// Gets or sets LanguageCode.
+ /// </summary>
+ public string LanguageCode { get; set; }
+
+ /// <summary>
+ /// Gets or sets Description.
+ /// </summary>
+ public string Description { get; set; }
+
+ /// <summary>
+ /// Gets The primary format of this Audio Track
+ /// </summary>
+ public string Format { get; private set; }
+
+ /// <summary>
+ /// Gets The frequency (in MHz) of this Audio Track
+ /// </summary>
+ public int SampleRate { get; private set; }
+
+ /// <summary>
+ /// Gets The bitrate (in kbps) of this Audio Track
+ /// </summary>
+ public int Bitrate { get; private set; }
+
+ /// <summary>
+ /// Create a new Audio Track object
+ /// </summary>
+ /// <param name="track">
+ /// The track.
+ /// </param>
+ /// <param name="lang">
+ /// The lang.
+ /// </param>
+ /// <param name="langCode">
+ /// The lang code.
+ /// </param>
+ /// <param name="desc">
+ /// The desc.
+ /// </param>
+ /// <param name="format">
+ /// The format.
+ /// </param>
+ /// <param name="samplerate">
+ /// The samplerate.
+ /// </param>
+ /// <param name="bitrate">
+ /// The bitrate.
+ /// </param>
+ /// <returns>
+ /// A new Audio Track
+ /// </returns>
+ public static AudioTrack CreateAudioTrack(int track, string lang, string langCode, string desc, string format, int samplerate, int bitrate)
+ {
+ AudioTrack newTrack = new AudioTrack
+ {
+ TrackNumber = track,
+ Language = lang,
+ LanguageCode = langCode,
+ Description = desc,
+ Format = format,
+ SampleRate = samplerate,
+ Bitrate = bitrate
+ };
+
+ return newTrack;
+
+ }
+
+ /// <summary>
+ /// Parse the CLI input to an Audio Track object
+ /// </summary>
+ /// <param name="output">
+ /// The output.
+ /// </param>
+ /// <returns>
+ /// An Audio Track obkect
+ /// </returns>
+ public static AudioTrack Parse(StringReader output)
+ {
+ string audioTrack = output.ReadLine();
+ Match m = Regex.Match(audioTrack, @"^ \+ ([0-9]*), ([A-Za-z0-9,\s]*) \((.*)\) \((.*)\)");
+ Match track = Regex.Match(audioTrack, @"^ \+ ([0-9]*), ([A-Za-z0-9,\s]*) \((.*)\)"); // ID and Language
+ Match iso639_2 = Regex.Match(audioTrack, @"iso639-2: ([a-zA-Z]*)\)");
+ Match samplerate = Regex.Match(audioTrack, @"([0-9]*)Hz");
+ Match bitrate = Regex.Match(audioTrack, @"([0-9]*)bps");
+
+ string subformat = m.Groups[4].Value.Trim().Contains("iso639") ? null : m.Groups[4].Value;
+ string samplerateVal = samplerate.Success ? samplerate.Groups[0].Value.Replace("Hz", string.Empty).Trim() : "0";
+ string bitrateVal = bitrate.Success ? bitrate.Groups[0].Value.Replace("bps", string.Empty).Trim() : "0";
+
+ if (track.Success)
+ {
+ var thisTrack = new AudioTrack
+ {
+ TrackNumber = int.Parse(track.Groups[1].Value.Trim()),
+ Language = track.Groups[2].Value,
+ Format = m.Groups[3].Value,
+ Description = subformat,
+ SampleRate = int.Parse(samplerateVal),
+ Bitrate = int.Parse(bitrateVal),
+ LanguageCode = iso639_2.Value.Replace("iso639-2: ", string.Empty).Replace(")", string.Empty)
+ };
+ return thisTrack;
+ }
+
+ return null;
+ }
+
+ /// <summary>
+ /// Pase a list of audio tracks
+ /// </summary>
+ /// <param name="output">
+ /// The output.
+ /// </param>
+ /// <returns>
+ /// An array of audio tracks
+ /// </returns>
+ public static AudioTrack[] ParseList(StringReader output)
+ {
+ var tracks = new List<AudioTrack>();
+ while (true)
+ {
+ AudioTrack thisTrack = Parse(output);
+ if (thisTrack != null)
+ tracks.Add(thisTrack);
+ else
+ break;
+ }
+ return tracks.ToArray();
+ }
+
+ /// <summary>
+ /// Override of the ToString method to make this object easier to use in the UI
+ /// </summary>
+ /// <returns>A string formatted as: {track #} {language} ({format}) ({sub-format})</returns>
+ public override string ToString()
+ {
+ if (Description == null)
+ return string.Format("{0} {1} ({2})", TrackNumber, Language, Format);
+
+ return string.Format("{0} {1} ({2}) ({3})", TrackNumber, Language, Format, Description);
+ }
+ }
+} \ No newline at end of file
diff --git a/win/C#/HandBrake.ApplicationServices/Parsing/Chapter.cs b/win/C#/HandBrake.ApplicationServices/Parsing/Chapter.cs
new file mode 100644
index 000000000..b39f2baa4
--- /dev/null
+++ b/win/C#/HandBrake.ApplicationServices/Parsing/Chapter.cs
@@ -0,0 +1,110 @@
+/* Chapter.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+namespace HandBrake.ApplicationServices.Parsing
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text.RegularExpressions;
+
+ /// <summary>
+ /// An object representing a Chapter aosciated with a Title, in a DVD
+ /// </summary>
+ public class Chapter
+ {
+ /// <summary>
+ /// Gets The number of this Chapter, in regards to it's parent Title
+ /// </summary>
+ public int ChapterNumber { get; private set; }
+
+ /// <summary>
+ /// Gets The length in time this Chapter spans
+ /// </summary>
+ public TimeSpan Duration { get; private set; }
+
+ /// <summary>
+ /// Create a chapter Object
+ /// </summary>
+ /// <param name="number">
+ /// The number.
+ /// </param>
+ /// <param name="duration">
+ /// The duration.
+ /// </param>
+ /// <returns>
+ /// A new Chapter Object
+ /// </returns>
+ public static Chapter CreateChapterOjbect(int number, TimeSpan duration)
+ {
+ return new Chapter { ChapterNumber = number, Duration = duration };
+ }
+
+ /// <summary>
+ /// Parse a CLI string to a Chapter object
+ /// </summary>
+ /// <param name="output">
+ /// The output.
+ /// </param>
+ /// <returns>
+ /// A chapter Object
+ /// </returns>
+ public static Chapter Parse(StringReader output)
+ {
+ Match m = Regex.Match(
+ output.ReadLine(),
+ @"^ \+ ([0-9]*): cells ([0-9]*)->([0-9]*), ([0-9]*) blocks, duration ([0-9]{2}:[0-9]{2}:[0-9]{2})");
+ if (m.Success)
+ {
+ var thisChapter = new Chapter
+ {
+ ChapterNumber = int.Parse(m.Groups[1].Value.Trim()),
+ Duration = TimeSpan.Parse(m.Groups[5].Value)
+ };
+ return thisChapter;
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Prase a list of strings / chatpers
+ /// </summary>
+ /// <param name="output">
+ /// The output.
+ /// </param>
+ /// <returns>
+ /// An array of chapter objects
+ /// </returns>
+ public static Chapter[] ParseList(StringReader output)
+ {
+ var chapters = new List<Chapter>();
+
+ // this is to read the " + chapters:" line from the buffer
+ // so we can start reading the chapters themselvs
+ output.ReadLine();
+
+ while (true)
+ {
+ // Start of the chapter list for this Title
+ Chapter thisChapter = Parse(output);
+
+ if (thisChapter != null)
+ chapters.Add(thisChapter);
+ else
+ break;
+ }
+ return chapters.ToArray();
+ }
+
+ /// <summary>
+ /// Override of the ToString method to make this object easier to use in the UI
+ /// </summary>
+ /// <returns>A string formatted as: {chapter #}</returns>
+ public override string ToString()
+ {
+ return ChapterNumber.ToString();
+ }
+ }
+} \ No newline at end of file
diff --git a/win/C#/HandBrake.ApplicationServices/Parsing/DVD.cs b/win/C#/HandBrake.ApplicationServices/Parsing/DVD.cs
new file mode 100644
index 000000000..c7e5a27bb
--- /dev/null
+++ b/win/C#/HandBrake.ApplicationServices/Parsing/DVD.cs
@@ -0,0 +1,53 @@
+/* DVD.cs $ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+namespace HandBrake.ApplicationServices.Parsing
+{
+ using System.Collections.Generic;
+ using System.IO;
+
+ /// <summary>
+ /// An object representing a scanned DVD
+ /// </summary>
+ public class DVD
+ {
+ /// <summary>
+ /// Initializes a new instance of the <see cref="DVD"/> class.
+ /// Default constructor for this object
+ /// </summary>
+ public DVD()
+ {
+ Titles = new List<Title>();
+ }
+
+ /// <summary>
+ /// Gets Titles. A list of titles from the source
+ /// </summary>
+ public List<Title> Titles { get; private set; }
+
+ /// <summary>
+ /// Parse the StreamReader output into a List of Titles
+ /// </summary>
+ /// <param name="output">
+ /// The output.
+ /// </param>
+ /// <returns>
+ /// A DVD object which contains a list of title inforamtion
+ /// </returns>
+ public static DVD Parse(StreamReader output)
+ {
+ var thisDVD = new DVD();
+
+ while (!output.EndOfStream)
+ {
+ if ((char) output.Peek() == '+')
+ thisDVD.Titles.AddRange(Title.ParseList(output.ReadToEnd()));
+ else
+ output.ReadLine();
+ }
+
+ return thisDVD;
+ }
+ }
+} \ No newline at end of file
diff --git a/win/C#/HandBrake.ApplicationServices/Parsing/Parser.cs b/win/C#/HandBrake.ApplicationServices/Parsing/Parser.cs
new file mode 100644
index 000000000..1e6329db1
--- /dev/null
+++ b/win/C#/HandBrake.ApplicationServices/Parsing/Parser.cs
@@ -0,0 +1,159 @@
+/* Parser.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+namespace HandBrake.ApplicationServices.Parsing
+{
+ using System;
+ using System.Globalization;
+ using System.IO;
+ using System.Text;
+ using System.Text.RegularExpressions;
+
+ /// <summary>
+ /// A delegate to handle custom events regarding data being parsed from the buffer
+ /// </summary>
+ /// <param name="sender">The object which raised this delegate</param>
+ /// <param name="data">The data parsed from the stream</param>
+ public delegate void DataReadEventHandler(object sender, string data);
+
+ /// <summary>
+ /// A delegate to handle events regarding progress during DVD scanning
+ /// </summary>
+ /// <param name="sender">The object who's raising the event</param>
+ /// <param name="currentTitle">The title number currently being processed</param>
+ /// <param name="titleCount">The total number of titiles to be processed</param>
+ public delegate void ScanProgressEventHandler(object sender, int currentTitle, int titleCount);
+
+ /// <summary>
+ /// A delegate to handle encode progress updates // EXPERIMENTAL
+ /// </summary>
+ /// <param name="sender">The object which raised the event</param>
+ /// <param name="currentTask">The current task being processed from the queue</param>
+ /// <param name="taskCount">The total number of tasks in queue</param>
+ /// <param name="percentComplete">The percentage this task is complete</param>
+ /// <param name="currentFps">The current encoding fps</param>
+ /// <param name="averageFps">The average encoding fps for this task</param>
+ /// <param name="timeRemaining">The estimated time remaining for this task to complete</param>
+ public delegate void EncodeProgressEventHandler(object sender, int currentTask, int taskCount, float percentComplete, float currentFps, float averageFps, TimeSpan timeRemaining);
+
+ /// <summary>
+ /// A simple wrapper around a StreamReader to keep track of the entire output from a cli process
+ /// </summary>
+ public class Parser : StreamReader
+ {
+ /// <summary>
+ /// The Buffer StringBuilder
+ /// </summary>
+ private readonly StringBuilder buffer = new StringBuilder(string.Empty);
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Parser"/> class.
+ /// Default constructor for this object
+ /// </summary>
+ /// <param name="baseStream">
+ /// The stream to parse from
+ /// </param>
+ public Parser(Stream baseStream) : base(baseStream)
+ {
+ }
+
+ /// <summary>
+ /// Raised upon a new line being read from stdout/stderr
+ /// </summary>
+ public event DataReadEventHandler OnReadLine;
+
+ /// <summary>
+ /// Raised upon the entire stdout/stderr stream being read in a single call
+ /// </summary>
+ public event DataReadEventHandler OnReadToEnd;
+
+ /// <summary>
+ /// Raised upon the catching of a "Scanning title # of #..." in the stream
+ /// </summary>
+ public event ScanProgressEventHandler OnScanProgress;
+
+ /// <summary>
+ /// Raised upon the catching of a "Scanning title # of #..." in the stream
+ /// </summary>
+ public event EncodeProgressEventHandler OnEncodeProgress;
+
+ /// <summary>
+ /// Gets the buffer of data that came from the CLI standard input/error
+ /// </summary>
+ public StringBuilder Buffer
+ {
+ get { return buffer; }
+ }
+
+ /// <summary>
+ /// Read a line from standard in/err
+ /// </summary>
+ /// <returns>
+ /// The read line
+ /// </returns>
+ public override string ReadLine()
+ {
+ string tmp = base.ReadLine();
+
+ buffer.Append(tmp + Environment.NewLine);
+
+ Match m = null;
+ if (tmp.Contains("Scanning title"))
+ m = Regex.Match(tmp, "^Scanning title ([0-9]*) of ([0-9]*)");
+
+ if (OnReadLine != null)
+ OnReadLine(this, tmp);
+
+ if (m != null)
+ if (m.Success && OnScanProgress != null)
+ OnScanProgress(this, int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value));
+
+ return tmp;
+ }
+
+ /// <summary>
+ /// Read to the end of the input stream
+ /// </summary>
+ /// <returns>
+ /// A string of the input data
+ /// </returns>
+ public override string ReadToEnd()
+ {
+ string tmp = base.ReadToEnd();
+
+ buffer.Append(tmp + Environment.NewLine);
+
+ if (OnReadToEnd != null)
+ OnReadToEnd(this, tmp);
+
+ return tmp;
+ }
+
+ /// <summary>
+ /// Pase the CLI status output (from standard output)
+ /// </summary>
+ public void ReadEncodeStatus()
+ {
+ CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");
+ string tmp = base.ReadLine();
+
+ Match m = Regex.Match(tmp, @"^Encoding: task ([0-9]*) of ([0-9]*), ([0-9]*\.[0-9]*) %( \(([0-9]*\.[0-9]*) fps, avg ([0-9]*\.[0-9]*) fps, ETA ([0-9]{2})h([0-9]{2})m([0-9]{2})s\))?");
+ if (m.Success && OnEncodeProgress != null)
+ {
+ int currentTask = int.Parse(m.Groups[1].Value);
+ int totalTasks = int.Parse(m.Groups[2].Value);
+ float percent = float.Parse(m.Groups[3].Value, culture);
+ float currentFps = m.Groups[5].Value == string.Empty ? 0.0F : float.Parse(m.Groups[5].Value, culture);
+ float avgFps = m.Groups[6].Value == string.Empty ? 0.0F : float.Parse(m.Groups[6].Value, culture);
+ TimeSpan remaining = TimeSpan.Zero;
+ if (m.Groups[7].Value != string.Empty)
+ {
+ remaining = TimeSpan.Parse(m.Groups[7].Value + ":" + m.Groups[8].Value + ":" + m.Groups[9].Value);
+ }
+ OnEncodeProgress(this, currentTask, totalTasks, percent, currentFps, avgFps, remaining);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/win/C#/HandBrake.ApplicationServices/Parsing/Subtitle.cs b/win/C#/HandBrake.ApplicationServices/Parsing/Subtitle.cs
new file mode 100644
index 000000000..31ec350fa
--- /dev/null
+++ b/win/C#/HandBrake.ApplicationServices/Parsing/Subtitle.cs
@@ -0,0 +1,134 @@
+/* Subtitle.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+namespace HandBrake.ApplicationServices.Parsing
+{
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Text.RegularExpressions;
+
+ using HandBrake.ApplicationServices.Model;
+
+ /// <summary>
+ /// An object that represents a subtitle associated with a Title, in a DVD
+ /// </summary>
+ public class Subtitle
+ {
+ /// <summary>
+ /// Gets the track number of this Subtitle
+ /// </summary>
+ public int TrackNumber { get; private set; }
+
+ /// <summary>
+ /// Gets the The language (if detected) of this Subtitle
+ /// </summary>
+ public string Language { get; private set; }
+
+ /// <summary>
+ /// Gets the Langauage Code
+ /// </summary>
+ public string LanguageCode { get; private set; }
+
+ /// <summary>
+ /// Gets the Subtitle Type
+ /// </summary>
+ public SubtitleType SubtitleType { get; private set; }
+
+ /// <summary>
+ /// Gets Subtitle Type
+ /// </summary>
+ public string TypeString
+ {
+ get
+ {
+ return this.SubtitleType == SubtitleType.Picture ? "Bitmap" : "Text";
+ }
+ }
+
+ /// <summary>
+ /// Create a new Subtitle Object
+ /// </summary>
+ /// <param name="track">
+ /// The track.
+ /// </param>
+ /// <param name="lang">
+ /// The lang.
+ /// </param>
+ /// <param name="langCode">
+ /// The lang code.
+ /// </param>
+ /// <param name="type">
+ /// The type.
+ /// </param>
+ /// <returns>
+ /// A Subtitle Object
+ /// </returns>
+ public static Subtitle CreateSubtitleObject(int track, string lang, string langCode, SubtitleType type)
+ {
+ return new Subtitle { TrackNumber = track, Language = lang, LanguageCode = langCode, SubtitleType = type };
+ }
+
+ /// <summary>
+ /// Parse the input strings related to subtitles
+ /// </summary>
+ /// <param name="output">
+ /// The output.
+ /// </param>
+ /// <returns>
+ /// A Subitle object
+ /// </returns>
+ public static Subtitle Parse(StringReader output)
+ {
+ string curLine = output.ReadLine();
+
+ Match m = Regex.Match(curLine, @"^ \+ ([0-9]*), ([A-Za-z, ]*) \((.*)\) \(([a-zA-Z]*)\)");
+ if (m.Success && !curLine.Contains("HandBrake has exited."))
+ {
+ var thisSubtitle = new Subtitle
+ {
+ TrackNumber = int.Parse(m.Groups[1].Value.Trim()),
+ Language = m.Groups[2].Value,
+ LanguageCode = m.Groups[3].Value,
+ SubtitleType = m.Groups[4].Value.Contains("Text") ? SubtitleType.Text : SubtitleType.Picture
+ };
+ return thisSubtitle;
+ }
+ return null;
+ }
+
+ /// <summary>
+ /// Parse a list of Subtitle tracks from an input string.
+ /// </summary>
+ /// <param name="output">
+ /// The output.
+ /// </param>
+ /// <returns>
+ /// An array of Subtitle objects
+ /// </returns>
+ public static IEnumerable<Subtitle> ParseList(StringReader output)
+ {
+ var subtitles = new List<Subtitle>();
+ while ((char) output.Peek() != '+')
+ {
+ Subtitle thisSubtitle = Parse(output);
+
+ if (thisSubtitle != null)
+ subtitles.Add(thisSubtitle);
+ else
+ break;
+ }
+ return subtitles.ToArray();
+ }
+
+ /// <summary>
+ /// Override of the ToString method to make this object easier to use in the UI
+ /// </summary>
+ /// <returns>A string formatted as: {track #} {language}</returns>
+ public override string ToString()
+ {
+ return string.Format("{0} {1} ({2})", TrackNumber, Language, TypeString);
+ }
+ }
+} \ No newline at end of file
diff --git a/win/C#/HandBrake.ApplicationServices/Parsing/Title.cs b/win/C#/HandBrake.ApplicationServices/Parsing/Title.cs
new file mode 100644
index 000000000..0aad4d5f3
--- /dev/null
+++ b/win/C#/HandBrake.ApplicationServices/Parsing/Title.cs
@@ -0,0 +1,291 @@
+/* Title.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+namespace HandBrake.ApplicationServices.Parsing
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Drawing;
+ using System.Globalization;
+ using System.IO;
+ using System.Text.RegularExpressions;
+
+ using HandBrake.ApplicationServices.Model;
+
+ /// <summary>
+ /// An object that represents a single Title of a DVD
+ /// </summary>
+ public class Title
+ {
+ /// <summary>
+ /// The Culture Info
+ /// </summary>
+ private static readonly CultureInfo Culture = new CultureInfo("en-US", false);
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Title"/> class.
+ /// </summary>
+ public Title()
+ {
+ AudioTracks = new List<AudioTrack>();
+ Chapters = new List<Chapter>();
+ Subtitles = new List<Subtitle>();
+ }
+
+ #region Properties
+
+ /// <summary>
+ /// Gets a Collection of chapters in this Title
+ /// </summary>
+ public List<Chapter> Chapters { get; private set; }
+
+ /// <summary>
+ /// Gets a Collection of audio tracks associated with this Title
+ /// </summary>
+ public List<AudioTrack> AudioTracks { get; private set; }
+
+ /// <summary>
+ /// Gets aCollection of subtitles associated with this Title
+ /// </summary>
+ public List<Subtitle> Subtitles { get; private set; }
+
+ /// <summary>
+ /// Gets The track number of this Title
+ /// </summary>
+ public int TitleNumber { get; private set; }
+
+ /// <summary>
+ /// Gets the length in time of this Title
+ /// </summary>
+ public TimeSpan Duration { get; private set; }
+
+ /// <summary>
+ /// Gets the resolution (width/height) of this Title
+ /// </summary>
+ public Size Resolution { get; private set; }
+
+ /// <summary>
+ /// Gets the aspect ratio of this Title
+ /// </summary>
+ public double AspectRatio { get; private set; }
+
+ /// <summary>
+ /// Gets AngleCount.
+ /// </summary>
+ public int AngleCount { get; private set; }
+
+ /// <summary>
+ /// Gets Par Value
+ /// </summary>
+ public Size ParVal { get; private set; }
+
+ /// <summary>
+ /// Gets the automatically detected crop region for this Title.
+ /// This is an int array with 4 items in it as so:
+ /// 0: T
+ /// 1: B
+ /// 2: L
+ /// 3: R
+ /// </summary>
+ public Cropping AutoCropDimensions { get; private set; }
+
+ /// <summary>
+ /// Gets the FPS of the source.
+ /// </summary>
+ public double Fps { get; private set; }
+
+ /// <summary>
+ /// Gets a value indicating whether this is a MainTitle.
+ /// </summary>
+ public bool MainTitle { get; private set; }
+
+ /// <summary>
+ /// Gets the Source Name
+ /// </summary>
+ public string SourceName { get; private set; }
+
+ #endregion
+
+ /// <summary>
+ /// Creates a Title
+ /// </summary>
+ /// <param name="angles">
+ /// The angles.
+ /// </param>
+ /// <param name="aspectRatio">
+ /// The aspect Ratio.
+ /// </param>
+ /// <param name="audioTracks">
+ /// The audio Tracks.
+ /// </param>
+ /// <param name="crop">
+ /// The crop.
+ /// </param>
+ /// <param name="chapters">
+ /// The chapters.
+ /// </param>
+ /// <param name="duration">
+ /// The duration.
+ /// </param>
+ /// <param name="fps">
+ /// The fps.
+ /// </param>
+ /// <param name="mainTitle">
+ /// The main Title.
+ /// </param>
+ /// <param name="parVal">
+ /// The par Val.
+ /// </param>
+ /// <param name="resolution">
+ /// The resolution.
+ /// </param>
+ /// <param name="sourceName">
+ /// The source Name.
+ /// </param>
+ /// <param name="subtitles">
+ /// The subtitles.
+ /// </param>
+ /// <param name="titleNumber">
+ /// The title Number.
+ /// </param>
+ /// <returns>
+ /// A Title Object
+ /// </returns>
+ public static Title CreateTitle(int angles, double aspectRatio, List<AudioTrack> audioTracks, Cropping crop, List<Chapter> chapters,
+ TimeSpan duration, float fps, bool mainTitle, Size parVal, Size resolution, string sourceName, List<Subtitle> subtitles,
+ int titleNumber)
+ {
+ Title title = new Title
+ {
+ AngleCount = angles,
+ AspectRatio = aspectRatio,
+ AudioTracks = audioTracks,
+ AutoCropDimensions = crop,
+ Chapters = chapters,
+ Duration = duration,
+ Fps = fps,
+ MainTitle = mainTitle,
+ ParVal = parVal,
+ Resolution = resolution,
+ SourceName = sourceName,
+ Subtitles = subtitles,
+ TitleNumber = titleNumber
+ };
+
+ return title;
+ }
+
+ /// <summary>
+ /// Parse the Title Information
+ /// </summary>
+ /// <param name="output">A stingreader of output data</param>
+ /// <returns>A Title</returns>
+ public static Title Parse(StringReader output)
+ {
+ var thisTitle = new Title();
+
+ Match m = Regex.Match(output.ReadLine(), @"^\+ title ([0-9]*):");
+ // Match track number for this title
+ if (m.Success)
+ thisTitle.TitleNumber = int.Parse(m.Groups[1].Value.Trim());
+
+ // If we are scanning a groupd of files, we'll want to get the source name.
+ string path = output.ReadLine();
+
+ m = Regex.Match(path, @" \+ Main Feature");
+ if (m.Success)
+ {
+ thisTitle.MainTitle = true;
+ path = output.ReadLine();
+ }
+
+ m = Regex.Match(path, @"^ \+ stream:");
+ if (m.Success)
+ thisTitle.SourceName = path.Replace("+ stream:", string.Empty).Trim();
+
+ if (!Properties.Settings.Default.disableDvdNav)
+ {
+ // Get the Angles for the title.
+ m = Regex.Match(output.ReadLine(), @" \+ angle\(s\) ([0-9])");
+ if (m.Success)
+ {
+ string angleList = m.Value.Replace("+ angle(s) ", string.Empty).Trim();
+ int angleCount;
+ int.TryParse(angleList, out angleCount);
+
+ thisTitle.AngleCount = angleCount;
+ }
+ }
+
+ // Get duration for this title
+ m = Regex.Match(output.ReadLine(), @"^ \+ duration: ([0-9]{2}:[0-9]{2}:[0-9]{2})");
+ if (m.Success)
+ thisTitle.Duration = TimeSpan.Parse(m.Groups[1].Value);
+
+ // Get resolution, aspect ratio and FPS for this title
+ m = Regex.Match(output.ReadLine(), @"^ \+ size: ([0-9]*)x([0-9]*), pixel aspect: ([0-9]*)/([0-9]*), display aspect: ([0-9]*\.[0-9]*), ([0-9]*\.[0-9]*) fps");
+ if (m.Success)
+ {
+ thisTitle.Resolution = new Size(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value));
+ thisTitle.ParVal = new Size(int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value));
+ thisTitle.AspectRatio = float.Parse(m.Groups[5].Value, Culture);
+ thisTitle.Fps = float.Parse(m.Groups[6].Value, Culture);
+ }
+
+ // Get autocrop region for this title
+ m = Regex.Match(output.ReadLine(), @"^ \+ autocrop: ([0-9]*)/([0-9]*)/([0-9]*)/([0-9]*)");
+ if (m.Success)
+ {
+ thisTitle.AutoCropDimensions = new Cropping
+ {
+ Top = int.Parse(m.Groups[1].Value),
+ Bottom = int.Parse(m.Groups[2].Value),
+ Left = int.Parse(m.Groups[3].Value),
+ Right = int.Parse(m.Groups[4].Value)
+ };
+ }
+
+ thisTitle.Chapters.AddRange(Chapter.ParseList(output));
+
+ thisTitle.AudioTracks.AddRange(AudioTrack.ParseList(output));
+
+ thisTitle.Subtitles.AddRange(Subtitle.ParseList(output));
+
+ return thisTitle;
+ }
+
+ /// <summary>
+ /// Return a list of parsed titles
+ /// </summary>
+ /// <param name="output">The Output</param>
+ /// <returns>A List of titles</returns>
+ public static Title[] ParseList(string output)
+ {
+ var titles = new List<Title>();
+ var sr = new StringReader(output);
+
+ while (sr.Peek() == '+' || sr.Peek() == ' ')
+ {
+ // If the the character is a space, then chances are the line
+ if (sr.Peek() == ' ') // If the character is a space, then chances are it's the combing detected line.
+ sr.ReadLine(); // Skip over it
+ else
+ titles.Add(Parse(sr));
+ }
+
+ return titles.ToArray();
+ }
+
+ /// <summary>
+ /// Override of the ToString method to provide an easy way to use this object in the UI
+ /// </summary>
+ /// <returns>A string representing this track in the format: {title #} (00:00:00)</returns>
+ public override string ToString()
+ {
+ return string.Format("{0} ({1:00}:{2:00}:{3:00})", TitleNumber, Duration.Hours, Duration.Minutes, Duration.Seconds);
+ }
+
+ }
+} \ No newline at end of file