OSDN Git Service

LinGui: fix a couple problems with the preset translation tool
[handbrake-jp/handbrake-jp-git.git] / gtk / src / preset_xlat.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <glib.h>
4 #include <fcntl.h>
5
6 #define BUF_SIZ (128*1024)
7 #define IS_TAG(a,b)     (strcmp((a),(b)) == 0)
8 #define IS_KEY(a,b)     (strcmp((a),(b)) == 0)
9 #define IS_VAL(a,b)     (strcmp((a),(b)) == 0)
10
11 enum
12 {
13         NONE,
14         START,
15         ARRAY,
16         DICT,
17         KEY,
18         INT,
19         STR,
20         REAL,
21 };
22
23 typedef struct
24 {
25         gint state;
26         gchar *preset;
27         gchar *key;
28         gchar *value;
29         GHashTable *settings;
30         GHashTable *xlat_key;
31         GHashTable *xlat_value;
32 } parse_data_t;
33
34 static void
35 start_element(
36         GMarkupParseContext *ctx, 
37         const gchar *name, 
38         const gchar **attr_names,
39         const gchar **attr_values,
40         gpointer ud,
41         GError **error)
42 {
43         parse_data_t *pd = (parse_data_t*)ud;
44
45         if (IS_TAG(name, "array"))
46         {
47                 pd->state = ARRAY;
48         }
49         else if (IS_TAG(name, "dict"))
50         {
51                 g_hash_table_remove_all(pd->settings);
52                 pd->state = DICT;
53         }
54         else if (IS_TAG(name, "key"))
55         {
56                 pd->state = KEY;
57         }
58         else if (IS_TAG(name, "string"))
59         {
60                 pd->state = STR;
61         }
62         else if (IS_TAG(name, "integer"))
63         {
64                 pd->state = INT;
65         }
66         else if (IS_TAG(name, "real"))
67         {
68                 pd->state = REAL;
69         }
70         else
71         {
72                 g_debug("start unrecognized (%s)", name);
73         }
74 }
75
76 gchar *settings[] = 
77 {
78         "preset_description",
79         "subtitle_lang",
80         "forced_subtitles",
81         "source_audio_lang",
82         "pref_audio_codec",
83         "pref_audio_bitrate",
84         "pref_audio_rate",
85         "pref_audio_mix",
86         "pref_audio_drc",
87         "chapter_markers",
88         "container",
89         "ipod_file",
90         "large_mp4",
91         "autocrop",
92         "autoscale",
93         "max_width",
94         "max_height",
95         "anamorphic",
96         "round_dimensions",
97         "keep_aspect",
98         "detelecine",
99         "decomb",
100         "deinterlace",
101         "denoise",
102         "grayscale",
103         "deblock",
104         "video_codec",
105         "two_pass",
106         "turbo",
107         "constant_rate_factor",
108         "variable_frame_rate",
109         "framerate",
110         "vquality_type_constant",
111         "vquality_type_bitrate",
112         "vquality_type_target",
113         "video_bitrate",
114         "video_target_size",
115         "video_quality",
116         "x264_options",
117         "directqp",
118         NULL
119 };
120
121 static void
122 verify_keys(parse_data_t *pd)
123 {
124         GList *keys, *link;
125
126         link = keys = g_hash_table_get_keys(pd->settings);
127         while (link)
128         {
129                 gboolean found = FALSE;
130                 gchar *key = (gchar*)link->data;
131                 gint ii;
132                 for (ii = 0; settings[ii] != NULL; ii++)
133                 {
134                         if (IS_KEY(settings[ii], key))
135                         {
136                                 found = TRUE;
137                         }
138                 }
139                 if (!found)
140                 {
141                         g_message("bad key (%s)", key);
142                 }
143                 link = link->next;
144         }
145         g_list_free(keys);
146 }
147
148 GKeyFile *presets;
149
150 static void
151 save_preset(parse_data_t *pd)
152 {
153         gint ii;
154         if (pd->preset == NULL)
155         {
156                 g_message("failed to save preset");
157                 return;
158         }
159         for (ii = 0; settings[ii] != NULL; ii++)
160         {
161                 const gchar *value;
162                 value = (const gchar*)g_hash_table_lookup( pd->settings, settings[ii]);
163                 if (value)
164                 {
165                         g_key_file_set_value(presets, pd->preset, settings[ii], value);
166                 }
167         }
168         verify_keys(pd);
169 }
170
171 gchar *audio_track[2];
172 gchar *audio_enc[2];
173 gchar *audio_bitrate[2];
174 gchar *audio_rate[2];
175 gchar *audio_mix[2];
176 gchar *audio_drc[2];
177
178 static void
179 add_keys(parse_data_t *pd)
180 {
181         // These are needed to override default values that
182         // are not set in the xml file (yet)
183         const gchar *val;
184         // Check to see if its really not set. Future xml versions will set it.
185         val = (const gchar*)g_hash_table_lookup(pd->settings, "decomb");
186         if (!val)
187                 g_hash_table_insert(pd->settings, g_strdup("decomb"), g_strdup("0"));
188 }
189
190 static void
191 do_one(gchar **strs, GString *res)
192 {
193         gint ii;
194         for (ii = 0; ii < 2 && strs[ii]; ii++)
195         {
196                 if (audio_track[ii] == NULL) break;
197                 if (ii)
198                         g_string_append_c(res, ',');
199                 g_string_append_printf(res, "%s", strs[ii]);
200         }
201 }
202
203 static void
204 do_audio(parse_data_t *pd)
205 {
206         gint ii;
207         GString *enc, *br, *rate, *mix, *drc;
208         gchar *res;
209
210         enc = g_string_new("");
211         br = g_string_new("");
212         rate = g_string_new("");
213         mix = g_string_new("");
214         drc = g_string_new("");
215         do_one(audio_enc, enc);
216         do_one(audio_bitrate, br);
217         do_one(audio_rate, rate);
218         do_one(audio_mix, mix);
219         do_one(audio_drc, drc);
220         res = g_string_free(enc, FALSE);
221         g_hash_table_insert(pd->settings, g_strdup("pref_audio_codec"), res);
222         res = g_string_free(br, FALSE);
223         g_hash_table_insert(pd->settings, g_strdup("pref_audio_bitrate"), res);
224         res = g_string_free(rate, FALSE);
225         g_hash_table_insert(pd->settings, g_strdup("pref_audio_rate"), res);
226         res = g_string_free(mix, FALSE);
227         g_hash_table_insert(pd->settings, g_strdup("pref_audio_mix"), res);
228         res = g_string_free(drc, FALSE);
229         g_hash_table_insert(pd->settings, g_strdup("pref_audio_drc"), res);
230 }
231
232 static void
233 null_audio()
234 {
235         gint ii;
236         for (ii = 0; ii < 2; ii++)
237         {
238                 audio_track[ii] = NULL;
239                 audio_enc[ii] = NULL;
240                 audio_bitrate[ii] = NULL;
241                 audio_rate[ii] = NULL;
242                 audio_mix[ii] = NULL;
243                 audio_drc[ii] = NULL;
244         }
245 }
246
247 static void
248 clear_audio()
249 {
250         gint ii;
251         for (ii = 0; ii < 2; ii++)
252         {
253                 if (audio_track[ii]) g_free(audio_track[ii]);
254                 if (audio_enc[ii]) g_free(audio_enc[ii]);
255                 if (audio_bitrate[ii]) g_free(audio_bitrate[ii]);
256                 if (audio_rate[ii]) g_free(audio_rate[ii]);
257                 if (audio_mix[ii]) g_free(audio_mix[ii]);
258                 if (audio_drc[ii]) g_free(audio_drc[ii]);
259                 audio_track[ii] = NULL;
260                 audio_enc[ii] = NULL;
261                 audio_bitrate[ii] = NULL;
262                 audio_rate[ii] = NULL;
263                 audio_mix[ii] = NULL;
264                 audio_drc[ii] = NULL;
265         }
266 }
267
268 static void
269 end_element(
270         GMarkupParseContext *ctx, 
271         const gchar *name, 
272         gpointer ud,
273         GError **error)
274 {
275         parse_data_t *pd = (parse_data_t*)ud;
276
277         if (IS_TAG(name, "string") ||
278                 IS_TAG(name, "integer") ||
279                 IS_TAG(name, "real"))
280         {
281                 if (IS_KEY(pd->key, "PresetName"))
282                 {
283                         if (pd->preset)
284                         {
285                                 g_message("Preset named twice");
286                         }
287                         else
288                                 pd->preset = g_strdup(pd->value);
289                         pd->state = NONE;
290                         return;
291                 }
292                 const gchar *my_key;
293                 my_key = (const gchar*)g_hash_table_lookup(pd->xlat_key, pd->key);
294                 if (my_key != NULL)
295                 { // Do something with it
296                         if (my_key[0] != 0) // intentionally ignored keys
297                         {
298                                 if (pd->value != NULL)
299                                 {
300                                         g_hash_table_insert(pd->settings, 
301                                                 g_strdup(my_key), g_strdup(pd->value));
302                                 }
303                                 else
304                                 {
305                                         g_message("NULL value");
306                                 }
307                         }
308                 }
309                 else if (IS_KEY(pd->key, "Audio1Encoder"))
310                 {
311                         if (audio_enc[0]) g_free(audio_enc[0]);
312                         audio_enc[0] = g_strdup(pd->value);
313                 }
314                 else if (IS_KEY(pd->key, "Audio1Bitrate"))
315                 {
316                         if (audio_bitrate[0]) g_free(audio_bitrate[0]);
317                         audio_bitrate[0] = g_strdup(pd->value);
318                 }
319                 else if (IS_KEY(pd->key, "Audio1Samplerate"))
320                 {
321                         if (audio_rate[0]) g_free(audio_rate[0]);
322                         audio_rate[0] = g_strdup(pd->value);
323                 }
324                 else if (IS_KEY(pd->key, "Audio1Mixdown"))
325                 {
326                         if (audio_mix[0]) g_free(audio_mix[0]);
327                         audio_mix[0] = g_strdup(pd->value);
328                 }
329                 else if (IS_KEY(pd->key, "Audio1TrackDRCSlider"))
330                 {
331                         if (audio_drc[0]) g_free(audio_drc[0]);
332                         audio_drc[0] = g_strdup(pd->value);
333                 }
334                 else if (IS_KEY(pd->key, "Audio1Track"))
335                 {
336                         if (audio_track[0]) g_free(audio_track[0]);
337                         audio_track[0] = g_strdup(pd->value);
338                 }
339                 else if (IS_KEY(pd->key, "Audio2Encoder"))
340                 {
341                         if (audio_enc[1]) g_free(audio_enc[1]);
342                         audio_enc[1] = g_strdup(pd->value);
343                 }
344                 else if (IS_KEY(pd->key, "Audio2Bitrate"))
345                 {
346                         if (audio_bitrate[1]) g_free(audio_bitrate[1]);
347                         audio_bitrate[1] = g_strdup(pd->value);
348                 }
349                 else if (IS_KEY(pd->key, "Audio2Samplerate"))
350                 {
351                         if (audio_rate[1]) g_free(audio_rate[1]);
352                         audio_rate[1] = g_strdup(pd->value);
353                 }
354                 else if (IS_KEY(pd->key, "Audio2Mixdown"))
355                 {
356                         if (audio_mix[1]) g_free(audio_mix[1]);
357                         audio_mix[1] = g_strdup(pd->value);
358                 }
359                 else if (IS_KEY(pd->key, "Audio2TrackDRCSlider"))
360                 {
361                         if (audio_drc[1]) g_free(audio_drc[1]);
362                         audio_drc[1] = g_strdup(pd->value);
363                 }
364                 else if (IS_KEY(pd->key, "Audio2Track"))
365                 {
366                         if (audio_track[1]) g_free(audio_track[1]);
367                         audio_track[1] = g_strdup(pd->value);
368                 }
369                 else if (IS_KEY(pd->key, "VideoQualityType"))
370                 {
371                         // VideoQualityType/0/1/2 - vquality_type_/target/bitrate/constant
372                         if (IS_VAL(pd->value, "0"))
373                         {
374                                 g_hash_table_insert(pd->settings, 
375                                                 g_strdup("vquality_type_target"), 
376                                                 g_strdup("1"));
377                                 g_hash_table_remove(pd->settings, "vquality_type_bitrate");
378                                 g_hash_table_remove(pd->settings, "vquality_type_constant");
379                         }
380                         else if (IS_VAL(pd->value, "1"))
381                         {
382                                 g_hash_table_remove(pd->settings, "vquality_type_target");
383                                 g_hash_table_insert(pd->settings, 
384                                                 g_strdup("vquality_type_bitrate"), 
385                                                 g_strdup("1"));
386                                 g_hash_table_remove(pd->settings, "vquality_type_constant");
387                         }
388                         else if (IS_VAL(pd->value, "2"))
389                         {
390                                 g_hash_table_remove(pd->settings, "vquality_type_target");
391                                 g_hash_table_remove(pd->settings, "vquality_type_bitrate");
392                                 g_hash_table_insert(pd->settings, 
393                                                 g_strdup("vquality_type_constant"), 
394                                                 g_strdup("1"));
395                         }
396                 }
397                 else
398                 {
399                         g_message("Key not found (%s)", pd->key);
400                 }
401         }
402         else if (IS_TAG(name, "dict"))
403         {
404                 gint ii;
405                 add_keys(pd);
406                 do_audio(pd);
407                 clear_audio();
408                 save_preset(pd);
409
410                 if (pd->preset) 
411                 {
412                         g_free(pd->preset);
413                         pd->preset = NULL;
414                 }
415                 else
416                         g_message("Preset has no name");
417                 g_hash_table_remove_all(pd->settings);
418         }
419         pd->state = NONE;
420 }
421
422 static gboolean
423 is_number(const gchar *str)
424 {
425         gboolean result = TRUE;
426         gint ii;
427         for (ii = 0; str[ii] != 0; ii++)
428         {
429                 if (!g_ascii_isdigit(str[ii]) && str[ii] != '.')
430                         result = FALSE;
431         }
432         return result;
433 }
434
435 static void
436 text_data(
437         GMarkupParseContext *ctx, 
438         const gchar *text, 
439         gsize len,
440         gpointer ud,
441         GError **error)
442 {
443         gboolean is_value = FALSE;
444         parse_data_t *pd = (parse_data_t*)ud;
445         const gchar *val = NULL;
446
447         if (pd->state == KEY)
448         {
449                 if (pd->key) g_free(pd->key);
450                 pd->key = g_strdup(text);
451                 return;
452         }
453         if (pd->state == STR)
454         {
455                 val = (gchar*)g_hash_table_lookup(pd->xlat_value, text);
456                 if (val != NULL)
457                 { // Do something with it
458                 }
459                 else if (IS_KEY(pd->key, "PresetName") ||
460                                 IS_KEY(pd->key, "PresetDescription") ||
461                                 IS_KEY(pd->key, "x264Option") ||
462                                 is_number(text))
463                 {
464                         val = text;
465                 }
466                 else
467                 {
468                         g_message("Unrecognized val (%s)", text);
469                 }
470         }
471         if (pd->state == INT || pd->state == REAL)
472         {
473                 val = text;
474         }
475
476         // Some keys need further translation of their values
477         if (val)
478         {
479                 if (IS_KEY(pd->key, "PictureDeinterlace"))
480                 {
481                         if (IS_VAL(val, "0"))
482                         {
483                                 val = "none";
484                         }
485                         else if (IS_VAL(val, "1"))
486                         {
487                                 val = "fast";
488                         }
489                         else if (IS_VAL(val, "2"))
490                         {
491                                 val = "slow";
492                         }
493                         else if (IS_VAL(val, "3"))
494                         {
495                                 val = "slower";
496                         }
497                 }
498                 else if (IS_KEY(pd->key, "VideoQualitySlider"))
499                 {
500                         gdouble dval;
501                         dval = g_strtod(val, NULL);
502                         dval *= 100;
503                         if (pd->value) g_free(pd->value);
504                         pd->value = g_strdup_printf("%d", (gint)dval);
505                         return;
506                 }
507                 else if (IS_KEY(pd->key, "Audio1Samplerate") ||
508                                 IS_KEY(pd->key, "Audio2Samplerate"))
509                 {
510                         if (IS_VAL(val, "auto"))
511                         {
512                                 val = "source";
513                         }
514                 }
515                 else if (IS_KEY(pd->key, "Audio1Mixdown") ||
516                                 IS_KEY(pd->key, "Audio2Mixdown"))
517                 {
518                         if (IS_VAL(val, "ac3"))
519                         {
520                                 val = "none";
521                         }
522                 }
523                 if (pd->value) g_free(pd->value);
524                 pd->value = g_strdup(val);
525         }
526 }
527
528 static void
529 passthrough(
530         GMarkupParseContext *ctx, 
531         const gchar *text, 
532         gsize len,
533         gpointer ud,
534         GError **error)
535 {
536         parse_data_t *pd = (parse_data_t*)ud;
537
538         g_debug("passthrough %s", text);
539 }
540
541 static void
542 delete_key(gpointer str)
543 {
544         g_free(str);
545 }
546
547 static void
548 delete_value(gpointer str)
549 {
550         g_free(str);
551 }
552
553 typedef struct
554 {
555         gchar *from;
556         gchar *to;
557 } xlat_t;
558
559 static xlat_t keys[] =
560 {
561         {"VFR", "variable_frame_rate"},
562         {"ChapterMarkers", "chapter_markers"},
563         {"Default", ""},
564         {"FileFormat", "container"},
565         {"PictureAutoCrop", "autocrop"},
566         {"PictureBottomCrop", ""},
567         {"PictureTopCrop", ""},
568         {"PictureLeftCrop", ""},
569         {"PictureRightCrop", ""},
570         {"PictureDeblock", "deblock"},
571         {"PictureDeinterlace", "deinterlace"}, // v
572         {"PictureDenoise", "denoise"}, // v
573         {"PictureDetelecine", "detelecine"},
574         {"PictureHeight", "max_height"},
575         {"PictureWidth", "max_width"},
576         {"PictureKeepRatio", "keep_aspect"},
577         {"PicturePAR", "anamorphic"}, // v
578         {"PresetDescription", "preset_description"},
579         {"Subtitles", "subtitle_lang"},
580         {"Subtitles", "subtitle_lang"},
581         {"Type", ""}, // preset type builtin/custom
582         {"UsesMaxPictureSettings", "autoscale"},
583         {"UsesPictureFilters", ""},
584         {"UsesPictureSettings", ""},
585         {"VideoAvgBitrate", "video_bitrate"},
586         {"VideoEncoder", "video_codec"},
587         {"VideoFramerate", "framerate"},
588         {"VideoGrayScale", "grayscale"},
589         {"VideoQualitySlider", "video_quality"},
590         {"VideoTargetSize", "video_target_size"},
591         {"VideoTurboTwoPass", "turbo"},
592         {"VideoTwoPass", "two_pass"},
593         {"x264Option", "x264_options"},
594         {"Mp4LargeFile", "large_mp4"},
595         {"Mp4iPodCompatible", "ipod_file"},
596         {NULL, NULL}
597 };
598
599 // VideoQualityType/0/1/2 - vquality_type_/target/bitrate/constant
600 // Audio1Bitrate - pref_audio_bitrate
601 // Audio1Encoder - pref_audio_codec
602 // Audio1Mixdown - pref_audio_mix
603 // Audio1Samplerate - pref_audio_rate
604 // Audio1Track - na
605 // Audio1DRCSlider - pref_audio_drc
606
607 static xlat_t values[] =
608 {
609         {"AAC (faac)", "faac"},
610         {"AC3 Passthru", "ac3"},
611         {"H.264 (x264)", "x264"},
612         {"MPEG-4 (FFmpeg)", "ffmpeg"},
613         {"Dolby Pro Logic II", "dpl2"},
614         {"Auto", "auto"},
615         {"MKV file", "mkv"},
616         {"MP4 file", "mp4"},
617         {"None", "none"},
618         {"Same as source", "source"},
619         {"160", "160"},
620         {NULL, NULL}
621 };
622
623 static void
624 store_key_file(GKeyFile *key_file, const gchar *name)
625 {
626     gchar *settingsString;
627     gsize length;
628     gint fd;
629
630     settingsString = g_key_file_to_data(key_file, &length, NULL);
631
632     fd = g_open(name, O_RDWR|O_CREAT|O_TRUNC, 0777);
633     write(fd, settingsString, length);
634     close(fd);
635     g_free(settingsString);
636 }
637
638 static void
639 parse_it(gchar *buf, gssize len)
640 {
641         GMarkupParseContext *ctx;
642         GMarkupParser parser;
643         parse_data_t pd;
644
645         null_audio();
646         presets = g_key_file_new();
647         pd.state = START;
648         pd.key = NULL;
649         pd.value = NULL;
650         pd.preset = NULL;
651         pd.settings = g_hash_table_new_full(g_str_hash, g_str_equal, 
652                                                                           delete_key, delete_value);
653         pd.xlat_key = g_hash_table_new(g_str_hash, g_str_equal);
654         gint ii;
655         for (ii = 0; keys[ii].from != NULL; ii++)
656         {
657                 g_hash_table_insert(pd.xlat_key, keys[ii].from, keys[ii].to);
658         }
659         pd.xlat_value = g_hash_table_new(g_str_hash, g_str_equal);
660         for (ii = 0; values[ii].from != NULL; ii++)
661         {
662                 g_hash_table_insert(pd.xlat_value, values[ii].from, values[ii].to);
663         }
664         parser.start_element = start_element;
665         parser.end_element = end_element;
666         parser.text = text_data;
667         parser.passthrough = passthrough;
668         ctx = g_markup_parse_context_new(&parser, 0, &pd, NULL);
669         g_markup_parse_context_parse(ctx, buf, len, NULL);
670         store_key_file(presets, "xlat_presets");
671 }
672
673 gint
674 main(gint argc, gchar *argv[])
675 {
676         FILE *fd;
677         gchar buffer[BUF_SIZ];
678         size_t size;
679
680         fd = fopen(argv[1], "r");
681         size = fread(buffer, 1, BUF_SIZ, fd);
682         if (size >= BUF_SIZ)
683         {
684                 g_error("buffer too small");
685                 exit(1);
686         }
687         buffer[size] = 0;
688         parse_it(buffer, (gssize)size);
689 }
690