2 This file is part of the HandBrake source code.
\r
3 Homepage: <http://handbrake.fr>.
\r
4 It may be used under the terms of the GNU General Public License. */
\r
6 namespace HandBrake.ApplicationServices.Parsing
\r
9 using System.Collections.Generic;
\r
10 using System.Drawing;
\r
11 using System.Globalization;
\r
13 using System.Text.RegularExpressions;
\r
15 using HandBrake.ApplicationServices.Model;
\r
18 /// An object that represents a single Title of a DVD
\r
23 /// The Culture Info
\r
25 private static readonly CultureInfo Culture = new CultureInfo("en-US", false);
\r
28 /// Initializes a new instance of the <see cref="Title"/> class.
\r
32 AudioTracks = new List<AudioTrack>();
\r
33 Chapters = new List<Chapter>();
\r
34 Subtitles = new List<Subtitle>();
\r
40 /// Gets or sets a Collection of chapters in this Title
\r
42 public List<Chapter> Chapters { get; set; }
\r
45 /// Gets or sets a Collection of audio tracks associated with this Title
\r
47 public List<AudioTrack> AudioTracks { get; set; }
\r
50 /// Gets or sets a Collection of subtitles associated with this Title
\r
52 public List<Subtitle> Subtitles { get; set; }
\r
55 /// Gets or sets The track number of this Title
\r
57 public int TitleNumber { get; set; }
\r
60 /// Gets or sets the length in time of this Title
\r
62 public TimeSpan Duration { get; set; }
\r
65 /// Gets or sets the resolution (width/height) of this Title
\r
67 public Size Resolution { get; set; }
\r
70 /// Gets or sets the aspect ratio of this Title
\r
72 public double AspectRatio { get; set; }
\r
75 /// Gets or sets AngleCount.
\r
77 public int AngleCount { get; set; }
\r
80 /// Gets or sets Par Value
\r
82 public Size ParVal { get; set; }
\r
85 /// Gets or sets the automatically detected crop region for this Title.
\r
86 /// This is an int array with 4 items in it as so:
\r
92 public Cropping AutoCropDimensions { get; set; }
\r
95 /// Gets or sets the FPS of the source.
\r
97 public double Fps { get; set; }
\r
100 /// Gets or sets a value indicating whether this is a MainTitle.
\r
102 public bool MainTitle { get; set; }
\r
105 /// Gets or sets the Source Name
\r
107 public string SourceName { get; set; }
\r
112 /// Parse the Title Information
\r
114 /// <param name="output">A stingreader of output data</param>
\r
115 /// <returns>A Title</returns>
\r
116 public static Title Parse(StringReader output)
\r
118 var thisTitle = new Title();
\r
119 string nextLine = output.ReadLine();
\r
121 // Get the Title Number
\r
122 Match m = Regex.Match(nextLine, @"^\+ title ([0-9]*):");
\r
124 thisTitle.TitleNumber = int.Parse(m.Groups[1].Value.Trim());
\r
125 nextLine = output.ReadLine();
\r
127 // Detect if this is the main feature
\r
128 m = Regex.Match(nextLine, @" \+ Main Feature");
\r
131 thisTitle.MainTitle = true;
\r
132 nextLine = output.ReadLine();
\r
135 // Get the stream name for file import
\r
136 m = Regex.Match(nextLine, @"^ \+ stream:");
\r
139 thisTitle.SourceName = nextLine.Replace("+ stream:", string.Empty).Trim();
\r
140 nextLine = output.ReadLine();
\r
143 // Jump over the VTS and blocks line
\r
144 m = Regex.Match(nextLine, @"^ \+ vts:");
\r
145 if (nextLine.Contains("blocks") || nextLine.Contains("+ vts "))
\r
147 nextLine = output.ReadLine();
\r
150 // Multi-Angle Support if LibDvdNav is enabled
\r
151 if (!Init.DisableDvdNav)
\r
153 m = Regex.Match(nextLine, @" \+ angle\(s\) ([0-9])");
\r
156 string angleList = m.Value.Replace("+ angle(s) ", string.Empty).Trim();
\r
158 int.TryParse(angleList, out angleCount);
\r
160 thisTitle.AngleCount = angleCount;
\r
161 nextLine = output.ReadLine();
\r
165 // Get duration for this title
\r
166 m = Regex.Match(nextLine, @"^ \+ duration: ([0-9]{2}:[0-9]{2}:[0-9]{2})");
\r
168 thisTitle.Duration = TimeSpan.Parse(m.Groups[1].Value);
\r
170 // Get resolution, aspect ratio and FPS for this title
\r
171 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");
\r
174 thisTitle.Resolution = new Size(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value));
\r
175 thisTitle.ParVal = new Size(int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value));
\r
176 thisTitle.AspectRatio = float.Parse(m.Groups[5].Value, Culture);
\r
177 thisTitle.Fps = float.Parse(m.Groups[6].Value, Culture);
\r
180 // Get autocrop region for this title
\r
181 m = Regex.Match(output.ReadLine(), @"^ \+ autocrop: ([0-9]*)/([0-9]*)/([0-9]*)/([0-9]*)");
\r
184 thisTitle.AutoCropDimensions = new Cropping
\r
186 Top = int.Parse(m.Groups[1].Value),
\r
187 Bottom = int.Parse(m.Groups[2].Value),
\r
188 Left = int.Parse(m.Groups[3].Value),
\r
189 Right = int.Parse(m.Groups[4].Value)
\r
193 thisTitle.Chapters.AddRange(Chapter.ParseList(output));
\r
195 thisTitle.AudioTracks.AddRange(AudioTrack.ParseList(output));
\r
197 thisTitle.Subtitles.AddRange(Subtitle.ParseList(output));
\r
203 /// Return a list of parsed titles
\r
205 /// <param name="output">The Output</param>
\r
206 /// <returns>A List of titles</returns>
\r
207 public static Title[] ParseList(string output)
\r
209 var titles = new List<Title>();
\r
210 var sr = new StringReader(output);
\r
212 while (sr.Peek() == '+' || sr.Peek() == ' ')
\r
214 // If the the character is a space, then chances are the line
\r
215 if (sr.Peek() == ' ') // If the character is a space, then chances are it's the combing detected line.
\r
216 sr.ReadLine(); // Skip over it
\r
218 titles.Add(Parse(sr));
\r
221 return titles.ToArray();
\r
225 /// Override of the ToString method to provide an easy way to use this object in the UI
\r
227 /// <returns>A string representing this track in the format: {title #} (00:00:00)</returns>
\r
228 public override string ToString()
\r
230 return string.Format("{0} ({1:00}:{2:00}:{3:00})", TitleNumber, Duration.Hours, Duration.Minutes, Duration.Seconds);
\r