OSDN Git Service

Add Bluray support
[handbrake-jp/handbrake-jp-git.git] / gtk / src / preset_xlat.c
index 1c77e77..990ea58 100644 (file)
 #include <stdio.h>
-#include <stdlib.h>
+#include <string.h>
 #include <glib.h>
-#include <fcntl.h>
+#include <glib/gstdio.h>
+#include "plist.h"
+#include "values.h"
 
-#define BUF_SIZ        (128*1024)
-#define IS_TAG(a,b)    (strcmp((a),(b)) == 0)
-#define IS_KEY(a,b)    (strcmp((a),(b)) == 0)
-#define IS_VAL(a,b)    (strcmp((a),(b)) == 0)
+static GValue *defaults;
 
-enum
+typedef struct
 {
-       NONE,
-       START,
-       ARRAY,
-       DICT,
-       KEY,
-       INT,
-       STR,
-       REAL,
+       gchar *mac_val;
+       gchar *lin_val;
+} value_map_t;
+
+#if 0
+static value_map_t subtitle_xlat[] =
+{ 
+       { "None", "none" },
+       { "Auto", "auto" },
+       { "Any", "und" },
+       { "Afar", "aar" },
+       { "Abkhazian", "abk" },
+       { "Afrikaans", "afr" },
+       { "Akan", "aka" },
+       { "Albanian", "sqi" },
+       { "Amharic", "amh" },
+       { "Arabic", "ara" },
+       { "Aragonese", "arg" },
+       { "Armenian", "hye" },
+       { "Assamese", "asm" },
+       { "Avaric", "ava" },
+       { "Avestan", "ave" },
+       { "Aymara", "aym" },
+       { "Azerbaijani", "aze" },
+       { "Bashkir", "bak" },
+       { "Bambara", "bam" },
+       { "Basque", "eus" },
+       { "Belarusian", "bel" },
+       { "Bengali", "ben" },
+       { "Bihari", "bih" },
+       { "Bislama", "bis" },
+       { "Bosnian", "bos" },
+       { "Breton", "bre" },
+       { "Bulgarian", "bul" },
+       { "Burmese", "mya" },
+       { "Catalan", "cat" },
+       { "Chamorro", "cha" },
+       { "Chechen", "che" },
+       { "Chinese", "zho" },
+       { "Church Slavic", "chu" },
+       { "Chuvash", "chv" },
+       { "Cornish", "cor" },
+       { "Corsican", "cos" },
+       { "Cree", "cre" },
+       { "Czech", "ces" },
+       { "Danish", "dan" },
+       { "Divehi", "div" },
+       { "Dutch", "nld" },
+       { "Dzongkha", "dzo" },
+       { "English", "eng" },
+       { "Esperanto", "epo" },
+       { "Estonian", "est" },
+       { "Ewe", "ewe" },
+       { "Faroese", "fao" },
+       { "Fijian", "fij" },
+       { "Finnish", "fin" },
+       { "French", "fra" },
+       { "Western Frisian", "fry" },
+       { "Fulah", "ful" },
+       { "Georgian", "kat" },
+       { "German", "deu" },
+       { "Gaelic (Scots)", "gla" },
+       { "Irish", "gle" },
+       { "Galician", "glg" },
+       { "Manx", "glv" },
+       { "Greek, Modern", "ell" },
+       { "Guarani", "grn" },
+       { "Gujarati", "guj" },
+       { "Haitian", "hat" },
+       { "Hausa", "hau" },
+       { "Hebrew", "heb" },
+       { "Herero", "her" },
+       { "Hindi", "hin" },
+       { "Hiri Motu", "hmo" },
+       { "Hungarian", "hun" },
+       { "Igbo", "ibo" },
+       { "Icelandic", "isl" },
+       { "Ido", "ido" },
+       { "Sichuan Yi", "iii" },
+       { "Inuktitut", "iku" },
+       { "Interlingue", "ile" },
+       { "Interlingua", "ina" },
+       { "Indonesian", "ind" },
+       { "Inupiaq", "ipk" },
+       { "Italian", "ita" },
+       { "Javanese", "jav" },
+       { "Japanese", "jpn" },
+       { "Kalaallisut", "kal" },
+       { "Kannada", "kan" },
+       { "Kashmiri", "kas" },
+       { "Kanuri", "kau" },
+       { "Kazakh", "kaz" },
+       { "Central Khmer", "khm" },
+       { "Kikuyu", "kik" },
+       { "Kinyarwanda", "kin" },
+       { "Kirghiz", "kir" },
+       { "Komi", "kom" },
+       { "Kongo", "kon" },
+       { "Korean", "kor" },
+       { "Kuanyama", "kua" },
+       { "Kurdish", "kur" },
+       { "Lao", "lao" },
+       { "Latin", "lat" },
+       { "Latvian", "lav" },
+       { "Limburgan", "lim" },
+       { "Lingala", "lin" },
+       { "Lithuanian", "lit" },
+       { "Luxembourgish", "ltz" },
+       { "Luba-Katanga", "lub" },
+       { "Ganda", "lug" },
+       { "Macedonian", "mkd" },
+       { "Marshallese", "mah" },
+       { "Malayalam", "mal" },
+       { "Maori", "mri" },
+       { "Marathi", "mar" },
+       { "Malay", "msa" },
+       { "Malagasy", "mlg" },
+       { "Maltese", "mlt" },
+       { "Moldavian", "mol" },
+       { "Mongolian", "mon" },
+       { "Nauru", "nau" },
+       { "Navajo", "nav" },
+       { "Ndebele, South", "nbl" },
+       { "Ndebele, North", "nde" },
+       { "Ndonga", "ndo" },
+       { "Nepali", "nep" },
+       { "Norwegian Nynorsk", "nno" },
+       { "Norwegian Bokmål", "nob" },
+       { "Norwegian", "nor" },
+       { "Chichewa; Nyanja", "nya" },
+       { "Occitan", "oci" },
+       { "Ojibwa", "oji" },
+       { "Oriya", "ori" },
+       { "Oromo", "orm" },
+       { "Ossetian", "oss" },
+       { "Panjabi", "pan" },
+       { "Persian", "fas" },
+       { "Pali", "pli" },
+       { "Polish", "pol" },
+       { "Portuguese", "por" },
+       { "Pushto", "pus" },
+       { "Quechua", "que" },
+       { "Romansh", "roh" },
+       { "Romanian", "ron" },
+       { "Rundi", "run" },
+       { "Russian", "rus" },
+       { "Sango", "sag" },
+       { "Sanskrit", "san" },
+       { "Serbian", "srp" },
+       { "Croatian", "hrv" },
+       { "Sinhala", "sin" },
+       { "Slovak", "slk" },
+       { "Slovenian", "slv" },
+       { "Northern Sami", "sme" },
+       { "Samoan", "smo" },
+       { "Shona", "sna" },
+       { "Sindhi", "snd" },
+       { "Somali", "som" },
+       { "Sotho, Southern", "sot" },
+       { "Spanish", "spa" },
+       { "Sardinian", "srd" },
+       { "Swati", "ssw" },
+       { "Sundanese", "sun" },
+       { "Swahili", "swa" },
+       { "Swedish", "swe" },
+       { "Tahitian", "tah" },
+       { "Tamil", "tam" },
+       { "Tatar", "tat" },
+       { "Telugu", "tel" },
+       { "Tajik", "tgk" },
+       { "Tagalog", "tgl" },
+       { "Thai", "tha" },
+       { "Tibetan", "bod" },
+       { "Tigrinya", "tir" },
+       { "Tonga", "ton" },
+       { "Tswana", "tsn" },
+       { "Tsonga", "tso" },
+       { "Turkmen", "tuk" },
+       { "Turkish", "tur" },
+       { "Twi", "twi" },
+       { "Uighur", "uig" },
+       { "Ukrainian", "ukr" },
+       { "Urdu", "urd" },
+       { "Uzbek", "uzb" },
+       { "Venda", "ven" },
+       { "Vietnamese", "vie" },
+       { "Volapük", "vol" },
+       { "Welsh", "cym" },
+       { "Walloon", "wln" },
+       { "Wolof", "wol" },
+       { "Xhosa", "xho" },
+       { "Yiddish", "yid" },
+       { "Yoruba", "yor" },
+       { "Zhuang", "zha" },
+       { "Zulu", "zul" },
+       {NULL, NULL}
 };
 
-typedef struct
+static value_map_t vcodec_xlat[] =
 {
-       gint state;
-       gchar *preset;
-       gchar *key;
-       gchar *value;
-       GHashTable *settings;
-       GHashTable *xlat_key;
-       GHashTable *xlat_value;
-} parse_data_t;
+       {"MPEG-4 (FFmpeg)", "ffmpeg"},
+       {"MPEG-4 (XviD)", "ffmpeg"},
+       {"H.264 (x264)", "x264"},
+       {"VP3 (Theora)", "theora"},
+       {NULL,NULL}
+};
 
-static void
-start_element(
-       GMarkupParseContext *ctx, 
-       const gchar *name, 
-       const gchar **attr_names,
-       const gchar **attr_values,
-       gpointer ud,
-       GError **error)
+value_map_t container_xlat[] =
 {
-       parse_data_t *pd = (parse_data_t*)ud;
-
-       if (IS_TAG(name, "array"))
-       {
-               pd->state = ARRAY;
-       }
-       else if (IS_TAG(name, "dict"))
-       {
-               g_hash_table_remove_all(pd->settings);
-               pd->state = DICT;
-       }
-       else if (IS_TAG(name, "key"))
-       {
-               pd->state = KEY;
-       }
-       else if (IS_TAG(name, "string"))
-       {
-               pd->state = STR;
-       }
-       else if (IS_TAG(name, "integer"))
-       {
-               pd->state = INT;
-       }
-       else if (IS_TAG(name, "real"))
-       {
-               pd->state = REAL;
-       }
-       else
-       {
-               g_debug("start unrecognized (%s)", name);
-       }
-}
+       {"MP4 file", "mp4"},
+       {"M4V file", "m4v"},
+       {"MKV file", "mkv"},
+       {"AVI file", "avi"},
+       {"OGM file", "ogm"},
+       {NULL, NULL}
+};
 
-gchar *settings[] = 
+value_map_t framerate_xlat[] =
 {
-       "preset_description",
-       "subtitle_lang",
-       "forced_subtitles",
-       "source_audio_lang",
-       "pref_audio_codec",
-       "pref_audio_bitrate",
-       "pref_audio_rate",
-       "pref_audio_mix",
-       "pref_audio_drc",
-       "chapter_markers",
-       "container",
-       "ipod_file",
-       "large_mp4",
-       "autocrop",
-       "autoscale",
-       "max_width",
-       "max_height",
-       "anamorphic",
-       "round_dimensions",
-       "keep_aspect",
-       "detelecine",
-       "decomb",
-       "deinterlace",
-       "denoise",
-       "grayscale",
-       "deblock",
-       "video_codec",
-       "two_pass",
-       "turbo",
-       "constant_rate_factor",
-       "variable_frame_rate",
-       "framerate",
-       "vquality_type_constant",
-       "vquality_type_bitrate",
-       "vquality_type_target",
-       "video_bitrate",
-       "video_target_size",
-       "video_quality",
-       "x264_options",
-       "directqp",
-       NULL
+       {"Same as source", "source"},
+       {"5", "5"},
+       {"10", "10"},
+       {"12", "12"},
+       {"15", "15"},
+       {"23.976", "23.976"},
+       {"24", "24"},
+       {"25", "25"},
+       {"29.97", "29.97"},
+       {NULL, NULL}
 };
 
-static void
-verify_keys(parse_data_t *pd)
+value_map_t deint_xlat[] =
 {
-       GList *keys, *link;
-
-       link = keys = g_hash_table_get_keys(pd->settings);
-       while (link)
-       {
-               gboolean found = FALSE;
-               gchar *key = (gchar*)link->data;
-               gint ii;
-               for (ii = 0; settings[ii] != NULL; ii++)
-               {
-                       if (IS_KEY(settings[ii], key))
-                       {
-                               found = TRUE;
-                       }
-               }
-               if (!found)
-               {
-                       g_message("bad key (%s)", key);
-               }
-               link = link->next;
-       }
-       g_list_free(keys);
-}
-
-GKeyFile *presets;
+       {"0", "none"},
+       {"1", "fast"},
+       {"2", "slow"},
+       {"3", "slower"},
+       {NULL, NULL}
+};
 
-static void
-save_preset(parse_data_t *pd)
+value_map_t denoise_xlat[] =
 {
-       gint ii;
-       if (pd->preset == NULL)
-       {
-               g_message("failed to save preset");
-               return;
-       }
-       for (ii = 0; settings[ii] != NULL; ii++)
-       {
-               const gchar *value;
-               value = (const gchar*)g_hash_table_lookup( pd->settings, settings[ii]);
-               if (value)
-               {
-                       g_key_file_set_value(presets, pd->preset, settings[ii], value);
-               }
-       }
-       verify_keys(pd);
-}
+       {"0", "none"},
+       {"1", "weak"},
+       {"2", "medium"},
+       {"3", "strong"},
+       {NULL, NULL}
+};
 
-gchar *audio_track[2];
-gchar *audio_enc[2];
-gchar *audio_bitrate[2];
-gchar *audio_rate[2];
-gchar *audio_mix[2];
-gchar *audio_drc[2];
+static value_map_t acodec_xlat[] =
+{
+       {"AAC (faac)", "faac"},
+       {"AC3 Passthru", "ac3"},
+       {"MP3 (lame)", "lame"},
+       {"Vorbis (vorbis)", "vorbis"},
+       {NULL,NULL}
+};
 
-static void
-do_one(gchar **strs, GString *res)
+value_map_t samplerate_xlat[] =
 {
-       gint ii;
-       for (ii = 0; ii < 2 && strs[ii]; ii++)
-       {
-               if (audio_track[ii] == NULL) break;
-               if (ii)
-                       g_string_append_c(res, ',');
-               g_string_append_printf(res, "%s", strs[ii]);
-       }
-}
+       {"Auto", "source"},
+       {"22.05", "22.05"},
+       {"24", "24"},
+       {"32", "32"},
+       {"44.1", "44.1"},
+       {"48", "48"},
+       {NULL, NULL}
+};
 
-static void
-do_audio(parse_data_t *pd)
+value_map_t mix_xlat[] =
 {
-       gint ii;
-       GString *enc, *br, *rate, *mix, *drc;
-       gchar *res;
-
-       enc = g_string_new("");
-       br = g_string_new("");
-       rate = g_string_new("");
-       mix = g_string_new("");
-       drc = g_string_new("");
-       do_one(audio_enc, enc);
-       do_one(audio_bitrate, br);
-       do_one(audio_rate, rate);
-       do_one(audio_mix, mix);
-       do_one(audio_drc, drc);
-       res = g_string_free(enc, FALSE);
-       g_hash_table_insert(pd->settings, g_strdup("pref_audio_codec"), res);
-       res = g_string_free(br, FALSE);
-       g_hash_table_insert(pd->settings, g_strdup("pref_audio_bitrate"), res);
-       res = g_string_free(rate, FALSE);
-       g_hash_table_insert(pd->settings, g_strdup("pref_audio_rate"), res);
-       res = g_string_free(mix, FALSE);
-       g_hash_table_insert(pd->settings, g_strdup("pref_audio_mix"), res);
-       res = g_string_free(drc, FALSE);
-       g_hash_table_insert(pd->settings, g_strdup("pref_audio_drc"), res);
-}
+       {"Mono", "mono"},
+       {"Stereo", "stereo"},
+       {"Dolby Surround", "dpl1"},
+       {"Dolby Pro Logic II", "dpl2"},
+       {"6-channel discrete", "6ch"},
+       {"AC3 Passthru", "none"},
+       {NULL, NULL}
+};
+#endif
 
-static void
-null_audio()
+typedef struct
 {
-       gint ii;
-       for (ii = 0; ii < 2; ii++)
-       {
-               audio_track[ii] = NULL;
-               audio_enc[ii] = NULL;
-               audio_bitrate[ii] = NULL;
-               audio_rate[ii] = NULL;
-               audio_mix[ii] = NULL;
-               audio_drc[ii] = NULL;
-       }
-}
+       gchar *mac_key;
+       gchar *lin_key;
+       value_map_t *value_map;
+       gboolean same;
+       gboolean ignore;
+} key_map_t;
+
+key_map_t key_map[] = 
+{
+       {"Audio1Bitrate", NULL, NULL, FALSE, FALSE},
+       {"Audio1Encoder", NULL, NULL, FALSE, FALSE},
+       {"Audio1Mixdown", NULL, NULL, FALSE, FALSE},
+       {"Audio1Samplerate", NULL, NULL, FALSE, FALSE},
+       {"Audio1Track", NULL, NULL, FALSE, FALSE},
+       {"Audio1TrackDescription", NULL, NULL, FALSE, FALSE},
+       {"Audio1TrackDRCSlider", NULL, NULL, FALSE, FALSE},
+       {"Audio2Bitrate", NULL, NULL, FALSE, FALSE},
+       {"Audio2Encoder", NULL, NULL, FALSE, FALSE},
+       {"Audio2Mixdown", NULL, NULL, FALSE, FALSE},
+       {"Audio2Samplerate", NULL, NULL, FALSE, FALSE},
+       {"Audio2Track", NULL, NULL, FALSE, FALSE},
+       {"Audio2TrackDescription", NULL, NULL, FALSE, FALSE},
+       {"Audio2TrackDRCSlider", NULL, NULL, FALSE, FALSE},
+       {"ChapterMarkers", NULL, NULL, TRUE, FALSE},
+       {"Default", NULL, NULL, TRUE, FALSE},
+       {"FileFormat", NULL, NULL, TRUE, FALSE},
+       {"Folder", NULL, NULL, TRUE, FALSE},
+       {"Mp4HttpOptimize", NULL, NULL, TRUE, FALSE},
+       {"Mp4iPodCompatible", NULL, NULL, TRUE, FALSE},
+       {"Mp4LargeFile", NULL, NULL, TRUE, FALSE},
+       {"PictureAutoCrop", NULL, NULL, TRUE, FALSE},
+       {"PictureBottomCrop", NULL, NULL, TRUE, FALSE},
+       {"PictureDeblock", NULL, NULL, TRUE, FALSE},
+       {"PictureDecomb", NULL, NULL, TRUE, FALSE},
+       {"PictureDeinterlace", NULL, NULL, TRUE, FALSE},
+       {"PictureDenoise", NULL, NULL, TRUE, FALSE},
+       {"PictureDetelecine", NULL, NULL, TRUE, FALSE},
+       {"PictureHeight", NULL, NULL, TRUE, FALSE},
+       {"PictureKeepRatio", NULL, NULL, TRUE, FALSE},
+       {"PictureLeftCrop", NULL, NULL, TRUE, FALSE},
+       {"PicturePAR", NULL, NULL, TRUE, FALSE},
+       {"PictureRightCrop", NULL, NULL, TRUE, FALSE},
+       {"PictureTopCrop", NULL, NULL, TRUE, FALSE},
+       {"PictureWidth", NULL, NULL, TRUE, FALSE},
+       {"PresetDescription", NULL, NULL, TRUE, FALSE},
+       {"PresetName", NULL, NULL, TRUE, FALSE},
+       {"Subtitles", NULL, NULL, TRUE, FALSE},
+       {"SubtitlesForced", NULL, NULL, TRUE, FALSE},
+       {"Type", NULL, NULL, TRUE, FALSE},
+       {"UsesMaxPictureSettings", NULL, NULL, TRUE, FALSE},
+       {"UsesPictureFilters", NULL, NULL, TRUE, FALSE},
+       {"UsesPictureSettings", NULL, NULL, TRUE, FALSE},
+       {"VFR", NULL, NULL, FALSE, TRUE},
+       {"VideoAvgBitrate", NULL, NULL, TRUE, FALSE},
+       {"VideoEncoder", NULL, NULL, TRUE, FALSE},
+       {"VideoFramerate", NULL, NULL, TRUE, FALSE},
+       {"VideoGrayScale", NULL, NULL, TRUE, FALSE},
+       {"VideoQualitySlider", NULL, NULL, TRUE, FALSE},
+       {"VideoQualityType", NULL, NULL, TRUE, FALSE},
+       {"VideoTargetSize", NULL, NULL, TRUE, FALSE},
+       {"VideoTwoPass", NULL, NULL, TRUE, FALSE},
+       {"VideoTurboTwoPass", NULL, NULL, TRUE, FALSE},
+       {"x264Option", NULL, NULL, TRUE, FALSE},
+       {NULL, NULL}
+};
 
-static void
-clear_audio()
+const gint
+key_xlat(key_map_t *key_map, const gchar *mac_key)
 {
        gint ii;
-       for (ii = 0; ii < 2; ii++)
+
+       for (ii = 0; key_map[ii].mac_key; ii++)
        {
-               if (audio_track[ii]) g_free(audio_track[ii]);
-               if (audio_enc[ii]) g_free(audio_enc[ii]);
-               if (audio_bitrate[ii]) g_free(audio_bitrate[ii]);
-               if (audio_rate[ii]) g_free(audio_rate[ii]);
-               if (audio_mix[ii]) g_free(audio_mix[ii]);
-               if (audio_drc[ii]) g_free(audio_drc[ii]);
-               audio_track[ii] = NULL;
-               audio_enc[ii] = NULL;
-               audio_bitrate[ii] = NULL;
-               audio_rate[ii] = NULL;
-               audio_mix[ii] = NULL;
-               audio_drc[ii] = NULL;
+               if (strcmp(mac_key, key_map[ii].mac_key) == 0)
+               {
+                       if (key_map[ii].ignore)
+                               return -1;
+                       return ii;
+               }
        }
+       g_warning("Unrecognized key: (%s)", mac_key);
+       return -1;
 }
 
-static void
-end_element(
-       GMarkupParseContext *ctx
-       const gchar *name
-       gpointer ud,
-       GError **error)
+static GValue*
+value_xlat(
+       GValue *defaults
+       key_map_t *key_map
+       gint key_index, 
+       GValue *mac_val)
 {
-       parse_data_t *pd = (parse_data_t*)ud;
+       GValue *gval, *def_val;
+       const gchar *lin_key;
+       if (key_map[key_index].same)
+               lin_key = key_map[key_index].mac_key;
+       else
+               lin_key = key_map[key_index].lin_key;
+       value_map_t *value_map = key_map[key_index].value_map;
 
-       if (IS_TAG(name, "string") ||
-               IS_TAG(name, "integer") ||
-               IS_TAG(name, "real"))
+       def_val = ghb_dict_lookup(defaults, lin_key);
+       if (def_val)
        {
-               if (IS_KEY(pd->key, "PresetName"))
+               if (value_map)
                {
-                       if (pd->preset)
-                       {
-                               g_message("Preset named twice");
-                       }
-                       else
-                               pd->preset = g_strdup(pd->value);
-                       pd->state = NONE;
-                       return;
-               }
-               const gchar *my_key;
-               my_key = (const gchar*)g_hash_table_lookup(pd->xlat_key, pd->key);
-               if (my_key != NULL)
-               { // Do something with it
-                       if (my_key[0] != 0) // intentionally ignored keys
+                       gint ii;
+                       gchar *str;
+                       GValue *sval;
+
+                       str = ghb_value_string(mac_val);
+                       for (ii = 0; value_map[ii].mac_val; ii++)
                        {
-                               if (pd->value != NULL)
+                               if (strcmp(str, value_map[ii].mac_val) == 0)
                                {
-                                       g_hash_table_insert(pd->settings, 
-                                               g_strdup(my_key), g_strdup(pd->value));
-                               }
-                               else
-                               {
-                                       g_message("NULL value");
+                                       sval = ghb_string_value_new(value_map[ii].lin_val);
+                                       g_free(str);
+                                       gval = ghb_value_new(G_VALUE_TYPE(def_val));
+                                       if (!g_value_transform(sval, gval))
+                                       {
+                                               g_warning("1 can't transform");
+                                               ghb_value_free(gval);
+                                               ghb_value_free(sval);
+                                               return NULL;
+                                       }
+                                       ghb_value_free(sval);
+                                       return gval;
                                }
                        }
+                       g_warning("Can't map value: (%s)", str);
+                       g_free(str);
                }
-               else if (IS_KEY(pd->key, "Audio1Encoder"))
-               {
-                       if (audio_enc[0]) g_free(audio_enc[0]);
-                       audio_enc[0] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio1Bitrate"))
-               {
-                       if (audio_bitrate[0]) g_free(audio_bitrate[0]);
-                       audio_bitrate[0] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio1Samplerate"))
-               {
-                       if (audio_rate[0]) g_free(audio_rate[0]);
-                       audio_rate[0] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio1Mixdown"))
-               {
-                       if (audio_mix[0]) g_free(audio_mix[0]);
-                       audio_mix[0] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio1TrackDRCSlider"))
-               {
-                       if (audio_drc[0]) g_free(audio_drc[0]);
-                       audio_drc[0] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio1Track"))
-               {
-                       if (audio_track[0]) g_free(audio_track[0]);
-                       audio_track[0] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio2Encoder"))
-               {
-                       if (audio_enc[1]) g_free(audio_enc[1]);
-                       audio_enc[1] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio2Bitrate"))
-               {
-                       if (audio_bitrate[1]) g_free(audio_bitrate[1]);
-                       audio_bitrate[1] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio2Samplerate"))
-               {
-                       if (audio_rate[1]) g_free(audio_rate[1]);
-                       audio_rate[1] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio2Mixdown"))
-               {
-                       if (audio_mix[1]) g_free(audio_mix[1]);
-                       audio_mix[1] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio2TrackDRCSlider"))
-               {
-                       if (audio_drc[1]) g_free(audio_drc[1]);
-                       audio_drc[1] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "Audio2Track"))
-               {
-                       if (audio_track[1]) g_free(audio_track[1]);
-                       audio_track[1] = g_strdup(pd->value);
-               }
-               else if (IS_KEY(pd->key, "VideoQualityType"))
+               else
                {
-                       // VideoQualityType/0/1/2 - vquality_type_/target/bitrate/constant
-                       if (IS_VAL(pd->value, "0"))
+                       gval = ghb_value_new(G_VALUE_TYPE(def_val));
+                       if (!g_value_transform(mac_val, gval))
                        {
-                               g_hash_table_insert(pd->settings, 
-                                               g_strdup("vquality_type_target"), 
-                                               g_strdup("1"));
-                               g_hash_table_remove(pd->settings, "vquality_type_bitrate");
-                               g_hash_table_remove(pd->settings, "vquality_type_constant");
+                               g_warning("2 can't transform");
+                               ghb_value_free(gval);
+                               return NULL;
                        }
-                       else if (IS_VAL(pd->value, "1"))
-                       {
-                               g_hash_table_remove(pd->settings, "vquality_type_target");
-                               g_hash_table_insert(pd->settings, 
-                                               g_strdup("vquality_type_bitrate"), 
-                                               g_strdup("1"));
-                               g_hash_table_remove(pd->settings, "vquality_type_constant");
-                       }
-                       else if (IS_VAL(pd->value, "2"))
-                       {
-                               g_hash_table_remove(pd->settings, "vquality_type_target");
-                               g_hash_table_remove(pd->settings, "vquality_type_bitrate");
-                               g_hash_table_insert(pd->settings, 
-                                               g_strdup("vquality_type_constant"), 
-                                               g_strdup("1"));
-                       }
-               }
-               else
-               {
-                       g_message("Key not found (%s)", pd->key);
+                       return gval;
                }
        }
-       else if (IS_TAG(name, "dict"))
+       else
        {
-               gint ii;
-               do_audio(pd);
-               clear_audio();
-               save_preset(pd);
-
-               if (pd->preset) 
-               {
-                       g_free(pd->preset);
-                       pd->preset = NULL;
-               }
-               else
-                       g_message("Preset has no name");
-               g_hash_table_remove_all(pd->settings);
+               g_warning("Bad key: (%s)", lin_key);
+               return NULL;
        }
-       pd->state = NONE;
+       return NULL;
 }
 
-static gboolean
-is_number(const gchar *str)
+key_map_t audio_key_map[] =
 {
-       gboolean result = TRUE;
-       gint ii;
-       for (ii = 0; str[ii] != 0; ii++)
-       {
-               if (!g_ascii_isdigit(str[ii]) && str[ii] != '.')
-                       result = FALSE;
-       }
-       return result;
-}
+       {"Audio1Bitrate", "AudioBitrate", NULL, FALSE, FALSE},
+       {"Audio1Encoder", "AudioEncoder", NULL, FALSE, FALSE},
+       {"Audio1Mixdown", "AudioMixdown", NULL, FALSE},
+       {"Audio1Samplerate", "AudioSamplerate", NULL, FALSE, FALSE},
+       {"Audio1Track", "AudioTrack", NULL, FALSE, FALSE},
+       {"Audio1TrackDescription", "AudioTrackDescription", NULL, FALSE, FALSE},
+       {"Audio1TrackDRCSlider", "AudioTrackDRCSlider", NULL, FALSE, FALSE},
+       {"Audio2Bitrate", "AudioBitrate", NULL, FALSE, FALSE},
+       {"Audio2Encoder", "AudioEncoder", NULL, FALSE, FALSE},
+       {"Audio2Mixdown", "AudioMixdown", NULL, FALSE, FALSE},
+       {"Audio2Samplerate", "AudioSamplerate", NULL, FALSE, FALSE},
+       {"Audio2Track", "AudioTrack", NULL, FALSE, FALSE},
+       {"Audio2TrackDescription", "AudioTrackDescription", NULL, FALSE, FALSE},
+       {"Audio2TrackDRCSlider", "AudioTrackDRCSlider", NULL, FALSE, FALSE},
+       {NULL, NULL}
+};
 
 static void
-text_data(
-       GMarkupParseContext *ctx, 
-       const gchar *text, 
-       gsize len,
-       gpointer ud,
-       GError **error)
+hard_value_xlat(GValue *lin_dict, const gchar *mac_key, GValue *mac_val)
 {
-       gboolean is_value = FALSE;
-       parse_data_t *pd = (parse_data_t*)ud;
-       const gchar *val = NULL;
-
-       if (pd->state == KEY)
-       {
-               if (pd->key) g_free(pd->key);
-               pd->key = g_strdup(text);
-               return;
-       }
-       if (pd->state == STR)
-       {
-               val = (gchar*)g_hash_table_lookup(pd->xlat_value, text);
-               if (val != NULL)
-               { // Do something with it
-               }
-               else if (IS_KEY(pd->key, "PresetName") ||
-                               IS_KEY(pd->key, "PresetDescription") ||
-                               IS_KEY(pd->key, "x264Option") ||
-                               is_number(text))
-               {
-                       val = text;
-               }
-               else
-               {
-                       g_message("Unrecognized val (%s)", text);
-               }
-       }
-       if (pd->state == INT || pd->state == REAL)
        {
-               val = text;
-       }
+               gint key_index;
+               GValue *audio_defaults;
 
-       // Some keys need further translation of their values
-       if (val)
-       {
-               if (IS_KEY(pd->key, "PictureDeinterlace"))
+               audio_defaults = ghb_array_get_nth(
+                       ghb_dict_lookup(defaults, "AudioList"), 0);
+               key_index = key_xlat(audio_key_map, mac_key);
+               if (key_index >= 0)
                {
-                       if (IS_VAL(val, "0"))
-                       {
-                               val = "none";
-                       }
-                       else if (IS_VAL(val, "1"))
-                       {
-                               val = "fast";
-                       }
-                       else if (IS_VAL(val, "2"))
-                       {
-                               val = "slow";
-                       }
-                       else if (IS_VAL(val, "3"))
+                       gint audio_index, count, ii;
+                       GValue *alist, *adict, *val;
+                       const gchar *lin_key;
+
+                       if (audio_key_map[key_index].same)
+                               lin_key = audio_key_map[key_index].mac_key;
+                       else
+                               lin_key = audio_key_map[key_index].lin_key;
+                       audio_index = mac_key[5] - '1';
+                       alist = ghb_dict_lookup(lin_dict, "AudioList");
+                       if (alist == NULL)
                        {
-                               val = "slower";
+                               alist = ghb_array_value_new(8);
+                               ghb_dict_insert(lin_dict, "AudioList", alist);
                        }
-               }
-               else if (IS_KEY(pd->key, "Audio1Samplerate") ||
-                               IS_KEY(pd->key, "Audio2Samplerate"))
-               {
-                       if (IS_VAL(val, "auto"))
+                       count = ghb_array_len(alist);
+                       for (ii = count; ii <= audio_index; ii++)
                        {
-                               val = "source";
+                               adict = ghb_value_dup(audio_defaults);
+                               ghb_array_append(alist, adict);
                        }
-               }
-               else if (IS_KEY(pd->key, "Audio1Mixdown") ||
-                               IS_KEY(pd->key, "Audio2Mixdown"))
-               {
-                       if (IS_VAL(val, "ac3"))
+                       adict = ghb_array_get_nth(alist, audio_index);
+                       val = value_xlat(audio_defaults, audio_key_map, key_index, mac_val);
+                       if (val)
                        {
-                               val = "none";
+                               ghb_dict_insert(adict, g_strdup(lin_key), val);
                        }
                }
-               if (pd->value) g_free(pd->value);
-               pd->value = g_strdup(val);
        }
 }
 
 static void
-passthrough(
-       GMarkupParseContext *ctx, 
-       const gchar *text, 
-       gsize len,
-       gpointer ud,
-       GError **error)
+parse_preset_dict(GValue *mac_dict, GValue *lin_dict)
 {
-       parse_data_t *pd = (parse_data_t*)ud;
+    GHashTableIter iter;
+    gchar *key;
+    GValue *mac_val, *val;
+
+    ghb_dict_iter_init(&iter, mac_dict);
+    // middle (void*) cast prevents gcc warning "defreferencing type-punned
+    // pointer will break strict-aliasing rules"
+       while (g_hash_table_iter_next(
+                       &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&mac_val))
+       {
+               gint key_index;
 
-       g_debug("passthrough %s", text);
-}
+               key_index = key_xlat(key_map, key);
+               if (key_index >= 0)
+               { // The simple translations
+                       const gchar *lin_key;
 
-static void
-delete_key(gpointer str)
-{
-       g_free(str);
+                       if (key_map[key_index].same)
+                               lin_key = key_map[key_index].mac_key;
+                       else
+                               lin_key = key_map[key_index].lin_key;
+                       if (lin_key)
+                       {
+                               val = value_xlat(defaults, key_map, key_index, mac_val);
+                               if (val)
+                               {
+                                       ghb_dict_insert(lin_dict, g_strdup(lin_key), val);
+                               }
+                       }
+                       else
+                       {
+                               hard_value_xlat(lin_dict, key, mac_val);
+                       }
+               }
+       }
 }
 
 static void
-delete_value(gpointer str)
+parse_preset_array(GValue *mac_array, GValue *lin_array)
 {
-       g_free(str);
-}
+       gint count, ii;
+       GValue *mac_dict, *lin_dict, *gval;
 
-typedef struct
-{
-       gchar *from;
-       gchar *to;
-} xlat_t;
-
-static xlat_t keys[] =
-{
-       {"VFR", "variable_frame_rate"},
-       {"ChapterMarkers", "chapter_markers"},
-       {"Default", ""},
-       {"FileFormat", "container"},
-       {"PictureAutoCrop", "autocrop"},
-       {"PictureBottomCrop", ""},
-       {"PictureTopCrop", ""},
-       {"PictureLeftCrop", ""},
-       {"PictureRightCrop", ""},
-       {"PictureDeblock", "deblock"},
-       {"PictureDeinterlace", "deinterlace"}, // v
-       {"PictureDenoise", "denoise"}, // v
-       {"PictureDetelecine", "detelecine"},
-       {"PictureHeight", "max_height"},
-       {"PictureWidth", "max_width"},
-       {"PictureKeepRatio", "keep_aspect"},
-       {"PicturePAR", "anamorphic"}, // v
-       {"PresetDescription", "preset_description"},
-       {"Subtitles", "subtitle_lang"},
-       {"Subtitles", "subtitle_lang"},
-       {"Type", ""}, // preset type builtin/custom
-       {"UsesMaxPictureSettings", "autoscale"},
-       {"UsesPictureFilters", ""},
-       {"UsesPictureSettings", ""},
-       {"VideoAvgBitrate", "video_bitrate"},
-       {"VideoEncoder", "video_codec"},
-       {"VideoFramerate", "framerate"},
-       {"VideoGrayScale", "grayscale"},
-       {"VideoQualitySlider", "video_quality"},
-       {"VideoTargetSize", "video_target_size"},
-       {"VideoTurboTwoPass", "turbo"},
-       {"VideoTwoPass", "two_pass"},
-       {"x264Option", "x264_options"},
-       {"Mp4LargeFile", "large_mp4"},
-       {"Mp4iPodCompatible", "ipod_file"},
-       {NULL, NULL}
-};
-
-// VideoQualityType/0/1/2 - vquality_type_/target/bitrate/constant
-// Audio1Bitrate - pref_audio_bitrate
-// Audio1Encoder - pref_audio_codec
-// Audio1Mixdown - pref_audio_mix
-// Audio1Samplerate - pref_audio_rate
-// Audio1Track - na
-// Audio1DRCSlider - pref_audio_drc
-
-static xlat_t values[] =
-{
-       {"AAC (faac)", "faac"},
-       {"AC3 Passthru", "ac3"},
-       {"H.264 (x264)", "x264"},
-       {"MPEG-4 (FFmpeg)", "x264"},
-       {"Dolby Pro Logic II", "dpl2"},
-       {"Auto", "auto"},
-       {"MKV file", "mkv"},
-       {"MP4 file", "mp4"},
-       {"None", "none"},
-       {"Same as source", "source"},
-       {"160", "160"},
-       {NULL, NULL}
-};
-
-static void
-store_key_file(GKeyFile *key_file, const gchar *name)
-{
-    gchar *settingsString;
-    gsize length;
-    gint fd;
-
-    settingsString = g_key_file_to_data(key_file, &length, NULL);
-
-    fd = g_open(name, O_RDWR|O_CREAT|O_TRUNC, 0777);
-    write(fd, settingsString, length);
-    close(fd);
-    g_free(settingsString);
+       count = ghb_array_len(mac_array);
+       for (ii = 0; ii < count; ii++)
+       {
+               mac_dict = ghb_array_get_nth(mac_array, ii);
+               
+               // Only process builtin types
+               if (ghb_value_int(ghb_dict_lookup(mac_dict, "Type")) != 0)
+                       continue;
+
+               lin_dict = ghb_dict_value_new();
+               ghb_array_append(lin_array, lin_dict);
+               gval = ghb_dict_lookup(mac_dict, "PresetName");
+               if (gval)
+               {
+                       ghb_dict_insert(lin_dict, g_strdup("PresetName"), 
+                                                       ghb_value_dup(gval));
+               }
+               gval = ghb_dict_lookup(mac_dict, "PresetDescription");
+               if (gval)
+               {
+                       ghb_dict_insert(lin_dict, g_strdup("PresetDescription"), 
+                                                       ghb_value_dup(gval));
+               }
+               gval = ghb_dict_lookup(mac_dict, "Folder");
+               if (gval && ghb_value_boolean(gval))
+               { // Folder
+                       GValue *mval, *lval;
+
+                       mval = ghb_dict_lookup(mac_dict, "ChildrenArray");
+                       lval = ghb_array_value_new(32);
+                       ghb_dict_insert(lin_dict, g_strdup("ChildrenArray"), lval);
+                       ghb_dict_insert(lin_dict, g_strdup("Folder"), 
+                                                       ghb_boolean_value_new(TRUE));
+                       ghb_dict_insert(lin_dict, g_strdup("Type"), 
+                                                       ghb_int_value_new(0));
+                       parse_preset_array(mval, lval);
+               }
+               else
+               { // Normal preset
+                       ghb_dict_insert(lin_dict, g_strdup("Type"), 
+                                                       ghb_int_value_new(0));
+                       parse_preset_dict(mac_dict, lin_dict);
+               }
+       }
 }
 
 static void
-parse_it(gchar *buf, gssize len)
+xlat(GValue *mac, GValue *lin)
 {
-       GMarkupParseContext *ctx;
-       GMarkupParser parser;
-       parse_data_t pd;
-
-       null_audio();
-       presets = g_key_file_new();
-       pd.state = START;
-       pd.key = NULL;
-       pd.value = NULL;
-       pd.preset = NULL;
-       pd.settings = g_hash_table_new_full(g_str_hash, g_str_equal, 
-                                                                         delete_key, delete_value);
-       pd.xlat_key = g_hash_table_new(g_str_hash, g_str_equal);
-       gint ii;
-       for (ii = 0; keys[ii].from != NULL; ii++)
-       {
-               g_hash_table_insert(pd.xlat_key, keys[ii].from, keys[ii].to);
-       }
-       pd.xlat_value = g_hash_table_new(g_str_hash, g_str_equal);
-       for (ii = 0; values[ii].from != NULL; ii++)
-       {
-               g_hash_table_insert(pd.xlat_value, values[ii].from, values[ii].to);
-       }
-       parser.start_element = start_element;
-       parser.end_element = end_element;
-       parser.text = text_data;
-       parser.passthrough = passthrough;
-       ctx = g_markup_parse_context_new(&parser, 0, &pd, NULL);
-       g_markup_parse_context_parse(ctx, buf, len, NULL);
-       store_key_file(presets, "xlat_presets");
+       return parse_preset_array(mac, lin);
 }
 
 gint
 main(gint argc, gchar *argv[])
 {
-       FILE *fd;
-       gchar buffer[BUF_SIZ];
-       size_t size;
+       GValue *mac_plist, *lin_plist;
+       GValue *internal;
 
-       fd = fopen(argv[1], "r");
-       size = fread(buffer, 1, BUF_SIZ, fd);
-       if (size >= BUF_SIZ)
+       if (argc < 3)
        {
-               g_error("buffer too small");
-               exit(1);
+               fprintf(stderr, "Usage: <mac plist> <lin plist>\n");
+               return 1;
        }
-       buffer[size] = 0;
-       parse_it(buffer, (gssize)size);
+       g_type_init();
+
+       ghb_register_transforms();
+       internal = ghb_plist_parse_file("internal_defaults.xml");
+       defaults = ghb_dict_lookup(internal, "Presets");
+       mac_plist = ghb_plist_parse_file(argv[1]);
+       lin_plist = ghb_array_value_new(32);
+       xlat(mac_plist, lin_plist);
+       ghb_plist_write_file(argv[2], lin_plist);
+       return 0;
 }