3 This file is part of the HandBrake source code.
\r
4 Homepage: <http://handbrake.fr>.
\r
5 It may be used under the terms of the GNU General Public License. */
\r
8 using System.Collections.Generic;
\r
9 using System.Drawing;
\r
10 using System.Globalization;
\r
12 using System.Text.RegularExpressions;
\r
14 namespace Handbrake.Parsing
\r
17 /// An object that represents a single Title of a DVD
\r
21 private static readonly CultureInfo Culture = new CultureInfo("en-US", false);
\r
22 private readonly List<AudioTrack> m_audioTracks;
\r
23 private readonly List<Chapter> m_chapters;
\r
24 private readonly List<Subtitle> m_subtitles;
\r
25 private List<String> m_angles = new List<string>();
\r
26 private float m_aspectRatio;
\r
27 private float m_fps;
\r
28 private int[] m_autoCrop;
\r
29 private string source;
\r
30 private TimeSpan m_duration;
\r
31 private Size m_resolution;
\r
32 private int m_titleNumber;
\r
33 private Size m_parVal;
\r
36 /// The constructor for this object
\r
40 m_audioTracks = new List<AudioTrack>();
\r
41 m_chapters = new List<Chapter>();
\r
42 m_subtitles = new List<Subtitle>();
\r
46 /// Collection of chapters in this Title
\r
48 public List<Chapter> Chapters
\r
50 get { return m_chapters; }
\r
54 /// Collection of audio tracks associated with this Title
\r
56 public List<AudioTrack> AudioTracks
\r
58 get { return m_audioTracks; }
\r
62 /// Collection of subtitles associated with this Title
\r
64 public List<Subtitle> Subtitles
\r
66 get { return m_subtitles; }
\r
70 /// The track number of this Title
\r
72 public int TitleNumber
\r
74 get { return m_titleNumber; }
\r
80 public string SourceName
\r
82 get { return source; }
\r
86 /// The length in time of this Title
\r
88 public TimeSpan Duration
\r
90 get { return m_duration; }
\r
94 /// The resolution (width/height) of this Title
\r
96 public Size Resolution
\r
98 get { return m_resolution; }
\r
102 /// The aspect ratio of this Title
\r
104 public float AspectRatio
\r
106 get { return m_aspectRatio; }
\r
114 get { return m_parVal; }
\r
118 /// The automatically detected crop region for this Title.
\r
119 /// This is an int array with 4 items in it as so:
\r
125 public int[] AutoCropDimensions
\r
127 get { return m_autoCrop; }
\r
131 /// Collection of Angles in this Title
\r
133 public List<string> Angles
\r
135 get { return m_angles; }
\r
139 /// Collection of Angles in this Title
\r
143 get { return m_fps; }
\r
147 /// Override of the ToString method to provide an easy way to use this object in the UI
\r
149 /// <returns>A string representing this track in the format: {title #} (00:00:00)</returns>
\r
150 public override string ToString()
\r
152 return string.Format("{0} ({1:00}:{2:00}:{3:00})", m_titleNumber, m_duration.Hours,
\r
153 m_duration.Minutes, m_duration.Seconds);
\r
157 /// Parse the Title Information
\r
159 /// <param name="output"></param>
\r
160 /// <returns></returns>
\r
161 public static Title Parse(StringReader output)
\r
163 var thisTitle = new Title();
\r
165 Match m = Regex.Match(output.ReadLine(), @"^\+ title ([0-9]*):");
\r
166 // Match track number for this title
\r
168 thisTitle.m_titleNumber = int.Parse(m.Groups[1].Value.Trim());
\r
170 // If we are scanning a groupd of files, we'll want to get the source name.
\r
171 string path = output.ReadLine();
\r
172 m = Regex.Match(path, @"^ \+ stream:");
\r
174 thisTitle.source = path.Replace("+ stream:", "").Trim();
\r
176 if (!Properties.Settings.Default.noDvdNav)
\r
178 // Get the Angles for the title.
\r
179 m = Regex.Match(output.ReadLine(), @" \+ angle\(s\) ([0-9])");
\r
182 String angleList = m.Value.Replace("+ angle(s) ", "").Trim();
\r
184 int.TryParse(angleList, out angleCount);
\r
186 for (int i = 1; i <= angleCount; i++)
\r
187 thisTitle.m_angles.Add(i.ToString());
\r
191 // Get duration for this title
\r
192 m = Regex.Match(output.ReadLine(), @"^ \+ duration: ([0-9]{2}:[0-9]{2}:[0-9]{2})");
\r
194 thisTitle.m_duration = TimeSpan.Parse(m.Groups[1].Value);
\r
196 // Get resolution, aspect ratio and FPS for this title
\r
197 m = Regex.Match(output.ReadLine(),
\r
198 @"^ \+ size: ([0-9]*)x([0-9]*), pixel aspect: ([0-9]*)/([0-9]*), display aspect: ([0-9]*\.[0-9]*), ([0-9]*\.[0-9]*) fps");
\r
199 //size: 720x576, pixel aspect: 16/15, display aspect: 1.33, 25.000 fps
\r
203 thisTitle.m_resolution = new Size(int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value));
\r
204 thisTitle.m_parVal = new Size(int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value));
\r
205 thisTitle.m_aspectRatio = float.Parse(m.Groups[5].Value, Culture);
\r
206 thisTitle.m_fps = float.Parse(m.Groups[6].Value, Culture);
\r
209 // Get autocrop region for this title
\r
210 m = Regex.Match(output.ReadLine(), @"^ \+ autocrop: ([0-9]*)/([0-9]*)/([0-9]*)/([0-9]*)");
\r
212 thisTitle.m_autoCrop = new int[]
\r
214 int.Parse(m.Groups[1].Value), int.Parse(m.Groups[2].Value),
\r
215 int.Parse(m.Groups[3].Value), int.Parse(m.Groups[4].Value)
\r
218 thisTitle.m_chapters.AddRange(Chapter.ParseList(output));
\r
220 thisTitle.m_audioTracks.AddRange(AudioTrack.ParseList(output));
\r
222 thisTitle.m_subtitles.AddRange(Subtitle.ParseList(output));
\r
228 /// Return a list of parsed titles
\r
230 /// <param name="output"></param>
\r
231 /// <returns></returns>
\r
232 public static Title[] ParseList(string output)
\r
234 var titles = new List<Title>();
\r
235 var sr = new StringReader(output);
\r
237 while (sr.Peek() == '+' || sr.Peek() == ' ')
\r
239 // If the the character is a space, then chances are the line
\r
240 if (sr.Peek() == ' ') // If the character is a space, then chances are it's the combing detected line.
\r
241 sr.ReadLine(); // Skip over it
\r
243 titles.Add(Parse(sr));
\r
246 return titles.ToArray();
\r