OSDN Git Service

10a5630746ca3f47738d71eaf78f258f8316e865
[handbrake-jp/handbrake-jp-git.git] / gtk / src / hb-backend.c
1 /***************************************************************************
2  *            hb-backend.c
3  *
4  *  Fri Mar 28 10:38:44 2008
5  *  Copyright  2008  John Stebbins
6  *  <john at stebbins dot name>
7  ****************************************************************************/
8
9 /*
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Library General Public License for more details.
19  * 
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
23  */
24 #define _GNU_SOURCE
25 #include <limits.h>
26 #include <math.h>
27 #include "hb.h"
28 #include <gtk/gtk.h>
29 #include <glib/gstdio.h>
30 #include "hb-backend.h"
31 #include "settings.h"
32 #include "callbacks.h"
33 #include "preview.h"
34 #include "values.h"
35 #include "lang.h"
36
37 typedef struct
38 {
39         const gchar *option;
40         const gchar *shortOpt;
41         gdouble ivalue;
42         const gchar *svalue;
43 } options_map_t;
44
45 typedef struct
46 {
47         gint count;
48         options_map_t *map;
49 } combo_opts_t;
50
51 static const gchar *index_str[] =
52 {
53         "0",
54         "1",
55         "2",
56         "3",
57         "4",
58         "5",
59         "6",
60         "7",
61         "8",
62         "9",
63         "10",
64 };
65
66 static options_map_t d_par_opts[] =
67 {
68         {"Off", "0", 0, "0"},
69         {"Strict", "1", 1, "1"},
70         {"Loose", "2", 2, "2"},
71         {"Custom", "3", 3, "3"},
72 };
73 combo_opts_t par_opts =
74 {
75         sizeof(d_par_opts)/sizeof(options_map_t),
76         d_par_opts
77 };
78
79 static options_map_t d_alignment_opts[] =
80 {
81         {"2", "2", 2, "2"},
82         {"4", "4", 4, "4"},
83         {"8", "8", 8, "8"},
84         {"16", "16", 16, "16"},
85 };
86 combo_opts_t alignment_opts =
87 {
88         sizeof(d_alignment_opts)/sizeof(options_map_t),
89         d_alignment_opts
90 };
91
92 static options_map_t d_logging_opts[] =
93 {
94         {"0", "0", 0, "0"},
95         {"1", "1", 1, "1"},
96         {"2", "2", 2, "2"},
97 };
98 combo_opts_t logging_opts =
99 {
100         sizeof(d_logging_opts)/sizeof(options_map_t),
101         d_logging_opts
102 };
103
104 static options_map_t d_vqual_granularity_opts[] =
105 {
106         {"0.2",  "0.2",  0.2,  "0.2"},
107         {"0.25", "0.25", 0.25, "0.25"},
108         {"0.5",  "0.5",  0.5,  "0.5"},
109         {"1",    "1",    1,    "1"},
110 };
111 combo_opts_t vqual_granularity_opts =
112 {
113         sizeof(d_vqual_granularity_opts)/sizeof(options_map_t),
114         d_vqual_granularity_opts
115 };
116
117 static options_map_t d_container_opts[] =
118 {
119         {"MKV", "mkv", HB_MUX_MKV, "mkv"},
120         {"MP4", "mp4", HB_MUX_MP4, "mp4"},
121         {"M4V", "m4v", HB_MUX_MP4, "m4v"},
122 };
123 combo_opts_t container_opts =
124 {
125         sizeof(d_container_opts)/sizeof(options_map_t),
126         d_container_opts
127 };
128
129 static options_map_t d_detel_opts[] =
130 {
131         {"None",   "none",   0, ""},
132         {"Custom", "custom", 1, ""},
133         {"Default","default",2, NULL},
134 };
135 combo_opts_t detel_opts =
136 {
137         sizeof(d_detel_opts)/sizeof(options_map_t),
138         d_detel_opts
139 };
140
141 static options_map_t d_decomb_opts[] =
142 {
143         {"None",   "none",   0, ""},
144         {"Custom", "custom", 1, ""},
145         {"Default","default",2, NULL},
146 };
147 combo_opts_t decomb_opts =
148 {
149         sizeof(d_decomb_opts)/sizeof(options_map_t),
150         d_decomb_opts
151 };
152
153 static options_map_t d_deint_opts[] =
154 {
155         {"None",   "none",   0, ""},
156         {"Custom", "custom", 1, ""},
157         {"Fast",   "fast",   2, "-1:-1:-1:0:1"},
158         {"Slow",   "slow",   3, "2:-1:-1:0:1"},
159         {"Slower", "slower", 4, "0:-1:-1:0:1"},
160 };
161 combo_opts_t deint_opts =
162 {
163         sizeof(d_deint_opts)/sizeof(options_map_t),
164         d_deint_opts
165 };
166
167 static options_map_t d_denoise_opts[] =
168 {
169         {"None",   "none",   0, ""},
170         {"Custom", "custom", 1, ""},
171         {"Weak",   "weak",   2, "2:1:2:3"},
172         {"Medium", "medium", 3, "3:2:2:3"},
173         {"Strong", "strong", 4, "7:7:5:5"},
174 };
175 combo_opts_t denoise_opts =
176 {
177         sizeof(d_denoise_opts)/sizeof(options_map_t),
178         d_denoise_opts
179 };
180
181 static options_map_t d_vcodec_opts[] =
182 {
183         {"H.264 (x264)",    "x264",   HB_VCODEC_X264, ""},
184         {"MPEG-4 (FFMPEG)", "ffmpeg", HB_VCODEC_FFMPEG, ""},
185         {"Theora",          "theora", HB_VCODEC_THEORA, ""},
186 };
187 combo_opts_t vcodec_opts =
188 {
189         sizeof(d_vcodec_opts)/sizeof(options_map_t),
190         d_vcodec_opts
191 };
192
193 static options_map_t d_acodec_opts[] =
194 {
195         {"AAC (faac)",      "faac",   HB_ACODEC_FAAC, "faac"},
196         {"MP3 (lame)",      "lame",   HB_ACODEC_LAME, "lame"},
197         {"Vorbis",          "vorbis", HB_ACODEC_VORBIS, "vorbis"},
198         {"AC3 (pass-thru)", "ac3",    HB_ACODEC_AC3, "ac3"},
199         {"DTS (pass-thru)", "dts",    HB_ACODEC_DCA, "dts"},
200         {"Auto Pass-Thru", "auto",    HB_ACODEC_DCA|HB_ACODEC_AC3, "auto"},
201 };
202 combo_opts_t acodec_opts =
203 {
204         sizeof(d_acodec_opts)/sizeof(options_map_t),
205         d_acodec_opts
206 };
207
208 static options_map_t d_direct_opts[] =
209 {
210         {"None",      "none",     0, "none"},
211         {"Spatial",   "spatial",  1, "spatial"},
212         {"Temporal",  "temporal", 2, "temporal"},
213         {"Automatic", "auto",     3, "auto"},
214 };
215 combo_opts_t direct_opts =
216 {
217         sizeof(d_direct_opts)/sizeof(options_map_t),
218         d_direct_opts
219 };
220
221 static options_map_t d_badapt_opts[] =
222 {
223         {"Off",             "0", 0, "0"},
224         {"Fast",            "1", 1, "1"},
225         {"Optimal",         "2", 2, "2"},
226 };
227 combo_opts_t badapt_opts =
228 {
229         sizeof(d_badapt_opts)/sizeof(options_map_t),
230         d_badapt_opts
231 };
232
233 static options_map_t d_me_opts[] =
234 {
235         {"Diamond",              "dia",  0, "dia"},
236         {"Hexagon",              "hex",  1, "hex"},
237         {"Uneven Multi-Hexagon", "umh",  2, "umh"},
238         {"Exhaustive",           "esa",  3, "esa"},
239         {"Hadamard Exhaustive",  "tesa", 4, "tesa"},
240 };
241 combo_opts_t me_opts =
242 {
243         sizeof(d_me_opts)/sizeof(options_map_t),
244         d_me_opts
245 };
246
247 static options_map_t d_subme_opts[] =
248 {
249         {"1", "1", 1, "1"},
250         {"2", "2", 2, "2"},
251         {"3", "3", 3, "3"},
252         {"4", "4", 4, "4"},
253         {"5", "5", 5, "5"},
254         {"6", "6", 6, "6"},
255         {"7", "7", 7, "7"},
256         {"8", "8", 8, "8"},
257         {"9", "9", 9, "9"},
258 };
259 combo_opts_t subme_opts =
260 {
261         sizeof(d_subme_opts)/sizeof(options_map_t),
262         d_subme_opts
263 };
264
265 static options_map_t d_analyse_opts[] =
266 {
267         {"Some", "some", 0, "some"},
268         {"None", "none", 1, "none"},
269         {"All",  "all",  2, "all"},
270         {"Custom",  "custom",  3, "all"},
271 };
272 combo_opts_t analyse_opts =
273 {
274         sizeof(d_analyse_opts)/sizeof(options_map_t),
275         d_analyse_opts
276 };
277
278 static options_map_t d_trellis_opts[] =
279 {
280         {"Disabled",          "0", 0, "0"},
281         {"Final Macro Block", "1", 1, "1"},
282         {"Always",            "2", 2, "2"},
283 };
284 combo_opts_t trellis_opts =
285 {
286         sizeof(d_trellis_opts)/sizeof(options_map_t),
287         d_trellis_opts
288 };
289
290 combo_opts_t subtitle_opts =
291 {
292         0,
293         NULL
294 };
295
296 combo_opts_t title_opts =
297 {
298         0,
299         NULL
300 };
301
302 combo_opts_t audio_track_opts =
303 {
304         0,
305         NULL
306 };
307
308 typedef struct
309 {
310         const gchar *name;
311         combo_opts_t *opts;
312 } combo_name_map_t;
313
314 combo_name_map_t combo_name_map[] =
315 {
316         {"PicturePAR", &par_opts},
317         {"PictureModulus", &alignment_opts},
318         {"LoggingLevel", &logging_opts},
319         {"VideoQualityGranularity", &vqual_granularity_opts},
320         {"FileFormat", &container_opts},
321         {"PictureDeinterlace", &deint_opts},
322         {"PictureDecomb", &decomb_opts},
323         {"PictureDetelecine", &detel_opts},
324         {"PictureDenoise", &denoise_opts},
325         {"VideoEncoder", &vcodec_opts},
326         {"AudioEncoder", &acodec_opts},
327         {"x264_direct", &direct_opts},
328         {"x264_b_adapt", &badapt_opts},
329         {"x264_me", &me_opts},
330         {"x264_subme", &subme_opts},
331         {"x264_analyse", &analyse_opts},
332         {"x264_trellis", &trellis_opts},
333         {"Subtitles", &subtitle_opts},
334         {"title", &title_opts},
335         {"AudioTrack", &audio_track_opts},
336         {NULL, NULL}
337 };
338
339 #if 0
340 typedef struct iso639_lang_t
341 {
342     char * eng_name;        /* Description in English */
343     char * native_name;     /* Description in native language */
344     char * iso639_1;       /* ISO-639-1 (2 characters) code */
345     char * iso639_2;        /* ISO-639-2/t (3 character) code */
346     char * iso639_2b;       /* ISO-639-2/b code (if different from above) */
347 } iso639_lang_t;
348 #endif
349
350 const iso639_lang_t ghb_language_table[] =
351
352         { "Any", "", "zz", "und" },
353         { "Afar", "", "aa", "aar" },
354         { "Abkhazian", "", "ab", "abk" },
355         { "Afrikaans", "", "af", "afr" },
356         { "Akan", "", "ak", "aka" },
357         { "Albanian", "", "sq", "sqi", "alb" },
358         { "Amharic", "", "am", "amh" },
359         { "Arabic", "", "ar", "ara" },
360         { "Aragonese", "", "an", "arg" },
361         { "Armenian", "", "hy", "hye", "arm" },
362         { "Assamese", "", "as", "asm" },
363         { "Avaric", "", "av", "ava" },
364         { "Avestan", "", "ae", "ave" },
365         { "Aymara", "", "ay", "aym" },
366         { "Azerbaijani", "", "az", "aze" },
367         { "Bashkir", "", "ba", "bak" },
368         { "Bambara", "", "bm", "bam" },
369         { "Basque", "", "eu", "eus", "baq" },
370         { "Belarusian", "", "be", "bel" },
371         { "Bengali", "", "bn", "ben" },
372         { "Bihari", "", "bh", "bih" },
373         { "Bislama", "", "bi", "bis" },
374         { "Bosnian", "", "bs", "bos" },
375         { "Breton", "", "br", "bre" },
376         { "Bulgarian", "", "bg", "bul" },
377         { "Burmese", "", "my", "mya", "bur" },
378         { "Catalan", "", "ca", "cat" },
379         { "Chamorro", "", "ch", "cha" },
380         { "Chechen", "", "ce", "che" },
381         { "Chinese", "", "zh", "zho", "chi" },
382         { "Church Slavic", "", "cu", "chu" },
383         { "Chuvash", "", "cv", "chv" },
384         { "Cornish", "", "kw", "cor" },
385         { "Corsican", "", "co", "cos" },
386         { "Cree", "", "cr", "cre" },
387         { "Czech", "", "cs", "ces", "cze" },
388         { "Danish", "Dansk", "da", "dan" },
389         { "Divehi", "", "dv", "div" },
390         { "Dutch", "Nederlands", "nl", "nld", "dut" },
391         { "Dzongkha", "", "dz", "dzo" },
392         { "English", "English", "en", "eng" },
393         { "Esperanto", "", "eo", "epo" },
394         { "Estonian", "", "et", "est" },
395         { "Ewe", "", "ee", "ewe" },
396         { "Faroese", "", "fo", "fao" },
397         { "Fijian", "", "fj", "fij" },
398         { "Finnish", "Suomi", "fi", "fin" },
399         { "French", "Francais", "fr", "fra", "fre" },
400         { "Western Frisian", "", "fy", "fry" },
401         { "Fulah", "", "ff", "ful" },
402         { "Georgian", "", "ka", "kat", "geo" },
403         { "German", "Deutsch", "de", "deu", "ger" },
404         { "Gaelic (Scots)", "", "gd", "gla" },
405         { "Irish", "", "ga", "gle" },
406         { "Galician", "", "gl", "glg" },
407         { "Manx", "", "gv", "glv" },
408         { "Greek, Modern", "", "el", "ell", "gre" },
409         { "Guarani", "", "gn", "grn" },
410         { "Gujarati", "", "gu", "guj" },
411         { "Haitian", "", "ht", "hat" },
412         { "Hausa", "", "ha", "hau" },
413         { "Hebrew", "", "he", "heb" },
414         { "Herero", "", "hz", "her" },
415         { "Hindi", "", "hi", "hin" },
416         { "Hiri Motu", "", "ho", "hmo" },
417         { "Hungarian", "Magyar", "hu", "hun" },
418         { "Igbo", "", "ig", "ibo" },
419         { "Icelandic", "Islenska", "is", "isl", "ice" },
420         { "Ido", "", "io", "ido" },
421         { "Sichuan Yi", "", "ii", "iii" },
422         { "Inuktitut", "", "iu", "iku" },
423         { "Interlingue", "", "ie", "ile" },
424         { "Interlingua", "", "ia", "ina" },
425         { "Indonesian", "", "id", "ind" },
426         { "Inupiaq", "", "ik", "ipk" },
427         { "Italian", "Italiano", "it", "ita" },
428         { "Javanese", "", "jv", "jav" },
429         { "Japanese", "", "ja", "jpn" },
430         { "Kalaallisut", "", "kl", "kal" },
431         { "Kannada", "", "kn", "kan" },
432         { "Kashmiri", "", "ks", "kas" },
433         { "Kanuri", "", "kr", "kau" },
434         { "Kazakh", "", "kk", "kaz" },
435         { "Central Khmer", "", "km", "khm" },
436         { "Kikuyu", "", "ki", "kik" },
437         { "Kinyarwanda", "", "rw", "kin" },
438         { "Kirghiz", "", "ky", "kir" },
439         { "Komi", "", "kv", "kom" },
440         { "Kongo", "", "kg", "kon" },
441         { "Korean", "", "ko", "kor" },
442         { "Kuanyama", "", "kj", "kua" },
443         { "Kurdish", "", "ku", "kur" },
444         { "Lao", "", "lo", "lao" },
445         { "Latin", "", "la", "lat" },
446         { "Latvian", "", "lv", "lav" },
447         { "Limburgan", "", "li", "lim" },
448         { "Lingala", "", "ln", "lin" },
449         { "Lithuanian", "", "lt", "lit" },
450         { "Luxembourgish", "", "lb", "ltz" },
451         { "Luba-Katanga", "", "lu", "lub" },
452         { "Ganda", "", "lg", "lug" },
453         { "Macedonian", "", "mk", "mkd", "mac" },
454         { "Marshallese", "", "mh", "mah" },
455         { "Malayalam", "", "ml", "mal" },
456         { "Maori", "", "mi", "mri", "mao" },
457         { "Marathi", "", "mr", "mar" },
458         { "Malay", "", "ms", "msa", "msa" },
459         { "Malagasy", "", "mg", "mlg" },
460         { "Maltese", "", "mt", "mlt" },
461         { "Moldavian", "", "mo", "mol" },
462         { "Mongolian", "", "mn", "mon" },
463         { "Nauru", "", "na", "nau" },
464         { "Navajo", "", "nv", "nav" },
465         { "Ndebele, South", "", "nr", "nbl" },
466         { "Ndebele, North", "", "nd", "nde" },
467         { "Ndonga", "", "ng", "ndo" },
468         { "Nepali", "", "ne", "nep" },
469         { "Norwegian Nynorsk", "", "nn", "nno" },
470         { "Norwegian Bokmål", "", "nb", "nob" },
471         { "Norwegian", "Norsk", "no", "nor" },
472         { "Chichewa; Nyanja", "", "ny", "nya" },
473         { "Occitan", "", "oc", "oci" },
474         { "Ojibwa", "", "oj", "oji" },
475         { "Oriya", "", "or", "ori" },
476         { "Oromo", "", "om", "orm" },
477         { "Ossetian", "", "os", "oss" },
478         { "Panjabi", "", "pa", "pan" },
479         { "Persian", "", "fa", "fas", "per" },
480         { "Pali", "", "pi", "pli" },
481         { "Polish", "", "pl", "pol" },
482         { "Portuguese", "Portugues", "pt", "por" },
483         { "Pushto", "", "ps", "pus" },
484         { "Quechua", "", "qu", "que" },
485         { "Romansh", "", "rm", "roh" },
486         { "Romanian", "", "ro", "ron", "rum" },
487         { "Rundi", "", "rn", "run" },
488         { "Russian", "", "ru", "rus" },
489         { "Sango", "", "sg", "sag" },
490         { "Sanskrit", "", "sa", "san" },
491         { "Serbian", "", "sr", "srp", "scc" },
492         { "Croatian", "Hrvatski", "hr", "hrv", "scr" },
493         { "Sinhala", "", "si", "sin" },
494         { "Slovak", "", "sk", "slk", "slo" },
495         { "Slovenian", "", "sl", "slv" },
496         { "Northern Sami", "", "se", "sme" },
497         { "Samoan", "", "sm", "smo" },
498         { "Shona", "", "sn", "sna" },
499         { "Sindhi", "", "sd", "snd" },
500         { "Somali", "", "so", "som" },
501         { "Sotho, Southern", "", "st", "sot" },
502         { "Spanish", "Espanol", "es", "spa" },
503         { "Sardinian", "", "sc", "srd" },
504         { "Swati", "", "ss", "ssw" },
505         { "Sundanese", "", "su", "sun" },
506         { "Swahili", "", "sw", "swa" },
507         { "Swedish", "Svenska", "sv", "swe" },
508         { "Tahitian", "", "ty", "tah" },
509         { "Tamil", "", "ta", "tam" },
510         { "Tatar", "", "tt", "tat" },
511         { "Telugu", "", "te", "tel" },
512         { "Tajik", "", "tg", "tgk" },
513         { "Tagalog", "", "tl", "tgl" },
514         { "Thai", "", "th", "tha" },
515         { "Tibetan", "", "bo", "bod", "tib" },
516         { "Tigrinya", "", "ti", "tir" },
517         { "Tonga", "", "to", "ton" },
518         { "Tswana", "", "tn", "tsn" },
519         { "Tsonga", "", "ts", "tso" },
520         { "Turkmen", "", "tk", "tuk" },
521         { "Turkish", "", "tr", "tur" },
522         { "Twi", "", "tw", "twi" },
523         { "Uighur", "", "ug", "uig" },
524         { "Ukrainian", "", "uk", "ukr" },
525         { "Urdu", "", "ur", "urd" },
526         { "Uzbek", "", "uz", "uzb" },
527         { "Venda", "", "ve", "ven" },
528         { "Vietnamese", "", "vi", "vie" },
529         { "Volapük", "", "vo", "vol" },
530         { "Welsh", "", "cy", "cym", "wel" },
531         { "Walloon", "", "wa", "wln" },
532         { "Wolof", "", "wo", "wol" },
533         { "Xhosa", "", "xh", "xho" },
534         { "Yiddish", "", "yi", "yid" },
535         { "Yoruba", "", "yo", "yor" },
536         { "Zhuang", "", "za", "zha" },
537         { "Zulu", "", "zu", "zul" },
538         {NULL, NULL, NULL, NULL}
539 };
540 #define LANG_TABLE_SIZE (sizeof(ghb_language_table)/ sizeof(iso639_lang_t)-1)
541
542 static void audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name);
543
544 static void
545 del_tree(const gchar *name, gboolean del_top)
546 {
547         const gchar *file;
548
549         if (g_file_test(name, G_FILE_TEST_IS_DIR))
550         {
551                 GDir *gdir = g_dir_open(name, 0, NULL);
552                 file = g_dir_read_name(gdir);
553                 while (file)
554                 {
555                         gchar *path;
556                         path = g_strdup_printf("%s/%s", name, file);
557                         del_tree(path, TRUE);
558                         g_free(path);
559                         file = g_dir_read_name(gdir);
560                 }
561                 if (del_top)
562                         g_rmdir(name);
563                 g_dir_close(gdir);
564         }
565         else
566         {
567                 g_unlink(name);
568         }
569 }
570
571 const gchar*
572 ghb_version()
573 {
574         return hb_get_version(NULL);
575 }
576
577 void
578 ghb_vquality_range(
579         signal_user_data_t *ud, 
580         gdouble *min, 
581         gdouble *max,
582         gdouble *step,
583         gdouble *page,
584         gint *digits,
585         gboolean *inverted)
586 {
587         gint vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
588         *page = 10;
589         *digits = 0;
590         switch (vcodec)
591         {
592                 case HB_VCODEC_X264:
593                 {
594                         *min = 0;
595                         *max = 51;
596                         *step = ghb_settings_combo_double(ud->settings, 
597                                                                                         "VideoQualityGranularity");
598                         if (*step == 0.2 || *step == 0.5)
599                                 *digits = 1;
600                         else if (*step == 0.25)
601                                 *digits = 2;
602                         *inverted = TRUE;
603                 } break;
604
605                 case HB_VCODEC_XVID:
606                 case HB_VCODEC_FFMPEG:
607                 {
608                         *min = 1;
609                         *max = 31;
610                         *step = 1;
611                         *inverted = TRUE;
612                 } break;
613
614                 case HB_VCODEC_THEORA:
615                 {
616                         *min = 0;
617                         *max = 63;
618                         *step = 1;
619                         *inverted = FALSE;
620                 } break;
621
622                 default:
623                 {
624                         *min = 0;
625                         *max = 100;
626                         *step = 1;
627                         *inverted = FALSE;
628                 } break;
629         }
630 }
631
632 static gint
633 lookup_generic_int(combo_opts_t *opts, const GValue *gval)
634 {
635         gint ii;
636         gchar *str;
637         gint result = -1;
638
639         str = ghb_value_string(gval);
640         for (ii = 0; ii < opts->count; ii++)
641         {
642                 if (strcmp(opts->map[ii].shortOpt, str) == 0)
643                 {
644                         result = opts->map[ii].ivalue;
645                         break;
646                 }
647         }
648         g_free(str);
649         return result;
650 }
651
652 static gdouble
653 lookup_generic_double(combo_opts_t *opts, const GValue *gval)
654 {
655         gint ii;
656         gchar *str;
657         gdouble result = -1;
658
659         str = ghb_value_string(gval);
660         for (ii = 0; ii < opts->count; ii++)
661         {
662                 if (strcmp(opts->map[ii].shortOpt, str) == 0)
663                 {
664                         result = opts->map[ii].ivalue;
665                         break;
666                 }
667         }
668         g_free(str);
669         return result;
670 }
671
672 static const gchar*
673 lookup_generic_option(combo_opts_t *opts, const GValue *gval)
674 {
675         gint ii;
676         gchar *str;
677         const gchar *result = "";
678
679         str = ghb_value_string(gval);
680         for (ii = 0; ii < opts->count; ii++)
681         {
682                 if (strcmp(opts->map[ii].shortOpt, str) == 0)
683                 {
684                         result = opts->map[ii].option;
685                         break;
686                 }
687         }
688         g_free(str);
689         return result;
690 }
691
692 static gint
693 lookup_mix_int(const GValue *mix)
694 {
695         gint ii;
696         gchar *str;
697         gint result = 0;
698
699
700         str = ghb_value_string(mix);
701         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
702         {
703                 if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
704                 {
705                         result = hb_audio_mixdowns[ii].amixdown;
706                         break;
707                 }
708         }
709         g_free(str);
710         return result;
711 }
712
713 static const gchar*
714 lookup_mix_option(const GValue *mix)
715 {
716         gint ii;
717         gchar *str;
718         gchar *result = "None";
719
720
721         str = ghb_value_string(mix);
722         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
723         {
724                 if (strcmp(hb_audio_mixdowns[ii].short_name, str) == 0)
725                 {
726                         result = hb_audio_mixdowns[ii].human_readable_name;
727                         break;
728                 }
729         }
730         g_free(str);
731         return result;
732 }
733
734 static gint
735 lookup_video_rate_int(const GValue *vrate)
736 {
737         gint ii;
738         gchar *str;
739         gint result = 0;
740
741         str = ghb_value_string(vrate);
742         for (ii = 0; ii < hb_video_rates_count; ii++)
743         {
744                 if (strcmp(hb_video_rates[ii].string, str) == 0)
745                 {
746                         result = hb_video_rates[ii].rate;
747                         break;
748                 }
749         }
750         g_free(str);
751         // Default to "same as source"
752         return result;
753 }
754
755 static const gchar*
756 lookup_video_rate_option(const GValue *vrate)
757 {
758         gint ii;
759         gchar *str;
760         const gchar *result = "Same as source";
761
762         str = ghb_value_string(vrate);
763         for (ii = 0; ii < hb_video_rates_count; ii++)
764         {
765                 if (strcmp(hb_video_rates[ii].string, str) == 0)
766                 {
767                         result = hb_video_rates[ii].string;
768                         break;
769                 }
770         }
771         g_free(str);
772         // Default to "same as source"
773         return result;
774 }
775
776 static gint
777 lookup_audio_rate_int(const GValue *rate)
778 {
779         gint ii;
780         gchar *str;
781         gint result = 0;
782
783         // Coincidentally, the string "source" will return 0
784         // which is our flag to use "same as source"
785         str = ghb_value_string(rate);
786         for (ii = 0; ii < hb_audio_rates_count; ii++)
787         {
788                 if (strcmp(hb_audio_rates[ii].string, str) == 0)
789                 {
790                         result = hb_audio_rates[ii].rate;
791                         break;
792                 }
793         }
794         g_free(str);
795         return result;
796 }
797
798 static const gchar*
799 lookup_audio_rate_option(const GValue *rate)
800 {
801         gint ii;
802         gchar *str;
803         const gchar *result = "Same as source";
804
805         // Coincidentally, the string "source" will return 0
806         // which is our flag to use "same as source"
807         str = ghb_value_string(rate);
808         for (ii = 0; ii < hb_audio_rates_count; ii++)
809         {
810                 if (strcmp(hb_audio_rates[ii].string, str) == 0)
811                 {
812                         result = hb_audio_rates[ii].string;
813                         break;
814                 }
815         }
816         g_free(str);
817         return result;
818 }
819
820 static gint
821 lookup_audio_bitrate_int(const GValue *rate)
822 {
823         gint ii;
824         gchar *str;
825         gint result = 0;
826
827         // Coincidentally, the string "source" will return 0
828         // which is our flag to use "same as source"
829         str = ghb_value_string(rate);
830         for (ii = 0; ii < hb_audio_bitrates_count; ii++)
831         {
832                 if (strcmp(hb_audio_bitrates[ii].string, str) == 0)
833                 {
834                         result = hb_audio_bitrates[ii].rate;
835                         break;
836                 }
837         }
838         g_free(str);
839         return result;
840 }
841
842 static const gchar*
843 lookup_audio_bitrate_option(const GValue *rate)
844 {
845         gint ii;
846         gchar *str;
847         const gchar *result = "Same as source";
848
849         // Coincidentally, the string "source" will return 0
850         // which is our flag to use "same as source"
851         str = ghb_value_string(rate);
852         for (ii = 0; ii < hb_audio_bitrates_count; ii++)
853         {
854                 if (strcmp(hb_audio_bitrates[ii].string, str) == 0)
855                 {
856                         result = hb_audio_bitrates[ii].string;
857                         break;
858                 }
859         }
860         g_free(str);
861         return result;
862 }
863
864 static gint
865 lookup_audio_lang_int(const GValue *rate)
866 {
867         gint ii;
868         gchar *str;
869         gint result = 0;
870
871         // Coincidentally, the string "source" will return 0
872         // which is our flag to use "same as source"
873         str = ghb_value_string(rate);
874         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
875         {
876                 if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
877                 {
878                         result = ii;
879                         break;
880                 }
881         }
882         g_free(str);
883         return result;
884 }
885
886 static const gchar*
887 lookup_audio_lang_option(const GValue *rate)
888 {
889         gint ii;
890         gchar *str;
891         const gchar *result = "Same as source";
892
893         // Coincidentally, the string "source" will return 0
894         // which is our flag to use "same as source"
895         str = ghb_value_string(rate);
896         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
897         {
898                 if (strcmp(ghb_language_table[ii].iso639_2, str) == 0)
899                 {
900                         result = ghb_language_table[ii].eng_name;
901                         break;
902                 }
903         }
904         g_free(str);
905         return result;
906 }
907
908 static GValue*
909 get_acodec_value(gint val)
910 {
911         GValue *value = NULL;
912         gint ii;
913
914         for (ii = 0; ii < acodec_opts.count; ii++)
915         {
916                 if ((int)acodec_opts.map[ii].ivalue == val)
917                 {
918                         value = ghb_string_value_new(acodec_opts.map[ii].shortOpt);
919                         break;
920                 }
921         }
922         return value;
923 }
924
925 #if 0
926 static GValue*
927 get_abitrate_value(gint val)
928 {
929         GValue *value = NULL;
930         gint ii;
931
932         for (ii = 0; ii < hb_audio_bitrates_count; ii++)
933         {
934                 if (hb_audio_bitrates[ii].rate == val)
935                 {
936                         value = ghb_string_value_new(hb_audio_bitrates[ii].string);
937                         break;
938                 }
939         }
940         return value;
941 }
942 #endif
943
944 static GValue*
945 get_amix_value(gint val)
946 {
947         GValue *value = NULL;
948         gint ii;
949
950         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
951         {
952                 if (hb_audio_mixdowns[ii].amixdown == val)
953                 {
954                         value = ghb_string_value_new(hb_audio_mixdowns[ii].short_name);
955                         break;
956                 }
957         }
958         return value;
959 }
960
961 // Handle for libhb.  Gets set by ghb_backend_init()
962 static hb_handle_t * h_scan = NULL;
963 static hb_handle_t * h_queue = NULL;
964
965 extern void hb_get_tempory_directory(hb_handle_t *h, char path[512]);
966
967 gchar*
968 ghb_get_tmp_dir()
969 {
970         char dir[512];
971
972         hb_get_tempory_directory(h_scan, dir);
973         return g_strdup(dir);
974 }
975
976 void
977 ghb_hb_cleanup(gboolean partial)
978 {
979         char dir[512];
980
981         hb_get_tempory_directory(h_scan, dir);
982         del_tree(dir, !partial);
983 }
984
985 gint
986 ghb_get_title_number(gint titleindex)
987 {
988         hb_list_t  * list;
989         hb_title_t * title;
990         
991         if (h_scan == NULL) return 1;
992         list = hb_get_titles( h_scan );
993         if( !hb_list_count( list ) )
994         {
995                 /* No valid title, stop right there */
996                 return 1;
997         }
998         title = hb_list_item( list, titleindex );
999         if (title == NULL) return 1;    // Bad titleindex
1000         return title->index;
1001 }
1002
1003 static hb_audio_config_t*
1004 get_hb_audio(gint titleindex, gint track)
1005 {
1006         hb_list_t  * list;
1007         hb_title_t * title;
1008     hb_audio_config_t *audio = NULL;
1009         
1010     if (h_scan == NULL) return NULL;
1011         list = hb_get_titles( h_scan );
1012         if( !hb_list_count( list ) )
1013         {
1014                 /* No valid title, stop right there */
1015                 return NULL;
1016         }
1017     title = hb_list_item( list, titleindex );
1018         if (title == NULL) return NULL; // Bad titleindex
1019         if (!hb_list_count(title->list_audio))
1020         {
1021                 return NULL;
1022         }
1023     audio = (hb_audio_config_t *)hb_list_audio_config_item(title->list_audio, track);
1024         return audio;
1025 }
1026
1027 static gint
1028 search_rates(hb_rate_t *rates, gint rate, gint count)
1029 {
1030         gint ii;
1031         for (ii = 0; ii < count; ii++)
1032         {
1033                 if (rates[ii].rate == rate)
1034                         return ii;
1035         }
1036         return -1;
1037 }
1038
1039 static gboolean find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter);
1040
1041 static GtkListStore*
1042 get_combo_box_store(GtkBuilder *builder, const gchar *name)
1043 {
1044         GtkComboBox *combo;
1045         GtkListStore *store;
1046
1047         g_debug("get_combo_box_store() %s\n", name);
1048         // First modify the combobox model to allow greying out of options
1049         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
1050         store = GTK_LIST_STORE(gtk_combo_box_get_model (combo));
1051         return store;
1052 }
1053
1054 static void
1055 grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean grey)
1056 {
1057         GtkListStore *store;
1058         GtkTreeIter iter;
1059         
1060         store = get_combo_box_store(builder, name);
1061         if (find_combo_item_by_int(GTK_TREE_MODEL(store), value, &iter))
1062         {
1063                 gtk_list_store_set(store, &iter, 
1064                                                    1, !grey, 
1065                                                    -1);
1066         }
1067 }
1068
1069 void
1070 ghb_grey_combo_options(GtkBuilder *builder)
1071 {
1072         GtkWidget *widget;
1073         gint container, track, titleindex, acodec;
1074     hb_audio_config_t *audio = NULL;
1075         GValue *gval;
1076         
1077         widget = GHB_WIDGET (builder, "title");
1078         gval = ghb_widget_value(widget);
1079         titleindex = ghb_lookup_combo_int("title", gval);
1080         ghb_value_free(gval);
1081         widget = GHB_WIDGET (builder, "AudioTrack");
1082         gval = ghb_widget_value(widget);
1083         track = ghb_lookup_combo_int("AudioTrack", gval);
1084         ghb_value_free(gval);
1085         audio = get_hb_audio(titleindex, track);
1086         widget = GHB_WIDGET (builder, "FileFormat");
1087         gval = ghb_widget_value(widget);
1088         container = ghb_lookup_combo_int("FileFormat", gval);
1089         ghb_value_free(gval);
1090
1091         grey_combo_box_item(builder, "x264_analyse", 3, TRUE);
1092         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_FAAC, FALSE);
1093         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_LAME, FALSE);
1094         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, FALSE);
1095
1096         gboolean allow_dca = TRUE;
1097         allow_dca = (container != HB_MUX_MP4);
1098
1099         grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3, FALSE);
1100         if (allow_dca)
1101                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA, FALSE);
1102         else
1103                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA, TRUE);
1104
1105         if (audio && audio->in.codec != HB_ACODEC_AC3)
1106         {
1107                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_AC3, TRUE);
1108         }
1109         if (audio && audio->in.codec != HB_ACODEC_DCA)
1110         {
1111                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_DCA, TRUE);
1112         }
1113         grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, FALSE);
1114
1115         widget = GHB_WIDGET (builder, "AudioEncoder");
1116         gval = ghb_widget_value(widget);
1117         acodec = ghb_lookup_combo_int("AudioEncoder", gval);
1118         ghb_value_free(gval);
1119         if (acodec != HB_ACODEC_AC3)
1120         {
1121                 grey_combo_box_item(builder, "AudioMixdown", 0, TRUE);
1122         }
1123         if (container == HB_MUX_MP4)
1124         {
1125                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_LAME, TRUE);
1126                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, TRUE);
1127                 grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, TRUE);
1128         }
1129         else if (container == HB_MUX_AVI)
1130         {
1131                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_FAAC, TRUE);
1132                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_VORBIS, TRUE);
1133                 grey_combo_box_item(builder, "VideoEncoder", HB_VCODEC_THEORA, TRUE);
1134         }
1135         else if (container == HB_MUX_OGM)
1136         {
1137                 grey_combo_box_item(builder, "AudioEncoder", HB_ACODEC_FAAC, TRUE);
1138         }
1139
1140         gboolean allow_mono = TRUE;
1141         gboolean allow_stereo = TRUE;
1142         gboolean allow_dolby = TRUE;
1143         gboolean allow_dpl2 = TRUE;
1144         gboolean allow_6ch = TRUE;
1145         if (audio)
1146         {
1147                 allow_mono =
1148                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
1149                         (acodec != HB_ACODEC_LAME);
1150                 gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
1151                 allow_stereo =
1152                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
1153                 allow_dolby =
1154                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
1155                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
1156                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
1157                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
1158                 allow_6ch =
1159                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
1160                         (acodec != HB_ACODEC_LAME) &&
1161                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
1162                         (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
1163         }
1164         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_MONO, !allow_mono);
1165         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_STEREO, !allow_stereo);
1166         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_DOLBY, !allow_dolby);
1167         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_DOLBYPLII, !allow_dpl2);
1168         grey_combo_box_item(builder, "AudioMixdown", HB_AMIXDOWN_6CH, !allow_6ch);
1169 }
1170
1171 gint
1172 ghb_get_best_mix(gint titleindex, gint track, gint acodec, gint mix)
1173 {
1174     hb_audio_config_t *audio = NULL;
1175         gboolean allow_mono = TRUE;
1176         gboolean allow_stereo = TRUE;
1177         gboolean allow_dolby = TRUE;
1178         gboolean allow_dpl2 = TRUE;
1179         gboolean allow_6ch = TRUE;
1180         
1181         if (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
1182         {
1183                 // Audio codec pass-thru.  No mixdown
1184                 return 0;
1185         }
1186         audio = get_hb_audio(titleindex, track);
1187         if (audio)
1188         {
1189                 allow_mono =
1190                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
1191                         (acodec != HB_ACODEC_LAME);
1192                 gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
1193                 allow_stereo =
1194                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
1195                 allow_dolby =
1196                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
1197                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
1198                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
1199                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
1200                 allow_6ch =
1201                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
1202                         (acodec != HB_ACODEC_LAME) &&
1203                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
1204                         (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
1205         }
1206         gboolean greater = FALSE;
1207         if (mix == 0) 
1208         {
1209                 // If no mix is specified, select the best available.
1210                 mix = HB_AMIXDOWN_6CH;
1211         }
1212         if (mix == HB_AMIXDOWN_6CH)
1213         {
1214                 greater = TRUE;
1215                 if (allow_6ch) return HB_AMIXDOWN_6CH;
1216         }
1217         if (mix == HB_AMIXDOWN_DOLBYPLII || greater)
1218         {
1219                 greater = TRUE;
1220                 if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
1221         }
1222         if (mix == HB_AMIXDOWN_DOLBY || greater)
1223         {
1224                 greater = TRUE;
1225                 if (allow_dolby) return HB_AMIXDOWN_DOLBY;
1226         }
1227         if (mix == HB_AMIXDOWN_STEREO || greater)
1228         {
1229                 greater = TRUE;
1230                 if (allow_stereo) return HB_AMIXDOWN_STEREO;
1231         }
1232         if (mix == HB_AMIXDOWN_MONO || greater)
1233         {
1234                 greater = TRUE;
1235                 if (allow_mono) return HB_AMIXDOWN_MONO;
1236         }
1237         if (allow_stereo) return HB_AMIXDOWN_STEREO;
1238         if (allow_dolby) return HB_AMIXDOWN_DOLBY;
1239         if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
1240         if (allow_6ch) return HB_AMIXDOWN_6CH;
1241         return 0;
1242 }
1243
1244 // Set up the model for the combo box
1245 static void
1246 init_combo_box(GtkBuilder *builder, const gchar *name)
1247 {
1248         GtkComboBox *combo;
1249         GtkListStore *store;
1250         GtkCellRenderer *cell;
1251
1252         g_debug("init_combo_box() %s\n", name);
1253         // First modify the combobox model to allow greying out of options
1254         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
1255         // Store contains:
1256         // 1 - String to display
1257         // 2 - bool indicating whether the entry is selectable (grey or not)
1258         // 3 - String that is used for presets
1259         // 4 - Int value determined by backend
1260         // 5 - String value determined by backend
1261         store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_BOOLEAN, 
1262                                                            G_TYPE_STRING, G_TYPE_DOUBLE, G_TYPE_STRING);
1263         gtk_combo_box_set_model(combo, GTK_TREE_MODEL(store));
1264
1265         if (GTK_WIDGET_TYPE(combo) == GTK_TYPE_COMBO_BOX)
1266         {
1267                 gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo));
1268         cell = GTK_CELL_RENDERER(gtk_cell_renderer_text_new());
1269         gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
1270         gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell,
1271                 "text", 0, "sensitive", 1, NULL);
1272         }
1273         else
1274         { // Combo box entry
1275                 gtk_combo_box_entry_set_text_column(GTK_COMBO_BOX_ENTRY(combo), 0);
1276         }
1277 }       
1278
1279 static void
1280 audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
1281 {
1282         GtkTreeIter iter;
1283         GtkListStore *store;
1284         gint ii;
1285         
1286         g_debug("audio_samplerate_opts_set ()\n");
1287         store = get_combo_box_store(builder, name);
1288         gtk_list_store_clear(store);
1289         // Add an item for "Same As Source"
1290         gtk_list_store_append(store, &iter);
1291         gtk_list_store_set(store, &iter, 
1292                                            0, "Same as source", 
1293                                            1, TRUE, 
1294                                            2, "source", 
1295                                            3, 0.0, 
1296                                            4, "source", 
1297                                            -1);
1298         for (ii = 0; ii < count; ii++)
1299         {
1300                 gtk_list_store_append(store, &iter);
1301                 gtk_list_store_set(store, &iter, 
1302                                                    0, rates[ii].string, 
1303                                                    1, TRUE, 
1304                                                    2, rates[ii].string, 
1305                                                    3, (gdouble)rates[ii].rate, 
1306                                                    4, rates[ii].string, 
1307                                                    -1);
1308         }
1309 }
1310
1311 static void
1312 video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
1313 {
1314         GtkTreeIter iter;
1315         GtkListStore *store;
1316         gint ii;
1317         
1318         g_debug("video_rate_opts_set ()\n");
1319         store = get_combo_box_store(builder, name);
1320         gtk_list_store_clear(store);
1321         // Add an item for "Same As Source"
1322         gtk_list_store_append(store, &iter);
1323         gtk_list_store_set(store, &iter, 
1324                                            0, "Same as source", 
1325                                            1, TRUE, 
1326                                            2, "source", 
1327                                            3, 0.0, 
1328                                            4, "source", 
1329                                            -1);
1330         for (ii = 0; ii < count; ii++)
1331         {
1332                 gchar *desc = "";
1333                 gchar *option;
1334                 if (strcmp(rates[ii].string, "23.976") == 0)
1335                 {
1336                         desc = "(NTSC Film)";
1337                 }
1338                 else if (strcmp(rates[ii].string, "25") == 0)
1339                 {
1340                         desc = "(PAL Film/Video)";
1341                 }
1342                 else if (strcmp(rates[ii].string, "29.97") == 0)
1343                 {
1344                         desc = "(NTSC Video)";
1345                 }
1346                 option = g_strdup_printf ("%s %s", rates[ii].string, desc);
1347                 gtk_list_store_append(store, &iter);
1348                 gtk_list_store_set(store, &iter, 
1349                                                    0, option, 
1350                                                    1, TRUE, 
1351                                                    2, rates[ii].string, 
1352                                                    3, (gdouble)rates[ii].rate, 
1353                                                    4, rates[ii].string, 
1354                                                    -1);
1355                 g_free(option);
1356         }
1357 }
1358
1359 static void
1360 mix_opts_set(GtkBuilder *builder, const gchar *name)
1361 {
1362         GtkTreeIter iter;
1363         GtkListStore *store;
1364         gint ii;
1365         
1366         g_debug("mix_opts_set ()\n");
1367         store = get_combo_box_store(builder, name);
1368         gtk_list_store_clear(store);
1369         gtk_list_store_append(store, &iter);
1370         gtk_list_store_set(store, &iter, 
1371                                            0, "None", 
1372                                            1, TRUE, 
1373                                            2, "none", 
1374                                            3, 0.0, 
1375                                            4, "none", 
1376                                            -1);
1377         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
1378         {
1379                 gtk_list_store_append(store, &iter);
1380                 gtk_list_store_set(store, &iter, 
1381                                                    0, hb_audio_mixdowns[ii].human_readable_name, 
1382                                                    1, TRUE, 
1383                                                    2, hb_audio_mixdowns[ii].short_name, 
1384                                                    3, (gdouble)hb_audio_mixdowns[ii].amixdown, 
1385                                                    4, hb_audio_mixdowns[ii].internal_name, 
1386                                                    -1);
1387         }
1388 }
1389
1390 static void
1391 language_opts_set(GtkBuilder *builder, const gchar *name)
1392 {
1393         GtkTreeIter iter;
1394         GtkListStore *store;
1395         gint ii;
1396         
1397         g_debug("language_opts_set ()\n");
1398         store = get_combo_box_store(builder, name);
1399         gtk_list_store_clear(store);
1400         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1401         {
1402                 gtk_list_store_append(store, &iter);
1403                 gtk_list_store_set(store, &iter, 
1404                                                    0, ghb_language_table[ii].eng_name, 
1405                                                    1, TRUE, 
1406                                                    2, ghb_language_table[ii].iso639_2, 
1407                                                    3, (gdouble)ii, 
1408                                                    4, ghb_language_table[ii].iso639_1, 
1409                                                    -1);
1410         }
1411 }
1412
1413 static gchar **titles = NULL;
1414
1415 void
1416 title_opts_set(GtkBuilder *builder, const gchar *name)
1417 {
1418         GtkTreeIter iter;
1419         GtkListStore *store;
1420         hb_list_t  * list = NULL;
1421         hb_title_t * title = NULL;
1422         gint ii;
1423         gint count = 0;
1424         
1425         g_debug("title_opts_set ()\n");
1426         store = get_combo_box_store(builder, name);
1427         gtk_list_store_clear(store);
1428         if (h_scan != NULL)
1429         {
1430                 list = hb_get_titles( h_scan );
1431                 count = hb_list_count( list );
1432                 if (count > 100) count = 100;
1433         }
1434         if (titles) g_strfreev(titles);
1435         if (title_opts.map) g_free(title_opts.map);
1436         if (count > 0)
1437         {
1438                 title_opts.count = count;
1439                 title_opts.map = g_malloc(count*sizeof(options_map_t));
1440                 titles = g_malloc((count+1) * sizeof(gchar*));
1441         }
1442         else
1443         {
1444                 title_opts.count = 1;
1445                 title_opts.map = g_malloc(sizeof(options_map_t));
1446                 titles = NULL;
1447         }
1448         if( count <= 0 )
1449         {
1450                 // No titles.  Fill in a default.
1451                 gtk_list_store_append(store, &iter);
1452                 gtk_list_store_set(store, &iter, 
1453                                                    0, "No Titles", 
1454                                                    1, TRUE, 
1455                                                    2, "none", 
1456                                                    3, -1.0, 
1457                                                    4, "none", 
1458                                                    -1);
1459                 title_opts.map[0].option = "No Titles";
1460                 title_opts.map[0].shortOpt = "none";
1461                 title_opts.map[0].ivalue = -1;
1462                 title_opts.map[0].svalue = "none";
1463                 return;
1464         }
1465         for (ii = 0; ii < count; ii++)
1466         {
1467                 title = (hb_title_t*)hb_list_item(list, ii);
1468                 if (title->duration != 0)
1469                 {
1470                         titles[ii]  = g_strdup_printf ("%d - %02dh%02dm%02ds",
1471                                 title->index, title->hours, title->minutes, title->seconds);
1472                 }
1473                 else
1474                 {
1475                         titles[ii]  = g_strdup_printf ("%d - Unknown Length", title->index);
1476                 }
1477                 gtk_list_store_append(store, &iter);
1478                 gtk_list_store_set(store, &iter, 
1479                                                    0, titles[ii], 
1480                                                    1, TRUE, 
1481                                                    2, titles[ii], 
1482                                                    3, (gdouble)ii, 
1483                                                    4, titles[ii], 
1484                                                    -1);
1485                 title_opts.map[ii].option = titles[ii];
1486                 title_opts.map[ii].shortOpt = titles[ii];
1487                 title_opts.map[ii].ivalue = ii;
1488                 title_opts.map[ii].svalue = titles[ii];
1489         }
1490         titles[ii] = NULL;
1491 }
1492
1493 static gboolean
1494 find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter)
1495 {
1496         gdouble ivalue;
1497         gboolean foundit = FALSE;
1498         
1499         if (gtk_tree_model_get_iter_first (store, iter))
1500         {
1501                 do
1502                 {
1503                         gtk_tree_model_get(store, iter, 3, &ivalue, -1);
1504                         if (value == (int)ivalue)
1505                         {
1506                                 foundit = TRUE;
1507                                 break;
1508                         }
1509                 } while (gtk_tree_model_iter_next (store, iter));
1510         }
1511         return foundit;
1512 }
1513
1514 void
1515 audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1516 {
1517         GtkTreeIter iter;
1518         GtkListStore *store;
1519         hb_list_t  * list = NULL;
1520         hb_title_t * title = NULL;
1521     hb_audio_config_t * audio;
1522         gint ii;
1523         gint count = 0;
1524         
1525         g_debug("audio_track_opts_set ()\n");
1526         store = get_combo_box_store(builder, name);
1527         gtk_list_store_clear(store);
1528         if (h_scan != NULL)
1529         {
1530                 list = hb_get_titles( h_scan );
1531             title = (hb_title_t*)hb_list_item( list, titleindex );
1532                 if (title != NULL)
1533                 {
1534                         count = hb_list_count( title->list_audio );
1535                 }
1536         }
1537         if (count > 100) count = 100;
1538         if (audio_track_opts.map) g_free(audio_track_opts.map);
1539         if (count > 0)
1540         {
1541                 audio_track_opts.count = count;
1542                 audio_track_opts.map = g_malloc(count*sizeof(options_map_t));
1543         }
1544         else
1545         {
1546                 audio_track_opts.count = 1;
1547                 audio_track_opts.map = g_malloc(sizeof(options_map_t));
1548         }
1549         if( count <= 0 )
1550         {
1551                 // No audio. set some default
1552                 gtk_list_store_append(store, &iter);
1553                 gtk_list_store_set(store, &iter, 
1554                                                    0, "No Audio", 
1555                                                    1, TRUE, 
1556                                                    2, "none", 
1557                                                    3, -1.0, 
1558                                                    4, "none", 
1559                                                    -1);
1560                 audio_track_opts.map[0].option = "No Audio";
1561                 audio_track_opts.map[0].shortOpt = "none";
1562                 audio_track_opts.map[0].ivalue = -1;
1563                 audio_track_opts.map[0].svalue = "none";
1564                 return;
1565         }
1566         for (ii = 0; ii < count; ii++)
1567         {
1568         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, ii );
1569                 gtk_list_store_append(store, &iter);
1570                 gtk_list_store_set(store, &iter, 
1571                                                    0, audio->lang.description, 
1572                                                    1, TRUE, 
1573                                                    2, index_str[ii], 
1574                                                    3, (gdouble)ii, 
1575                                                    4, index_str[ii], 
1576                                                    -1);
1577                 audio_track_opts.map[ii].option = audio->lang.description,
1578                 audio_track_opts.map[ii].shortOpt = index_str[ii];
1579                 audio_track_opts.map[ii].ivalue = ii;
1580                 audio_track_opts.map[ii].svalue = index_str[ii];
1581         }
1582 }
1583
1584
1585 void
1586 subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1587 {
1588         GtkTreeIter iter;
1589         GtkListStore *store;
1590         hb_list_t  * list = NULL;
1591         hb_title_t * title = NULL;
1592     hb_subtitle_t * subtitle;
1593         gint ii;
1594         gint count = 0;
1595         
1596         g_debug("subtitle_opts_set () %s\n", name);
1597         store = get_combo_box_store(builder, name);
1598         gtk_list_store_clear(store);
1599         if (h_scan != NULL)
1600         {
1601                 list = hb_get_titles( h_scan );
1602             title = (hb_title_t*)hb_list_item( list, titleindex );
1603                 if (title != NULL)
1604                 {
1605                         count = hb_list_count( title->list_subtitle );
1606                 }
1607         }
1608         if (count > 100) count = 100;
1609         if (subtitle_opts.map) g_free(subtitle_opts.map);
1610         if (count > 0)
1611         {
1612                 subtitle_opts.count = count+2;
1613                 subtitle_opts.map = g_malloc((count+2)*sizeof(options_map_t));
1614         }
1615         else
1616         {
1617                 subtitle_opts.count = LANG_TABLE_SIZE+2;
1618                 subtitle_opts.map = g_malloc((LANG_TABLE_SIZE+2)*sizeof(options_map_t));
1619         }
1620         // Add options for "none" and "autoselect"
1621         gtk_list_store_append(store, &iter);
1622         gtk_list_store_set(store, &iter, 
1623                                            0, "None", 
1624                                            1, TRUE, 
1625                                            2, "none", 
1626                                            3, -2.0, 
1627                                            4, "none", 
1628                                            -1);
1629         subtitle_opts.map[0].option = "None";
1630         subtitle_opts.map[0].shortOpt = "none";
1631         subtitle_opts.map[0].ivalue = -2;
1632         subtitle_opts.map[0].svalue = "none";
1633         gtk_list_store_append(store, &iter);
1634         gtk_list_store_set(store, &iter, 
1635                                            0, "Autoselect", 
1636                                            1, TRUE, 
1637                                            2, "auto", 
1638                                            3, -1.0, 
1639                                            4, "auto", 
1640                                            -1);
1641         subtitle_opts.map[0].option = "Same as audio";
1642         subtitle_opts.map[0].shortOpt = "auto";
1643         subtitle_opts.map[0].ivalue = -1;
1644         subtitle_opts.map[0].svalue = "auto";
1645         if (count > 0)
1646         {
1647                 for (ii = 0; ii < count; ii++)
1648                 {
1649                 subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
1650                         gtk_list_store_append(store, &iter);
1651                         gtk_list_store_set(store, &iter, 
1652                                                 0, subtitle->lang, 
1653                                                 1, TRUE, 
1654                                                 2, subtitle->iso639_2, 
1655                                                 3, (gdouble)ii, 
1656                                                 4, subtitle->iso639_2, 
1657                                                 -1);
1658                         subtitle_opts.map[ii+2].option = subtitle->lang;
1659                         subtitle_opts.map[ii+2].shortOpt = subtitle->iso639_2;
1660                         subtitle_opts.map[ii+2].ivalue = ii;
1661                         subtitle_opts.map[ii+2].svalue = subtitle->iso639_2;
1662                 }
1663         }
1664         else
1665         {
1666                 for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1667                 {
1668                         gtk_list_store_append(store, &iter);
1669                         gtk_list_store_set(store, &iter, 
1670                                 0, ghb_language_table[ii].eng_name, 
1671                                 1, TRUE, 
1672                                 2, ghb_language_table[ii].iso639_2, 
1673                                 3, (gdouble)ii, 
1674                                 4, ghb_language_table[ii].iso639_2, 
1675                                 -1);
1676                         subtitle_opts.map[ii+2].option = ghb_language_table[ii].eng_name;
1677                         subtitle_opts.map[ii+2].shortOpt = ghb_language_table[ii].iso639_2;
1678                         subtitle_opts.map[ii+2].ivalue = ii;
1679                         subtitle_opts.map[ii+2].svalue = ghb_language_table[ii].iso639_2;
1680                 }
1681         }
1682 }
1683
1684 gint
1685 ghb_longest_title()
1686 {
1687         hb_list_t  * list;
1688         hb_title_t * title;
1689         gint ii;
1690         gint count = 0;
1691         guint64 longest = 0;
1692         gint titleindex = 0;
1693         
1694         g_debug("ghb_longest_title ()\n");
1695         if (h_scan == NULL) return 0;
1696         list = hb_get_titles( h_scan );
1697         count = hb_list_count( list );
1698         if (count > 100) count = 100;
1699         for (ii = 0; ii < count; ii++)
1700         {
1701                 title = (hb_title_t*)hb_list_item(list, ii);
1702                 if (title->duration > longest)
1703                 {
1704                         titleindex = ii;
1705                         longest = title->duration;
1706                 }
1707         }
1708         return titleindex;
1709 }
1710
1711 gint
1712 ghb_find_audio_track(
1713         gint titleindex, 
1714         const gchar *lang, 
1715         gint acodec,
1716         GHashTable *track_indices)
1717 {
1718         hb_list_t  * list;
1719         hb_title_t * title;
1720     hb_audio_config_t * audio;
1721         gint ii;
1722         gint count = 0;
1723         gint track = -1;
1724         gint max_chan = 0;
1725         gboolean *used;
1726         
1727         g_debug("find_audio_track ()\n");
1728         if (h_scan == NULL) return -1;
1729         list = hb_get_titles( h_scan );
1730     title = (hb_title_t*)hb_list_item( list, titleindex );
1731         if (title != NULL)
1732         {
1733                 count = hb_list_count( title->list_audio );
1734         }
1735         if (count > 10) count = 10;
1736         used = g_hash_table_lookup(track_indices, &acodec);
1737         if (used == NULL)
1738         {
1739                 used = g_malloc0(count * sizeof(gboolean));
1740                 g_hash_table_insert(track_indices, &acodec, used);
1741         }
1742         // Try to find an item that matches the preferred language and
1743         // the passthru codec type
1744         if (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
1745         {
1746                 for (ii = 0; ii < count; ii++)
1747                 {
1748                         gint channels;
1749
1750                         if (used[ii])
1751                                 continue;
1752
1753                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
1754                                                                                                         title->list_audio, ii );
1755                         channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
1756                                                                                                         audio->in.channel_layout);
1757                         // Find a track that is not visually impaired or dirctor's
1758                         // commentary, and has the highest channel count.
1759                         if ((audio->in.codec & acodec) &&
1760                                 (audio->lang.type < 2) &&
1761                                 ((strcmp(lang, audio->lang.iso639_2) == 0) ||
1762                                 (strcmp(lang, "und") == 0)))
1763                         {
1764                                 if (channels > max_chan)
1765                                 {
1766                                         track = ii;
1767                                         max_chan = channels;
1768                                 }
1769                         }
1770                 }
1771         }
1772         if (track > -1)
1773         {
1774                 used[track] = TRUE;
1775                 return track;
1776         }
1777         // Try to find an item that matches the preferred language
1778         for (ii = 0; ii < count; ii++)
1779         {
1780                 if (used[ii])
1781                         continue;
1782         audio = (hb_audio_config_t*)hb_list_audio_config_item( 
1783                                                                                                         title->list_audio, ii );
1784                 // Find a track that is not visually impaired or dirctor's commentary
1785                 if ((audio->lang.type < 2) &&
1786                         ((strcmp(lang, audio->lang.iso639_2) == 0) ||
1787                         (strcmp(lang, "und") == 0)))
1788                 {
1789                         track = ii;
1790                         break;
1791                 }
1792         }
1793         if (track > -1)
1794         {
1795                 used[track] = TRUE;
1796                 return track;
1797         }
1798         // Try to fine an item that does not match the preferred language and
1799         // matches the passthru codec type
1800         if (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
1801         {
1802                 for (ii = 0; ii < count; ii++)
1803                 {
1804                         gint channels;
1805
1806                         if (used[ii])
1807                                 continue;
1808
1809                 audio = (hb_audio_config_t*)hb_list_audio_config_item( 
1810                                                                                                         title->list_audio, ii );
1811                         channels = HB_INPUT_CH_LAYOUT_GET_DISCRETE_COUNT(
1812                                                                                                         audio->in.channel_layout);
1813                         // Find a track that is not visually impaired or dirctor's
1814                         // commentary, and has the highest channel count.
1815                         if ((audio->in.codec & acodec) &&
1816                                 (audio->lang.type < 2))
1817                         {
1818                                 if (channels > max_chan)
1819                                 {
1820                                         track = ii;
1821                                         max_chan = channels;
1822                                 }
1823                         }
1824                 }
1825         }
1826         if (track > -1)
1827         {
1828                 used[track] = TRUE;
1829                 return track;
1830         }
1831         // Try to fine an item that does not match the preferred language
1832         for (ii = 0; ii < count; ii++)
1833         {
1834                 if (used[ii])
1835                         continue;
1836         audio = (hb_audio_config_t*)hb_list_audio_config_item( 
1837                                                                                                         title->list_audio, ii );
1838                 // Find a track that is not visually impaired or dirctor's commentary
1839                 if (audio->lang.type < 2)
1840                 {
1841                         track = ii;
1842                         break;
1843                 }
1844         }
1845         if (track > -1)
1846         {
1847                 used[track] = TRUE;
1848                 return track;
1849         }
1850         // Last ditch, anything goes
1851         for (ii = 0; ii < count; ii++)
1852         {
1853         audio = (hb_audio_config_t*)hb_list_audio_config_item( 
1854                                                                                                         title->list_audio, ii );
1855                 if (!used[ii])
1856                 {
1857                         track = ii;
1858                         break;
1859                 }
1860         }
1861         if (track > -1)
1862         {
1863                 used[track] = TRUE;
1864         }
1865         return track;
1866 }
1867
1868 static void
1869 generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
1870 {
1871         GtkTreeIter iter;
1872         GtkListStore *store;
1873         gint ii;
1874         
1875         g_debug("generic_opts_set ()\n");
1876         if (name == NULL || opts == NULL) return;
1877         store = get_combo_box_store(builder, name);
1878         gtk_list_store_clear(store);
1879         for (ii = 0; ii < opts->count; ii++)
1880         {
1881                 gtk_list_store_append(store, &iter);
1882                 gtk_list_store_set(store, &iter, 
1883                                                    0, opts->map[ii].option, 
1884                                                    1, TRUE, 
1885                                                    2, opts->map[ii].shortOpt, 
1886                                                    3, opts->map[ii].ivalue, 
1887                                                    4, opts->map[ii].svalue, 
1888                                                    -1);
1889         }
1890 }
1891
1892 combo_opts_t*
1893 find_combo_table(const gchar *name)
1894 {
1895         gint ii;
1896
1897         for (ii = 0; combo_name_map[ii].name != NULL; ii++)
1898         {
1899                 if (strcmp(name, combo_name_map[ii].name) == 0)
1900                 {
1901                         return combo_name_map[ii].opts;
1902                 }
1903         }
1904         return NULL;
1905 }
1906
1907 gint
1908 ghb_lookup_combo_int(const gchar *name, const GValue *gval)
1909 {
1910         if (strcmp(name, "AudioBitrate") == 0)
1911                 return lookup_audio_bitrate_int(gval);
1912         else if (strcmp(name, "AudioSamplerate") == 0)
1913                 return lookup_audio_rate_int(gval);
1914         else if (strcmp(name, "VideoFramerate") == 0)
1915                 return lookup_video_rate_int(gval);
1916         else if (strcmp(name, "AudioMixdown") == 0)
1917                 return lookup_mix_int(gval);
1918         else if (strcmp(name, "SourceAudioLang") == 0)
1919                 return lookup_audio_lang_int(gval);
1920         else
1921         {
1922                 return lookup_generic_int(find_combo_table(name), gval);
1923         }
1924         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
1925         return 0;
1926 }
1927
1928 gdouble
1929 ghb_lookup_combo_double(const gchar *name, const GValue *gval)
1930 {
1931         if (strcmp(name, "AudioBitrate") == 0)
1932                 return lookup_audio_bitrate_int(gval);
1933         else if (strcmp(name, "AudioSamplerate") == 0)
1934                 return lookup_audio_rate_int(gval);
1935         else if (strcmp(name, "VideoFramerate") == 0)
1936                 return lookup_video_rate_int(gval);
1937         else if (strcmp(name, "AudioMixdown") == 0)
1938                 return lookup_mix_int(gval);
1939         else if (strcmp(name, "SourceAudioLang") == 0)
1940                 return lookup_audio_lang_int(gval);
1941         else
1942         {
1943                 return lookup_generic_double(find_combo_table(name), gval);
1944         }
1945         g_warning("ghb_lookup_combo_double() couldn't find %s", name);
1946         return 0;
1947 }
1948
1949 const gchar*
1950 ghb_lookup_combo_option(const gchar *name, const GValue *gval)
1951 {
1952         if (strcmp(name, "AudioBitrate") == 0)
1953                 return lookup_audio_bitrate_option(gval);
1954         else if (strcmp(name, "AudioSamplerate") == 0)
1955                 return lookup_audio_rate_option(gval);
1956         else if (strcmp(name, "VideoFramerate") == 0)
1957                 return lookup_video_rate_option(gval);
1958         else if (strcmp(name, "AudioMixdown") == 0)
1959                 return lookup_mix_option(gval);
1960         else if (strcmp(name, "SourceAudioLang") == 0)
1961                 return lookup_audio_lang_option(gval);
1962         else
1963         {
1964                 return lookup_generic_option(find_combo_table(name), gval);
1965         }
1966         g_warning("ghb_lookup_combo_int() couldn't find %s", name);
1967         return 0;
1968 }
1969
1970 void
1971 ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data, gboolean all)
1972 {
1973         GtkComboBox *combo = NULL;
1974         gint signal_id;
1975         gint handler_id = 0;
1976
1977         if (name != NULL)
1978         {               
1979                 g_debug("ghb_update_ui_combo_box() %s\n", name);
1980                 // Clearing a combo box causes a rash of "changed" events, even when
1981                 // the active item is -1 (inactive).  To control things, I'm disabling
1982                 // the event till things are settled down.
1983                 combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
1984                 signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX);
1985                 if (signal_id > 0)
1986                 {
1987                         // Valid signal id found.  This should always succeed.
1988                         handler_id = g_signal_handler_find ((gpointer)combo, G_SIGNAL_MATCH_ID, 
1989                                                                                                 signal_id, 0, 0, 0, 0);
1990                         if (handler_id > 0)
1991                         {
1992                                 // This should also always succeed
1993                                 g_signal_handler_block ((gpointer)combo, handler_id);
1994                         }
1995                 }
1996         }       
1997         if (all)
1998         {
1999                 audio_bitrate_opts_set(builder, "AudioBitrate");
2000                 audio_samplerate_opts_set(builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
2001                 video_rate_opts_set(builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
2002                 mix_opts_set(builder, "AudioMixdown");
2003                 language_opts_set(builder, "SourceAudioLang");
2004                 subtitle_opts_set(builder, "Subtitles", user_data);
2005                 title_opts_set(builder, "title");
2006                 audio_track_opts_set(builder, "AudioTrack", user_data);
2007                 generic_opts_set(builder, "VideoQualityGranularity", &vqual_granularity_opts);
2008                 generic_opts_set(builder, "PicturePAR", &par_opts);
2009                 generic_opts_set(builder, "PictureModulus", &alignment_opts);
2010                 generic_opts_set(builder, "LoggingLevel", &logging_opts);
2011                 generic_opts_set(builder, "FileFormat", &container_opts);
2012                 generic_opts_set(builder, "PictureDeinterlace", &deint_opts);
2013                 generic_opts_set(builder, "PictureDetelecine", &detel_opts);
2014                 generic_opts_set(builder, "PictureDecomb", &decomb_opts);
2015                 generic_opts_set(builder, "PictureDenoise", &denoise_opts);
2016                 generic_opts_set(builder, "VideoEncoder", &vcodec_opts);
2017                 generic_opts_set(builder, "AudioEncoder", &acodec_opts);
2018                 generic_opts_set(builder, "x264_direct", &direct_opts);
2019                 generic_opts_set(builder, "x264_b_adapt", &badapt_opts);
2020                 generic_opts_set(builder, "x264_me", &me_opts);
2021                 generic_opts_set(builder, "x264_subme", &subme_opts);
2022                 generic_opts_set(builder, "x264_analyse", &analyse_opts);
2023                 generic_opts_set(builder, "x264_trellis", &trellis_opts);
2024         }
2025         else
2026         {
2027                 if (strcmp(name, "AudioBitrate") == 0)
2028                         audio_bitrate_opts_set(builder, "AudioBitrate");
2029                 else if (strcmp(name, "AudioSamplerate") == 0)
2030                         audio_samplerate_opts_set(builder, "AudioSamplerate", hb_audio_rates, hb_audio_rates_count);
2031                 else if (strcmp(name, "VideoFramerate") == 0)
2032                         video_rate_opts_set(builder, "VideoFramerate", hb_video_rates, hb_video_rates_count);
2033                 else if (strcmp(name, "AudioMixdown") == 0)
2034                         mix_opts_set(builder, "AudioMixdown");
2035                 else if (strcmp(name, "SourceAudioLang") == 0)
2036                         language_opts_set(builder, "SourceAudioLang");
2037                 else if (strcmp(name, "Subtitles") == 0)
2038                         subtitle_opts_set(builder, "Subtitles", user_data);
2039                 else if (strcmp(name, "title") == 0)
2040                         title_opts_set(builder, "title");
2041                 else if (strcmp(name, "AudioTrack") == 0)
2042                         audio_track_opts_set(builder, "AudioTrack", user_data);
2043                 else
2044                         generic_opts_set(builder, name, find_combo_table(name));
2045         }
2046         if (handler_id > 0)
2047         {
2048                 g_signal_handler_unblock ((gpointer)combo, handler_id);
2049         }
2050 }
2051         
2052 static void
2053 init_ui_combo_boxes(GtkBuilder *builder)
2054 {
2055         gint ii;
2056
2057         init_combo_box(builder, "AudioBitrate");
2058         init_combo_box(builder, "AudioSamplerate");
2059         init_combo_box(builder, "VideoFramerate");
2060         init_combo_box(builder, "AudioMixdown");
2061         init_combo_box(builder, "SourceAudioLang");
2062         init_combo_box(builder, "Subtitles");
2063         init_combo_box(builder, "title");
2064         init_combo_box(builder, "AudioTrack");
2065         for (ii = 0; combo_name_map[ii].name != NULL; ii++)
2066         {
2067                 init_combo_box(builder, combo_name_map[ii].name);
2068         }
2069 }
2070         
2071 static const char * turbo_opts = 
2072         "ref=1:subme=1:me=dia:analyse=none:trellis=0:"
2073         "no-fast-pskip=0:8x8dct=0:weightb=0";
2074
2075 // Construct the x264 options string
2076 // The result is allocated, so someone must free it at some point.
2077 gchar*
2078 ghb_build_x264opts_string(GValue *settings)
2079 {
2080         gchar *result;
2081         gchar *opts = ghb_settings_get_string(settings, "x264Option");
2082         if (opts != NULL)
2083         {
2084                 result = opts;
2085         }
2086         else
2087         {
2088                 result = g_strdup("");
2089         }
2090         return result;
2091 }
2092
2093 void
2094 ghb_get_chapter_duration(gint ti, gint ii, gint *hh, gint *mm, gint *ss)
2095 {
2096         hb_list_t  * list;
2097         hb_title_t * title;
2098     hb_chapter_t * chapter;
2099         gint count;
2100         
2101         g_debug("ghb_get_chapter_duration (title = %d)\n", ti);
2102         *hh = *mm = *ss = 0;
2103         if (h_scan == NULL) return;
2104         list = hb_get_titles( h_scan );
2105     title = (hb_title_t*)hb_list_item( list, ti );
2106         if (title == NULL) return;
2107         count = hb_list_count( title->list_chapter );
2108         if (ii >= count) return;
2109         chapter = hb_list_item(title->list_chapter, ii);
2110         if (chapter == NULL) return;
2111         *hh = chapter->hours;
2112         *mm = chapter->minutes;
2113         *ss = chapter->seconds;
2114 }
2115
2116 GValue*
2117 ghb_get_chapters(gint titleindex)
2118 {
2119         hb_list_t  * list;
2120         hb_title_t * title;
2121     hb_chapter_t * chapter;
2122         gint count, ii;
2123         GValue *chapters = NULL;
2124         
2125         g_debug("ghb_get_chapters (title = %d)\n", titleindex);
2126         if (h_scan == NULL) return NULL;
2127         list = hb_get_titles( h_scan );
2128     title = (hb_title_t*)hb_list_item( list, titleindex );
2129         if (title == NULL) return NULL;
2130         count = hb_list_count( title->list_chapter );
2131         chapters = ghb_array_value_new(count);
2132         for (ii = 0; ii < count; ii++)
2133         {
2134                 chapter = hb_list_item(title->list_chapter, ii);
2135                 if (chapter == NULL) break;
2136                 if (chapter->title == NULL || chapter->title[0] == 0)
2137                 {
2138                         gchar *str;
2139                         str = g_strdup_printf ("Chapter %2d", ii+1);
2140                         ghb_array_append(chapters, ghb_string_value_new(str));
2141                         g_free(str);
2142                 }
2143                 else 
2144                 {
2145                         ghb_array_append(chapters, ghb_string_value_new(chapter->title));
2146                 }
2147         }
2148         return chapters;
2149 }
2150
2151 gboolean
2152 ghb_ac3_in_audio_list(const GValue *audio_list)
2153 {
2154         gint count, ii;
2155
2156         count = ghb_array_len(audio_list);
2157         for (ii = 0; ii < count; ii++)
2158         {
2159                 GValue *asettings;
2160                 gint acodec;
2161
2162                 asettings = ghb_array_get_nth(audio_list, ii);
2163                 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
2164                 if (acodec == HB_ACODEC_AC3)
2165                         return TRUE;
2166         }
2167         return FALSE;
2168 }
2169
2170 static void
2171 audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
2172 {
2173         GtkTreeIter iter;
2174         GtkListStore *store;
2175         gchar *str;
2176         
2177         g_debug("audio_rate_opts_add ()\n");
2178         store = get_combo_box_store(builder, name);
2179         if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
2180         {
2181                 str = g_strdup_printf ("%d", rate);
2182                 gtk_list_store_append(store, &iter);
2183                 gtk_list_store_set(store, &iter, 
2184                                                    0, str, 
2185                                                    1, TRUE, 
2186                                                    2, str, 
2187                                                    3, (gdouble)rate, 
2188                                                    4, str, 
2189                                                    -1);
2190                 g_free(str);
2191         }
2192 }
2193
2194 static void
2195 audio_bitrate_opts_clean(GtkBuilder *builder, const gchar *name, gint last_rate)
2196 {
2197         GtkTreeIter iter;
2198         GtkListStore *store;
2199         gdouble ivalue;
2200         gboolean done = FALSE;
2201         gint ii = 0;
2202         guint last = (guint)last_rate;
2203         
2204         g_debug("audio_bitrate_opts_clean ()\n");
2205         store = get_combo_box_store(builder, name);
2206         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
2207         {
2208                 do
2209                 {
2210                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
2211                         if (search_rates(
2212                                 hb_audio_bitrates, ivalue, hb_audio_bitrates_count) < 0)
2213                         {
2214                                 done = !gtk_list_store_remove(store, &iter);
2215                         }
2216                         else if (ivalue > last)
2217                         {
2218                                 ii++;
2219                                 gtk_list_store_set(store, &iter, 1, FALSE, -1);
2220                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
2221                         }
2222                         else
2223                         {
2224                                 ii++;
2225                                 gtk_list_store_set(store, &iter, 1, TRUE, -1);
2226                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
2227                         }
2228                 } while (!done);
2229         }
2230 }
2231
2232 static void
2233 audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
2234 {
2235         GtkTreeIter iter;
2236         GtkListStore *store;
2237         gint ii;
2238         
2239         g_debug("audio_bitrate_opts_set ()\n");
2240         store = get_combo_box_store(builder, name);
2241         gtk_list_store_clear(store);
2242         for (ii = 0; ii < hb_audio_bitrates_count; ii++)
2243         {
2244                 gtk_list_store_append(store, &iter);
2245                 gtk_list_store_set(store, &iter, 
2246                                                    0, hb_audio_bitrates[ii].string, 
2247                                                    1, TRUE, 
2248                                                    2, hb_audio_bitrates[ii].string, 
2249                                                    3, (gdouble)hb_audio_bitrates[ii].rate, 
2250                                                    4, hb_audio_bitrates[ii].string, 
2251                                                    -1);
2252         }
2253 }
2254
2255 void
2256 ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate)
2257 {
2258         audio_bitrate_opts_add(builder, "AudioBitrate", bitrate);
2259 }
2260
2261 void
2262 ghb_set_default_bitrate_opts(GtkBuilder *builder, gint last_rate)
2263 {
2264         audio_bitrate_opts_clean(builder, "AudioBitrate", last_rate);
2265 }
2266
2267 static ghb_status_t hb_status;
2268
2269 void
2270 ghb_combo_init(GtkBuilder *builder)
2271 {
2272         // Set up the list model for the combos
2273         init_ui_combo_boxes(builder);
2274         // Populate all the combos
2275         ghb_update_ui_combo_box(builder, NULL, 0, TRUE);
2276 }
2277
2278 void
2279 ghb_backend_init(gint debug)
2280 {
2281     /* Init libhb */
2282     h_scan = hb_init( debug, 0 );
2283     h_queue = hb_init( debug, 0 );
2284 }
2285
2286 void
2287 ghb_backend_close()
2288 {
2289         hb_close(&h_queue);
2290         hb_close(&h_scan);
2291 }
2292
2293 void
2294 ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count)
2295 {
2296     hb_scan( h_scan, path, titleindex, preview_count, 1 );
2297         hb_status.scan.state |= GHB_STATE_SCANNING;
2298         // initialize count and cur to something that won't cause FPE
2299         // when computing progress
2300         hb_status.scan.title_count = 1;
2301         hb_status.scan.title_cur = 0;
2302 }
2303
2304 void
2305 ghb_backend_queue_scan(const gchar *path, gint titlenum)
2306 {
2307         g_debug("ghb_backend_queue_scan()");
2308         hb_scan( h_queue, path, titlenum, 10, 0 );
2309         hb_status.queue.state |= GHB_STATE_SCANNING;
2310 }
2311
2312 gint
2313 ghb_get_scan_state()
2314 {
2315         return hb_status.scan.state;
2316 }
2317
2318 gint
2319 ghb_get_queue_state()
2320 {
2321         return hb_status.queue.state;
2322 }
2323
2324 void
2325 ghb_clear_scan_state(gint state)
2326 {
2327         hb_status.scan.state &= ~state;
2328 }
2329
2330 void
2331 ghb_clear_queue_state(gint state)
2332 {
2333         hb_status.queue.state &= ~state;
2334 }
2335
2336 void
2337 ghb_set_scan_state(gint state)
2338 {
2339         hb_status.scan.state |= state;
2340 }
2341
2342 void
2343 ghb_set_queue_state(gint state)
2344 {
2345         hb_status.queue.state |= state;
2346 }
2347
2348 void
2349 ghb_get_status(ghb_status_t *status)
2350 {
2351         memcpy(status, &hb_status, sizeof(ghb_status_t));
2352 }
2353
2354 void 
2355 ghb_track_status()
2356 {
2357     hb_state_t s_scan;
2358     hb_state_t s_queue;
2359
2360         if (h_scan == NULL) return;
2361     hb_get_state( h_scan, &s_scan );
2362         switch( s_scan.state )
2363     {
2364 #define p s_scan.param.scanning
2365         case HB_STATE_SCANNING:
2366                 {
2367                         hb_status.scan.state |= GHB_STATE_SCANNING;
2368                         hb_status.scan.title_count = p.title_count;
2369                         hb_status.scan.title_cur = p.title_cur;
2370                 } break;
2371 #undef p
2372
2373         case HB_STATE_SCANDONE:
2374         {
2375                         hb_status.scan.state &= ~GHB_STATE_SCANNING;
2376                         hb_status.scan.state |= GHB_STATE_SCANDONE;
2377         } break;
2378
2379 #define p s_scan.param.working
2380         case HB_STATE_WORKING:
2381                         hb_status.scan.state |= GHB_STATE_WORKING;
2382                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
2383                         hb_status.scan.job_cur = p.job_cur;
2384                         hb_status.scan.job_count = p.job_count;
2385                         hb_status.scan.progress = p.progress;
2386                         hb_status.scan.rate_cur = p.rate_cur;
2387                         hb_status.scan.rate_avg = p.rate_avg;
2388                         hb_status.scan.hours = p.hours;
2389                         hb_status.scan.minutes = p.minutes;
2390                         hb_status.scan.seconds = p.seconds;
2391                         hb_status.scan.unique_id = p.sequence_id & 0xFFFFFF;
2392             break;
2393 #undef p
2394
2395         case HB_STATE_PAUSED:
2396                         hb_status.scan.state |= GHB_STATE_PAUSED;
2397             break;
2398                                 
2399         case HB_STATE_MUXING:
2400         {
2401                         hb_status.scan.state |= GHB_STATE_MUXING;
2402         } break;
2403
2404 #define p s_scan.param.workdone
2405         case HB_STATE_WORKDONE:
2406                 {
2407             hb_job_t *job;
2408
2409                         hb_status.scan.state |= GHB_STATE_WORKDONE;
2410                         hb_status.scan.state &= ~GHB_STATE_MUXING;
2411                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
2412                         hb_status.scan.state &= ~GHB_STATE_WORKING;
2413                         switch (p.error)
2414                         {
2415                         case HB_ERROR_NONE:
2416                                 hb_status.scan.error = GHB_ERROR_NONE;
2417                                 break;
2418                         case HB_ERROR_CANCELED:
2419                                 hb_status.scan.error = GHB_ERROR_CANCELED;
2420                                 break;
2421                         default:
2422                                 hb_status.scan.error = GHB_ERROR_FAIL;
2423                                 break;
2424                         }
2425                         // Delete all remaining jobs of this encode.
2426                         // An encode can be composed of multiple associated jobs.
2427                         // When a job is stopped, libhb removes it from the job list,
2428                         // but does not remove other jobs that may be associated with it.
2429                         // Associated jobs are taged in the sequence id.
2430             while ((job = hb_job(h_scan, 0)) != NULL) 
2431                 hb_rem( h_scan, job );
2432                 } break;
2433 #undef p
2434     }
2435     hb_get_state( h_queue, &s_queue );
2436         switch( s_queue.state )
2437     {
2438 #define p s_queue.param.scanning
2439         case HB_STATE_SCANNING:
2440                 {
2441                         hb_status.queue.state |= GHB_STATE_SCANNING;
2442                         hb_status.queue.title_count = p.title_count;
2443                         hb_status.queue.title_cur = p.title_cur;
2444                 } break;
2445 #undef p
2446
2447         case HB_STATE_SCANDONE:
2448         {
2449                         hb_status.queue.state &= ~GHB_STATE_SCANNING;
2450                         hb_status.queue.state |= GHB_STATE_SCANDONE;
2451         } break;
2452
2453 #define p s_queue.param.working
2454         case HB_STATE_WORKING:
2455                         hb_status.queue.state |= GHB_STATE_WORKING;
2456                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
2457                         hb_status.queue.job_cur = p.job_cur;
2458                         hb_status.queue.job_count = p.job_count;
2459                         hb_status.queue.progress = p.progress;
2460                         hb_status.queue.rate_cur = p.rate_cur;
2461                         hb_status.queue.rate_avg = p.rate_avg;
2462                         hb_status.queue.hours = p.hours;
2463                         hb_status.queue.minutes = p.minutes;
2464                         hb_status.queue.seconds = p.seconds;
2465                         hb_status.queue.unique_id = p.sequence_id & 0xFFFFFF;
2466             break;
2467 #undef p
2468
2469         case HB_STATE_PAUSED:
2470                         hb_status.queue.state |= GHB_STATE_PAUSED;
2471             break;
2472                                 
2473         case HB_STATE_MUXING:
2474         {
2475                         hb_status.queue.state |= GHB_STATE_MUXING;
2476         } break;
2477
2478 #define p s_queue.param.workdone
2479         case HB_STATE_WORKDONE:
2480                 {
2481             hb_job_t *job;
2482
2483                         hb_status.queue.state |= GHB_STATE_WORKDONE;
2484                         hb_status.queue.state &= ~GHB_STATE_MUXING;
2485                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
2486                         hb_status.queue.state &= ~GHB_STATE_WORKING;
2487                         switch (p.error)
2488                         {
2489                         case HB_ERROR_NONE:
2490                                 hb_status.queue.error = GHB_ERROR_NONE;
2491                                 break;
2492                         case HB_ERROR_CANCELED:
2493                                 hb_status.queue.error = GHB_ERROR_CANCELED;
2494                                 break;
2495                         default:
2496                                 hb_status.queue.error = GHB_ERROR_FAIL;
2497                                 break;
2498                         }
2499                         // Delete all remaining jobs of this encode.
2500                         // An encode can be composed of multiple associated jobs.
2501                         // When a job is stopped, libhb removes it from the job list,
2502                         // but does not remove other jobs that may be associated with it.
2503                         // Associated jobs are taged in the sequence id.
2504             while ((job = hb_job(h_queue, 0)) != NULL) 
2505                 hb_rem( h_queue, job );
2506                 } break;
2507 #undef p
2508     }
2509 }
2510
2511 gboolean
2512 ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
2513 {
2514         hb_list_t  * list;
2515         hb_title_t * title;
2516         
2517     if (h_scan == NULL) return FALSE;
2518         list = hb_get_titles( h_scan );
2519         if( !hb_list_count( list ) )
2520         {
2521                 /* No valid title, stop right there */
2522                 return FALSE;
2523         }
2524
2525     title = hb_list_item( list, titleindex );
2526         if (title == NULL) return FALSE;        // Bad titleindex
2527         tinfo->width = title->width;
2528         tinfo->height = title->height;
2529         memcpy(tinfo->crop, title->crop, 4 * sizeof(int));
2530         // Don't allow crop to 0
2531         if (title->crop[0] + title->crop[1] >= title->height)
2532                 title->crop[0] = title->crop[1] = 0;
2533         if (title->crop[2] + title->crop[3] >= title->width)
2534                 title->crop[2] = title->crop[3] = 0;
2535         tinfo->num_chapters = hb_list_count(title->list_chapter);
2536         tinfo->rate_base = title->rate_base;
2537         tinfo->rate = title->rate;
2538         hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), 
2539                                 title->width * title->pixel_aspect_width, 
2540                                 title->height * title->pixel_aspect_height);
2541         tinfo->hours = title->hours;
2542         tinfo->minutes = title->minutes;
2543         tinfo->seconds = title->seconds;
2544         tinfo->duration = title->duration;
2545
2546         tinfo->angle_count = title->angle_count;
2547         return TRUE;
2548 }
2549
2550 gboolean
2551 ghb_get_audio_info(ghb_audio_info_t *ainfo, gint titleindex, gint audioindex)
2552 {
2553     hb_audio_config_t *audio;
2554         
2555         audio = get_hb_audio(titleindex, audioindex);
2556         if (audio == NULL) return FALSE; // Bad audioindex
2557         ainfo->codec = audio->in.codec;
2558         ainfo->bitrate = audio->in.bitrate;
2559         ainfo->samplerate = audio->in.samplerate;
2560         return TRUE;
2561 }
2562
2563 gboolean
2564 ghb_audio_is_passthru(gint acodec)
2565 {
2566         g_debug("ghb_audio_is_passthru () \n");
2567         return (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA));
2568 }
2569
2570 gint
2571 ghb_get_default_acodec()
2572 {
2573         return HB_ACODEC_FAAC;
2574 }
2575
2576 static void
2577 picture_settings_deps(signal_user_data_t *ud)
2578 {
2579         gboolean autoscale, keep_aspect, enable_keep_aspect;
2580         gboolean enable_scale_width, enable_scale_height;
2581         gboolean enable_disp_width, enable_disp_height;
2582         gint pic_par;
2583         GtkWidget *widget;
2584
2585         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
2586         if (pic_par == 1)
2587         {
2588                 ghb_ui_update(ud, "autoscale", ghb_boolean_value(TRUE));
2589                 ghb_ui_update(ud, "PictureModulus", ghb_int_value(2));
2590                 ghb_ui_update(ud, "PictureLooseCrop", ghb_boolean_value(TRUE));
2591         }
2592         enable_keep_aspect = (pic_par != 1 && pic_par != 2);
2593         if (!enable_keep_aspect)
2594         {
2595                 ghb_ui_update(ud, "PictureKeepRatio", ghb_boolean_value(TRUE));
2596         }
2597         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
2598         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
2599
2600         enable_scale_width = !autoscale && (pic_par != 1);
2601         enable_scale_height = !autoscale && (pic_par != 1);
2602         enable_disp_width = (pic_par == 3) && !keep_aspect;
2603         enable_disp_height = FALSE;
2604
2605         widget = GHB_WIDGET(ud->builder, "PictureModulus");
2606         gtk_widget_set_sensitive(widget, pic_par != 1);
2607         widget = GHB_WIDGET(ud->builder, "PictureLooseCrop");
2608         gtk_widget_set_sensitive(widget, pic_par != 1);
2609         widget = GHB_WIDGET(ud->builder, "scale_width");
2610         gtk_widget_set_sensitive(widget, enable_scale_width);
2611         widget = GHB_WIDGET(ud->builder, "scale_height");
2612         gtk_widget_set_sensitive(widget, enable_scale_height);
2613         widget = GHB_WIDGET(ud->builder, "PictureDisplayWidth");
2614         gtk_widget_set_sensitive(widget, enable_disp_width);
2615         widget = GHB_WIDGET(ud->builder, "PictureDisplayHeight");
2616         gtk_widget_set_sensitive(widget, enable_disp_height);
2617         widget = GHB_WIDGET(ud->builder, "PictureKeepRatio");
2618         gtk_widget_set_sensitive(widget, enable_keep_aspect);
2619         widget = GHB_WIDGET(ud->builder, "autoscale");
2620         gtk_widget_set_sensitive(widget, pic_par != 1);
2621 }
2622
2623 void
2624 ghb_set_scale(signal_user_data_t *ud, gint mode)
2625 {
2626         hb_list_t  * list;
2627         hb_title_t * title;
2628         hb_job_t   * job;
2629         gboolean keep_aspect;
2630         gint pic_par;
2631         gboolean autocrop, autoscale, noscale;
2632         gint crop[4], width, height, par_width, par_height;
2633         gint crop_width, crop_height;
2634         gint aspect_n, aspect_d;
2635         gboolean keep_width = (mode & GHB_PIC_KEEP_WIDTH);
2636         gboolean keep_height = (mode & GHB_PIC_KEEP_HEIGHT);
2637         gint step;
2638         GtkWidget *widget;
2639         gint mod;
2640         gint max_width = 0;
2641         gint max_height = 0;
2642         static gboolean busy = FALSE;
2643         
2644         g_debug("ghb_set_scale ()\n");
2645         if (h_scan == NULL) return;
2646         list = hb_get_titles( h_scan );
2647         if( !hb_list_count( list ) )
2648         {
2649                 /* No valid title, stop right there */
2650                 return;
2651         }
2652         gint titleindex;
2653
2654         titleindex = ghb_settings_combo_int(ud->settings, "title");
2655     title = hb_list_item( list, titleindex );
2656         if (title == NULL) return;
2657         job   = title->job;
2658         if (job == NULL) return;
2659
2660         picture_settings_deps(ud);
2661         if (busy) return;
2662         busy = TRUE;
2663
2664         
2665         // First configure widgets
2666         mod = ghb_settings_combo_int(ud->settings, "PictureModulus");
2667         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
2668         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
2669         autocrop = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop");
2670         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
2671         // "Noscale" is a flag that says we prefer to crop extra to satisfy
2672         // alignment constraints rather than scaling to satisfy them.
2673         noscale = ghb_settings_get_boolean(ud->settings, "PictureLooseCrop");
2674         // Align dimensions to either 16 or 2 pixels
2675         // The scaler crashes if the dimensions are not divisible by 2
2676         // x264 also will not accept dims that are not multiple of 2
2677         if (autoscale)
2678         {
2679                 keep_width = FALSE;
2680                 keep_height = FALSE;
2681         }
2682         // Step needs to be at least 2 because odd widths cause scaler crash
2683         step = mod;
2684         widget = GHB_WIDGET (ud->builder, "scale_width");
2685         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2686         widget = GHB_WIDGET (ud->builder, "scale_height");
2687         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2688         if (noscale)
2689         {
2690                 widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
2691                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2692                 widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
2693                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2694                 widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
2695                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2696                 widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
2697                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2698         }
2699         else
2700         {
2701                 widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
2702                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
2703                 widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
2704                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
2705                 widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
2706                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
2707                 widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
2708                 gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), 1, 16);
2709         }
2710         ghb_title_info_t tinfo;
2711         ghb_get_title_info (&tinfo, titleindex);
2712         if (autocrop)
2713         {
2714                 crop[0] = tinfo.crop[0];
2715                 crop[1] = tinfo.crop[1];
2716                 crop[2] = tinfo.crop[2];
2717                 crop[3] = tinfo.crop[3];
2718                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(crop[0]));
2719                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(crop[1]));
2720                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(crop[2]));
2721                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(crop[3]));
2722         }
2723         else
2724         {
2725                 crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
2726                 crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
2727                 crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
2728                 crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
2729         }
2730         if (noscale)
2731         {
2732                 gint need1, need2;
2733
2734                 // Adjust the cropping to accomplish the desired width and height
2735                 crop_width = tinfo.width - crop[2] - crop[3];
2736                 crop_height = tinfo.height - crop[0] - crop[1];
2737                 width = MOD_DOWN(crop_width, mod);
2738                 height = MOD_DOWN(crop_height, mod);
2739
2740                 need1 = (crop_height - height) / 2;
2741                 need2 = crop_height - height - need1;
2742                 crop[0] += need1;
2743                 crop[1] += need2;
2744                 need1 = (crop_width - width) / 2;
2745                 need2 = crop_width - width - need1;
2746                 crop[2] += need1;
2747                 crop[3] += need2;
2748                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(crop[0]));
2749                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(crop[1]));
2750                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(crop[2]));
2751                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(crop[3]));
2752         }
2753         hb_reduce(&aspect_n, &aspect_d, 
2754                                 title->width * title->pixel_aspect_width, 
2755                                 title->height * title->pixel_aspect_height);
2756         crop_width = title->width - crop[2] - crop[3];
2757         crop_height = title->height - crop[0] - crop[1];
2758         if (autoscale)
2759         {
2760                 width = crop_width;
2761                 height = crop_height;
2762         }
2763         else
2764         {
2765                 width = ghb_settings_get_int(ud->settings, "scale_width");
2766                 height = ghb_settings_get_int(ud->settings, "scale_height");
2767                 max_width = MOD_DOWN(
2768                         ghb_settings_get_int(ud->settings, "PictureWidth"), mod);
2769                 max_height = MOD_DOWN(
2770                         ghb_settings_get_int(ud->settings, "PictureHeight"), mod);
2771         }
2772         // Adjust dims according to max values
2773         if (!max_height)
2774         {
2775                 max_height = MOD_DOWN(crop_height, mod);
2776         }
2777         if (!max_width)
2778         {
2779                 max_width = MOD_DOWN(crop_width, mod);
2780         }
2781         // Align max dims 
2782         g_debug("max_width %d, max_height %d\n", max_width, max_height);
2783
2784         if (width < 16)
2785                 width = title->width - crop[2] - crop[3];
2786         if (height < 16)
2787                 height = title->height - crop[0] - crop[1];
2788
2789         width = MOD_ROUND(width, mod);
2790         height = MOD_ROUND(height, mod);
2791         if (max_height)
2792                 height = MIN(height, max_height);
2793         if (max_width)
2794                 width = MIN(width, max_width);
2795
2796         if (pic_par)
2797         {
2798                 job->anamorphic.mode = pic_par;
2799                 // The scaler crashes if the dimensions are not divisible by 2
2800                 // Align mod 2.  And so does something in x264_encoder_headers()
2801                 job->anamorphic.modulus = mod;
2802                 if (keep_height && pic_par == 2)
2803                         width = ((double)height * crop_width / crop_height) + 0.5;
2804                 job->width = width;
2805                 job->height = height;
2806                 if (max_width) 
2807                         job->maxWidth = max_width;
2808                 if (max_height) 
2809                         job->maxHeight = max_height;
2810                 job->crop[0] = crop[0]; job->crop[1] = crop[1];
2811                 job->crop[2] = crop[2]; job->crop[3] = crop[3];
2812                 if (job->anamorphic.mode == 3 && !keep_aspect)
2813                 {
2814                         gint dar_width, dar_height;
2815                         if (mode & GHB_PIC_KEEP_PAR)
2816                         {
2817                                 par_width = ghb_settings_get_int(ud->settings, 
2818                                                                                                 "PicturePARWidth");
2819                                 par_height = ghb_settings_get_int(ud->settings, 
2820                                                                                                 "PicturePARHeight");
2821                                 dar_width = ((gdouble)width * par_width / par_height) + 0.5;
2822                                 dar_height = height;
2823                         }
2824                         else
2825                         {
2826                                 dar_width = ghb_settings_get_int(ud->settings, 
2827                                                                                                 "PictureDisplayWidth");
2828                                 dar_height = ghb_settings_get_int(ud->settings, 
2829                                                                                                 "PictureDisplayHeight");
2830                         }
2831                         job->anamorphic.dar_width = dar_width;
2832                         job->anamorphic.dar_height = dar_height;
2833                 }
2834                 else
2835                 {
2836                         job->anamorphic.dar_width = 0;
2837                         job->anamorphic.dar_height = 0;
2838                 }
2839                 hb_set_anamorphic_size( job, &width, &height, 
2840                                                                 &par_width, &par_height );
2841         }
2842         else 
2843         {
2844                 job->anamorphic.mode = pic_par;
2845                 if (keep_aspect)
2846                 {
2847                         gdouble par;
2848                         gint new_width, new_height;
2849                         
2850                         // Compute pixel aspect ration.  
2851                         par = (gdouble)(title->height * aspect_n) / (title->width * aspect_d);
2852                         // Must scale so that par becomes 1:1
2853                         // Try to keep largest dimension
2854                         new_height = (crop_height * ((gdouble)width/crop_width) / par);
2855                         new_width = (crop_width * ((gdouble)height/crop_height) * par);
2856
2857                         if (max_width && new_width > max_width)
2858                         {
2859                                 height = new_height;
2860                         }
2861                         else if (max_height && new_height > max_height)
2862                         {
2863                                 width = new_width;
2864                         }
2865                         else if (keep_width)
2866                         {
2867                                 height = new_height;
2868                         }
2869                         else if (keep_height)
2870                         {
2871                                 width = new_width;
2872                         }
2873                         else if (width > new_width)
2874                         {
2875                                 height = new_height;
2876                         }
2877                         else
2878                         {
2879                                 width = new_width;
2880                         }
2881                         g_debug("new w %d h %d\n", width, height);
2882                 }
2883                 width = MOD_ROUND(width, mod);
2884                 height = MOD_ROUND(height, mod);
2885                 if (max_height)
2886                         height = MIN(height, max_height);
2887                 if (max_width)
2888                         width = MIN(width, max_width);
2889                 par_width = par_height = 1;
2890         }
2891         ghb_ui_update(ud, "scale_width", ghb_int64_value(width));
2892         ghb_ui_update(ud, "scale_height", ghb_int64_value(height));
2893
2894         gint disp_width, dar_width, dar_height;
2895         gchar *str;
2896
2897         disp_width = (gdouble)(width * par_width / par_height) + 0.5;
2898         hb_reduce(&dar_width, &dar_height, disp_width, height);
2899                 
2900         gint iaspect = dar_width * 9 / dar_height;
2901         if (dar_width > 2 * dar_height)
2902         {
2903                 str = g_strdup_printf("%.2f : 1", (gdouble)dar_width / dar_height);
2904         }
2905         else if (iaspect <= 16 && iaspect >= 15)
2906         {
2907                 str = g_strdup_printf("%.2f : 9", (gdouble)dar_width * 9 / dar_height);
2908         }
2909         else if (iaspect <= 12 && iaspect >= 11)
2910         {
2911                 str = g_strdup_printf("%.2f : 3", (gdouble)dar_width * 3 / dar_height);
2912         }
2913         else
2914         {
2915                 str = g_strdup_printf("%d : %d", dar_width, dar_height);
2916         }
2917         ghb_ui_update(ud, "display_aspect", ghb_string_value(str));
2918         g_free(str);
2919         ghb_ui_update(ud, "par_width", ghb_int64_value(par_width));
2920         ghb_ui_update(ud, "par_height", ghb_int64_value(par_height));
2921         ghb_ui_update(ud, "PictureDisplayWidth", ghb_int64_value(disp_width));
2922         ghb_ui_update(ud, "PictureDisplayHeight", ghb_int64_value(height));
2923         busy = FALSE;
2924 }
2925
2926 static void
2927 set_preview_job_settings(hb_job_t *job, GValue *settings)
2928 {
2929         job->crop[0] = ghb_settings_get_int(settings, "PictureTopCrop");
2930         job->crop[1] = ghb_settings_get_int(settings, "PictureBottomCrop");
2931         job->crop[2] = ghb_settings_get_int(settings, "PictureLeftCrop");
2932         job->crop[3] = ghb_settings_get_int(settings, "PictureRightCrop");
2933
2934         job->anamorphic.mode = ghb_settings_combo_int(settings, "PicturePAR");
2935         job->anamorphic.modulus = 
2936                 ghb_settings_combo_int(settings, "PictureModulus");
2937         job->width = ghb_settings_get_int(settings, "scale_width");
2938         job->height = ghb_settings_get_int(settings, "scale_height");
2939
2940         gint deint = ghb_settings_combo_int(settings, "PictureDeinterlace");
2941         gint decomb = ghb_settings_combo_int(settings, "PictureDecomb");
2942         job->deinterlace = (!decomb && deint == 0) ? 0 : 1;
2943
2944         gboolean keep_aspect;
2945         keep_aspect = ghb_settings_get_boolean(settings, "PictureKeepRatio");
2946         if (job->anamorphic.mode == 3 && !keep_aspect)
2947         {
2948                 gint disp_width, disp_height;
2949                 disp_width = ghb_settings_get_int(settings, "PictureDisplayWidth");
2950                 disp_height = ghb_settings_get_int(settings, "PictureDisplayHeight");
2951                 job->anamorphic.dar_width = disp_width;
2952                 job->anamorphic.dar_height = disp_height;
2953         }
2954         else
2955         {
2956                 job->anamorphic.dar_width = 0;
2957                 job->anamorphic.dar_height = 0;
2958         }
2959 }
2960
2961 gint
2962 ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
2963 {
2964         hb_list_t  * list;
2965         hb_title_t * title;
2966         hb_job_t   * job;
2967         gint size;
2968
2969         if (h_scan == NULL) return 1500;
2970         list = hb_get_titles( h_scan );
2971     title = hb_list_item( list, titleindex );
2972         if (title == NULL) return 1500;
2973         job   = title->job;
2974         if (job == NULL) return 1500;
2975         size = ghb_settings_get_int(settings, "VideoTargetSize");
2976         return hb_calc_bitrate( job, size );
2977 }
2978
2979 gboolean
2980 ghb_validate_filter_string(const gchar *str, gint max_fields)
2981 {
2982         gint fields = 0;
2983         gchar *end;
2984         gdouble val;
2985
2986         if (str == NULL || *str == 0) return TRUE;
2987         while (*str)
2988         {
2989                 val = g_strtod(str, &end);
2990                 if (str != end)
2991                 { // Found a numeric value
2992                         fields++;
2993                         // negative max_fields means infinate
2994                         if (max_fields >= 0 && fields > max_fields) return FALSE;
2995                         if (*end == 0)
2996                                 return TRUE;
2997                         if (*end != ':')
2998                                 return FALSE;
2999                         str = end + 1;
3000                 }
3001                 else
3002                         return FALSE;
3003         }
3004         return FALSE;
3005 }
3006
3007 gboolean
3008 ghb_validate_filters(signal_user_data_t *ud)
3009 {
3010         gchar *str;
3011         gint index;
3012         gchar *message;
3013
3014         // deinte 4
3015         index = ghb_settings_combo_int(ud->settings, "PictureDeinterlace");
3016         if (index == 1)
3017         {
3018                 str = ghb_settings_get_string(ud->settings, "PictureDeinterlaceCustom");
3019                 if (!ghb_validate_filter_string(str, 4))
3020                 {
3021                         message = g_strdup_printf(
3022                                                 "Invalid Deinterlace Settings:\n\n%s\n",
3023                                                 str);
3024                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3025                         g_free(message);
3026                         g_free(str);
3027                         return FALSE;
3028                 }
3029                 g_free(str);
3030         }
3031         // detel
3032         index = ghb_settings_combo_int(ud->settings, "PictureDetelecine");
3033         if (index == 1)
3034         {
3035                 str = ghb_settings_get_string(ud->settings, "PictureDetelecineCustom");
3036                 if (!ghb_validate_filter_string(str, 6))
3037                 {
3038                         message = g_strdup_printf(
3039                                                 "Invalid Detelecine Settings:\n\n%s\n",
3040                                                 str);
3041                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3042                         g_free(message);
3043                         g_free(str);
3044                         return FALSE;
3045                 }
3046                 g_free(str);
3047         }
3048         // decomb 4
3049         index = ghb_settings_combo_int(ud->settings, "PictureDecomb");
3050         if (index == 1)
3051         {
3052                 str = ghb_settings_get_string(ud->settings, "PictureDecombCustom");
3053                 if (!ghb_validate_filter_string(str, 7))
3054                 {
3055                         message = g_strdup_printf(
3056                                                 "Invalid Decomb Settings:\n\n%s\n",
3057                                                 str);
3058                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3059                         g_free(message);
3060                         g_free(str);
3061                         return FALSE;
3062                 }
3063                 g_free(str);
3064         }
3065         // denois 4
3066         index = ghb_settings_combo_int(ud->settings, "PictureDenoise");
3067         if (index == 1)
3068         {
3069                 str = ghb_settings_get_string(ud->settings, "PictureDenoiseCustom");
3070                 if (!ghb_validate_filter_string(str, 4))
3071                 {
3072                         message = g_strdup_printf(
3073                                                 "Invalid Denoise Settings:\n\n%s\n",
3074                                                 str);
3075                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3076                         g_free(str);
3077                         g_free(message);
3078                         return FALSE;
3079                 }
3080                 g_free(str);
3081         }
3082         return TRUE;
3083 }
3084
3085 gboolean
3086 ghb_validate_video(signal_user_data_t *ud)
3087 {
3088         gint vcodec, mux;
3089         gchar *message;
3090
3091         mux = ghb_settings_combo_int(ud->settings, "FileFormat");
3092         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
3093         if ((mux == HB_MUX_MP4 || mux == HB_MUX_AVI) && 
3094                 (vcodec == HB_VCODEC_THEORA))
3095         {
3096                 // mp4|avi/theora combination is not supported.
3097                 message = g_strdup_printf(
3098                                         "Theora is not supported in the MP4 and AVI containers.\n\n"
3099                                         "You should choose a different video codec or container.\n"
3100                                         "If you continue, XviD will be chosen for you.");
3101                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3102                 {
3103                         g_free(message);
3104                         return FALSE;
3105                 }
3106                 g_free(message);
3107                 vcodec = HB_VCODEC_XVID;
3108                 ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
3109         }
3110         return TRUE;
3111 }
3112
3113 gboolean
3114 ghb_validate_audio(signal_user_data_t *ud)
3115 {
3116         hb_list_t  * list;
3117         hb_title_t * title;
3118         gchar *message;
3119         GValue *value;
3120
3121         if (h_scan == NULL) return FALSE;
3122         list = hb_get_titles( h_scan );
3123         if( !hb_list_count( list ) )
3124         {
3125                 /* No valid title, stop right there */
3126                 g_message("No title found.\n");
3127                 return FALSE;
3128         }
3129
3130         gint titleindex;
3131
3132         titleindex = ghb_settings_combo_int(ud->settings, "title");
3133     title = hb_list_item( list, titleindex );
3134         if (title == NULL) return FALSE;
3135         gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
3136
3137         const GValue *audio_list;
3138         gint count, ii;
3139
3140         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
3141         count = ghb_array_len(audio_list);
3142         for (ii = 0; ii < count; ii++)
3143         {
3144                 GValue *asettings;
3145             hb_audio_config_t *taudio;
3146
3147                 asettings = ghb_array_get_nth(audio_list, ii);
3148                 gint track = ghb_settings_combo_int(asettings, "AudioTrack");
3149                 gint codec = ghb_settings_combo_int(asettings, "AudioEncoder");
3150         taudio = (hb_audio_config_t *) hb_list_audio_config_item(
3151                                                                                         title->list_audio, track );
3152                 if (!(taudio->in.codec & codec) && 
3153                         (codec & (HB_ACODEC_AC3 | HB_ACODEC_DCA)))
3154                 {
3155                         // Not supported.  AC3 is passthrough only, so input must be AC3
3156                         message = g_strdup_printf(
3157                                                 "The source does not support Pass-Thru.\n\n"
3158                                                 "You should choose a different audio codec.\n"
3159                                                 "If you continue, one will be chosen for you.");
3160                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3161                         {
3162                                 g_free(message);
3163                                 return FALSE;
3164                         }
3165                         g_free(message);
3166                         if (mux == HB_MUX_AVI)
3167                         {
3168                                 codec = HB_ACODEC_LAME;
3169                         }
3170                         else
3171                         {
3172                                 codec = HB_ACODEC_FAAC;
3173                         }
3174                         value = get_acodec_value(codec);
3175                         ghb_settings_take_value(asettings, "AudioEncoder", value);
3176                 }
3177                 gchar *a_unsup = NULL;
3178                 gchar *mux_s = NULL;
3179                 if (mux == HB_MUX_MP4)
3180                 { 
3181                         mux_s = "MP4";
3182                         // mp4/mp3|vorbis combination is not supported.
3183                         if (codec == HB_ACODEC_LAME)
3184                         {
3185                                 a_unsup = "MP3";
3186                                 codec = HB_ACODEC_FAAC;
3187                         }
3188                         if (codec == HB_ACODEC_VORBIS)
3189                         {
3190                                 a_unsup = "Vorbis";
3191                                 codec = HB_ACODEC_FAAC;
3192                         }
3193                         if (codec == HB_ACODEC_DCA)
3194                         {
3195                                 a_unsup = "DTS";
3196                                 codec = HB_ACODEC_FAAC;
3197                         }
3198                 }
3199                 else if (mux == HB_MUX_AVI)
3200                 {
3201                         mux_s = "AVI";
3202                         // avi/faac|vorbis combination is not supported.
3203                         if (codec == HB_ACODEC_FAAC)
3204                         {
3205                                 a_unsup = "FAAC";
3206                                 codec = HB_ACODEC_LAME;
3207                         }
3208                         if (codec == HB_ACODEC_VORBIS)
3209                         {
3210                                 a_unsup = "Vorbis";
3211                                 codec = HB_ACODEC_LAME;
3212                         }
3213                 }
3214                 else if (mux == HB_MUX_OGM)
3215                 {
3216                         mux_s = "OGM";
3217                         // avi/faac|vorbis combination is not supported.
3218                         if (codec == HB_ACODEC_FAAC)
3219                         {
3220                                 a_unsup = "FAAC";
3221                                 codec = HB_ACODEC_VORBIS;
3222                         }
3223                         if (codec == HB_ACODEC_AC3)
3224                         {
3225                                 a_unsup = "AC-3";
3226                                 codec = HB_ACODEC_VORBIS;
3227                         }
3228                         if (codec == HB_ACODEC_DCA)
3229                         {
3230                                 a_unsup = "DTS";
3231                                 codec = HB_ACODEC_VORBIS;
3232                         }
3233                 }
3234                 if (a_unsup)
3235                 {
3236                         message = g_strdup_printf(
3237                                                 "%s is not supported in the %s container.\n\n"
3238                                                 "You should choose a different audio codec.\n"
3239                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
3240                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3241                         {
3242                                 g_free(message);
3243                                 return FALSE;
3244                         }
3245                         g_free(message);
3246                         value = get_acodec_value(codec);
3247                         ghb_settings_take_value(asettings, "AudioEncoder", value);
3248                 }
3249                 gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
3250                 gboolean allow_mono = TRUE;
3251                 gboolean allow_stereo = TRUE;
3252                 gboolean allow_dolby = TRUE;
3253                 gboolean allow_dpl2 = TRUE;
3254                 gboolean allow_6ch = TRUE;
3255                 allow_mono =
3256                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3257                         (codec != HB_ACODEC_LAME);
3258                 gint layout = taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
3259                 allow_stereo =
3260                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
3261                 allow_dolby =
3262                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
3263                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
3264                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
3265                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
3266                 allow_6ch =
3267                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3268                         (codec != HB_ACODEC_LAME) &&
3269                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
3270                         (taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
3271
3272                 gchar *mix_unsup = NULL;
3273                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
3274                 {
3275                         mix_unsup = "mono";
3276                 }
3277                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
3278                 {
3279                         mix_unsup = "stereo";
3280                 }
3281                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
3282                 {
3283                         mix_unsup = "Dolby";
3284                 }
3285                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
3286                 {
3287                         mix_unsup = "Dolby Pro Logic II";
3288                 }
3289                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
3290                 {
3291                         mix_unsup = "6 Channel";
3292                 }
3293                 if (mix_unsup)
3294                 {
3295                         message = g_strdup_printf(
3296                                                 "The source audio does not support %s mixdown.\n\n"
3297                                                 "You should choose a different mixdown.\n"
3298                                                 "If you continue, one will be chosen for you.", mix_unsup);
3299                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3300                         {
3301                                 g_free(message);
3302                                 return FALSE;
3303                         }
3304                         g_free(message);
3305                         mix = ghb_get_best_mix(titleindex, track, codec, mix);
3306                         value = get_amix_value(mix);
3307                         ghb_settings_take_value(asettings, "AudioMixdown", value);
3308                 }
3309         }
3310         return TRUE;
3311 }
3312
3313 gboolean
3314 ghb_validate_vquality(GValue *settings)
3315 {
3316         gint vcodec;
3317         gchar *message;
3318         gint min, max;
3319
3320         if (ghb_settings_get_boolean(settings, "nocheckvquality")) return TRUE;
3321         vcodec = ghb_settings_combo_int(settings, "VideoEncoder");
3322         gdouble vquality;
3323         vquality = ghb_settings_get_double(settings, "VideoQualitySlider");
3324         if (ghb_settings_get_boolean(settings, "vquality_type_constant"))
3325         {
3326                 switch (vcodec)
3327                 {
3328                         case HB_VCODEC_X264:
3329                         {
3330                                 min = 16;
3331                                 max = 30;
3332                         } break;
3333
3334                         case HB_VCODEC_XVID:
3335                         case HB_VCODEC_FFMPEG:
3336                         {
3337                                 min = 1;
3338                                 max = 8;
3339                         } break;
3340
3341                         case HB_VCODEC_THEORA:
3342                         {
3343                                 min = 0;
3344                                 max = 63;
3345                         } break;
3346
3347                         default:
3348                         {
3349                                 min = 48;
3350                                 max = 62;
3351                         } break;
3352                 }
3353                 if (vquality < min || vquality > max)
3354                 {
3355                         message = g_strdup_printf(
3356                                                 "Interesting video quality choise: %d\n\n"
3357                                                 "Typical values range from %d to %d.\n"
3358                                                 "Are you sure you wish to use this setting?",
3359                                                 (gint)vquality, min, max);
3360                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
3361                                                                         "Cancel", "Continue"))
3362                         {
3363                                 g_free(message);
3364                                 return FALSE;
3365                         }
3366                         g_free(message);
3367                 }
3368         }
3369         return TRUE;
3370 }
3371
3372 static void
3373 add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
3374 {
3375         hb_list_t  * list;
3376         hb_title_t * title;
3377         hb_job_t   * job;
3378         static gchar *x264opts;
3379         gint sub_id = 0;
3380         gboolean tweaks = FALSE;
3381         gchar *detel_str = NULL;
3382         gchar *decomb_str = NULL;
3383         gchar *deint_str = NULL;
3384         gchar *deblock_str = NULL;
3385         gchar *denoise_str = NULL;
3386         gchar *dest_str = NULL;
3387
3388         g_debug("add_job()\n");
3389         if (h == NULL) return;
3390         list = hb_get_titles( h );
3391         if( !hb_list_count( list ) )
3392         {
3393                 /* No valid title, stop right there */
3394                 return;
3395         }
3396
3397     title = hb_list_item( list, titleindex );
3398         if (title == NULL) return;
3399
3400         /* Set job settings */
3401         job   = title->job;
3402         if (job == NULL) return;
3403
3404         job->start_at_preview = ghb_settings_get_int(js, "start_frame") + 1;
3405         if (job->start_at_preview)
3406         {
3407                 job->seek_points = ghb_settings_get_int(js, "preview_count");
3408                 job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL;
3409         }
3410
3411         tweaks = ghb_settings_get_boolean(js, "allow_tweaks");
3412         job->mux = ghb_settings_combo_int(js, "FileFormat");
3413         if (job->mux == HB_MUX_MP4)
3414         {
3415                 job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile");
3416                 job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize");
3417         }
3418         else
3419         {
3420                 job->largeFileSize = FALSE;
3421                 job->mp4_optimize = FALSE;
3422         }
3423         if (!job->start_at_preview)
3424         {
3425                 gint chapter_start, chapter_end;
3426                 chapter_start = ghb_settings_get_int(js, "start_chapter");
3427                 chapter_end = ghb_settings_get_int(js, "end_chapter");
3428                 gint num_chapters = hb_list_count(title->list_chapter);
3429                 job->chapter_start = MIN( num_chapters, chapter_start );
3430                 job->chapter_end   = MAX( job->chapter_start, chapter_end );
3431
3432                 job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
3433                 if ( job->chapter_markers )
3434                 {
3435                         GValue *chapters;
3436                         GValue *chapter;
3437                         gint chap;
3438                         gint count;
3439                 
3440                         chapters = ghb_settings_get_value(js, "chapter_list");
3441                         count = ghb_array_len(chapters);
3442                         for(chap = chapter_start; chap <= chapter_end; chap++)
3443                         {
3444                                 hb_chapter_t * chapter_s;
3445                                 gchar *name;
3446                                 
3447                                 name = NULL;
3448                                 if (chap-1 < count)
3449                                 {
3450                                         chapter = ghb_array_get_nth(chapters, chap-1);
3451                                         name = ghb_value_string(chapter); 
3452                                 }
3453                                 if (name == NULL)
3454                                 {
3455                                         name = g_strdup_printf ("Chapter %2d", chap);
3456                                 }
3457                                 chapter_s = hb_list_item( job->title->list_chapter, chap - 1);
3458                                 strncpy(chapter_s->title, name, 1023);
3459                                 chapter_s->title[1023] = '\0';
3460                                 g_free(name);
3461                         }
3462                 }
3463         }
3464         job->crop[0] = ghb_settings_get_int(js, "PictureTopCrop");
3465         job->crop[1] = ghb_settings_get_int(js, "PictureBottomCrop");
3466         job->crop[2] = ghb_settings_get_int(js, "PictureLeftCrop");
3467         job->crop[3] = ghb_settings_get_int(js, "PictureRightCrop");
3468
3469         
3470         gint decomb = ghb_settings_combo_int(js, "PictureDecomb");
3471         gint deint = ghb_settings_combo_int(js, "PictureDeinterlace");
3472         if (!decomb)
3473                 job->deinterlace = (deint != 0) ? 1 : 0;
3474         else
3475                 job->deinterlace = 0;
3476     job->grayscale   = ghb_settings_get_boolean(js, "VideoGrayScale");
3477
3478         job->anamorphic.mode = ghb_settings_combo_int(js, "PicturePAR");
3479         job->anamorphic.modulus = ghb_settings_combo_int(js, "PictureModulus");
3480
3481         /* Add selected filters */
3482         job->filters = hb_list_init();
3483         gint detel = ghb_settings_combo_int(js, "PictureDetelecine");
3484         if ( detel )
3485         {
3486                 if (detel != 1)
3487                 {
3488                         if (detel_opts.map[detel].svalue != NULL)
3489                                 detel_str = g_strdup(detel_opts.map[detel].svalue);
3490                 }
3491                 else
3492                         detel_str = ghb_settings_get_string(js, "PictureDetelecineCustom");
3493                 hb_filter_detelecine.settings = detel_str;
3494                 hb_list_add( job->filters, &hb_filter_detelecine );
3495         }
3496         if ( decomb )
3497         {
3498                 if (decomb != 1)
3499                 {
3500                         if (decomb_opts.map[decomb].svalue != NULL)
3501                                 decomb_str = g_strdup(decomb_opts.map[decomb].svalue);
3502                 }
3503                 else
3504                         decomb_str = ghb_settings_get_string(js, "PictureDecombCustom");
3505                 hb_filter_decomb.settings = decomb_str;
3506                 hb_list_add( job->filters, &hb_filter_decomb );
3507         }
3508         if( job->deinterlace )
3509         {
3510                 if (deint != 1)
3511                 {
3512                         if (deint_opts.map[deint].svalue != NULL)
3513                                 deint_str = g_strdup(deint_opts.map[deint].svalue);
3514                 }
3515                 else
3516                         deint_str = ghb_settings_get_string(js, "PictureDeinterlaceCustom");
3517                 hb_filter_deinterlace.settings = deint_str;
3518                 hb_list_add( job->filters, &hb_filter_deinterlace );
3519         }
3520         gint deblock = ghb_settings_get_int(js, "PictureDeblock");
3521         if( deblock >= 5 )
3522         {
3523                 deblock_str = g_strdup_printf("%d", deblock);
3524                 hb_filter_deblock.settings = deblock_str;
3525                 hb_list_add( job->filters, &hb_filter_deblock );
3526         }
3527         gint denoise = ghb_settings_combo_int(js, "PictureDenoise");
3528         if( denoise )
3529         {
3530                 if (denoise != 1)
3531                 {
3532                         if (denoise_opts.map[denoise].svalue != NULL)
3533                                 denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
3534                 }
3535                 else
3536                         denoise_str = ghb_settings_get_string(js, "PictureDenoiseCustom");
3537                 hb_filter_denoise.settings = denoise_str;
3538                 hb_list_add( job->filters, &hb_filter_denoise );
3539         }
3540         job->width = ghb_settings_get_int(js, "scale_width");
3541         job->height = ghb_settings_get_int(js, "scale_height");
3542
3543         job->vcodec = ghb_settings_combo_int(js, "VideoEncoder");
3544         if ((job->mux == HB_MUX_MP4 || job->mux == HB_MUX_AVI) && 
3545                 (job->vcodec == HB_VCODEC_THEORA))
3546         {
3547                 // mp4|avi/theora combination is not supported.
3548                 job->vcodec = HB_VCODEC_XVID;
3549         }
3550         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
3551         {
3552                 job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible");
3553         }
3554         if (ghb_settings_get_boolean(js, "vquality_type_constant"))
3555         {
3556                 gdouble vquality;
3557                 vquality = ghb_settings_get_double(js, "VideoQualitySlider");
3558                 job->vquality =  vquality;
3559                 job->vbitrate = 0;
3560         }
3561         else if (ghb_settings_get_boolean(js, "vquality_type_bitrate"))
3562         {
3563                 job->vquality = -1.0;
3564                 job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
3565         }
3566
3567         gint vrate = ghb_settings_combo_int(js, "VideoFramerate");
3568         if( vrate == 0 )
3569         {
3570                 job->vrate = title->rate;
3571                 job->vrate_base = title->rate_base;
3572                 job->cfr = 0;
3573         }
3574         else
3575         {
3576                 job->vrate = 27000000;
3577                 job->vrate_base = vrate;
3578                 job->cfr = 1;
3579         }
3580
3581         // AVI container does not support variable frame rate.
3582         // OGM supports variable frame rate, but bases all timing on
3583         // DTS, which breaks when b-frames are used since it is
3584         // impossible to reconstruct PTS from DTS when the framerate
3585         // is variable.  
3586         if (job->mux == HB_MUX_AVI || job->mux == HB_MUX_OGM)
3587         {
3588                 job->cfr = 1;
3589         }
3590
3591         // First remove any audios that are already in the list
3592         // This happens if you are encoding the same title a second time.
3593         gint num_audio_tracks = hb_list_count(job->list_audio);
3594         gint ii;
3595     for(ii = 0; ii < num_audio_tracks; ii++)
3596     {
3597         hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
3598         hb_list_rem(job->list_audio, audio);
3599     }
3600
3601         const GValue *audio_list;
3602         gint count;
3603         gint tcount = 0;
3604         
3605         audio_list = ghb_settings_get_value(js, "audio_list");
3606         count = ghb_array_len(audio_list);
3607         for (ii = 0; ii < count; ii++)
3608         {
3609                 GValue *asettings;
3610             hb_audio_config_t audio;
3611             hb_audio_config_t *taudio;
3612
3613                 hb_audio_config_init(&audio);
3614                 asettings = ghb_array_get_nth(audio_list, ii);
3615                 audio.in.track = ghb_settings_get_int(asettings, "AudioTrack");
3616                 audio.out.track = tcount;
3617                 audio.out.codec = ghb_settings_combo_int(asettings, "AudioEncoder");
3618         taudio = (hb_audio_config_t *) hb_list_audio_config_item(
3619                                                                         title->list_audio, audio.in.track );
3620                 if (audio.out.codec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
3621                 {
3622                         if (!(taudio->in.codec & audio.out.codec))
3623                         {
3624                                 // Not supported.  AC3 is passthrough only, so input must be AC3
3625                                 if (job->mux == HB_MUX_AVI)
3626                                 {
3627                                         audio.out.codec = HB_ACODEC_LAME;
3628                                 }
3629                                 else
3630                                 {
3631                                         audio.out.codec = HB_ACODEC_FAAC;
3632                                 }
3633                         }
3634                         else
3635                         {
3636                                 audio.out.codec &= taudio->in.codec;
3637                         }
3638                 }
3639                 if ((job->mux == HB_MUX_MP4) && 
3640                         ((audio.out.codec == HB_ACODEC_LAME) ||
3641                         (audio.out.codec == HB_ACODEC_VORBIS)))
3642                 {
3643                         // mp4/mp3|vorbis combination is not supported.
3644                         audio.out.codec = HB_ACODEC_FAAC;
3645                 }
3646                 if ((job->mux == HB_MUX_AVI) && 
3647                         ((audio.out.codec == HB_ACODEC_FAAC) ||
3648                         (audio.out.codec == HB_ACODEC_VORBIS)))
3649                 {
3650                         // avi/faac|vorbis combination is not supported.
3651                         audio.out.codec = HB_ACODEC_LAME;
3652                 }
3653                 if ((job->mux == HB_MUX_OGM) && 
3654                         ((audio.out.codec == HB_ACODEC_FAAC) ||
3655                         (audio.out.codec == HB_ACODEC_AC3) ||
3656                         (audio.out.codec == HB_ACODEC_DCA)))
3657                 {
3658                         // ogm/faac|ac3 combination is not supported.
3659                         audio.out.codec = HB_ACODEC_VORBIS;
3660                 }
3661         audio.out.dynamic_range_compression = 
3662                         ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
3663                 // It would be better if this were done in libhb for us, but its not yet.
3664                 if (audio.out.codec == HB_ACODEC_AC3 || audio.out.codec == HB_ACODEC_DCA)
3665                 {
3666                         audio.out.mixdown = 0;
3667                 }
3668                 else
3669                 {
3670                         audio.out.mixdown = ghb_settings_combo_int(asettings, "AudioMixdown");
3671                         // Make sure the mixdown is valid and pick a new one if not.
3672                         audio.out.mixdown = ghb_get_best_mix(titleindex, 
3673                                 audio.in.track, audio.out.codec, audio.out.mixdown);
3674                         audio.out.bitrate = 
3675                                 ghb_settings_combo_int(asettings, "AudioBitrate");
3676                         gint srate = ghb_settings_combo_int(asettings, "AudioSamplerate");
3677                         if (srate == 0) // 0 is same as source
3678                                 audio.out.samplerate = taudio->in.samplerate;
3679                         else
3680                                 audio.out.samplerate = srate;
3681                 }
3682
3683                 // Add it to the jobs audio list
3684         hb_audio_add( job, &audio );
3685                 tcount++;
3686         }
3687         // I was tempted to move this up with the reset of the video quality
3688         // settings, but I suspect the settings above need to be made
3689         // first in order for hb_calc_bitrate to be accurate.
3690         if (ghb_settings_get_boolean(js, "vquality_type_target"))
3691         {
3692                 gint size;
3693                 
3694                 size = ghb_settings_get_int(js, "VideoTargetSize");
3695         job->vbitrate = hb_calc_bitrate( job, size );
3696                 job->vquality = -1.0;
3697         }
3698
3699         dest_str = ghb_settings_get_string(js, "destination");
3700         job->file = dest_str;
3701         job->crf = ghb_settings_get_boolean(js, "constant_rate_factor");
3702         // TODO: libhb holds onto a reference to the x264opts and is not
3703         // finished with it until encoding the job is done.  But I can't
3704         // find a way to get at the job before it is removed in order to
3705         // free up the memory I am allocating here.
3706         // The short story is THIS LEAKS.
3707         x264opts = ghb_build_x264opts_string(js);
3708         
3709         if( x264opts != NULL && *x264opts != '\0' )
3710         {
3711                 job->x264opts = x264opts;
3712         }
3713         else /*avoids a bus error crash when options aren't specified*/
3714         {
3715                 job->x264opts =  NULL;
3716         }
3717         gint subtitle;
3718         gchar *slang = ghb_settings_get_string(js, "Subtitles");
3719         subtitle = -2; // default to none
3720         if (strcmp(slang, "auto") == 0)
3721         {
3722                 subtitle = -1;
3723         }
3724         else
3725         {
3726                 gint scount;
3727         hb_subtitle_t * subt;
3728
3729                 scount = hb_list_count(title->list_subtitle);
3730                 for (ii = 0; ii < scount; ii++)
3731                 {
3732                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
3733                         if (strcmp(slang, subt->iso639_2) == 0)
3734                         {
3735                                 subtitle = ii;
3736                                 break;
3737                         }
3738                 }
3739         }
3740         gboolean forced_subtitles = ghb_settings_get_boolean(js, "SubtitlesForced");
3741         job->subtitle_force = forced_subtitles;
3742         if (subtitle >= 0)
3743                 job->subtitle = subtitle;
3744         else
3745                 job->subtitle = -1;
3746         if (subtitle == -1)
3747         {
3748                 // Subtitle scan. Look for subtitle matching audio language
3749                 char *x264opts_tmp;
3750
3751                 /*
3752                  * When subtitle scan is enabled do a fast pre-scan job
3753                  * which will determine which subtitles to enable, if any.
3754                  */
3755                 job->pass = -1;
3756                 job->indepth_scan = 1;
3757
3758                 x264opts_tmp = job->x264opts;
3759                 job->x264opts = NULL;
3760
3761                 job->select_subtitle = malloc(sizeof(hb_subtitle_t*));
3762                 *(job->select_subtitle) = NULL;
3763
3764                 /*
3765                  * Add the pre-scan job
3766                  */
3767                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3768                 hb_add( h, job );
3769                 //if (job->x264opts != NULL)
3770                 //      g_free(job->x264opts);
3771
3772                 job->x264opts = x264opts_tmp;
3773         }
3774         else
3775         {
3776                 job->select_subtitle = NULL;
3777         }
3778         if( ghb_settings_get_boolean(js, "VideoTwoPass") &&
3779                 !ghb_settings_get_boolean(js, "vquality_type_constant"))
3780         {
3781                 /*
3782                  * If subtitle_scan is enabled then only turn it on
3783                  * for the second pass and then off again for the
3784                  * second.
3785                  */
3786                 hb_subtitle_t **subtitle_tmp = job->select_subtitle;
3787                 job->select_subtitle = NULL;
3788                 job->pass = 1;
3789                 job->indepth_scan = 0;
3790                 gchar *x264opts2 = NULL;
3791                 if (x264opts)
3792                 {
3793                         x264opts2 = g_strdup(x264opts);
3794                 }
3795                 /*
3796                  * If turbo options have been selected then append them
3797                  * to the x264opts now (size includes one ':' and the '\0')
3798                  */
3799                 if( ghb_settings_get_boolean(js, "VideoTurboTwoPass") )
3800                 {
3801                         char *tmp_x264opts;
3802
3803                         if ( x264opts )
3804                         {
3805                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, turbo_opts);
3806                                 g_free(x264opts);
3807                         } 
3808                         else 
3809                         {
3810                                 /*
3811                                  * No x264opts to modify, but apply the turbo options
3812                                  * anyway as they may be modifying defaults
3813                                  */
3814                                 tmp_x264opts = g_strdup_printf("%s", turbo_opts);
3815                         }
3816                         x264opts = tmp_x264opts;
3817
3818                         job->x264opts = x264opts;
3819                 }
3820                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3821                 hb_add( h, job );
3822                 //if (job->x264opts != NULL)
3823                 //      g_free(job->x264opts);
3824
3825                 job->select_subtitle = subtitle_tmp;
3826                 job->pass = 2;
3827                 /*
3828                  * On the second pass we turn off subtitle scan so that we
3829                  * can actually encode using any subtitles that were auto
3830                  * selected in the first pass (using the whacky select-subtitle
3831                  * attribute of the job).
3832                  */
3833                 job->indepth_scan = 0;
3834                 job->x264opts = x264opts2;
3835                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3836                 hb_add( h, job );
3837                 //if (job->x264opts != NULL)
3838                 //      g_free(job->x264opts);
3839         }
3840         else
3841         {
3842                 job->indepth_scan = 0;
3843                 job->pass = 0;
3844                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3845                 hb_add( h, job );
3846                 //if (job->x264opts != NULL)
3847                 //      g_free(job->x264opts);
3848         }
3849         if (detel_str) g_free(detel_str);
3850         if (decomb_str) g_free(decomb_str);
3851         if (deint_str) g_free(deint_str);
3852         if (deblock_str) g_free(deblock_str);
3853         if (denoise_str) g_free(denoise_str);
3854         if (dest_str) g_free(dest_str);
3855 }
3856
3857 void
3858 ghb_add_job(GValue *js, gint unique_id)
3859 {
3860         // Since I'm doing a scan of the single title I want just prior 
3861         // to adding the job, there is only the one title to choose from.
3862         add_job(h_queue, js, unique_id, 0);
3863 }
3864
3865 void
3866 ghb_add_live_job(GValue *js, gint unique_id)
3867 {
3868         // Since I'm doing a scan of the single title I want just prior 
3869         // to adding the job, there is only the one title to choose from.
3870         gint titleindex = ghb_settings_combo_int(js, "title");
3871         add_job(h_scan, js, unique_id, titleindex);
3872 }
3873
3874 void
3875 ghb_remove_job(gint unique_id)
3876 {
3877     hb_job_t * job;
3878     gint ii;
3879         
3880         // Multiples passes all get the same id
3881         // remove them all.
3882         // Go backwards through list, so reordering doesn't screw me.
3883         ii = hb_count(h_queue) - 1;
3884     while ((job = hb_job(h_queue, ii--)) != NULL)
3885     {
3886         if ((job->sequence_id & 0xFFFFFF) == unique_id)
3887                         hb_rem(h_queue, job);
3888     }
3889 }
3890
3891 void
3892 ghb_start_queue()
3893 {
3894         hb_start( h_queue );
3895 }
3896
3897 void
3898 ghb_stop_queue()
3899 {
3900         hb_stop( h_queue );
3901 }
3902
3903 void
3904 ghb_start_live_encode()
3905 {
3906         hb_start( h_scan );
3907 }
3908
3909 void
3910 ghb_stop_live_encode()
3911 {
3912         hb_stop( h_scan );
3913 }
3914
3915 void
3916 ghb_pause_queue()
3917 {
3918     hb_state_t s;
3919     hb_get_state2( h_queue, &s );
3920
3921     if( s.state == HB_STATE_PAUSED )
3922     {
3923         hb_resume( h_queue );
3924     }
3925     else
3926     {
3927         hb_pause( h_queue );
3928     }
3929 }
3930
3931 #define RED_HEIGHT      720.0
3932 #define RED_WIDTH       1280.0
3933
3934 GdkPixbuf*
3935 ghb_get_preview_image(
3936         gint titleindex, 
3937         gint index, 
3938         signal_user_data_t *ud,
3939         gboolean borders,
3940         gint *out_width,
3941         gint *out_height)
3942 {
3943         GValue *settings;
3944         hb_title_t *title;
3945         hb_list_t  *list;
3946         
3947         settings = ud->settings;
3948         list = hb_get_titles( h_scan );
3949         if( !hb_list_count( list ) )
3950         {
3951                 /* No valid title, stop right there */
3952                 return NULL;
3953         }
3954     title = hb_list_item( list, titleindex );
3955         if (title == NULL) return NULL;
3956         if (title->job == NULL) return NULL;
3957         set_preview_job_settings(title->job, settings);
3958
3959         // hb_get_preview can't handle sizes that are larger than the original title
3960         // dimensions
3961         if (title->job->width > title->width)
3962                 title->job->width = title->width;
3963         
3964         if (title->job->height > title->height)
3965                 title->job->height = title->height;
3966
3967         // hb_get_preview doesn't compensate for anamorphic, so lets
3968         // calculate scale factors
3969         gint width, height, par_width = 1, par_height = 1;
3970         gint pic_par = ghb_settings_combo_int(settings, "PicturePAR");
3971         if (pic_par)
3972         {
3973                 hb_set_anamorphic_size( title->job, &width, &height, 
3974                                                                 &par_width, &par_height );
3975         }
3976
3977         // And also creates artifacts if the width is not a multiple of 8
3978         //title->job->width = ((title->job->width + 4) >> 3) << 3;
3979         // And the height must be a multiple of 2
3980         //title->job->height = ((title->job->height + 1) >> 1) << 1;
3981         
3982         // Make sure we have a big enough buffer to receive the image from libhb. libhb
3983         // creates images with a one-pixel border around the original content. Hence we
3984         // add 2 pixels horizontally and vertically to the buffer size.
3985         gint srcWidth = title->width + 2;
3986         gint srcHeight= title->height + 2;
3987         gint dstWidth = title->width;
3988         gint dstHeight= title->height;
3989         gint borderTop = 1;
3990         gint borderLeft = 1;
3991     if (borders)
3992     {
3993         //     |<---------- title->width ----------->|
3994         //     |   |<---- title->job->width ---->|   |
3995         //     |   |                             |   |
3996         //     .......................................
3997         //     ....+-----------------------------+....
3998         //     ....|                             |....<-- gray border
3999         //     ....|                             |....
4000         //     ....|                             |....
4001         //     ....|                             |<------- image
4002         //     ....|                             |....
4003         //     ....|                             |....
4004         //     ....|                             |....
4005         //     ....|                             |....
4006         //     ....|                             |....
4007         //     ....+-----------------------------+....
4008         //     .......................................
4009                 dstWidth = title->job->width;
4010         dstHeight = title->job->height;
4011                 borderTop = (srcHeight - dstHeight) / 2;
4012                 borderLeft = (srcWidth - dstWidth) / 2;
4013                 g_debug("boarders removed\n");
4014         }
4015
4016         g_debug("src %d x %d\n", srcWidth, srcHeight);
4017         g_debug("dst %d x %d\n", dstWidth, dstHeight);
4018         g_debug("job dim %d x %d\n", title->job->width, title->job->height);
4019         g_debug("title crop %d:%d:%d:%d\n", 
4020                         title->crop[0],
4021                         title->crop[1],
4022                         title->crop[2],
4023                         title->crop[3]);
4024         g_debug("job crop %d:%d:%d:%d\n", 
4025                         title->job->crop[0],
4026                         title->job->crop[1],
4027                         title->job->crop[2],
4028                         title->job->crop[3]);
4029         static guint8 *buffer = NULL;
4030         static gint bufferSize = 0;
4031
4032         gint newSize;
4033         newSize = srcWidth * srcHeight * 4;
4034         if( bufferSize < newSize )
4035         {
4036                 bufferSize = newSize;
4037                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
4038         }
4039         hb_get_preview( h_scan, title, index, buffer );
4040
4041         // Create an GdkPixbuf and copy the libhb image into it, converting it from
4042         // libhb's format something suitable. Along the way, we'll strip off the
4043         // border around libhb's image.
4044         
4045         // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format.
4046         // Alpha is ignored.
4047
4048         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
4049         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
4050         
4051         guint32 *src = (guint32*)buffer;
4052         guint8 *dst = pixels;
4053         src += borderTop * srcWidth;    // skip top rows in src to get to first row of dst
4054         src += borderLeft;              // skip left pixels in src to get to first pixel of dst
4055         gint ii, jj;
4056         gint channels = gdk_pixbuf_get_n_channels (preview);
4057         gint stride = gdk_pixbuf_get_rowstride (preview);
4058         guint8 *tmp;
4059         for (ii = 0; ii < dstHeight; ii++)
4060         {
4061                 tmp = dst;
4062                 for (jj = 0; jj < dstWidth; jj++)
4063                 {
4064                         tmp[0] = src[0] >> 16;
4065                         tmp[1] = src[0] >> 8;
4066                         tmp[2] = src[0] >> 0;
4067                         tmp += channels;
4068                         src++;
4069                 }
4070                 dst += stride;
4071                 src += (srcWidth - dstWidth);   // skip to next row in src
4072         }
4073         ghb_par_scale(ud, &dstWidth, &dstHeight, par_width, par_height);
4074         *out_width = dstWidth;
4075         *out_height = dstHeight;
4076         if (ghb_settings_get_boolean(settings, "reduce_hd_preview"))
4077         {
4078                 GdkScreen *ss;
4079                 gint s_w, s_h;
4080                 gint orig_w, orig_h;
4081                 gint factor = 80;
4082
4083                 if (ghb_settings_get_boolean(settings, "preview_fullscreen"))
4084                 {
4085                         factor = 100;
4086                 }
4087                 ss = gdk_screen_get_default();
4088                 s_w = gdk_screen_get_width(ss);
4089                 s_h = gdk_screen_get_height(ss);
4090                 orig_w = dstWidth;
4091                 orig_h = dstHeight;
4092
4093                 if (dstWidth > s_w * factor / 100)
4094                 {
4095                         dstWidth = s_w * factor / 100;
4096                         dstHeight = dstHeight * dstWidth / orig_w;
4097                 }
4098                 if (dstHeight > s_h * factor / 100)
4099                 {
4100                         dstHeight = s_h * factor / 100;
4101                         dstWidth = dstWidth * dstHeight / orig_h;
4102                 }
4103         }
4104         g_debug("scaled %d x %d\n", dstWidth, dstHeight);
4105         GdkPixbuf *scaled_preview;
4106         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
4107         g_object_unref (preview);
4108         return scaled_preview;
4109 }
4110
4111 static void
4112 sanitize_volname(gchar *name)
4113 {
4114         gchar *a, *b;
4115
4116         a = b = name;
4117         while (*b)
4118         {
4119                 switch(*b)
4120                 {
4121                 case '<':
4122                         b++;
4123                         break;
4124                 case '>':
4125                         b++;
4126                         break;
4127                 default:
4128                         *a = *b;
4129                         a++; b++;
4130                         break;
4131                 }
4132         }
4133         *a = 0;
4134 }
4135
4136 gchar*
4137 ghb_dvd_volname(const gchar *device)
4138 {
4139         gchar *name;
4140         name = hb_dvd_name((gchar*)device);
4141         if (name != NULL)
4142         {
4143                 sanitize_volname(name);
4144                 return g_strdup(name);
4145         }
4146         return name;
4147 }