/* Title.cs $ This file is part of the HandBrake source code. Homepage: . It may be used under the terms of the GNU General Public License. */ namespace Handbrake.Parsing { using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; using System.Text.RegularExpressions; /// /// An object that represents a single Title of a DVD /// public class Title { private static readonly CultureInfo Culture = new CultureInfo("en-US", false); private readonly List m_audioTracks; private readonly List m_chapters; private readonly List m_subtitles; private List m_angles = new List(); private float m_aspectRatio; private float m_fps; private int[] m_autoCrop; private string source; private TimeSpan m_duration; private Size m_resolution; private int m_titleNumber; private Size m_parVal; /// /// Initializes a new instance of the class. /// The constructor for this object /// public Title() { m_audioTracks = new List(); m_chapters = new List(); m_subtitles = new List(); } /// /// Collection of chapters in this Title /// public List Chapters { get { return m_chapters; } } /// /// Collection of audio tracks associated with this Title /// public List AudioTracks { get { return m_audioTracks; } } /// /// Collection of subtitles associated with this Title /// public List Subtitles { get { return m_subtitles; } } /// /// The track number of this Title /// public int TitleNumber { get { return m_titleNumber; } } /// /// Source Name /// public string SourceName { get { return source; } } /// /// The length in time of this Title /// public TimeSpan Duration { get { return m_duration; } } /// /// The resolution (width/height) of this Title /// public Size Resolution { get { return m_resolution; } } /// /// The aspect ratio of this Title /// public float AspectRatio { get { return m_aspectRatio; } } /// /// Par Value /// public Size ParVal { get { return m_parVal; } } /// /// The automatically detected crop region for this Title. /// This is an int array with 4 items in it as so: /// 0: /// 1: /// 2: /// 3: /// public int[] AutoCropDimensions { get { return m_autoCrop; } } /// /// Collection of Angles in this Title /// public List Angles { get { return m_angles; } } /// /// Collection of Angles in this Title /// public float Fps { get { return m_fps; } } /// /// Override of the ToString method to provide an easy way to use this object in the UI /// /// A string representing this track in the format: {title #} (00:00:00) public override string ToString() { return string.Format("{0} ({1:00}:{2:00}:{3:00})", m_titleNumber, m_duration.Hours, m_duration.Minutes, m_duration.Seconds); } /// /// Parse the Title Information /// /// /// 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.m_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, @"^ \+ stream:"); if (m.Success) thisTitle.source = path.Replace("+ stream:", string.Empty).Trim(); if (!Properties.Settings.Default.noDvdNav) { // 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); for (int i = 1; i <= angleCount; i++) thisTitle.m_angles.Add(i.ToString()); } } // Get duration for this title m = Regex.Match(output.ReadLine(), @"^ \+ duration: ([0-9]{2}:[0-9]{2}:[0-9]{2})"); if (m.Success) thisTitle.m_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"); // size: 720x576, pixel aspect: 16/15, display aspect: 1.33, 25.000 fps if (m.Success) { thisTitle.m_resolution = new Size(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value)); thisTitle.m_parVal = new Size(int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value)); thisTitle.m_aspectRatio = float.Parse(m.Groups[5].Value, Culture); thisTitle.m_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.m_autoCrop = new[] { int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value), int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value) }; thisTitle.m_chapters.AddRange(Chapter.ParseList(output)); thisTitle.m_audioTracks.AddRange(AudioTrack.ParseList(output)); thisTitle.m_subtitles.AddRange(Subtitle.ParseList(output)); return thisTitle; } /// /// Return a list of parsed titles /// /// /// public static Title[] ParseList(string output) { var titles = new List(); 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(); } } }