OSDN Git Service

9a2982276b19590350ebc7bc5d31bc1af9aa9f98
[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 || keep_aspect ? 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, keep_aspect;
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         keep_aspect = ghb_settings_get_boolean(settings, "PictureKeepRatio");
2780         if (anamorphic)
2781         {
2782                 job->anamorphic.modulus = round_dimensions ? 16 : 2;
2783                 job->anamorphic.mode = autoscale || keep_aspect ? 2 : 3;
2784         }
2785         else
2786         {
2787                 job->anamorphic.modulus = 2;
2788                 job->anamorphic.mode = 0;
2789         }
2790         job->width = ghb_settings_get_int(settings, "scale_width");
2791         job->height = ghb_settings_get_int(settings, "scale_height");
2792         gint deint = ghb_settings_combo_int(settings, "PictureDeinterlace");
2793         gint decomb = ghb_settings_combo_int(settings, "PictureDecomb");
2794         job->deinterlace = (!decomb && deint == 0) ? 0 : 1;
2795 }
2796
2797 gint
2798 ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
2799 {
2800         hb_list_t  * list;
2801         hb_title_t * title;
2802         hb_job_t   * job;
2803         gint size;
2804
2805         if (h_scan == NULL) return 1500;
2806         list = hb_get_titles( h_scan );
2807     title = hb_list_item( list, titleindex );
2808         if (title == NULL) return 1500;
2809         job   = title->job;
2810         if (job == NULL) return 1500;
2811         size = ghb_settings_get_int(settings, "VideoTargetSize");
2812         return hb_calc_bitrate( job, size );
2813 }
2814
2815 gboolean
2816 ghb_validate_filter_string(const gchar *str, gint max_fields)
2817 {
2818         gint fields = 0;
2819         gchar *end;
2820         gdouble val;
2821
2822         if (str == NULL || *str == 0) return TRUE;
2823         while (*str)
2824         {
2825                 val = g_strtod(str, &end);
2826                 if (str != end)
2827                 { // Found a numeric value
2828                         fields++;
2829                         // negative max_fields means infinate
2830                         if (max_fields >= 0 && fields > max_fields) return FALSE;
2831                         if (*end == 0)
2832                                 return TRUE;
2833                         if (*end != ':')
2834                                 return FALSE;
2835                         str = end + 1;
2836                 }
2837                 else
2838                         return FALSE;
2839         }
2840         return FALSE;
2841 }
2842
2843 gboolean
2844 ghb_validate_filters(signal_user_data_t *ud)
2845 {
2846         gchar *str;
2847         gint index;
2848         gchar *message;
2849
2850         // deinte 4
2851         index = ghb_settings_combo_int(ud->settings, "PictureDeinterlace");
2852         if (index == 1)
2853         {
2854                 str = ghb_settings_get_string(ud->settings, "PictureDeinterlaceCustom");
2855                 if (!ghb_validate_filter_string(str, 4))
2856                 {
2857                         message = g_strdup_printf(
2858                                                 "Invalid Deinterlace Settings:\n\n%s\n",
2859                                                 str);
2860                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2861                         g_free(message);
2862                         g_free(str);
2863                         return FALSE;
2864                 }
2865                 g_free(str);
2866         }
2867         // detel
2868         index = ghb_settings_combo_int(ud->settings, "PictureDetelecine");
2869         if (index == 1)
2870         {
2871                 str = ghb_settings_get_string(ud->settings, "PictureDetelecineCustom");
2872                 if (!ghb_validate_filter_string(str, 6))
2873                 {
2874                         message = g_strdup_printf(
2875                                                 "Invalid Detelecine Settings:\n\n%s\n",
2876                                                 str);
2877                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2878                         g_free(message);
2879                         g_free(str);
2880                         return FALSE;
2881                 }
2882                 g_free(str);
2883         }
2884         // decomb 4
2885         index = ghb_settings_combo_int(ud->settings, "PictureDecomb");
2886         if (index == 1)
2887         {
2888                 str = ghb_settings_get_string(ud->settings, "PictureDecombCustom");
2889                 if (!ghb_validate_filter_string(str, 7))
2890                 {
2891                         message = g_strdup_printf(
2892                                                 "Invalid Decomb Settings:\n\n%s\n",
2893                                                 str);
2894                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2895                         g_free(message);
2896                         g_free(str);
2897                         return FALSE;
2898                 }
2899                 g_free(str);
2900         }
2901         // denois 4
2902         index = ghb_settings_combo_int(ud->settings, "PictureDenoise");
2903         if (index == 1)
2904         {
2905                 str = ghb_settings_get_string(ud->settings, "PictureDenoiseCustom");
2906                 if (!ghb_validate_filter_string(str, 4))
2907                 {
2908                         message = g_strdup_printf(
2909                                                 "Invalid Denoise Settings:\n\n%s\n",
2910                                                 str);
2911                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2912                         g_free(str);
2913                         g_free(message);
2914                         return FALSE;
2915                 }
2916                 g_free(str);
2917         }
2918         return TRUE;
2919 }
2920
2921 gboolean
2922 ghb_validate_video(signal_user_data_t *ud)
2923 {
2924         gint vcodec, mux;
2925         gchar *message;
2926
2927         mux = ghb_settings_combo_int(ud->settings, "FileFormat");
2928         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
2929         if ((mux == HB_MUX_MP4 || mux == HB_MUX_AVI) && 
2930                 (vcodec == HB_VCODEC_THEORA))
2931         {
2932                 // mp4|avi/theora combination is not supported.
2933                 message = g_strdup_printf(
2934                                         "Theora is not supported in the MP4 and AVI containers.\n\n"
2935                                         "You should choose a different video codec or container.\n"
2936                                         "If you continue, XviD will be chosen for you.");
2937                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2938                 {
2939                         g_free(message);
2940                         return FALSE;
2941                 }
2942                 g_free(message);
2943                 vcodec = HB_VCODEC_XVID;
2944                 ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
2945         }
2946         return TRUE;
2947 }
2948
2949 gboolean
2950 ghb_validate_audio(signal_user_data_t *ud)
2951 {
2952         hb_list_t  * list;
2953         hb_title_t * title;
2954         gchar *message;
2955         GValue *value;
2956
2957         if (h_scan == NULL) return FALSE;
2958         list = hb_get_titles( h_scan );
2959         if( !hb_list_count( list ) )
2960         {
2961                 /* No valid title, stop right there */
2962                 g_message("No title found.\n");
2963                 return FALSE;
2964         }
2965
2966         gint titleindex;
2967
2968         titleindex = ghb_settings_combo_int(ud->settings, "title");
2969     title = hb_list_item( list, titleindex );
2970         if (title == NULL) return FALSE;
2971         gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
2972
2973         const GValue *audio_list;
2974         gint count, ii;
2975
2976         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
2977         count = ghb_array_len(audio_list);
2978         for (ii = 0; ii < count; ii++)
2979         {
2980                 GValue *asettings;
2981             hb_audio_config_t *taudio;
2982
2983                 asettings = ghb_array_get_nth(audio_list, ii);
2984                 gint track = ghb_settings_combo_int(asettings, "AudioTrack");
2985                 gint codec = ghb_settings_combo_int(asettings, "AudioEncoder");
2986         taudio = (hb_audio_config_t *) hb_list_audio_config_item(
2987                                                                                         title->list_audio, track );
2988                 if ((taudio->in.codec != HB_ACODEC_AC3 && codec == HB_ACODEC_AC3) ||
2989                     (taudio->in.codec != HB_ACODEC_DCA && codec == HB_ACODEC_DCA))
2990                 {
2991                         // Not supported.  AC3 is passthrough only, so input must be AC3
2992                         char *str;
2993                         str = (codec == HB_ACODEC_AC3) ? "AC-3" : "DTS";
2994                         message = g_strdup_printf(
2995                                                 "The source does not support %s Pass-Thru.\n\n"
2996                                                 "You should choose a different audio codec.\n"
2997                                                 "If you continue, one will be chosen for you.", str);
2998                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2999                         {
3000                                 g_free(message);
3001                                 return FALSE;
3002                         }
3003                         g_free(message);
3004                         if (mux == HB_MUX_AVI)
3005                         {
3006                                 codec = HB_ACODEC_LAME;
3007                         }
3008                         else
3009                         {
3010                                 codec = HB_ACODEC_FAAC;
3011                         }
3012                         value = get_acodec_value(codec);
3013                         ghb_settings_take_value(asettings, "AudioEncoder", value);
3014                 }
3015                 gchar *a_unsup = NULL;
3016                 gchar *mux_s = NULL;
3017                 if (mux == HB_MUX_MP4)
3018                 { 
3019                         mux_s = "MP4";
3020                         // mp4/mp3|vorbis combination is not supported.
3021                         if (codec == HB_ACODEC_LAME)
3022                         {
3023                                 a_unsup = "MP3";
3024                                 codec = HB_ACODEC_FAAC;
3025                         }
3026                         if (codec == HB_ACODEC_VORBIS)
3027                         {
3028                                 a_unsup = "Vorbis";
3029                                 codec = HB_ACODEC_FAAC;
3030                         }
3031                 }
3032                 else if (mux == HB_MUX_AVI)
3033                 {
3034                         mux_s = "AVI";
3035                         // avi/faac|vorbis combination is not supported.
3036                         if (codec == HB_ACODEC_FAAC)
3037                         {
3038                                 a_unsup = "FAAC";
3039                                 codec = HB_ACODEC_LAME;
3040                         }
3041                         if (codec == HB_ACODEC_VORBIS)
3042                         {
3043                                 a_unsup = "Vorbis";
3044                                 codec = HB_ACODEC_LAME;
3045                         }
3046                 }
3047                 else if (mux == HB_MUX_OGM)
3048                 {
3049                         mux_s = "OGM";
3050                         // avi/faac|vorbis combination is not supported.
3051                         if (codec == HB_ACODEC_FAAC)
3052                         {
3053                                 a_unsup = "FAAC";
3054                                 codec = HB_ACODEC_VORBIS;
3055                         }
3056                         if (codec == HB_ACODEC_AC3)
3057                         {
3058                                 a_unsup = "AC-3";
3059                                 codec = HB_ACODEC_VORBIS;
3060                         }
3061                         if (codec == HB_ACODEC_DCA)
3062                         {
3063                                 a_unsup = "DTS";
3064                                 codec = HB_ACODEC_VORBIS;
3065                         }
3066                 }
3067                 if (a_unsup)
3068                 {
3069                         message = g_strdup_printf(
3070                                                 "%s is not supported in the %s container.\n\n"
3071                                                 "You should choose a different audio codec.\n"
3072                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
3073                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3074                         {
3075                                 g_free(message);
3076                                 return FALSE;
3077                         }
3078                         g_free(message);
3079                         value = get_acodec_value(codec);
3080                         ghb_settings_take_value(asettings, "AudioEncoder", value);
3081                 }
3082                 gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
3083                 gboolean allow_mono = TRUE;
3084                 gboolean allow_stereo = TRUE;
3085                 gboolean allow_dolby = TRUE;
3086                 gboolean allow_dpl2 = TRUE;
3087                 gboolean allow_6ch = TRUE;
3088                 allow_mono =
3089                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3090                         (codec != HB_ACODEC_LAME);
3091                 gint layout = taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
3092                 allow_stereo =
3093                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
3094                 allow_dolby =
3095                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
3096                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
3097                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
3098                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
3099                 allow_6ch =
3100                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3101                         (codec != HB_ACODEC_LAME) &&
3102                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
3103                         (taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
3104
3105                 gchar *mix_unsup = NULL;
3106                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
3107                 {
3108                         mix_unsup = "mono";
3109                 }
3110                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
3111                 {
3112                         mix_unsup = "stereo";
3113                 }
3114                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
3115                 {
3116                         mix_unsup = "Dolby";
3117                 }
3118                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
3119                 {
3120                         mix_unsup = "Dolby Pro Logic II";
3121                 }
3122                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
3123                 {
3124                         mix_unsup = "6 Channel";
3125                 }
3126                 if (mix_unsup)
3127                 {
3128                         message = g_strdup_printf(
3129                                                 "The source audio does not support %s mixdown.\n\n"
3130                                                 "You should choose a different mixdown.\n"
3131                                                 "If you continue, one will be chosen for you.", mix_unsup);
3132                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3133                         {
3134                                 g_free(message);
3135                                 return FALSE;
3136                         }
3137                         g_free(message);
3138                         mix = ghb_get_best_mix(titleindex, track, codec, mix);
3139                         value = get_amix_value(mix);
3140                         ghb_settings_take_value(asettings, "AudioMixdown", value);
3141                 }
3142         }
3143         return TRUE;
3144 }
3145
3146 gboolean
3147 ghb_validate_vquality(GValue *settings)
3148 {
3149         gint vcodec;
3150         gchar *message;
3151         gint min, max;
3152
3153         if (ghb_settings_get_boolean(settings, "nocheckvquality")) return TRUE;
3154         vcodec = ghb_settings_combo_int(settings, "VideoEncoder");
3155         gdouble vquality;
3156         vquality = ghb_settings_get_double(settings, "VideoQualitySlider");
3157         if (ghb_settings_get_boolean(settings, "vquality_type_constant"))
3158         {
3159                 switch (vcodec)
3160                 {
3161                         case HB_VCODEC_X264:
3162                         {
3163                                 min = 16;
3164                                 max = 30;
3165                         } break;
3166
3167                         case HB_VCODEC_XVID:
3168                         case HB_VCODEC_FFMPEG:
3169                         {
3170                                 min = 1;
3171                                 max = 8;
3172                         } break;
3173
3174                         case HB_VCODEC_THEORA:
3175                         {
3176                                 min = 0;
3177                                 max = 63;
3178                         } break;
3179
3180                         default:
3181                         {
3182                                 min = 48;
3183                                 max = 62;
3184                         } break;
3185                 }
3186                 if (vquality < min || vquality > max)
3187                 {
3188                         message = g_strdup_printf(
3189                                                 "Interesting video quality choise: %d\n\n"
3190                                                 "Typical values range from %d to %d.\n"
3191                                                 "Are you sure you wish to use this setting?",
3192                                                 (gint)vquality, min, max);
3193                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
3194                                                                         "Cancel", "Continue"))
3195                         {
3196                                 g_free(message);
3197                                 return FALSE;
3198                         }
3199                         g_free(message);
3200                 }
3201         }
3202         return TRUE;
3203 }
3204
3205 static void
3206 add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
3207 {
3208         hb_list_t  * list;
3209         hb_title_t * title;
3210         hb_job_t   * job;
3211         static gchar *x264opts;
3212         gint sub_id = 0;
3213         gboolean tweaks = FALSE;
3214         gchar *detel_str = NULL;
3215         gchar *decomb_str = NULL;
3216         gchar *deint_str = NULL;
3217         gchar *deblock_str = NULL;
3218         gchar *denoise_str = NULL;
3219         gchar *dest_str = NULL;
3220
3221         g_debug("add_job()\n");
3222         if (h == NULL) return;
3223         list = hb_get_titles( h );
3224         if( !hb_list_count( list ) )
3225         {
3226                 /* No valid title, stop right there */
3227                 return;
3228         }
3229
3230     title = hb_list_item( list, titleindex );
3231         if (title == NULL) return;
3232
3233         /* Set job settings */
3234         job   = title->job;
3235         if (job == NULL) return;
3236
3237         job->start_at_preview = ghb_settings_get_int(js, "start_frame") + 1;
3238         if (job->start_at_preview)
3239         {
3240                 job->seek_points = ghb_settings_get_int(js, "preview_count");
3241                 job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL;
3242         }
3243
3244         tweaks = ghb_settings_get_boolean(js, "allow_tweaks");
3245         job->mux = ghb_settings_combo_int(js, "FileFormat");
3246         if (job->mux == HB_MUX_MP4)
3247         {
3248                 job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile");
3249                 job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize");
3250         }
3251         else
3252         {
3253                 job->largeFileSize = FALSE;
3254                 job->mp4_optimize = FALSE;
3255         }
3256         if (!job->start_at_preview)
3257         {
3258                 gint chapter_start, chapter_end;
3259                 chapter_start = ghb_settings_get_int(js, "start_chapter");
3260                 chapter_end = ghb_settings_get_int(js, "end_chapter");
3261                 gint num_chapters = hb_list_count(title->list_chapter);
3262                 job->chapter_start = MIN( num_chapters, chapter_start );
3263                 job->chapter_end   = MAX( job->chapter_start, chapter_end );
3264
3265                 job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
3266                 if ( job->chapter_markers )
3267                 {
3268                         GValue *chapters;
3269                         GValue *chapter;
3270                         gint chap;
3271                         gint count;
3272                 
3273                         chapters = ghb_settings_get_value(js, "chapter_list");
3274                         count = ghb_array_len(chapters);
3275                         for(chap = chapter_start; chap <= chapter_end; chap++)
3276                         {
3277                                 hb_chapter_t * chapter_s;
3278                                 gchar *name;
3279                                 
3280                                 name = NULL;
3281                                 if (chap-1 < count)
3282                                 {
3283                                         chapter = ghb_array_get_nth(chapters, chap-1);
3284                                         name = ghb_value_string(chapter); 
3285                                 }
3286                                 if (name == NULL)
3287                                 {
3288                                         name = g_strdup_printf ("Chapter %2d", chap);
3289                                 }
3290                                 chapter_s = hb_list_item( job->title->list_chapter, chap - 1);
3291                                 strncpy(chapter_s->title, name, 1023);
3292                                 chapter_s->title[1023] = '\0';
3293                                 g_free(name);
3294                         }
3295                 }
3296         }
3297         job->crop[0] = ghb_settings_get_int(js, "PictureTopCrop");
3298         job->crop[1] = ghb_settings_get_int(js, "PictureBottomCrop");
3299         job->crop[2] = ghb_settings_get_int(js, "PictureLeftCrop");
3300         job->crop[3] = ghb_settings_get_int(js, "PictureRightCrop");
3301
3302         
3303         gint decomb = ghb_settings_combo_int(js, "PictureDecomb");
3304         gint deint = ghb_settings_combo_int(js, "PictureDeinterlace");
3305         if (!decomb)
3306                 job->deinterlace = (deint != 0) ? 1 : 0;
3307         else
3308                 job->deinterlace = 0;
3309     job->grayscale   = ghb_settings_get_boolean(js, "VideoGrayScale");
3310
3311         gboolean autoscale, anamorphic, round_dimensions, keep_aspect;
3312
3313         autoscale = ghb_settings_get_boolean(js, "autoscale");
3314         anamorphic = ghb_settings_get_boolean(js, "anamorphic");
3315         round_dimensions = ghb_settings_get_boolean(js, "ModDimensions");
3316         keep_aspect = ghb_settings_get_boolean(js, "PictureKeepRatio");
3317         if (anamorphic)
3318         {
3319                 job->anamorphic.mode = autoscale || keep_aspect ? 2 : 3;
3320                 // Also, x264 requires things to be divisible by 2.
3321                 job->anamorphic.modulus = round_dimensions ? 16 : 2;
3322         }
3323         else
3324         {
3325                 job->anamorphic.mode = 0;
3326                 job->anamorphic.modulus = 2;
3327         }
3328         /* Add selected filters */
3329         job->filters = hb_list_init();
3330         gint vrate = ghb_settings_combo_int(js, "VideoFramerate");
3331         if( vrate == 0 && ghb_settings_combo_int(js, "PictureDetelecine" ) )
3332                 job->vfr = 1;
3333         else
3334                 job->vfr = 0;
3335
3336         gint detel = ghb_settings_combo_int(js, "PictureDetelecine");
3337         if ( detel )
3338         {
3339                 if (detel != 1)
3340                 {
3341                         if (detel_opts.map[detel].svalue != NULL)
3342                                 detel_str = g_strdup(detel_opts.map[detel].svalue);
3343                 }
3344                 else
3345                         detel_str = ghb_settings_get_string(js, "PictureDetelecineCustom");
3346                 hb_filter_detelecine.settings = detel_str;
3347                 hb_list_add( job->filters, &hb_filter_detelecine );
3348         }
3349         if ( decomb )
3350         {
3351                 if (decomb != 1)
3352                 {
3353                         if (decomb_opts.map[decomb].svalue != NULL)
3354                                 decomb_str = g_strdup(decomb_opts.map[decomb].svalue);
3355                 }
3356                 else
3357                         decomb_str = ghb_settings_get_string(js, "PictureDecombCustom");
3358                 hb_filter_decomb.settings = decomb_str;
3359                 hb_list_add( job->filters, &hb_filter_decomb );
3360         }
3361         if( job->deinterlace )
3362         {
3363                 if (deint != 1)
3364                 {
3365                         if (deint_opts.map[deint].svalue != NULL)
3366                                 deint_str = g_strdup(deint_opts.map[deint].svalue);
3367                 }
3368                 else
3369                         deint_str = ghb_settings_get_string(js, "PictureDeinterlaceCustom");
3370                 hb_filter_deinterlace.settings = deint_str;
3371                 hb_list_add( job->filters, &hb_filter_deinterlace );
3372         }
3373         gint deblock = ghb_settings_get_int(js, "PictureDeblock");
3374         if( deblock >= 5 )
3375         {
3376                 deblock_str = g_strdup_printf("%d", deblock);
3377                 hb_filter_deblock.settings = deblock_str;
3378                 hb_list_add( job->filters, &hb_filter_deblock );
3379         }
3380         gint denoise = ghb_settings_combo_int(js, "PictureDenoise");
3381         if( denoise )
3382         {
3383                 if (denoise != 1)
3384                 {
3385                         if (denoise_opts.map[denoise].svalue != NULL)
3386                                 denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
3387                 }
3388                 else
3389                         denoise_str = ghb_settings_get_string(js, "PictureDenoiseCustom");
3390                 hb_filter_denoise.settings = denoise_str;
3391                 hb_list_add( job->filters, &hb_filter_denoise );
3392         }
3393         job->width = ghb_settings_get_int(js, "scale_width");
3394         job->height = ghb_settings_get_int(js, "scale_height");
3395
3396         job->vcodec = ghb_settings_combo_int(js, "VideoEncoder");
3397         if ((job->mux == HB_MUX_MP4 || job->mux == HB_MUX_AVI) && 
3398                 (job->vcodec == HB_VCODEC_THEORA))
3399         {
3400                 // mp4|avi/theora combination is not supported.
3401                 job->vcodec = HB_VCODEC_XVID;
3402         }
3403         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
3404         {
3405                 job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible");
3406         }
3407         if (ghb_settings_get_boolean(js, "vquality_type_constant"))
3408         {
3409                 gdouble vquality;
3410                 vquality = ghb_settings_get_double(js, "VideoQualitySlider");
3411                 job->vquality =  vquality;
3412                 job->vbitrate = 0;
3413         }
3414         else if (ghb_settings_get_boolean(js, "vquality_type_bitrate"))
3415         {
3416                 job->vquality = -1.0;
3417                 job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
3418         }
3419         // AVI container does not support variable frame rate.
3420         if (job->mux == HB_MUX_AVI)
3421         {
3422                 job->vfr = FALSE;
3423                 job->cfr = 1;
3424         }
3425
3426         if( vrate == 0 )
3427         {
3428                 job->vrate = title->rate;
3429                 job->vrate_base = title->rate_base;
3430                 job->cfr = 0;
3431         }
3432         else
3433         {
3434                 job->vrate = 27000000;
3435                 job->vrate_base = vrate;
3436                 job->cfr = 1;
3437         }
3438         // First remove any audios that are already in the list
3439         // This happens if you are encoding the same title a second time.
3440         gint num_audio_tracks = hb_list_count(job->list_audio);
3441         gint ii;
3442     for(ii = 0; ii < num_audio_tracks; ii++)
3443     {
3444         hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
3445         hb_list_rem(job->list_audio, audio);
3446     }
3447
3448         const GValue *audio_list;
3449         gint count;
3450         gint tcount = 0;
3451         
3452         audio_list = ghb_settings_get_value(js, "audio_list");
3453         count = ghb_array_len(audio_list);
3454         for (ii = 0; ii < count; ii++)
3455         {
3456                 GValue *asettings;
3457             hb_audio_config_t audio;
3458             hb_audio_config_t *taudio;
3459
3460                 hb_audio_config_init(&audio);
3461                 asettings = ghb_array_get_nth(audio_list, ii);
3462                 audio.in.track = ghb_settings_get_int(asettings, "AudioTrack");
3463                 audio.out.track = tcount;
3464                 audio.out.codec = ghb_settings_combo_int(asettings, "AudioEncoder");
3465         taudio = (hb_audio_config_t *) hb_list_audio_config_item(
3466                                                                         title->list_audio, audio.in.track );
3467                 if ((taudio->in.codec != HB_ACODEC_AC3 && 
3468              audio.out.codec == HB_ACODEC_AC3) ||
3469                     (taudio->in.codec != HB_ACODEC_DCA && 
3470                          audio.out.codec == HB_ACODEC_DCA))
3471                 {
3472                         // Not supported.  AC3 is passthrough only, so input must be AC3
3473                         if (job->mux == HB_MUX_AVI)
3474                         {
3475                                 audio.out.codec = HB_ACODEC_LAME;
3476                         }
3477                         else
3478                         {
3479                                 audio.out.codec = HB_ACODEC_FAAC;
3480                         }
3481                 }
3482                 if ((job->mux == HB_MUX_MP4) && 
3483                         ((audio.out.codec == HB_ACODEC_LAME) ||
3484                         (audio.out.codec == HB_ACODEC_VORBIS)))
3485                 {
3486                         // mp4/mp3|vorbis combination is not supported.
3487                         audio.out.codec = HB_ACODEC_FAAC;
3488                 }
3489                 if ((job->mux == HB_MUX_AVI) && 
3490                         ((audio.out.codec == HB_ACODEC_FAAC) ||
3491                         (audio.out.codec == HB_ACODEC_VORBIS)))
3492                 {
3493                         // avi/faac|vorbis combination is not supported.
3494                         audio.out.codec = HB_ACODEC_LAME;
3495                 }
3496                 if ((job->mux == HB_MUX_OGM) && 
3497                         ((audio.out.codec == HB_ACODEC_FAAC) ||
3498                         (audio.out.codec == HB_ACODEC_AC3) ||
3499                         (audio.out.codec == HB_ACODEC_DCA)))
3500                 {
3501                         // ogm/faac|ac3 combination is not supported.
3502                         audio.out.codec = HB_ACODEC_VORBIS;
3503                 }
3504         audio.out.dynamic_range_compression = 
3505                         ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
3506                 // It would be better if this were done in libhb for us, but its not yet.
3507                 if (audio.out.codec == HB_ACODEC_AC3 || audio.out.codec == HB_ACODEC_DCA)
3508                 {
3509                         audio.out.mixdown = 0;
3510                 }
3511                 else
3512                 {
3513                         audio.out.mixdown = ghb_settings_combo_int(asettings, "AudioMixdown");
3514                         // Make sure the mixdown is valid and pick a new one if not.
3515                         audio.out.mixdown = ghb_get_best_mix(titleindex, 
3516                                 audio.in.track, audio.out.codec, audio.out.mixdown);
3517                         audio.out.bitrate = 
3518                                 ghb_settings_combo_int(asettings, "AudioBitrate");
3519                         gint srate = ghb_settings_combo_int(asettings, "AudioSamplerate");
3520                         if (srate == 0) // 0 is same as source
3521                                 audio.out.samplerate = taudio->in.samplerate;
3522                         else
3523                                 audio.out.samplerate = srate;
3524                 }
3525
3526                 // Add it to the jobs audio list
3527         hb_audio_add( job, &audio );
3528                 tcount++;
3529         }
3530         // I was tempted to move this up with the reset of the video quality
3531         // settings, but I suspect the settings above need to be made
3532         // first in order for hb_calc_bitrate to be accurate.
3533         if (ghb_settings_get_boolean(js, "vquality_type_target"))
3534         {
3535                 gint size;
3536                 
3537                 size = ghb_settings_get_int(js, "VideoTargetSize");
3538         job->vbitrate = hb_calc_bitrate( job, size );
3539                 job->vquality = -1.0;
3540         }
3541
3542         dest_str = ghb_settings_get_string(js, "destination");
3543         job->file = dest_str;
3544         job->crf = ghb_settings_get_boolean(js, "constant_rate_factor");
3545         // TODO: libhb holds onto a reference to the x264opts and is not
3546         // finished with it until encoding the job is done.  But I can't
3547         // find a way to get at the job before it is removed in order to
3548         // free up the memory I am allocating here.
3549         // The short story is THIS LEAKS.
3550         x264opts = ghb_build_x264opts_string(js);
3551         
3552         if( x264opts != NULL && *x264opts != '\0' )
3553         {
3554                 job->x264opts = x264opts;
3555         }
3556         else /*avoids a bus error crash when options aren't specified*/
3557         {
3558                 job->x264opts =  NULL;
3559         }
3560         gint subtitle;
3561         gchar *slang = ghb_settings_get_string(js, "Subtitles");
3562         subtitle = -2; // default to none
3563         if (strcmp(slang, "auto") == 0)
3564         {
3565                 subtitle = -1;
3566         }
3567         else
3568         {
3569                 gint scount;
3570         hb_subtitle_t * subt;
3571
3572                 scount = hb_list_count(title->list_subtitle);
3573                 for (ii = 0; ii < scount; ii++)
3574                 {
3575                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
3576                         if (strcmp(slang, subt->iso639_2) == 0)
3577                         {
3578                                 subtitle = ii;
3579                                 break;
3580                         }
3581                 }
3582         }
3583         gboolean forced_subtitles = ghb_settings_get_boolean(js, "SubtitlesForced");
3584         job->subtitle_force = forced_subtitles;
3585         if (subtitle >= 0)
3586                 job->subtitle = subtitle;
3587         else
3588                 job->subtitle = -1;
3589         if (subtitle == -1)
3590         {
3591                 // Subtitle scan. Look for subtitle matching audio language
3592                 char *x264opts_tmp;
3593
3594                 /*
3595                  * When subtitle scan is enabled do a fast pre-scan job
3596                  * which will determine which subtitles to enable, if any.
3597                  */
3598                 job->pass = -1;
3599                 job->indepth_scan = 1;
3600
3601                 x264opts_tmp = job->x264opts;
3602                 job->x264opts = NULL;
3603
3604                 job->select_subtitle = malloc(sizeof(hb_subtitle_t*));
3605                 *(job->select_subtitle) = NULL;
3606
3607                 /*
3608                  * Add the pre-scan job
3609                  */
3610                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3611                 hb_add( h, job );
3612                 //if (job->x264opts != NULL)
3613                 //      g_free(job->x264opts);
3614
3615                 job->x264opts = x264opts_tmp;
3616         }
3617         else
3618         {
3619                 job->select_subtitle = NULL;
3620         }
3621         if( ghb_settings_get_boolean(js, "VideoTwoPass") &&
3622                 !ghb_settings_get_boolean(js, "vquality_type_constant"))
3623         {
3624                 /*
3625                  * If subtitle_scan is enabled then only turn it on
3626                  * for the second pass and then off again for the
3627                  * second.
3628                  */
3629                 hb_subtitle_t **subtitle_tmp = job->select_subtitle;
3630                 job->select_subtitle = NULL;
3631                 job->pass = 1;
3632                 job->indepth_scan = 0;
3633                 gchar *x264opts2 = NULL;
3634                 if (x264opts)
3635                 {
3636                         x264opts2 = g_strdup(x264opts);
3637                 }
3638                 /*
3639                  * If turbo options have been selected then append them
3640                  * to the x264opts now (size includes one ':' and the '\0')
3641                  */
3642                 if( ghb_settings_get_boolean(js, "VideoTurboTwoPass") )
3643                 {
3644                         char *tmp_x264opts;
3645
3646                         if ( x264opts )
3647                         {
3648                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, turbo_opts);
3649                                 g_free(x264opts);
3650                         } 
3651                         else 
3652                         {
3653                                 /*
3654                                  * No x264opts to modify, but apply the turbo options
3655                                  * anyway as they may be modifying defaults
3656                                  */
3657                                 tmp_x264opts = g_strdup_printf("%s", turbo_opts);
3658                         }
3659                         x264opts = tmp_x264opts;
3660
3661                         job->x264opts = x264opts;
3662                 }
3663                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3664                 hb_add( h, job );
3665                 //if (job->x264opts != NULL)
3666                 //      g_free(job->x264opts);
3667
3668                 job->select_subtitle = subtitle_tmp;
3669                 job->pass = 2;
3670                 /*
3671                  * On the second pass we turn off subtitle scan so that we
3672                  * can actually encode using any subtitles that were auto
3673                  * selected in the first pass (using the whacky select-subtitle
3674                  * attribute of the job).
3675                  */
3676                 job->indepth_scan = 0;
3677                 job->x264opts = x264opts2;
3678                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3679                 hb_add( h, job );
3680                 //if (job->x264opts != NULL)
3681                 //      g_free(job->x264opts);
3682         }
3683         else
3684         {
3685                 job->indepth_scan = 0;
3686                 job->pass = 0;
3687                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3688                 hb_add( h, job );
3689                 //if (job->x264opts != NULL)
3690                 //      g_free(job->x264opts);
3691         }
3692         if (detel_str) g_free(detel_str);
3693         if (decomb_str) g_free(decomb_str);
3694         if (deint_str) g_free(deint_str);
3695         if (deblock_str) g_free(deblock_str);
3696         if (denoise_str) g_free(denoise_str);
3697         if (dest_str) g_free(dest_str);
3698 }
3699
3700 void
3701 ghb_add_job(GValue *js, gint unique_id)
3702 {
3703         // Since I'm doing a scan of the single title I want just prior 
3704         // to adding the job, there is only the one title to choose from.
3705         add_job(h_queue, js, unique_id, 0);
3706 }
3707
3708 void
3709 ghb_add_live_job(GValue *js, gint unique_id)
3710 {
3711         // Since I'm doing a scan of the single title I want just prior 
3712         // to adding the job, there is only the one title to choose from.
3713         gint titleindex = ghb_settings_combo_int(js, "title");
3714         add_job(h_scan, js, unique_id, titleindex);
3715 }
3716
3717 void
3718 ghb_remove_job(gint unique_id)
3719 {
3720     hb_job_t * job;
3721     gint ii;
3722         
3723         // Multiples passes all get the same id
3724         // remove them all.
3725         // Go backwards through list, so reordering doesn't screw me.
3726         ii = hb_count(h_queue) - 1;
3727     while ((job = hb_job(h_queue, ii--)) != NULL)
3728     {
3729         if ((job->sequence_id & 0xFFFFFF) == unique_id)
3730                         hb_rem(h_queue, job);
3731     }
3732 }
3733
3734 void
3735 ghb_start_queue()
3736 {
3737         hb_start( h_queue );
3738 }
3739
3740 void
3741 ghb_stop_queue()
3742 {
3743         hb_stop( h_queue );
3744 }
3745
3746 void
3747 ghb_start_live_encode()
3748 {
3749         hb_start( h_scan );
3750 }
3751
3752 void
3753 ghb_stop_live_encode()
3754 {
3755         hb_stop( h_scan );
3756 }
3757
3758 void
3759 ghb_pause_queue()
3760 {
3761     hb_state_t s;
3762     hb_get_state2( h_queue, &s );
3763
3764     if( s.state == HB_STATE_PAUSED )
3765     {
3766         hb_resume( h_queue );
3767     }
3768     else
3769     {
3770         hb_pause( h_queue );
3771     }
3772 }
3773
3774 #define RED_HEIGHT      720.0
3775 #define RED_WIDTH       1280.0
3776
3777 GdkPixbuf*
3778 ghb_get_preview_image(
3779         gint titleindex, 
3780         gint index, 
3781         signal_user_data_t *ud,
3782         gboolean borders,
3783         gint *out_width,
3784         gint *out_height)
3785 {
3786         GValue *settings;
3787         hb_title_t *title;
3788         hb_list_t  *list;
3789         
3790         settings = ud->settings;
3791         list = hb_get_titles( h_scan );
3792         if( !hb_list_count( list ) )
3793         {
3794                 /* No valid title, stop right there */
3795                 return NULL;
3796         }
3797     title = hb_list_item( list, titleindex );
3798         if (title == NULL) return NULL;
3799         if (title->job == NULL) return NULL;
3800         set_preview_job_settings(title->job, settings);
3801
3802         // hb_get_preview can't handle sizes that are larger than the original title
3803         // dimensions
3804         if (title->job->width > title->width)
3805                 title->job->width = title->width;
3806         
3807         if (title->job->height > title->height)
3808                 title->job->height = title->height;
3809
3810         // hb_get_preview doesn't compensate for anamorphic, so lets
3811         // calculate scale factors
3812         gint width, height, par_width = 1, par_height = 1;
3813         gboolean anamorphic = ghb_settings_get_boolean(settings, "anamorphic");
3814         if (anamorphic)
3815         {
3816                 hb_set_anamorphic_size( title->job, &width, &height, &par_width, &par_height );
3817         }
3818
3819         // And also creates artifacts if the width is not a multiple of 8
3820         //title->job->width = ((title->job->width + 4) >> 3) << 3;
3821         // And the height must be a multiple of 2
3822         //title->job->height = ((title->job->height + 1) >> 1) << 1;
3823         
3824         // Make sure we have a big enough buffer to receive the image from libhb. libhb
3825         // creates images with a one-pixel border around the original content. Hence we
3826         // add 2 pixels horizontally and vertically to the buffer size.
3827         gint srcWidth = title->width + 2;
3828         gint srcHeight= title->height + 2;
3829         gint dstWidth = title->width;
3830         gint dstHeight= title->height;
3831         gint borderTop = 1;
3832         gint borderLeft = 1;
3833     if (borders)
3834     {
3835         //     |<---------- title->width ----------->|
3836         //     |   |<---- title->job->width ---->|   |
3837         //     |   |                             |   |
3838         //     .......................................
3839         //     ....+-----------------------------+....
3840         //     ....|                             |....<-- gray border
3841         //     ....|                             |....
3842         //     ....|                             |....
3843         //     ....|                             |<------- image
3844         //     ....|                             |....
3845         //     ....|                             |....
3846         //     ....|                             |....
3847         //     ....|                             |....
3848         //     ....|                             |....
3849         //     ....+-----------------------------+....
3850         //     .......................................
3851                 dstWidth = title->job->width;
3852         dstHeight = title->job->height;
3853                 borderTop = (srcHeight - dstHeight) / 2;
3854                 borderLeft = (srcWidth - dstWidth) / 2;
3855                 g_debug("boarders removed\n");
3856         }
3857
3858         g_debug("src %d x %d\n", srcWidth, srcHeight);
3859         g_debug("dst %d x %d\n", dstWidth, dstHeight);
3860         g_debug("job dim %d x %d\n", title->job->width, title->job->height);
3861         g_debug("title crop %d:%d:%d:%d\n", 
3862                         title->crop[0],
3863                         title->crop[1],
3864                         title->crop[2],
3865                         title->crop[3]);
3866         g_debug("job crop %d:%d:%d:%d\n", 
3867                         title->job->crop[0],
3868                         title->job->crop[1],
3869                         title->job->crop[2],
3870                         title->job->crop[3]);
3871         static guint8 *buffer = NULL;
3872         static gint bufferSize = 0;
3873
3874         gint newSize;
3875         newSize = srcWidth * srcHeight * 4;
3876         if( bufferSize < newSize )
3877         {
3878                 bufferSize = newSize;
3879                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
3880         }
3881         hb_get_preview( h_scan, title, index, buffer );
3882
3883         // Create an GdkPixbuf and copy the libhb image into it, converting it from
3884         // libhb's format something suitable. Along the way, we'll strip off the
3885         // border around libhb's image.
3886         
3887         // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format.
3888         // Alpha is ignored.
3889
3890         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
3891         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
3892         
3893         guint32 *src = (guint32*)buffer;
3894         guint8 *dst = pixels;
3895         src += borderTop * srcWidth;    // skip top rows in src to get to first row of dst
3896         src += borderLeft;              // skip left pixels in src to get to first pixel of dst
3897         gint ii, jj;
3898         gint channels = gdk_pixbuf_get_n_channels (preview);
3899         gint stride = gdk_pixbuf_get_rowstride (preview);
3900         guint8 *tmp;
3901         for (ii = 0; ii < dstHeight; ii++)
3902         {
3903                 tmp = dst;
3904                 for (jj = 0; jj < dstWidth; jj++)
3905                 {
3906                         tmp[0] = src[0] >> 16;
3907                         tmp[1] = src[0] >> 8;
3908                         tmp[2] = src[0] >> 0;
3909                         tmp += channels;
3910                         src++;
3911                 }
3912                 dst += stride;
3913                 src += (srcWidth - dstWidth);   // skip to next row in src
3914         }
3915         ghb_par_scale(ud, &dstWidth, &dstHeight, par_width, par_height);
3916         *out_width = dstWidth;
3917         *out_height = dstHeight;
3918         if (ghb_settings_get_boolean(settings, "reduce_hd_preview"))
3919         {
3920                 GdkScreen *ss;
3921                 gint s_w, s_h;
3922                 gint orig_w, orig_h;
3923                 gint factor = 80;
3924
3925                 if (ghb_settings_get_boolean(settings, "preview_fullscreen"))
3926                 {
3927                         factor = 100;
3928                 }
3929                 ss = gdk_screen_get_default();
3930                 s_w = gdk_screen_get_width(ss);
3931                 s_h = gdk_screen_get_height(ss);
3932                 orig_w = dstWidth;
3933                 orig_h = dstHeight;
3934
3935                 if (dstWidth > s_w * factor / 100)
3936                 {
3937                         dstWidth = s_w * factor / 100;
3938                         dstHeight = dstHeight * dstWidth / orig_w;
3939                 }
3940                 if (dstHeight > s_h * factor / 100)
3941                 {
3942                         dstHeight = s_h * factor / 100;
3943                         dstWidth = dstWidth * dstHeight / orig_h;
3944                 }
3945         }
3946         g_debug("scaled %d x %d\n", dstWidth, dstHeight);
3947         GdkPixbuf *scaled_preview;
3948         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
3949         g_object_unref (preview);
3950         return scaled_preview;
3951 }
3952
3953 static void
3954 sanitize_volname(gchar *name)
3955 {
3956         gchar *a, *b;
3957
3958         a = b = name;
3959         while (*b)
3960         {
3961                 switch(*b)
3962                 {
3963                 case '<':
3964                         b++;
3965                         break;
3966                 case '>':
3967                         b++;
3968                         break;
3969                 default:
3970                         *a = *b;
3971                         a++; b++;
3972                         break;
3973                 }
3974         }
3975         *a = 0;
3976 }
3977
3978 gchar*
3979 ghb_dvd_volname(const gchar *device)
3980 {
3981         gchar *name;
3982         name = hb_dvd_name((gchar*)device);
3983         if (name != NULL)
3984         {
3985                 sanitize_volname(name);
3986                 return g_strdup(name);
3987         }
3988         return name;
3989 }