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.Functions
\r
9 using System.Collections;
\r
10 using System.Globalization;
\r
11 using System.Text.RegularExpressions;
\r
12 using System.Windows.Forms;
\r
16 /// Parse a CLI Query
\r
18 public class QueryParser
\r
23 private static readonly CultureInfo Culture = new CultureInfo("en-US", false);
\r
27 #region Source Title / Chapters
\r
29 /// Gets or sets Title.
\r
31 public int Title { get; set; }
\r
34 /// Gets or sets ChapterStart.
\r
36 public int ChapterStart { get; set; }
\r
39 /// Gets or sets ChapterFinish.
\r
41 public int ChapterFinish { get; set; }
\r
44 #region Output Settings
\r
46 /// Gets or sets the file Format. e.g mkv or mp4
\r
48 public string Format { get; set; }
\r
51 /// Gets or sets a value indicating whether LargeMP4 support is enabled.
\r
52 /// This is the 64bit MP4 file that allows >4GB files
\r
54 public bool LargeMP4 { get; set; }
\r
57 /// Gets or sets a value indicating whether IpodAtom is inserted
\r
59 public bool IpodAtom { get; set; }
\r
62 /// Gets or sets a value indicating whether OptimizeMP4 is enabed for web streaming
\r
64 public bool OptimizeMP4 { get; set; }
\r
67 #region Picture Settings
\r
70 /// Gets or sets Width.
\r
72 public int Width { get; set; }
\r
75 /// Gets or sets Height.
\r
77 public int Height { get; set; }
\r
80 /// Gets or sets MaxWidth.
\r
82 public int MaxWidth { get; set; }
\r
85 /// Gets or sets MaxHeight.
\r
87 public int MaxHeight { get; set; }
\r
90 /// Gets or sets CropValues.
\r
92 public string CropValues { get; set; }
\r
95 /// Gets or sets CropTop.
\r
97 public string CropTop { get; set; }
\r
100 /// Gets or sets CropBottom.
\r
102 public string CropBottom { get; set; }
\r
105 /// Gets or sets CropLeft.
\r
107 public string CropLeft { get; set; }
\r
110 /// Gets or sets CropRight.
\r
112 public string CropRight { get; set; }
\r
115 /// Gets or sets AnamorphicMode.
\r
117 public int AnamorphicMode { get; set; }
\r
120 /// Gets or sets a value indicating whether KeepDisplayAsect.
\r
122 public bool KeepDisplayAsect { get; set; }
\r
125 /// Gets or sets DisplayWidthValue.
\r
127 public double DisplayWidthValue { get; set; }
\r
130 /// Gets or sets PixelAspectWidth.
\r
132 public int PixelAspectWidth { get; set; }
\r
135 /// Gets or sets PixelAspectHeight.
\r
137 public int PixelAspectHeight { get; set; }
\r
140 /// Gets or sets AnamorphicModulus.
\r
142 public int AnamorphicModulus { get; set; }
\r
145 #region Video Filters
\r
148 /// Gets or sets DeTelecine.
\r
150 public string DeTelecine { get; set; }
\r
153 /// Gets or sets DeBlock.
\r
155 public int DeBlock { get; set; }
\r
158 /// Gets or sets DeInterlace.
\r
160 public string DeInterlace { get; set; }
\r
163 /// Gets or sets DeNoise.
\r
165 public string DeNoise { get; set; }
\r
168 /// Gets or sets Decomb.
\r
170 public string Decomb { get; set; }
\r
173 #region Video Settings
\r
175 /// Gets or sets VideoEncoder.
\r
177 public string VideoEncoder { get; set; }
\r
180 /// Gets or sets a value indicating whether Grayscale.
\r
182 public bool Grayscale { get; set; }
\r
185 /// Gets or sets a value indicating whether TwoPass.
\r
187 public bool TwoPass { get; set; }
\r
190 /// Gets or sets a value indicating whether TurboFirstPass.
\r
192 public bool TurboFirstPass { get; set; }
\r
195 /// Gets or sets VideoFramerate.
\r
197 public string VideoFramerate { get; set; }
\r
200 /// Gets or sets a value indicating whether Pfr.
\r
202 public bool Pfr { get; set; }
\r
205 /// Gets or sets AverageVideoBitrate.
\r
207 public string AverageVideoBitrate { get; set; }
\r
210 /// Gets or sets VideoTargetSize.
\r
212 public string VideoTargetSize { get; set; }
\r
215 /// Gets or sets VideoQuality.
\r
217 public float VideoQuality { get; set; }
\r
220 #region Audio Settings
\r
223 /// Gets or sets AudioInformation.
\r
225 public ArrayList AudioInformation { get; set; }
\r
228 /// Gets or sets Subtitles.
\r
230 public string Subtitles { get; set; }
\r
233 /// Gets or sets a value indicating whether ForcedSubtitles.
\r
235 public bool ForcedSubtitles { get; set; }
\r
240 /// Gets or sets a value indicating whether ChapterMarkers.
\r
242 public bool ChapterMarkers { get; set; }
\r
245 /// Gets or sets H264Query.
\r
247 public string H264Query { get; set; }
\r
250 /// Gets or sets a value indicating whether Verbose.
\r
252 public bool Verbose { get; set; }
\r
255 #region Preset Information
\r
258 /// Gets or sets PresetBuildNumber.
\r
260 public int PresetBuildNumber { get; set; }
\r
263 /// Gets or sets PresetDescription.
\r
265 public string PresetDescription { get; set; }
\r
268 /// Gets or sets PresetName.
\r
270 public string PresetName { get; set; }
\r
273 /// Gets or sets Type.
\r
275 public string Type { get; set; }
\r
278 /// Gets or sets a value indicating whether UsesMaxPictureSettings.
\r
280 public bool UsesMaxPictureSettings { get; set; }
\r
283 /// Gets or sets a value indicating whether UsesPictureFilters.
\r
285 public bool UsesPictureFilters { get; set; }
\r
288 /// Gets or sets a value indicating whether UsesPictureSettings.
\r
290 public bool UsesPictureSettings { get; set; }
\r
296 /// Takes in a query which can be in any order and parses it.
\r
297 /// All varibles are then set so they can be used elsewhere.
\r
299 /// <param name="input">A ClI Query</param>
\r
300 /// <returns>A Parsed Query</returns>
\r
301 public static QueryParser Parse(string input)
\r
303 var thisQuery = new QueryParser();
\r
305 #region Regular Expressions
\r
308 Match title = Regex.Match(input, @"-t ([0-9]*)");
\r
309 Match chapters = Regex.Match(input, @"-c ([0-9-]*)");
\r
312 Match format = Regex.Match(input, @"-f ([a-z0-9a-z0-9a-z0-9]*)");
\r
313 Match grayscale = Regex.Match(input, @" -g");
\r
314 Match largerMp4 = Regex.Match(input, @" -4");
\r
315 Match ipodAtom = Regex.Match(input, @" -I");
\r
317 // Picture Settings Tab
\r
318 Match width = Regex.Match(input, @"-w ([0-9]*)");
\r
319 Match height = Regex.Match(input, @"-l ([0-9]*)");
\r
320 Match maxWidth = Regex.Match(input, @"-X ([0-9]*)");
\r
321 Match maxHeight = Regex.Match(input, @"-Y ([0-9]*)");
\r
322 Match crop = Regex.Match(input, @"--crop ([0-9]*):([0-9]*):([0-9]*):([0-9]*)");
\r
324 Match looseAnamorphic = Regex.Match(input, @"--loose-anamorphic");
\r
325 Match strictAnamorphic = Regex.Match(input, @"--strict-anamorphic");
\r
326 Match customAnamorphic = Regex.Match(input, @"--custom-anamorphic");
\r
328 Match keepDisplayAsect = Regex.Match(input, @"--keep-display-aspect");
\r
329 Match displayWidth = Regex.Match(input, @"--display-width ([0-9]*)");
\r
330 Match pixelAspect = Regex.Match(input, @"--pixel-aspect ([0-9]*):([0-9]*)");
\r
331 Match modulus = Regex.Match(input, @"--modulus ([0-9]*)");
\r
333 // Picture Settings - Filters
\r
334 Match decomb = Regex.Match(input, @" --decomb");
\r
335 Match decombValue = Regex.Match(input, @" --decomb=\""([a-zA-Z0-9.:]*)\""");
\r
336 Match deinterlace = Regex.Match(input, @"--deinterlace=\""([a-zA-Z0-9.:]*)\""");
\r
337 Match denoise = Regex.Match(input, @"--denoise=\""([a-zA-Z0-9.:]*)\""");
\r
338 Match deblock = Regex.Match(input, @"--deblock=([0-9:]*)");
\r
339 Match detelecine = Regex.Match(input, @"--detelecine");
\r
340 Match detelecineValue = Regex.Match(input, @" --detelecine=\""([a-zA-Z0-9.:]*)\""");
\r
342 // Video Settings Tab
\r
343 Match videoEncoder = Regex.Match(input, @"-e ([a-zA-Z0-9]*)");
\r
344 Match videoFramerate = Regex.Match(input, @"-r ([0-9.]*)");
\r
345 Match videoBitrate = Regex.Match(input, @"-b ([0-9]*)");
\r
346 Match videoQuality = Regex.Match(input, @"-q ([0-9.]*)");
\r
347 Match videoFilesize = Regex.Match(input, @"-S ([0-9.]*)");
\r
348 Match twoPass = Regex.Match(input, @" -2");
\r
349 Match turboFirstPass = Regex.Match(input, @" -T");
\r
350 Match optimizeMP4 = Regex.Match(input, @" -O");
\r
351 Match pfr = Regex.Match(input, @" --pfr");
\r
353 // Audio Settings Tab
\r
354 Match noAudio = Regex.Match(input, @"-a none");
\r
355 Match audioTracks = Regex.Match(input, @"-a ([0-9,]*)");
\r
356 Match audioTrackMixes = Regex.Match(input, @"-6 ([0-9a-zA-Z,]*)");
\r
357 Match audioEncoders = Regex.Match(input, @"-E ([a-zA-Z0-9+,]*)");
\r
358 Match audioBitrates = Regex.Match(input, @"-B ([0-9a-zA-Z,]*)"); // Auto = a-z
\r
359 Match audioSampleRates = Regex.Match(input, @"-R ([0-9a-zA-Z.,]*)"); // Auto = a-z
\r
360 Match drcValues = Regex.Match(input, @"-D ([0-9.,]*)");
\r
362 Match subtitles = Regex.Match(input, @"-s ([0-9a-zA-Z]*)");
\r
363 Match subScan = Regex.Match(input, @" -U");
\r
364 Match forcedSubtitles = Regex.Match(input, @" -F");
\r
367 Match chapterMarkers = Regex.Match(input, @" -m");
\r
368 Match chapterMarkersFileMode = Regex.Match(input, @"--markers");
\r
371 Match x264 = Regex.Match(input, @"-x ([.,/a-zA-Z0-9=:-]*)");
\r
374 Match verbose = Regex.Match(input, @" -v");
\r
378 #region Set Varibles
\r
385 thisQuery.Title = int.Parse(title.ToString().Replace("-t ", string.Empty));
\r
387 if (chapters.Success)
\r
389 string[] actTitles = chapters.ToString().Replace("-c ", string.Empty).Split('-');
\r
390 thisQuery.ChapterStart = int.Parse(actTitles[0]);
\r
391 if (actTitles.Length > 1)
\r
393 thisQuery.ChapterFinish = int.Parse(actTitles[1]);
\r
396 if ((thisQuery.ChapterStart == 1) && (thisQuery.ChapterFinish == 0))
\r
397 thisQuery.ChapterFinish = thisQuery.ChapterStart;
\r
402 #region Output Settings
\r
404 if (format.Success)
\r
405 thisQuery.Format = format.ToString().Replace("-f ", string.Empty);
\r
406 thisQuery.LargeMP4 = largerMp4.Success;
\r
407 thisQuery.IpodAtom = ipodAtom.Success;
\r
408 thisQuery.OptimizeMP4 = optimizeMP4.Success;
\r
412 #region Picture Tab
\r
415 thisQuery.Width = int.Parse(width.Groups[0].Value.Replace("-w ", string.Empty));
\r
417 if (height.Success)
\r
418 thisQuery.Height = int.Parse(height.Groups[0].Value.Replace("-l ", string.Empty));
\r
420 if (maxWidth.Success)
\r
421 thisQuery.MaxWidth = int.Parse(maxWidth.Groups[0].Value.Replace("-X ", string.Empty));
\r
423 if (maxHeight.Success)
\r
424 thisQuery.MaxHeight = int.Parse(maxHeight.Groups[0].Value.Replace("-Y ", string.Empty));
\r
428 thisQuery.CropValues = crop.ToString().Replace("--crop ", string.Empty);
\r
429 string[] actCropValues = thisQuery.CropValues.Split(':');
\r
430 thisQuery.CropTop = actCropValues[0];
\r
431 thisQuery.CropBottom = actCropValues[1];
\r
432 thisQuery.CropLeft = actCropValues[2];
\r
433 thisQuery.CropRight = actCropValues[3];
\r
436 if (strictAnamorphic.Success)
\r
437 thisQuery.AnamorphicMode = 1;
\r
438 else if (looseAnamorphic.Success)
\r
439 thisQuery.AnamorphicMode = 2;
\r
440 else if (customAnamorphic.Success)
\r
441 thisQuery.AnamorphicMode = 3;
\r
443 thisQuery.AnamorphicMode = 0;
\r
445 thisQuery.KeepDisplayAsect = keepDisplayAsect.Success;
\r
447 if (displayWidth.Success)
\r
448 thisQuery.DisplayWidthValue =
\r
449 double.Parse(displayWidth.Groups[0].Value.Replace("--display-width ", string.Empty));
\r
451 if (pixelAspect.Success)
\r
452 thisQuery.PixelAspectWidth = int.Parse(pixelAspect.Groups[1].Value.Replace("--pixel-aspect ", string.Empty));
\r
454 if (pixelAspect.Success && pixelAspect.Groups.Count >= 3)
\r
455 thisQuery.PixelAspectHeight = int.Parse(pixelAspect.Groups[2].Value.Replace("--pixel-aspect ", string.Empty));
\r
457 if (modulus.Success)
\r
458 thisQuery.AnamorphicModulus = int.Parse(modulus.Groups[0].Value.Replace("--modulus ", string.Empty));
\r
464 thisQuery.Decomb = "Off";
\r
465 if (decomb.Success)
\r
467 thisQuery.Decomb = "Default";
\r
468 if (decombValue.Success)
\r
469 thisQuery.Decomb = decombValue.ToString().Replace("--decomb=", string.Empty).Replace("\"", string.Empty);
\r
472 thisQuery.DeInterlace = "Off";
\r
473 if (deinterlace.Success)
\r
475 thisQuery.DeInterlace = deinterlace.ToString().Replace("--deinterlace=", string.Empty).Replace("\"", string.Empty);
\r
476 thisQuery.DeInterlace =
\r
477 thisQuery.DeInterlace.Replace("fast", "Fast").Replace("slow", "Slow").Replace("slower", "Slower");
\r
478 thisQuery.DeInterlace = thisQuery.DeInterlace.Replace("slowest", "Slowest");
\r
481 thisQuery.DeNoise = "Off";
\r
482 if (denoise.Success)
\r
484 thisQuery.DeNoise = denoise.ToString().Replace("--denoise=", string.Empty).Replace("\"", string.Empty);
\r
485 thisQuery.DeNoise =
\r
486 thisQuery.DeNoise.Replace("weak", "Weak").Replace("medium", "Medium").Replace("strong", "Strong");
\r
489 string deblockValue = string.Empty;
\r
490 thisQuery.DeBlock = 0;
\r
491 if (deblock.Success)
\r
492 deblockValue = deblock.ToString().Replace("--deblock=", string.Empty);
\r
495 if (deblockValue != string.Empty)
\r
496 int.TryParse(deblockValue, out dval);
\r
497 thisQuery.DeBlock = dval;
\r
499 thisQuery.DeTelecine = "Off";
\r
500 if (detelecine.Success)
\r
502 thisQuery.DeTelecine = "Default";
\r
503 if (detelecineValue.Success)
\r
504 thisQuery.DeTelecine = detelecineValue.ToString().Replace("--detelecine=", string.Empty).Replace("\"", string.Empty);
\r
509 #region Video Settings Tab
\r
511 string videoEncoderConvertion = videoEncoder.ToString().Replace("-e ", string.Empty);
\r
512 switch (videoEncoderConvertion)
\r
515 videoEncoderConvertion = "MPEG-4 (FFmpeg)";
\r
518 videoEncoderConvertion = "H.264 (x264)";
\r
521 videoEncoderConvertion = "VP3 (Theora)";
\r
524 videoEncoderConvertion = "MPEG-4 (FFmpeg)";
\r
527 thisQuery.VideoEncoder = videoEncoderConvertion;
\r
528 thisQuery.VideoFramerate = videoFramerate.Success
\r
529 ? videoFramerate.ToString().Replace("-r ", string.Empty)
\r
530 : "Same as source";
\r
532 thisQuery.Pfr = pfr.Success;
\r
533 thisQuery.Grayscale = grayscale.Success;
\r
534 thisQuery.TwoPass = twoPass.Success;
\r
535 thisQuery.TurboFirstPass = turboFirstPass.Success;
\r
537 if (videoBitrate.Success)
\r
538 thisQuery.AverageVideoBitrate = videoBitrate.ToString().Replace("-b ", string.Empty);
\r
539 if (videoFilesize.Success)
\r
540 thisQuery.VideoTargetSize = videoFilesize.ToString().Replace("-S ", string.Empty);
\r
542 if (videoQuality.Success)
\r
544 float qConvert = float.Parse(videoQuality.ToString().Replace("-q ", string.Empty), Culture);
\r
545 thisQuery.VideoQuality = qConvert;
\r
548 thisQuery.VideoQuality = -1;
\r
554 // Find out how many tracks we need to add by checking how many encoders or audio tracks are selected.
\r
555 int encoderCount = 0;
\r
556 if (audioEncoders.Success)
\r
558 string[] audioDataCounters = audioEncoders.ToString().Replace("-E ", string.Empty).Split(',');
\r
559 encoderCount = audioDataCounters.Length;
\r
562 // Get the data from the regular expression results
\r
563 string[] trackData = null;
\r
564 string[] trackMixes = null;
\r
565 string[] trackEncoders = null;
\r
566 string[] trackBitrates = null;
\r
567 string[] trackSamplerates = null;
\r
568 string[] trackDRCvalues = null;
\r
570 if (audioTracks.Success)
\r
571 trackData = audioTracks.ToString().Replace("-a ", string.Empty).Split(',');
\r
572 if (audioTrackMixes.Success)
\r
573 trackMixes = audioTrackMixes.ToString().Replace("-6 ", string.Empty).Split(',');
\r
574 if (audioEncoders.Success)
\r
575 trackEncoders = audioEncoders.ToString().Replace("-E ", string.Empty).Split(',');
\r
576 if (audioBitrates.Success)
\r
577 trackBitrates = audioBitrates.ToString().Replace("-B ", string.Empty).Split(',');
\r
578 if (audioSampleRates.Success)
\r
579 trackSamplerates = audioSampleRates.ToString().Replace("-R ", string.Empty).Split(',');
\r
580 if (drcValues.Success)
\r
581 trackDRCvalues = drcValues.ToString().Replace("-D ", string.Empty).Split(',');
\r
583 // Create new Audio Track Classes and store them in the ArrayList
\r
584 ArrayList allAudioTrackInfo = new ArrayList();
\r
585 for (int x = 0; x < encoderCount; x++)
\r
587 AudioTrack track = new AudioTrack();
\r
588 if (trackData != null)
\r
589 if (trackData.Length >= (x + 1)) // Audio Track
\r
590 track.Track = trackData[x].Trim();
\r
592 if (trackMixes != null)
\r
593 if (trackMixes.Length >= (x + 1)) // Audio Mix
\r
594 track.MixDown = GetMixDown(trackMixes[x].Trim());
\r
596 if (trackEncoders != null)
\r
597 if (trackEncoders.Length >= (x + 1)) // Audio Mix
\r
598 track.Encoder = GetAudioEncoder(trackEncoders[x].Trim());
\r
600 if (trackBitrates != null)
\r
601 if (trackBitrates.Length >= (x + 1)) // Audio Encoder
\r
602 track.Bitrate = trackBitrates[x].Trim() == "auto" ? "Auto" : trackBitrates[x].Trim();
\r
604 if (trackSamplerates != null)
\r
605 if (trackSamplerates.Length >= (x + 1)) // Audio SampleRate
\r
606 track.SampleRate = trackSamplerates[x].Trim() == "0" ? "Auto" : trackSamplerates[x].Trim();
\r
608 if (trackDRCvalues != null)
\r
609 if (trackDRCvalues.Length >= (x + 1)) // Audio DRC Values
\r
610 track.DRC = trackDRCvalues[x].Trim();
\r
612 allAudioTrackInfo.Add(track);
\r
614 thisQuery.AudioInformation = allAudioTrackInfo;
\r
617 if (subtitles.Success)
\r
618 thisQuery.Subtitles = subtitles.ToString().Replace("-s ", string.Empty);
\r
620 thisQuery.Subtitles = subScan.Success ? "Autoselect" : "None";
\r
622 thisQuery.ForcedSubtitles = forcedSubtitles.Success;
\r
626 #region Chapters Tab
\r
628 if (chapterMarkersFileMode.Success || chapterMarkers.Success)
\r
629 thisQuery.ChapterMarkers = true;
\r
633 #region H.264 and other
\r
636 thisQuery.H264Query = x264.ToString().Replace("-x ", string.Empty);
\r
638 thisQuery.Verbose = verbose.Success;
\r
642 catch (Exception exc)
\r
644 frmExceptionWindow exceptionWindow = new frmExceptionWindow();
\r
645 exceptionWindow.Setup("An error has occured in the Query Parser.", exc.ToString());
\r
646 exceptionWindow.ShowDialog();
\r
655 /// Get the GUI equiv to a CLI mixdown
\r
657 /// <param name="mixdown">The Audio Mixdown</param>
\r
658 /// <returns>The GUI representation of the mixdown</returns>
\r
659 private static string GetMixDown(string mixdown)
\r
661 switch (mixdown.Trim())
\r
668 return "Dolby Surround";
\r
670 return "Dolby Pro Logic II";
\r
672 return "6 Channel Discrete";
\r
674 return "Automatic";
\r
679 /// Get the GUI equiv to a CLI audio encoder
\r
681 /// <param name="audioEnc">The Audio Encoder</param>
\r
682 /// <returns>The GUI representation of that audio encoder</returns>
\r
683 private static string GetAudioEncoder(string audioEnc)
\r
688 return "AAC (faac)";
\r
690 return "MP3 (lame)";
\r
692 return "Vorbis (vorbis)";
\r
694 return "AC3 Passthru";
\r
696 return "DTS Passthru";
\r
698 return "AAC (faac)";
\r