OSDN Git Service

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