OSDN Git Service

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