1 /* PlistPresetHandler.cs $
\r
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.Presets
\r
9 using System.Collections;
\r
12 using System.Windows.Forms;
\r
18 /// Plist Preset Converter
\r
20 public class PlistPresetHandler
\r
24 public static QueryParser Import(string filename)
\r
26 XmlNode root = loadFile(filename);
\r
27 if (root == null) return null;
\r
29 // We'll query a query parser object and use it's public var structures to store all the data.
\r
30 // This will allow the preset loader logic to be used instead of writing custom logic just for this file.
\r
31 QueryParser queryParsed = new QueryParser();
\r
32 string qualityMode = string.Empty;
\r
34 #region Get a List of Audio Track Objects
\r
35 XmlNode audioListDict = root.ChildNodes[2].ChildNodes[0].FirstChild.ChildNodes[1];
\r
36 ArrayList audioTracks = new ArrayList();
\r
38 for (int i = 0; i < audioListDict.ChildNodes.Count; i++)
\r
40 XmlNode audioChannel = audioListDict.ChildNodes[i];
\r
41 AudioTrack track = new AudioTrack();
\r
43 for (int subi = 0; subi < audioChannel.ChildNodes.Count; subi += 2)
\r
45 // Audio Channel Information is here.
\r
46 string key = audioChannel.ChildNodes[subi].InnerText;
\r
47 string value = audioChannel.ChildNodes[subi + 1].InnerText;
\r
50 case "AudioBitrate":
\r
51 track.Bitrate = value;
\r
53 case "AudioEncoder":
\r
54 track.Encoder = value.Replace("AAC (CoreAudio)", "AAC (faac)");
\r
56 case "AudioMixdown":
\r
57 track.MixDown = value;
\r
59 case "AudioSamplerate":
\r
60 track.SampleRate = value;
\r
63 track.Track = value;
\r
65 case "AudioTrackDRCSlider":
\r
70 audioTracks.Add(track);
\r
71 queryParsed.AudioInformation = audioTracks;
\r
75 #region Parse the reset of the plist keys into local variables
\r
77 XmlNode presetSettings = root.ChildNodes[2].ChildNodes[0].FirstChild;
\r
79 // Start from 2 to avoid the audio settings which we don't need.
\r
80 for (int i = 2; i < presetSettings.ChildNodes.Count; i += 2)
\r
82 string key = presetSettings.ChildNodes[i].InnerText;
\r
83 string value = presetSettings.ChildNodes[i + 1].InnerText;
\r
89 queryParsed.Format = value;
\r
91 case "Mp4HttpOptimize":
\r
92 queryParsed.OptimizeMP4 = value == "1";
\r
94 case "Mp4LargeFile":
\r
95 queryParsed.LargeMP4 = value == "1";
\r
97 case "Mp4iPodCompatible":
\r
98 queryParsed.IpodAtom = value == "1";
\r
101 // Picture Settings
\r
102 case "PictureAutoCrop":
\r
105 case "PictureTopCrop":
\r
106 queryParsed.CropTop = value;
\r
108 case "PictureBottomCrop":
\r
109 queryParsed.CropBottom = value;
\r
111 case "PictureLeftCrop":
\r
112 queryParsed.CropLeft = value;
\r
114 case "PictureRightCrop":
\r
115 queryParsed.CropRight = value;
\r
117 case "PictureHeight":
\r
118 queryParsed.Height = int.Parse(value);
\r
120 case "PictureWidth":
\r
121 queryParsed.Width = int.Parse(value);
\r
123 case "PictureKeepRatio":
\r
124 queryParsed.KeepDisplayAsect = value == "1";
\r
127 queryParsed.AnamorphicMode = int.Parse(value);
\r
131 case "PictureDeblock":
\r
132 queryParsed.DeBlock = int.Parse(value);
\r
134 case "PictureDecomb":
\r
135 queryParsed.Decomb = "Off";
\r
136 // Don't place custom here as it's handled in the filter panel
\r
137 if (value == "2") queryParsed.Decomb = "Default";
\r
139 case "PictureDecombCustom":
\r
140 if (value != string.Empty)
\r
141 queryParsed.Decomb = value;
\r
143 case "PictureDecombDeinterlace":
\r
146 case "PictureDeinterlace":
\r
150 queryParsed.DeInterlace = "Off";
\r
152 // Don't place custom here as it's handled in the filter panel
\r
154 queryParsed.DeInterlace = "Fast";
\r
157 queryParsed.DeInterlace = "Slow";
\r
160 queryParsed.DeInterlace = "Slowest";
\r
164 case "PictureDeinterlaceCustom":
\r
165 if (value != string.Empty)
\r
166 queryParsed.DeInterlace = value;
\r
168 case "PictureDenoise":
\r
172 queryParsed.DeNoise = "Off";
\r
174 // Don't place custom here as it's handled in the filter panel
\r
176 queryParsed.DeNoise = "Weak";
\r
179 queryParsed.DeNoise = "Medium";
\r
182 queryParsed.DeNoise = "Strong";
\r
187 case "PictureDenoiseCustom":
\r
188 if (value != string.Empty)
\r
189 queryParsed.DeNoise = value;
\r
191 case "PictureDetelecine":
\r
192 queryParsed.DeTelecine = "Off";
\r
193 if (value == "1") queryParsed.DeTelecine = "Default";
\r
195 case "PictureDetelecineCustom":
\r
196 if (value != string.Empty)
\r
197 queryParsed.DeTelecine = value;
\r
201 case "VideoAvgBitrate":
\r
202 queryParsed.AverageVideoBitrate = value;
\r
204 case "VideoEncoder":
\r
205 queryParsed.VideoEncoder = value;
\r
207 case "VideoFramerate":
\r
208 queryParsed.VideoFramerate = value;
\r
210 case "VideoGrayScale":
\r
211 queryParsed.Grayscale = value == "1";
\r
213 case "VideoQualitySlider":
\r
214 queryParsed.VideoQuality = float.Parse(value);
\r
216 case "VideoQualityType": // The Type of Quality Mode used
\r
217 qualityMode = value;
\r
219 case "VideoTargetSize":
\r
220 queryParsed.VideoTargetSize = value;
\r
222 case "VideoTurboTwoPass":
\r
223 queryParsed.TurboFirstPass = value == "1";
\r
225 case "VideoTwoPass":
\r
226 queryParsed.TwoPass = value == "1";
\r
229 // Chapter Markers Tab
\r
230 case "ChapterMarkers":
\r
231 queryParsed.ChapterMarkers = value == "1";
\r
234 // Advanced x264 tab
\r
236 queryParsed.H264Query = value;
\r
239 // Preset Information
\r
240 case "PresetBuildNumber":
\r
241 queryParsed.PresetBuildNumber = int.Parse(value);
\r
243 case "PresetDescription":
\r
244 queryParsed.PresetDescription = value;
\r
247 queryParsed.PresetName = value;
\r
250 queryParsed.Type = value;
\r
252 case "UsesMaxPictureSettings":
\r
253 queryParsed.UsesMaxPictureSettings = value == "1";
\r
255 case "UsesPictureFilters":
\r
256 queryParsed.UsesPictureFilters = value == "1";
\r
258 case "UsesPictureSettings":
\r
259 queryParsed.UsesPictureSettings = value == "1";
\r
264 // Kill any Quality values we don't need.
\r
265 switch (qualityMode)
\r
267 case "0": // FileSize
\r
268 queryParsed.VideoQuality = -1;
\r
269 queryParsed.AverageVideoBitrate = null;
\r
271 case "1": // Avg Bitrate
\r
272 queryParsed.VideoQuality = -1;
\r
273 queryParsed.VideoTargetSize = null;
\r
276 queryParsed.AverageVideoBitrate = null;
\r
277 queryParsed.VideoTargetSize = null;
\r
282 return queryParsed;
\r
285 private static XmlNode loadFile(string filename)
\r
291 if (!File.Exists(filename))
\r
294 StreamReader sr = File.OpenText(filename);
\r
295 string fromfile = string.Empty;
\r
297 while ((fileChar = sr.Read()) != -1)
\r
298 fromfile += Convert.ToChar(fileChar);
\r
300 XmlDocument doc = new XmlDocument();
\r
301 doc.LoadXml(fromfile);
\r
304 if (!root.HasChildNodes)
\r
307 "The Preset file you selected appears to be invlaid or from an older version of HandBrake",
\r
309 MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
318 "The Preset file you selected appears to be invlaid or from an older version of HandBrake.\n\n Please note, if you are exporting from the MacGui you may need to rebuild your preset so that it uses the current preset plist format.\n The MacGui does not currently update user presets automatically.",
\r
320 MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
329 /// Export a MacGui style plist preset.
\r
331 /// <param name="path">
\r
334 /// <param name="preset">
\r
337 public static void Export(string path, Preset preset)
\r
339 QueryParser parsed = QueryParser.Parse(preset.Query);
\r
340 XmlTextWriter xmlWriter = new XmlTextWriter(path, Encoding.UTF8) { Formatting = Formatting.Indented };
\r
343 xmlWriter.WriteStartDocument();
\r
344 xmlWriter.WriteDocType("plist", "-//Apple//DTD PLIST 1.0//EN",
\r
345 @"http://www.apple.com/DTDs/PropertyList-1.0.dtd", null);
\r
347 xmlWriter.WriteStartElement("plist");
\r
348 xmlWriter.WriteStartElement("array");
\r
350 // Add New Preset Here. Can write multiple presets here if required in future.
\r
351 WritePreset(xmlWriter, parsed, preset);
\r
354 xmlWriter.WriteEndElement();
\r
355 xmlWriter.WriteEndElement();
\r
357 xmlWriter.WriteEndDocument();
\r
364 /// Write the Preset to a file
\r
366 /// <param name="xmlWriter">
\r
367 /// The xml writer.
\r
369 /// <param name="parsed">
\r
372 /// <param name="preset">
\r
375 private static void WritePreset(XmlTextWriter xmlWriter, QueryParser parsed, Preset preset)
\r
377 xmlWriter.WriteStartElement("dict");
\r
378 AudioListArrayDict(xmlWriter, parsed);
\r
379 AddEncodeSettings(xmlWriter, parsed, preset);
\r
381 xmlWriter.WriteEndElement();
\r
385 /// Add the encode settings to the preset
\r
387 /// <param name="xmlWriter">
\r
388 /// The xml writer.
\r
390 /// <param name="parsed">
\r
393 /// <param name="preset">
\r
396 private static void AddEncodeSettings(XmlTextWriter xmlWriter, QueryParser parsed, Preset preset)
\r
398 AddEncodeElement(xmlWriter, "ChapterMarkers", "integer", parsed.ChapterMarkers ? "1" : "0");
\r
399 AddEncodeElement(xmlWriter, "Default", "integer", "0");
\r
400 AddEncodeElement(xmlWriter, "FileFormat", "string", parsed.Format.ToUpper() + " file");
\r
401 AddBooleanElement(xmlWriter, "Folder", false);
\r
402 AddEncodeElement(xmlWriter, "Mp4HttpOptimize", "integer", parsed.OptimizeMP4 ? "1" : "0");
\r
403 AddEncodeElement(xmlWriter, "Mp4LargeFile", "integer", parsed.LargeMP4 ? "1" : "0");
\r
404 AddEncodeElement(xmlWriter, "Mp4iPodCompatible", "integer", parsed.IpodAtom ? "1" : "0");
\r
405 AddEncodeElement(xmlWriter, "PictureAutoCrop", "integer", "1");
\r
406 AddEncodeElement(xmlWriter, "PictureBottomCrop", "integer", parsed.CropBottom);
\r
409 AddEncodeElement(xmlWriter, "PictureDeblock", "integer", parsed.DeBlock.ToString());
\r
411 switch (parsed.Decomb)
\r
414 AddEncodeElement(xmlWriter, "PictureDecomb", "integer", "0");
\r
415 AddEncodeElement(xmlWriter, "PictureDecombCustom", "string", string.Empty);
\r
418 AddEncodeElement(xmlWriter, "PictureDecomb", "integer", "1");
\r
419 AddEncodeElement(xmlWriter, "PictureDecombCustom", "string", string.Empty);
\r
422 AddEncodeElement(xmlWriter, "PictureDecomb", "integer", "2");
\r
423 AddEncodeElement(xmlWriter, "PictureDecombCustom", "string", parsed.Decomb);
\r
426 AddEncodeElement(xmlWriter, "PictureDecombDeinterlace", "integer", parsed.Decomb != "Off" ? "0" : "1");
\r
428 switch (parsed.DeInterlace)
\r
431 AddEncodeElement(xmlWriter, "PictureDeinterlace", "integer", "0");
\r
432 AddEncodeElement(xmlWriter, "PictureDeinterlaceCustom", "string", string.Empty);
\r
435 AddEncodeElement(xmlWriter, "PictureDeinterlace", "integer", "1");
\r
436 AddEncodeElement(xmlWriter, "PictureDeinterlaceCustom", "string", string.Empty);
\r
439 AddEncodeElement(xmlWriter, "PictureDeinterlace", "integer", "2");
\r
440 AddEncodeElement(xmlWriter, "PictureDeinterlaceCustom", "string", string.Empty);
\r
443 AddEncodeElement(xmlWriter, "PictureDeinterlace", "integer", "3");
\r
444 AddEncodeElement(xmlWriter, "PictureDeinterlaceCustom", "string", string.Empty);
\r
447 AddEncodeElement(xmlWriter, "PictureDeinterlace", "integer", "4");
\r
448 AddEncodeElement(xmlWriter, "PictureDeinterlaceCustom", "string", parsed.DeInterlace);
\r
452 switch (parsed.DeNoise)
\r
455 AddEncodeElement(xmlWriter, "PictureDenoise", "integer", "0");
\r
456 AddEncodeElement(xmlWriter, "PictureDenoiseCustom", "string", string.Empty);
\r
459 AddEncodeElement(xmlWriter, "PictureDenoise", "integer", "1");
\r
460 AddEncodeElement(xmlWriter, "PictureDenoiseCustom", "string", string.Empty);
\r
463 AddEncodeElement(xmlWriter, "PictureDenoise", "integer", "2");
\r
464 AddEncodeElement(xmlWriter, "PictureDenoiseCustom", "string", string.Empty);
\r
467 AddEncodeElement(xmlWriter, "PictureDenoise", "integer", "3");
\r
468 AddEncodeElement(xmlWriter, "PictureDenoiseCustom", "string", string.Empty);
\r
471 AddEncodeElement(xmlWriter, "PictureDenoise", "integer", "4");
\r
472 AddEncodeElement(xmlWriter, "PictureDenoiseCustom", "string", parsed.DeNoise);
\r
477 switch (parsed.DeTelecine)
\r
489 AddEncodeElement(xmlWriter, "PictureDetelecine", "integer", detelecine.ToString());
\r
490 AddEncodeElement(xmlWriter, "PictureDetelecineCustom", "string", detelecine == 1 ? parsed.DeTelecine : string.Empty);
\r
492 // Picture Settings
\r
493 AddEncodeElement(xmlWriter, "PictureHeight", "integer", parsed.Height.ToString());
\r
494 AddEncodeElement(xmlWriter, "PictureKeepRatio", "integer", parsed.KeepDisplayAsect ? "1" : "0");
\r
495 AddEncodeElement(xmlWriter, "PictureLeftCrop", "integer", parsed.CropLeft);
\r
496 AddEncodeElement(xmlWriter, "PictureModulus", "integer", parsed.AnamorphicModulus.ToString());
\r
497 AddEncodeElement(xmlWriter, "PicturePAR", "integer", parsed.AnamorphicMode.ToString());
\r
498 AddEncodeElement(xmlWriter, "PictureRightCrop", "integer", parsed.CropRight);
\r
499 AddEncodeElement(xmlWriter, "PictureTopCrop", "integer", parsed.CropTop);
\r
500 AddEncodeElement(xmlWriter, "PictureWidth", "integer", parsed.Width.ToString());
\r
502 // Preset Information
\r
503 AddEncodeElement(xmlWriter, "PresetBuildNumber", "string", Properties.Settings.Default.hb_build.ToString());
\r
504 AddEncodeElement(xmlWriter, "PresetDescription", "string", "No Description");
\r
505 AddEncodeElement(xmlWriter, "PresetName", "string", preset.Name);
\r
506 AddEncodeElement(xmlWriter, "Type", "integer", "1"); // 1 is user preset, 0 is built in
\r
509 AddEncodeElement(xmlWriter, "UsesMaxPictureSettings", "integer", (parsed.MaxWidth != 0 || parsed.MaxHeight != 0) ? "1" : "0");
\r
510 AddEncodeElement(xmlWriter, "UsesPictureFilters", "integer", "1");
\r
511 AddEncodeElement(xmlWriter, "UsesPictureSettings", "integer", "2");
\r
514 AddEncodeElement(xmlWriter, "VideoAvgBitrate", "string", parsed.AverageVideoBitrate);
\r
515 AddEncodeElement(xmlWriter, "VideoEncoder", "string", parsed.VideoEncoder);
\r
516 AddEncodeElement(xmlWriter, "VideoFramerate", "string", parsed.VideoFramerate);
\r
517 AddEncodeElement(xmlWriter, "VideFrameratePFR", "integer", parsed.Pfr ? "1" : "0");
\r
518 AddEncodeElement(xmlWriter, "VideoGrayScale", "integer", parsed.Grayscale ? "1" : "0");
\r
519 AddEncodeElement(xmlWriter, "VideoQualitySlider", "real", parsed.VideoQuality.ToString());
\r
521 int videoQualityType = 0;
\r
522 if (!string.IsNullOrEmpty(parsed.VideoTargetSize)) videoQualityType = 0;
\r
523 else if (!string.IsNullOrEmpty(parsed.AverageVideoBitrate)) videoQualityType = 1;
\r
524 else if (parsed.VideoQuality != 0) videoQualityType = 2;
\r
526 AddEncodeElement(xmlWriter, "VideoQualityType", "integer", videoQualityType.ToString());
\r
527 AddEncodeElement(xmlWriter, "VideoTargetSize", "string", parsed.VideoTargetSize);
\r
528 AddEncodeElement(xmlWriter, "VideoTurboTwoPass", "integer", parsed.TurboFirstPass ? "1" : "0");
\r
529 AddEncodeElement(xmlWriter, "VideoTwoPass", "integer", parsed.TwoPass ? "1" : "0");
\r
532 AddEncodeElement(xmlWriter, "x264Option", "string", parsed.H264Query);
\r
536 /// Add a boolean element
\r
538 /// <param name="xmlWriter">
\r
539 /// The xml writer.
\r
541 /// <param name="keyName">
\r
544 /// <param name="value">
\r
547 private static void AddBooleanElement(XmlTextWriter xmlWriter, string keyName, bool value)
\r
549 xmlWriter.WriteStartElement("key");
\r
550 xmlWriter.WriteString(keyName);
\r
551 xmlWriter.WriteEndElement();
\r
552 xmlWriter.WriteStartElement(value ? "true" : "false");
\r
553 xmlWriter.WriteEndElement();
\r
557 /// Add an encode setting element
\r
559 /// <param name="xmlWriter">
\r
560 /// The xml writer.
\r
562 /// <param name="keyName">
\r
565 /// <param name="type">
\r
568 /// <param name="value">
\r
571 private static void AddEncodeElement(XmlTextWriter xmlWriter, string keyName, string type, string value)
\r
573 xmlWriter.WriteElementString("key", keyName);
\r
575 // This is a hack for Apples XML parser. It doesn't understand <integer /> so instead, always set a default value
\r
576 // of 0 if the value is empty.
\r
577 if (type == "integer" && string.IsNullOrEmpty(value))
\r
581 xmlWriter.WriteElementString(type, value);
\r
585 /// Add an Audio Track Array Dict
\r
587 /// <param name="xmlWriter">
\r
588 /// The xml writer.
\r
590 /// <param name="parsed">
\r
593 private static void AudioListArrayDict(XmlTextWriter xmlWriter, QueryParser parsed)
\r
595 xmlWriter.WriteStartElement("key");
\r
596 xmlWriter.WriteString("AudioList");
\r
597 xmlWriter.WriteEndElement();
\r
599 xmlWriter.WriteStartElement("array");
\r
600 foreach (AudioTrack track in parsed.AudioInformation)
\r
602 AddAudioItem(xmlWriter, track);
\r
604 xmlWriter.WriteEndElement();
\r
608 /// Add an audio track
\r
610 /// <param name="xmlWriter">
\r
611 /// The xml writer.
\r
613 /// <param name="audioTrack">
\r
614 /// The audio track.
\r
616 private static void AddAudioItem(XmlTextWriter xmlWriter, AudioTrack audioTrack)
\r
618 xmlWriter.WriteStartElement("dict");
\r
620 xmlWriter.WriteElementString("key", "AudioBitrate");
\r
621 xmlWriter.WriteElementString("string", audioTrack.Bitrate);
\r
623 xmlWriter.WriteElementString("key", "AudioEncoder");
\r
624 xmlWriter.WriteElementString("string", audioTrack.Encoder);
\r
626 xmlWriter.WriteElementString("key", "AudioMixdown");
\r
627 xmlWriter.WriteElementString("string", audioTrack.MixDown);
\r
629 xmlWriter.WriteElementString("key", "AudioSamplerate");
\r
630 xmlWriter.WriteElementString("string", audioTrack.SampleRate);
\r
632 xmlWriter.WriteElementString("key", "AudioTrack");
\r
633 xmlWriter.WriteElementString("integer", audioTrack.Track);
\r
635 xmlWriter.WriteElementString("key", "AudioTrackDRCSlider");
\r
636 xmlWriter.WriteElementString("real", audioTrack.DRC);
\r
638 xmlWriter.WriteElementString("key", "AudioTrackDescription");
\r
639 xmlWriter.WriteElementString("string", "Unknown");
\r
641 xmlWriter.WriteEndElement();
\r