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.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.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 a Collection of chapters in this Title
\r
42 public List<Chapter> Chapters { get; private set; }
\r
45 /// Gets a Collection of audio tracks associated with this Title
\r
47 public List<AudioTrack> AudioTracks { get; private set; }
\r
50 /// Gets aCollection of subtitles associated with this Title
\r
52 public List<Subtitle> Subtitles { get; private set; }
\r
55 /// Gets The track number of this Title
\r
57 public int TitleNumber { get; private set; }
\r
60 /// Gets the length in time of this Title
\r
62 public TimeSpan Duration { get; private set; }
\r
65 /// Gets the resolution (width/height) of this Title
\r
67 public Size Resolution { get; private set; }
\r
70 /// Gets the aspect ratio of this Title
\r
72 public double AspectRatio { get; private set; }
\r
75 /// Gets AngleCount.
\r
77 public int AngleCount { get; private set; }
\r
82 public Size ParVal { get; private set; }
\r
85 /// Gets 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; private set; }
\r
95 /// Gets the FPS of the source.
\r
97 public double Fps { get; private set; }
\r
100 /// Gets a value indicating whether this is a MainTitle.
\r
102 public bool MainTitle { get; private set; }
\r
105 /// Gets the Source Name
\r
107 public string SourceName { get; private set; }
\r
112 /// Creates a Title
\r
114 /// <param name="angles">
\r
117 /// <param name="aspectRatio">
\r
118 /// The aspect Ratio.
\r
120 /// <param name="audioTracks">
\r
121 /// The audio Tracks.
\r
123 /// <param name="crop">
\r
126 /// <param name="chapters">
\r
129 /// <param name="duration">
\r
132 /// <param name="fps">
\r
135 /// <param name="mainTitle">
\r
136 /// The main Title.
\r
138 /// <param name="parVal">
\r
141 /// <param name="resolution">
\r
142 /// The resolution.
\r
144 /// <param name="sourceName">
\r
145 /// The source Name.
\r
147 /// <param name="subtitles">
\r
150 /// <param name="titleNumber">
\r
151 /// The title Number.
\r
156 public static Title CreateTitle(int angles, double aspectRatio, List<AudioTrack> audioTracks, Cropping crop, List<Chapter> chapters,
\r
157 TimeSpan duration, float fps, bool mainTitle, Size parVal, Size resolution, string sourceName, List<Subtitle> subtitles,
\r
160 Title title = new Title
\r
162 AngleCount = angles,
\r
163 AspectRatio = aspectRatio,
\r
164 AudioTracks = audioTracks,
\r
165 AutoCropDimensions = crop,
\r
166 Chapters = chapters,
\r
167 Duration = duration,
\r
169 MainTitle = mainTitle,
\r
171 Resolution = resolution,
\r
172 SourceName = sourceName,
\r
173 Subtitles = subtitles,
\r
174 TitleNumber = titleNumber
\r
181 /// Parse the Title Information
\r
183 /// <param name="output">A stingreader of output data</param>
\r
184 /// <returns>A Title</returns>
\r
185 public static Title Parse(StringReader output)
\r
187 var thisTitle = new Title();
\r
189 Match m = Regex.Match(output.ReadLine(), @"^\+ title ([0-9]*):");
\r
190 // Match track number for this title
\r
192 thisTitle.TitleNumber = int.Parse(m.Groups[1].Value.Trim());
\r
194 // If we are scanning a groupd of files, we'll want to get the source name.
\r
195 string path = output.ReadLine();
\r
197 m = Regex.Match(path, @" \+ Main Feature");
\r
200 thisTitle.MainTitle = true;
\r
201 path = output.ReadLine();
\r
204 m = Regex.Match(path, @"^ \+ stream:");
\r
206 thisTitle.SourceName = path.Replace("+ stream:", string.Empty).Trim();
\r
208 if (!Properties.Settings.Default.noDvdNav)
\r
210 // Get the Angles for the title.
\r
211 m = Regex.Match(output.ReadLine(), @" \+ angle\(s\) ([0-9])");
\r
214 string angleList = m.Value.Replace("+ angle(s) ", string.Empty).Trim();
\r
216 int.TryParse(angleList, out angleCount);
\r
218 thisTitle.AngleCount = angleCount;
\r
222 // Get duration for this title
\r
223 m = Regex.Match(output.ReadLine(), @"^ \+ duration: ([0-9]{2}:[0-9]{2}:[0-9]{2})");
\r
225 thisTitle.Duration = TimeSpan.Parse(m.Groups[1].Value);
\r
227 // Get resolution, aspect ratio and FPS for this title
\r
228 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
231 thisTitle.Resolution = new Size(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value));
\r
232 thisTitle.ParVal = new Size(int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value));
\r
233 thisTitle.AspectRatio = float.Parse(m.Groups[5].Value, Culture);
\r
234 thisTitle.Fps = float.Parse(m.Groups[6].Value, Culture);
\r
237 // Get autocrop region for this title
\r
238 m = Regex.Match(output.ReadLine(), @"^ \+ autocrop: ([0-9]*)/([0-9]*)/([0-9]*)/([0-9]*)");
\r
241 thisTitle.AutoCropDimensions = new Cropping
\r
243 Top = int.Parse(m.Groups[1].Value),
\r
244 Bottom = int.Parse(m.Groups[2].Value),
\r
245 Left = int.Parse(m.Groups[3].Value),
\r
246 Right = int.Parse(m.Groups[4].Value)
\r
250 thisTitle.Chapters.AddRange(Chapter.ParseList(output));
\r
252 thisTitle.AudioTracks.AddRange(AudioTrack.ParseList(output));
\r
254 thisTitle.Subtitles.AddRange(Subtitle.ParseList(output));
\r
260 /// Return a list of parsed titles
\r
262 /// <param name="output">The Output</param>
\r
263 /// <returns>A List of titles</returns>
\r
264 public static Title[] ParseList(string output)
\r
266 var titles = new List<Title>();
\r
267 var sr = new StringReader(output);
\r
269 while (sr.Peek() == '+' || sr.Peek() == ' ')
\r
271 // If the the character is a space, then chances are the line
\r
272 if (sr.Peek() == ' ') // If the character is a space, then chances are it's the combing detected line.
\r
273 sr.ReadLine(); // Skip over it
\r
275 titles.Add(Parse(sr));
\r
278 return titles.ToArray();
\r
282 /// Override of the ToString method to provide an easy way to use this object in the UI
\r
284 /// <returns>A string representing this track in the format: {title #} (00:00:00)</returns>
\r
285 public override string ToString()
\r
287 return string.Format("{0} ({1:00}:{2:00}:{3:00})", TitleNumber, Duration.Hours, Duration.Minutes, Duration.Seconds);
\r