OSDN Git Service

LinGui: clean up my improper use of HB_VERSION and HB_BUILD.
[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 GValue*
2070 ghb_get_chapters(gint titleindex)
2071 {
2072         hb_list_t  * list;
2073         hb_title_t * title;
2074     hb_chapter_t * chapter;
2075         gint count, ii;
2076         GValue *chapters = NULL;
2077         
2078         g_debug("ghb_get_chapters (title = %d)\n", titleindex);
2079         if (h_scan == NULL) return NULL;
2080         list = hb_get_titles( h_scan );
2081     title = (hb_title_t*)hb_list_item( list, titleindex );
2082         if (title == NULL) return NULL;
2083         count = hb_list_count( title->list_chapter );
2084         chapters = ghb_array_value_new(count);
2085         for (ii = 0; ii < count; ii++)
2086         {
2087                 chapter = hb_list_item(title->list_chapter, ii);
2088                 if (chapter == NULL) break;
2089                 if (chapter->title == NULL || chapter->title[0] == 0)
2090                 {
2091                         gchar *str;
2092                         str = g_strdup_printf ("Chapter %2d", ii+1);
2093                         ghb_array_append(chapters, ghb_string_value_new(str));
2094                         g_free(str);
2095                 }
2096                 else 
2097                 {
2098                         ghb_array_append(chapters, ghb_string_value_new(chapter->title));
2099                 }
2100         }
2101         return chapters;
2102 }
2103
2104 gboolean
2105 ghb_ac3_in_audio_list(const GValue *audio_list)
2106 {
2107         gint count, ii;
2108
2109         count = ghb_array_len(audio_list);
2110         for (ii = 0; ii < count; ii++)
2111         {
2112                 GValue *asettings;
2113                 gint acodec;
2114
2115                 asettings = ghb_array_get_nth(audio_list, ii);
2116                 acodec = ghb_settings_combo_int(asettings, "AudioEncoder");
2117                 if (acodec == HB_ACODEC_AC3)
2118                         return TRUE;
2119         }
2120         return FALSE;
2121 }
2122
2123 static void
2124 audio_bitrate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
2125 {
2126         GtkTreeIter iter;
2127         GtkListStore *store;
2128         gchar *str;
2129         
2130         g_debug("audio_rate_opts_add ()\n");
2131         store = get_combo_box_store(builder, name);
2132         if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
2133         {
2134                 str = g_strdup_printf ("%d", rate);
2135                 gtk_list_store_append(store, &iter);
2136                 gtk_list_store_set(store, &iter, 
2137                                                    0, str, 
2138                                                    1, TRUE, 
2139                                                    2, str, 
2140                                                    3, (gdouble)rate, 
2141                                                    4, str, 
2142                                                    -1);
2143                 g_free(str);
2144         }
2145 }
2146
2147 static void
2148 audio_bitrate_opts_clean(GtkBuilder *builder, const gchar *name, gint last_rate)
2149 {
2150         GtkTreeIter iter;
2151         GtkListStore *store;
2152         gdouble ivalue;
2153         gboolean done = FALSE;
2154         gint ii = 0;
2155         guint last = (guint)last_rate;
2156         
2157         g_debug("audio_bitrate_opts_clean ()\n");
2158         store = get_combo_box_store(builder, name);
2159         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
2160         {
2161                 do
2162                 {
2163                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
2164                         if (search_rates(
2165                                 hb_audio_bitrates, ivalue, hb_audio_bitrates_count) < 0)
2166                         {
2167                                 done = !gtk_list_store_remove(store, &iter);
2168                         }
2169                         else if (ivalue > last)
2170                         {
2171                                 ii++;
2172                                 gtk_list_store_set(store, &iter, 1, FALSE, -1);
2173                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
2174                         }
2175                         else
2176                         {
2177                                 ii++;
2178                                 gtk_list_store_set(store, &iter, 1, TRUE, -1);
2179                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
2180                         }
2181                 } while (!done);
2182         }
2183 }
2184
2185 static void
2186 audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name)
2187 {
2188         GtkTreeIter iter;
2189         GtkListStore *store;
2190         gint ii;
2191         
2192         g_debug("audio_bitrate_opts_set ()\n");
2193         store = get_combo_box_store(builder, name);
2194         gtk_list_store_clear(store);
2195         for (ii = 0; ii < hb_audio_bitrates_count; ii++)
2196         {
2197                 gtk_list_store_append(store, &iter);
2198                 gtk_list_store_set(store, &iter, 
2199                                                    0, hb_audio_bitrates[ii].string, 
2200                                                    1, TRUE, 
2201                                                    2, hb_audio_bitrates[ii].string, 
2202                                                    3, (gdouble)hb_audio_bitrates[ii].rate, 
2203                                                    4, hb_audio_bitrates[ii].string, 
2204                                                    -1);
2205         }
2206 }
2207
2208 void
2209 ghb_set_passthru_bitrate_opts(GtkBuilder *builder, gint bitrate)
2210 {
2211         audio_bitrate_opts_add(builder, "AudioBitrate", bitrate);
2212 }
2213
2214 void
2215 ghb_set_default_bitrate_opts(GtkBuilder *builder, gint last_rate)
2216 {
2217         audio_bitrate_opts_clean(builder, "AudioBitrate", last_rate);
2218 }
2219
2220 static ghb_status_t hb_status;
2221
2222 void
2223 ghb_combo_init(GtkBuilder *builder)
2224 {
2225         // Set up the list model for the combos
2226         init_ui_combo_boxes(builder);
2227         // Populate all the combos
2228         ghb_update_ui_combo_box(builder, NULL, 0, TRUE);
2229 }
2230
2231 void
2232 ghb_backend_init(gint debug)
2233 {
2234     /* Init libhb */
2235     h_scan = hb_init( debug, 0 );
2236     h_queue = hb_init( debug, 0 );
2237 }
2238
2239 void
2240 ghb_backend_close()
2241 {
2242         hb_close(&h_queue);
2243         hb_close(&h_scan);
2244 }
2245
2246 void
2247 ghb_backend_scan(const gchar *path, gint titleindex, gint preview_count)
2248 {
2249     hb_scan( h_scan, path, titleindex, preview_count, 1 );
2250         hb_status.scan.state |= GHB_STATE_SCANNING;
2251         // initialize count and cur to something that won't cause FPE
2252         // when computing progress
2253         hb_status.scan.title_count = 1;
2254         hb_status.scan.title_cur = 0;
2255 }
2256
2257 void
2258 ghb_backend_queue_scan(const gchar *path, gint titlenum)
2259 {
2260         g_debug("ghb_backend_queue_scan()");
2261         hb_scan( h_queue, path, titlenum, 10, 0 );
2262         hb_status.queue.state |= GHB_STATE_SCANNING;
2263 }
2264
2265 gint
2266 ghb_get_scan_state()
2267 {
2268         return hb_status.scan.state;
2269 }
2270
2271 gint
2272 ghb_get_queue_state()
2273 {
2274         return hb_status.queue.state;
2275 }
2276
2277 void
2278 ghb_clear_scan_state(gint state)
2279 {
2280         hb_status.scan.state &= ~state;
2281 }
2282
2283 void
2284 ghb_clear_queue_state(gint state)
2285 {
2286         hb_status.queue.state &= ~state;
2287 }
2288
2289 void
2290 ghb_set_scan_state(gint state)
2291 {
2292         hb_status.scan.state |= state;
2293 }
2294
2295 void
2296 ghb_set_queue_state(gint state)
2297 {
2298         hb_status.queue.state |= state;
2299 }
2300
2301 void
2302 ghb_get_status(ghb_status_t *status)
2303 {
2304         memcpy(status, &hb_status, sizeof(ghb_status_t));
2305 }
2306
2307 void 
2308 ghb_track_status()
2309 {
2310     hb_state_t s_scan;
2311     hb_state_t s_queue;
2312
2313         if (h_scan == NULL) return;
2314     hb_get_state( h_scan, &s_scan );
2315         switch( s_scan.state )
2316     {
2317 #define p s_scan.param.scanning
2318         case HB_STATE_SCANNING:
2319                 {
2320                         hb_status.scan.state |= GHB_STATE_SCANNING;
2321                         hb_status.scan.title_count = p.title_count;
2322                         hb_status.scan.title_cur = p.title_cur;
2323                 } break;
2324 #undef p
2325
2326         case HB_STATE_SCANDONE:
2327         {
2328                         hb_status.scan.state &= ~GHB_STATE_SCANNING;
2329                         hb_status.scan.state |= GHB_STATE_SCANDONE;
2330         } break;
2331
2332 #define p s_scan.param.working
2333         case HB_STATE_WORKING:
2334                         hb_status.scan.state |= GHB_STATE_WORKING;
2335                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
2336                         hb_status.scan.job_cur = p.job_cur;
2337                         hb_status.scan.job_count = p.job_count;
2338                         hb_status.scan.progress = p.progress;
2339                         hb_status.scan.rate_cur = p.rate_cur;
2340                         hb_status.scan.rate_avg = p.rate_avg;
2341                         hb_status.scan.hours = p.hours;
2342                         hb_status.scan.minutes = p.minutes;
2343                         hb_status.scan.seconds = p.seconds;
2344                         hb_status.scan.unique_id = p.sequence_id & 0xFFFFFF;
2345             break;
2346 #undef p
2347
2348         case HB_STATE_PAUSED:
2349                         hb_status.scan.state |= GHB_STATE_PAUSED;
2350             break;
2351                                 
2352         case HB_STATE_MUXING:
2353         {
2354                         hb_status.scan.state |= GHB_STATE_MUXING;
2355         } break;
2356
2357 #define p s_scan.param.workdone
2358         case HB_STATE_WORKDONE:
2359                 {
2360             hb_job_t *job;
2361
2362                         hb_status.scan.state |= GHB_STATE_WORKDONE;
2363                         hb_status.scan.state &= ~GHB_STATE_MUXING;
2364                         hb_status.scan.state &= ~GHB_STATE_PAUSED;
2365                         hb_status.scan.state &= ~GHB_STATE_WORKING;
2366                         switch (p.error)
2367                         {
2368                         case HB_ERROR_NONE:
2369                                 hb_status.scan.error = GHB_ERROR_NONE;
2370                                 break;
2371                         case HB_ERROR_CANCELED:
2372                                 hb_status.scan.error = GHB_ERROR_CANCELED;
2373                                 break;
2374                         default:
2375                                 hb_status.scan.error = GHB_ERROR_FAIL;
2376                                 break;
2377                         }
2378                         // Delete all remaining jobs of this encode.
2379                         // An encode can be composed of multiple associated jobs.
2380                         // When a job is stopped, libhb removes it from the job list,
2381                         // but does not remove other jobs that may be associated with it.
2382                         // Associated jobs are taged in the sequence id.
2383             while ((job = hb_job(h_scan, 0)) != NULL) 
2384                 hb_rem( h_scan, job );
2385                 } break;
2386 #undef p
2387     }
2388     hb_get_state( h_queue, &s_queue );
2389         switch( s_queue.state )
2390     {
2391 #define p s_queue.param.scanning
2392         case HB_STATE_SCANNING:
2393                 {
2394                         hb_status.queue.state |= GHB_STATE_SCANNING;
2395                         hb_status.queue.title_count = p.title_count;
2396                         hb_status.queue.title_cur = p.title_cur;
2397                 } break;
2398 #undef p
2399
2400         case HB_STATE_SCANDONE:
2401         {
2402                         hb_status.queue.state &= ~GHB_STATE_SCANNING;
2403                         hb_status.queue.state |= GHB_STATE_SCANDONE;
2404         } break;
2405
2406 #define p s_queue.param.working
2407         case HB_STATE_WORKING:
2408                         hb_status.queue.state |= GHB_STATE_WORKING;
2409                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
2410                         hb_status.queue.job_cur = p.job_cur;
2411                         hb_status.queue.job_count = p.job_count;
2412                         hb_status.queue.progress = p.progress;
2413                         hb_status.queue.rate_cur = p.rate_cur;
2414                         hb_status.queue.rate_avg = p.rate_avg;
2415                         hb_status.queue.hours = p.hours;
2416                         hb_status.queue.minutes = p.minutes;
2417                         hb_status.queue.seconds = p.seconds;
2418                         hb_status.queue.unique_id = p.sequence_id & 0xFFFFFF;
2419             break;
2420 #undef p
2421
2422         case HB_STATE_PAUSED:
2423                         hb_status.queue.state |= GHB_STATE_PAUSED;
2424             break;
2425                                 
2426         case HB_STATE_MUXING:
2427         {
2428                         hb_status.queue.state |= GHB_STATE_MUXING;
2429         } break;
2430
2431 #define p s_queue.param.workdone
2432         case HB_STATE_WORKDONE:
2433                 {
2434             hb_job_t *job;
2435
2436                         hb_status.queue.state |= GHB_STATE_WORKDONE;
2437                         hb_status.queue.state &= ~GHB_STATE_MUXING;
2438                         hb_status.queue.state &= ~GHB_STATE_PAUSED;
2439                         hb_status.queue.state &= ~GHB_STATE_WORKING;
2440                         switch (p.error)
2441                         {
2442                         case HB_ERROR_NONE:
2443                                 hb_status.queue.error = GHB_ERROR_NONE;
2444                                 break;
2445                         case HB_ERROR_CANCELED:
2446                                 hb_status.queue.error = GHB_ERROR_CANCELED;
2447                                 break;
2448                         default:
2449                                 hb_status.queue.error = GHB_ERROR_FAIL;
2450                                 break;
2451                         }
2452                         // Delete all remaining jobs of this encode.
2453                         // An encode can be composed of multiple associated jobs.
2454                         // When a job is stopped, libhb removes it from the job list,
2455                         // but does not remove other jobs that may be associated with it.
2456                         // Associated jobs are taged in the sequence id.
2457             while ((job = hb_job(h_queue, 0)) != NULL) 
2458                 hb_rem( h_queue, job );
2459                 } break;
2460 #undef p
2461     }
2462 }
2463
2464 gboolean
2465 ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
2466 {
2467         hb_list_t  * list;
2468         hb_title_t * title;
2469         
2470     if (h_scan == NULL) return FALSE;
2471         list = hb_get_titles( h_scan );
2472         if( !hb_list_count( list ) )
2473         {
2474                 /* No valid title, stop right there */
2475                 return FALSE;
2476         }
2477
2478     title = hb_list_item( list, titleindex );
2479         if (title == NULL) return FALSE;        // Bad titleindex
2480         tinfo->width = title->width;
2481         tinfo->height = title->height;
2482         memcpy(tinfo->crop, title->crop, 4 * sizeof(int));
2483         // Don't allow crop to 0
2484         if (title->crop[0] + title->crop[1] >= title->height)
2485                 title->crop[0] = title->crop[1] = 0;
2486         if (title->crop[2] + title->crop[3] >= title->width)
2487                 title->crop[2] = title->crop[3] = 0;
2488         tinfo->num_chapters = hb_list_count(title->list_chapter);
2489         tinfo->rate_base = title->rate_base;
2490         tinfo->rate = title->rate;
2491         hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), 
2492                                 title->width * title->pixel_aspect_width, 
2493                                 title->height * title->pixel_aspect_height);
2494         tinfo->hours = title->hours;
2495         tinfo->minutes = title->minutes;
2496         tinfo->seconds = title->seconds;
2497         tinfo->duration = title->duration;
2498         return TRUE;
2499 }
2500
2501 gboolean
2502 ghb_get_audio_info(ghb_audio_info_t *ainfo, gint titleindex, gint audioindex)
2503 {
2504     hb_audio_config_t *audio;
2505         
2506         audio = get_hb_audio(titleindex, audioindex);
2507         if (audio == NULL) return FALSE; // Bad audioindex
2508         ainfo->codec = audio->in.codec;
2509         ainfo->bitrate = audio->in.bitrate;
2510         ainfo->samplerate = audio->in.samplerate;
2511         return TRUE;
2512 }
2513
2514 gboolean
2515 ghb_audio_is_passthru(gint acodec)
2516 {
2517         g_debug("ghb_audio_is_passthru () \n");
2518         return (acodec == HB_ACODEC_AC3) || (acodec == HB_ACODEC_DCA);
2519 }
2520
2521 gint
2522 ghb_get_default_acodec()
2523 {
2524         return HB_ACODEC_FAAC;
2525 }
2526
2527 void
2528 ghb_set_scale(signal_user_data_t *ud, gint mode)
2529 {
2530         hb_list_t  * list;
2531         hb_title_t * title;
2532         hb_job_t   * job;
2533         gboolean keep_aspect, round_dims, anamorphic;
2534         gboolean autocrop, autoscale, noscale;
2535         gint crop[4], width, height, par_width, par_height;
2536         gint crop_width, crop_height;
2537         gint aspect_n, aspect_d;
2538         gboolean keep_width = (mode == GHB_SCALE_KEEP_WIDTH);
2539         gboolean keep_height = (mode == GHB_SCALE_KEEP_HEIGHT);
2540         gint step;
2541         GtkWidget *widget;
2542         gint modshift;
2543         gint modround;
2544         gint max_width = 0;
2545         gint max_height = 0;
2546         
2547         g_debug("ghb_set_scale ()\n");
2548
2549         if (h_scan == NULL) return;
2550         list = hb_get_titles( h_scan );
2551         if( !hb_list_count( list ) )
2552         {
2553                 /* No valid title, stop right there */
2554                 return;
2555         }
2556         gint titleindex;
2557
2558         titleindex = ghb_settings_combo_int(ud->settings, "title");
2559     title = hb_list_item( list, titleindex );
2560         if (title == NULL) return;
2561         job   = title->job;
2562         if (job == NULL) return;
2563         
2564         // First configure widgets
2565         round_dims = ghb_settings_get_boolean(ud->settings, "ModDimensions");
2566         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
2567         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
2568         autocrop = ghb_settings_get_boolean(ud->settings, "PictureAutoCrop");
2569         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
2570         // "Noscale" is a flag that says we prefer to crop extra to satisfy
2571         // alignment constraints rather than scaling to satisfy them.
2572         noscale = ghb_settings_get_boolean(ud->settings, "noscale");
2573         // Align dimensions to either 16 or 2 pixels
2574         // The scaler crashes if the dimensions are not divisible by 2
2575         // x264 also will not accept dims that are not multiple of 2
2576         modshift = round_dims ? 4 : 1;
2577         modround = round_dims ? 8 : 1;
2578         if (autoscale)
2579         {
2580                 keep_width = FALSE;
2581                 keep_height = FALSE;
2582         }
2583         if (keep_aspect)
2584         {
2585                 keep_height = FALSE;
2586         }
2587         // Step needs to be at least 2 because odd widths cause scaler crash
2588         step = round_dims ? 16 : 2;
2589         widget = GHB_WIDGET (ud->builder, "scale_width");
2590         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2591         widget = GHB_WIDGET (ud->builder, "scale_height");
2592         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
2593         if (autocrop)
2594         {
2595                 ghb_title_info_t tinfo;
2596
2597                 if (ghb_get_title_info (&tinfo, titleindex))
2598                 {
2599                         crop[0] = tinfo.crop[0];
2600                         crop[1] = tinfo.crop[1];
2601                         crop[2] = tinfo.crop[2];
2602                         crop[3] = tinfo.crop[3];
2603                         if (noscale)
2604                         {
2605                                 gint need1, need2;
2606
2607                                 // Adjust the cropping to accomplish the desired width and height
2608                                 crop_width = tinfo.width - crop[2] - crop[3];
2609                                 crop_height = tinfo.height - crop[0] - crop[1];
2610                                 width = (crop_width >> modshift) << modshift;
2611                                 height = (crop_height >> modshift) << modshift;
2612                                 need1 = (crop_height - height) / 2;
2613                                 need2 = crop_height - height - need1;
2614                                 crop[0] += need1;
2615                                 crop[1] += need2;
2616                                 need1 = (crop_width - width) / 2;
2617                                 need2 = crop_width - width - need1;
2618                                 crop[2] += need1;
2619                                 crop[3] += need2;
2620                         }
2621                         ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(crop[0]));
2622                         ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(crop[1]));
2623                         ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(crop[2]));
2624                         ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(crop[3]));
2625                 }
2626         }
2627         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
2628         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
2629         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
2630         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
2631         hb_reduce(&aspect_n, &aspect_d, 
2632                                 title->width * title->pixel_aspect_width, 
2633                                 title->height * title->pixel_aspect_height);
2634         crop_width = title->width - crop[2] - crop[3];
2635         crop_height = title->height - crop[0] - crop[1];
2636         if (autoscale)
2637         {
2638                 width = crop_width;
2639                 height = crop_height;
2640                 max_width = 0;
2641                 max_height = 0;
2642         }
2643         else
2644         {
2645                 width = ghb_settings_get_int(ud->settings, "scale_width");
2646                 height = ghb_settings_get_int(ud->settings, "scale_height");
2647                 max_width = ghb_settings_get_int(ud->settings, "PictureWidth");
2648                 max_height = ghb_settings_get_int(ud->settings, "PictureHeight");
2649                 // Align max dims 
2650                 max_width = (max_width >> modshift) << modshift;
2651                 max_height = (max_height >> modshift) << modshift;
2652                 // Adjust dims according to max values
2653                 if (!max_height)
2654                 {
2655                         max_height = crop_height;
2656                 }
2657                 if (!max_width)
2658                 {
2659                         max_width = crop_width;
2660                 }
2661                 height = MIN(height, max_height);
2662                 width = MIN(width, max_width);
2663                 g_debug("max_width %d, max_height %d\n", max_width, max_height);
2664         }
2665         if (width < 16)
2666                 width = title->width - crop[2] - crop[3];
2667         if (height < 16)
2668                 height = title->height - crop[0] - crop[1];
2669
2670         if (anamorphic)
2671         {
2672                 job->anamorphic.mode = autoscale ? 2 : 3;
2673                 // The scaler crashes if the dimensions are not divisible by 2
2674                 // Align mod 2.  And so does something in x264_encoder_headers()
2675                 job->anamorphic.modulus = round_dims ? 16 : 2;
2676                 job->width = width;
2677                 job->height = height;
2678                 if (max_height) 
2679                         job->maxHeight = max_height;
2680                 job->crop[0] = crop[0]; job->crop[1] = crop[1];
2681                 job->crop[2] = crop[2]; job->crop[3] = crop[3];
2682                 hb_set_anamorphic_size( job, &width, &height, 
2683                                                                 &par_width, &par_height );
2684         }
2685         else 
2686         {
2687                 job->anamorphic.mode = 0;
2688                 if (keep_aspect)
2689                 {
2690                         gdouble par;
2691                         gint new_width, new_height;
2692                         
2693                         g_debug("kw %s kh %s\n", keep_width ? "y":"n", keep_height ? "y":"n");
2694                         g_debug("w %d h %d\n", width, height);
2695                         // Compute pixel aspect ration.  
2696                         par = (gdouble)(title->height * aspect_n) / (title->width * aspect_d);
2697                         // Must scale so that par becomes 1:1
2698                         // Try to keep largest dimension
2699                         new_height = (crop_height * ((gdouble)width/crop_width) / par);
2700                         new_width = (crop_width * ((gdouble)height/crop_height) * par);
2701                         // Height and width are always multiples of 2, so do the rounding
2702                         new_height = ((new_height + 1) >> 1) << 1;
2703                         new_width = ((new_width + 1) >> 1) << 1;
2704                         if ((max_width && new_width > max_width) || 
2705                                 new_width > title->width)
2706                         {
2707                                 height = new_height;
2708                         }
2709                         else if ((max_height && new_height > max_height) || 
2710                                                 new_height > title->height)
2711                         {
2712                                 width = new_width;
2713                         }
2714                         else if (keep_width)
2715                         {
2716                                 height = new_height;
2717                         }
2718                         else if (keep_height)
2719                         {
2720                                 width = new_width;
2721                         }
2722                         else if (width > new_width)
2723                         {
2724                                 height = new_height;
2725                         }
2726                         else
2727                         {
2728                                 width = new_width;
2729                         }
2730                         g_debug("new w %d h %d\n", width, height);
2731                 }
2732                 width = ((width + modround) >> modshift) << modshift;
2733                 height = ((height + modround) >> modshift) << modshift;
2734         }
2735         ghb_ui_update(ud, "scale_width", ghb_int64_value(width));
2736         ghb_ui_update(ud, "scale_height", ghb_int64_value(height));
2737 }
2738
2739 static void
2740 set_preview_job_settings(hb_job_t *job, GValue *settings)
2741 {
2742         job->crop[0] = ghb_settings_get_int(settings, "PictureTopCrop");
2743         job->crop[1] = ghb_settings_get_int(settings, "PictureBottomCrop");
2744         job->crop[2] = ghb_settings_get_int(settings, "PictureLeftCrop");
2745         job->crop[3] = ghb_settings_get_int(settings, "PictureRightCrop");
2746
2747         gboolean anamorphic, round_dimensions, autoscale;
2748         autoscale = ghb_settings_get_boolean(settings, "autoscale");
2749         anamorphic = ghb_settings_get_boolean(settings, "anamorphic");
2750         round_dimensions = ghb_settings_get_boolean(settings, "ModDimensions");
2751         if (anamorphic)
2752         {
2753                 job->anamorphic.modulus = round_dimensions ? 16 : 2;
2754                 job->anamorphic.mode = autoscale ? 2 : 3;
2755         }
2756         else
2757         {
2758                 job->anamorphic.modulus = 2;
2759                 job->anamorphic.mode = 0;
2760         }
2761         job->width = ghb_settings_get_int(settings, "scale_width");
2762         job->height = ghb_settings_get_int(settings, "scale_height");
2763         gint deint = ghb_settings_combo_int(settings, "PictureDeinterlace");
2764         gint decomb = ghb_settings_combo_int(settings, "PictureDecomb");
2765         job->deinterlace = (!decomb && deint == 0) ? 0 : 1;
2766 }
2767
2768 gint
2769 ghb_calculate_target_bitrate(GValue *settings, gint titleindex)
2770 {
2771         hb_list_t  * list;
2772         hb_title_t * title;
2773         hb_job_t   * job;
2774         gint size;
2775
2776         if (h_scan == NULL) return 1500;
2777         list = hb_get_titles( h_scan );
2778     title = hb_list_item( list, titleindex );
2779         if (title == NULL) return 1500;
2780         job   = title->job;
2781         if (job == NULL) return 1500;
2782         size = ghb_settings_get_int(settings, "VideoTargetSize");
2783         return hb_calc_bitrate( job, size );
2784 }
2785
2786 gboolean
2787 ghb_validate_filter_string(const gchar *str, gint max_fields)
2788 {
2789         gint fields = 0;
2790         gchar *end;
2791         gdouble val;
2792
2793         if (str == NULL || *str == 0) return TRUE;
2794         while (*str)
2795         {
2796                 val = g_strtod(str, &end);
2797                 if (str != end)
2798                 { // Found a numeric value
2799                         fields++;
2800                         // negative max_fields means infinate
2801                         if (max_fields >= 0 && fields > max_fields) return FALSE;
2802                         if (*end == 0)
2803                                 return TRUE;
2804                         if (*end != ':')
2805                                 return FALSE;
2806                         str = end + 1;
2807                 }
2808                 else
2809                         return FALSE;
2810         }
2811         return FALSE;
2812 }
2813
2814 gboolean
2815 ghb_validate_filters(signal_user_data_t *ud)
2816 {
2817         gchar *str;
2818         gint index;
2819         gchar *message;
2820
2821         // deinte 4
2822         index = ghb_settings_combo_int(ud->settings, "PictureDeinterlace");
2823         if (index == 1)
2824         {
2825                 str = ghb_settings_get_string(ud->settings, "PictureDeinterlaceCustom");
2826                 if (!ghb_validate_filter_string(str, 4))
2827                 {
2828                         message = g_strdup_printf(
2829                                                 "Invalid Deinterlace Settings:\n\n%s\n",
2830                                                 str);
2831                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2832                         g_free(message);
2833                         g_free(str);
2834                         return FALSE;
2835                 }
2836                 g_free(str);
2837         }
2838         // detel
2839         index = ghb_settings_combo_int(ud->settings, "PictureDetelecine");
2840         if (index == 1)
2841         {
2842                 str = ghb_settings_get_string(ud->settings, "PictureDetelecineCustom");
2843                 if (!ghb_validate_filter_string(str, 6))
2844                 {
2845                         message = g_strdup_printf(
2846                                                 "Invalid Detelecine Settings:\n\n%s\n",
2847                                                 str);
2848                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2849                         g_free(message);
2850                         g_free(str);
2851                         return FALSE;
2852                 }
2853                 g_free(str);
2854         }
2855         // decomb 4
2856         index = ghb_settings_combo_int(ud->settings, "PictureDecomb");
2857         if (index == 1)
2858         {
2859                 str = ghb_settings_get_string(ud->settings, "PictureDecombCustom");
2860                 if (!ghb_validate_filter_string(str, 7))
2861                 {
2862                         message = g_strdup_printf(
2863                                                 "Invalid Decomb Settings:\n\n%s\n",
2864                                                 str);
2865                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2866                         g_free(message);
2867                         g_free(str);
2868                         return FALSE;
2869                 }
2870                 g_free(str);
2871         }
2872         // denois 4
2873         index = ghb_settings_combo_int(ud->settings, "PictureDenoise");
2874         if (index == 1)
2875         {
2876                 str = ghb_settings_get_string(ud->settings, "PictureDenoiseCustom");
2877                 if (!ghb_validate_filter_string(str, 4))
2878                 {
2879                         message = g_strdup_printf(
2880                                                 "Invalid Denoise Settings:\n\n%s\n",
2881                                                 str);
2882                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
2883                         g_free(str);
2884                         g_free(message);
2885                         return FALSE;
2886                 }
2887                 g_free(str);
2888         }
2889         return TRUE;
2890 }
2891
2892 gboolean
2893 ghb_validate_video(signal_user_data_t *ud)
2894 {
2895         gint vcodec, mux;
2896         gchar *message;
2897
2898         mux = ghb_settings_combo_int(ud->settings, "FileFormat");
2899         vcodec = ghb_settings_combo_int(ud->settings, "VideoEncoder");
2900         if ((mux == HB_MUX_MP4 || mux == HB_MUX_AVI) && 
2901                 (vcodec == HB_VCODEC_THEORA))
2902         {
2903                 // mp4|avi/theora combination is not supported.
2904                 message = g_strdup_printf(
2905                                         "Theora is not supported in the MP4 and AVI containers.\n\n"
2906                                         "You should choose a different video codec or container.\n"
2907                                         "If you continue, XviD will be chosen for you.");
2908                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2909                 {
2910                         g_free(message);
2911                         return FALSE;
2912                 }
2913                 g_free(message);
2914                 vcodec = HB_VCODEC_XVID;
2915                 ghb_ui_update(ud, "VideoEncoder", ghb_int64_value(vcodec));
2916         }
2917         return TRUE;
2918 }
2919
2920 gboolean
2921 ghb_validate_audio(signal_user_data_t *ud)
2922 {
2923         hb_list_t  * list;
2924         hb_title_t * title;
2925         gchar *message;
2926         GValue *value;
2927
2928         if (h_scan == NULL) return FALSE;
2929         list = hb_get_titles( h_scan );
2930         if( !hb_list_count( list ) )
2931         {
2932                 /* No valid title, stop right there */
2933                 g_message("No title found.\n");
2934                 return FALSE;
2935         }
2936
2937         gint titleindex;
2938
2939         titleindex = ghb_settings_combo_int(ud->settings, "title");
2940     title = hb_list_item( list, titleindex );
2941         if (title == NULL) return FALSE;
2942         gint mux = ghb_settings_combo_int(ud->settings, "FileFormat");
2943
2944         const GValue *audio_list;
2945         gint count, ii;
2946
2947         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
2948         count = ghb_array_len(audio_list);
2949         for (ii = 0; ii < count; ii++)
2950         {
2951                 GValue *asettings;
2952             hb_audio_config_t *taudio;
2953
2954                 asettings = ghb_array_get_nth(audio_list, ii);
2955                 gint track = ghb_settings_combo_int(asettings, "AudioTrack");
2956                 gint codec = ghb_settings_combo_int(asettings, "AudioEncoder");
2957         taudio = (hb_audio_config_t *) hb_list_audio_config_item(
2958                                                                                         title->list_audio, track );
2959                 if ((taudio->in.codec != HB_ACODEC_AC3 && codec == HB_ACODEC_AC3) ||
2960                     (taudio->in.codec != HB_ACODEC_DCA && codec == HB_ACODEC_DCA))
2961                 {
2962                         // Not supported.  AC3 is passthrough only, so input must be AC3
2963                         char *str;
2964                         str = (codec == HB_ACODEC_AC3) ? "AC-3" : "DTS";
2965                         message = g_strdup_printf(
2966                                                 "The source does not support %s Pass-Thru.\n\n"
2967                                                 "You should choose a different audio codec.\n"
2968                                                 "If you continue, one will be chosen for you.", str);
2969                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2970                         {
2971                                 g_free(message);
2972                                 return FALSE;
2973                         }
2974                         g_free(message);
2975                         if (mux == HB_MUX_AVI)
2976                         {
2977                                 codec = HB_ACODEC_LAME;
2978                         }
2979                         else
2980                         {
2981                                 codec = HB_ACODEC_FAAC;
2982                         }
2983                         value = get_acodec_value(codec);
2984                         ghb_settings_take_value(asettings, "AudioEncoder", value);
2985                 }
2986                 gchar *a_unsup = NULL;
2987                 gchar *mux_s = NULL;
2988                 if (mux == HB_MUX_MP4)
2989                 { 
2990                         mux_s = "MP4";
2991                         // mp4/mp3|vorbis combination is not supported.
2992                         if (codec == HB_ACODEC_LAME)
2993                         {
2994                                 a_unsup = "MP3";
2995                                 codec = HB_ACODEC_FAAC;
2996                         }
2997                         if (codec == HB_ACODEC_VORBIS)
2998                         {
2999                                 a_unsup = "Vorbis";
3000                                 codec = HB_ACODEC_FAAC;
3001                         }
3002                 }
3003                 else if (mux == HB_MUX_AVI)
3004                 {
3005                         mux_s = "AVI";
3006                         // avi/faac|vorbis combination is not supported.
3007                         if (codec == HB_ACODEC_FAAC)
3008                         {
3009                                 a_unsup = "FAAC";
3010                                 codec = HB_ACODEC_LAME;
3011                         }
3012                         if (codec == HB_ACODEC_VORBIS)
3013                         {
3014                                 a_unsup = "Vorbis";
3015                                 codec = HB_ACODEC_LAME;
3016                         }
3017                 }
3018                 else if (mux == HB_MUX_OGM)
3019                 {
3020                         mux_s = "OGM";
3021                         // avi/faac|vorbis combination is not supported.
3022                         if (codec == HB_ACODEC_FAAC)
3023                         {
3024                                 a_unsup = "FAAC";
3025                                 codec = HB_ACODEC_VORBIS;
3026                         }
3027                         if (codec == HB_ACODEC_AC3)
3028                         {
3029                                 a_unsup = "AC-3";
3030                                 codec = HB_ACODEC_VORBIS;
3031                         }
3032                         if (codec == HB_ACODEC_DCA)
3033                         {
3034                                 a_unsup = "DTS";
3035                                 codec = HB_ACODEC_VORBIS;
3036                         }
3037                 }
3038                 if (a_unsup)
3039                 {
3040                         message = g_strdup_printf(
3041                                                 "%s is not supported in the %s container.\n\n"
3042                                                 "You should choose a different audio codec.\n"
3043                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
3044                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3045                         {
3046                                 g_free(message);
3047                                 return FALSE;
3048                         }
3049                         g_free(message);
3050                         value = get_acodec_value(codec);
3051                         ghb_settings_take_value(asettings, "AudioEncoder", value);
3052                 }
3053                 gint mix = ghb_settings_combo_int (asettings, "AudioMixdown");
3054                 gboolean allow_mono = TRUE;
3055                 gboolean allow_stereo = TRUE;
3056                 gboolean allow_dolby = TRUE;
3057                 gboolean allow_dpl2 = TRUE;
3058                 gboolean allow_6ch = TRUE;
3059                 allow_mono =
3060                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3061                         (codec != HB_ACODEC_LAME);
3062                 gint layout = taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
3063                 allow_stereo =
3064                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
3065                 allow_dolby =
3066                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
3067                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
3068                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
3069                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
3070                 allow_6ch =
3071                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3072                         (codec != HB_ACODEC_LAME) &&
3073                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
3074                         (taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
3075
3076                 gchar *mix_unsup = NULL;
3077                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
3078                 {
3079                         mix_unsup = "mono";
3080                 }
3081                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
3082                 {
3083                         mix_unsup = "stereo";
3084                 }
3085                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
3086                 {
3087                         mix_unsup = "Dolby";
3088                 }
3089                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
3090                 {
3091                         mix_unsup = "Dolby Pro Logic II";
3092                 }
3093                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
3094                 {
3095                         mix_unsup = "6 Channel";
3096                 }
3097                 if (mix_unsup)
3098                 {
3099                         message = g_strdup_printf(
3100                                                 "The source audio does not support %s mixdown.\n\n"
3101                                                 "You should choose a different mixdown.\n"
3102                                                 "If you continue, one will be chosen for you.", mix_unsup);
3103                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
3104                         {
3105                                 g_free(message);
3106                                 return FALSE;
3107                         }
3108                         g_free(message);
3109                         mix = ghb_get_best_mix(titleindex, track, codec, mix);
3110                         value = get_amix_value(mix);
3111                         ghb_settings_take_value(asettings, "AudioMixdown", value);
3112                 }
3113         }
3114         return TRUE;
3115 }
3116
3117 gboolean
3118 ghb_validate_vquality(GValue *settings)
3119 {
3120         gint vcodec;
3121         gchar *message;
3122         gint min, max;
3123
3124         if (ghb_settings_get_boolean(settings, "nocheckvquality")) return TRUE;
3125         vcodec = ghb_settings_combo_int(settings, "VideoEncoder");
3126         gdouble vquality;
3127         vquality = ghb_settings_get_double(settings, "VideoQualitySlider");
3128         if (ghb_settings_get_boolean(settings, "vquality_type_constant"))
3129         {
3130                 switch (vcodec)
3131                 {
3132                         case HB_VCODEC_X264:
3133                         {
3134                                 min = 16;
3135                                 max = 30;
3136                         } break;
3137
3138                         case HB_VCODEC_XVID:
3139                         case HB_VCODEC_FFMPEG:
3140                         {
3141                                 min = 1;
3142                                 max = 8;
3143                         } break;
3144
3145                         case HB_VCODEC_THEORA:
3146                         {
3147                                 min = 0;
3148                                 max = 63;
3149                         } break;
3150
3151                         default:
3152                         {
3153                                 min = 48;
3154                                 max = 62;
3155                         } break;
3156                 }
3157                 if (vquality < min || vquality > max)
3158                 {
3159                         message = g_strdup_printf(
3160                                                 "Interesting video quality choise: %d\n\n"
3161                                                 "Typical values range from %d to %d.\n"
3162                                                 "Are you sure you wish to use this setting?",
3163                                                 (gint)vquality, min, max);
3164                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
3165                                                                         "Cancel", "Continue"))
3166                         {
3167                                 g_free(message);
3168                                 return FALSE;
3169                         }
3170                         g_free(message);
3171                 }
3172         }
3173         return TRUE;
3174 }
3175
3176 static void
3177 add_job(hb_handle_t *h, GValue *js, gint unique_id, gint titleindex)
3178 {
3179         hb_list_t  * list;
3180         hb_title_t * title;
3181         hb_job_t   * job;
3182         static gchar *x264opts;
3183         gint sub_id = 0;
3184         gboolean tweaks = FALSE;
3185         gchar *detel_str = NULL;
3186         gchar *decomb_str = NULL;
3187         gchar *deint_str = NULL;
3188         gchar *deblock_str = NULL;
3189         gchar *denoise_str = NULL;
3190         gchar *dest_str = NULL;
3191
3192         g_debug("add_job()\n");
3193         if (h == NULL) return;
3194         list = hb_get_titles( h );
3195         if( !hb_list_count( list ) )
3196         {
3197                 /* No valid title, stop right there */
3198                 return;
3199         }
3200
3201     title = hb_list_item( list, titleindex );
3202         if (title == NULL) return;
3203
3204         /* Set job settings */
3205         job   = title->job;
3206         if (job == NULL) return;
3207
3208         job->start_at_preview = ghb_settings_get_int(js, "start_frame") + 1;
3209         if (job->start_at_preview)
3210         {
3211                 job->seek_points = ghb_settings_get_int(js, "preview_count");
3212                 job->pts_to_stop = ghb_settings_get_int(js, "live_duration") * 90000LL;
3213         }
3214
3215         tweaks = ghb_settings_get_boolean(js, "allow_tweaks");
3216         job->mux = ghb_settings_combo_int(js, "FileFormat");
3217         if (job->mux == HB_MUX_MP4)
3218         {
3219                 job->largeFileSize = ghb_settings_get_boolean(js, "Mp4LargeFile");
3220                 job->mp4_optimize = ghb_settings_get_boolean(js, "Mp4HttpOptimize");
3221         }
3222         else
3223         {
3224                 job->largeFileSize = FALSE;
3225                 job->mp4_optimize = FALSE;
3226         }
3227         if (!job->start_at_preview)
3228         {
3229                 gint chapter_start, chapter_end;
3230                 chapter_start = ghb_settings_get_int(js, "start_chapter");
3231                 chapter_end = ghb_settings_get_int(js, "end_chapter");
3232                 gint num_chapters = hb_list_count(title->list_chapter);
3233                 job->chapter_start = MIN( num_chapters, chapter_start );
3234                 job->chapter_end   = MAX( job->chapter_start, chapter_end );
3235
3236                 job->chapter_markers = ghb_settings_get_boolean(js, "ChapterMarkers");
3237                 if ( job->chapter_markers )
3238                 {
3239                         GValue *chapters;
3240                         GValue *chapter;
3241                         gint chap;
3242                         gint count;
3243                 
3244                         chapters = ghb_settings_get_value(js, "chapter_list");
3245                         count = ghb_array_len(chapters);
3246                         for(chap = chapter_start; chap <= chapter_end; chap++)
3247                         {
3248                                 hb_chapter_t * chapter_s;
3249                                 gchar *name;
3250                                 
3251                                 name = NULL;
3252                                 if (chap-1 < count)
3253                                 {
3254                                         chapter = ghb_array_get_nth(chapters, chap-1);
3255                                         name = ghb_value_string(chapter); 
3256                                 }
3257                                 if (name == NULL)
3258                                 {
3259                                         name = g_strdup_printf ("Chapter %2d", chap);
3260                                 }
3261                                 chapter_s = hb_list_item( job->title->list_chapter, chap - 1);
3262                                 strncpy(chapter_s->title, name, 1023);
3263                                 chapter_s->title[1023] = '\0';
3264                                 g_free(name);
3265                         }
3266                 }
3267         }
3268         job->crop[0] = ghb_settings_get_int(js, "PictureTopCrop");
3269         job->crop[1] = ghb_settings_get_int(js, "PictureBottomCrop");
3270         job->crop[2] = ghb_settings_get_int(js, "PictureLeftCrop");
3271         job->crop[3] = ghb_settings_get_int(js, "PictureRightCrop");
3272
3273         
3274         gint decomb = ghb_settings_combo_int(js, "PictureDecomb");
3275         gint deint = ghb_settings_combo_int(js, "PictureDeinterlace");
3276         if (!decomb)
3277                 job->deinterlace = (deint != 0) ? 1 : 0;
3278         else
3279                 job->deinterlace = 0;
3280     job->grayscale   = ghb_settings_get_boolean(js, "VideoGrayScale");
3281
3282         gboolean autoscale = ghb_settings_get_boolean(js, "autoscale");
3283         gboolean anamorphic = ghb_settings_get_boolean(js, "anamorphic");
3284         gboolean round_dimensions = ghb_settings_get_boolean(js, "ModDimensions");
3285         if (anamorphic)
3286         {
3287                 job->anamorphic.mode = autoscale ? 2 : 3;
3288                 // Also, x264 requires things to be divisible by 2.
3289                 job->anamorphic.modulus = round_dimensions ? 16 : 2;
3290         }
3291         else
3292         {
3293                 job->anamorphic.mode = 0;
3294                 job->anamorphic.modulus = 2;
3295         }
3296         /* Add selected filters */
3297         job->filters = hb_list_init();
3298         gint vrate = ghb_settings_combo_int(js, "VideoFramerate");
3299         if( vrate == 0 && ghb_settings_combo_int(js, "PictureDetelecine" ) )
3300                 job->vfr = 1;
3301         else
3302                 job->vfr = 0;
3303
3304         gint detel = ghb_settings_combo_int(js, "PictureDetelecine");
3305         if ( detel )
3306         {
3307                 if (detel != 1)
3308                 {
3309                         if (detel_opts.map[detel].svalue != NULL)
3310                                 detel_str = g_strdup(detel_opts.map[detel].svalue);
3311                 }
3312                 else
3313                         detel_str = ghb_settings_get_string(js, "PictureDetelecineCustom");
3314                 hb_filter_detelecine.settings = detel_str;
3315                 hb_list_add( job->filters, &hb_filter_detelecine );
3316         }
3317         if ( decomb )
3318         {
3319                 if (decomb != 1)
3320                 {
3321                         if (decomb_opts.map[decomb].svalue != NULL)
3322                                 decomb_str = g_strdup(decomb_opts.map[decomb].svalue);
3323                 }
3324                 else
3325                         decomb_str = ghb_settings_get_string(js, "PictureDecombCustom");
3326                 hb_filter_decomb.settings = decomb_str;
3327                 hb_list_add( job->filters, &hb_filter_decomb );
3328         }
3329         if( job->deinterlace )
3330         {
3331                 if (deint != 1)
3332                 {
3333                         if (deint_opts.map[deint].svalue != NULL)
3334                                 deint_str = g_strdup(deint_opts.map[deint].svalue);
3335                 }
3336                 else
3337                         deint_str = ghb_settings_get_string(js, "PictureDeinterlaceCustom");
3338                 hb_filter_deinterlace.settings = deint_str;
3339                 hb_list_add( job->filters, &hb_filter_deinterlace );
3340         }
3341         gint deblock = ghb_settings_get_int(js, "PictureDeblock");
3342         if( deblock >= 5 )
3343         {
3344                 deblock_str = g_strdup_printf("%d", deblock);
3345                 hb_filter_deblock.settings = deblock_str;
3346                 hb_list_add( job->filters, &hb_filter_deblock );
3347         }
3348         gint denoise = ghb_settings_combo_int(js, "PictureDenoise");
3349         if( denoise )
3350         {
3351                 if (denoise != 1)
3352                 {
3353                         if (denoise_opts.map[denoise].svalue != NULL)
3354                                 denoise_str = g_strdup(denoise_opts.map[denoise].svalue);
3355                 }
3356                 else
3357                         denoise_str = ghb_settings_get_string(js, "PictureDenoiseCustom");
3358                 hb_filter_denoise.settings = denoise_str;
3359                 hb_list_add( job->filters, &hb_filter_denoise );
3360         }
3361         job->width = ghb_settings_get_int(js, "scale_width");
3362         job->height = ghb_settings_get_int(js, "scale_height");
3363
3364         job->vcodec = ghb_settings_combo_int(js, "VideoEncoder");
3365         if ((job->mux == HB_MUX_MP4 || job->mux == HB_MUX_AVI) && 
3366                 (job->vcodec == HB_VCODEC_THEORA))
3367         {
3368                 // mp4|avi/theora combination is not supported.
3369                 job->vcodec = HB_VCODEC_XVID;
3370         }
3371         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
3372         {
3373                 job->ipod_atom = ghb_settings_get_boolean(js, "Mp4iPodCompatible");
3374         }
3375         if (ghb_settings_get_boolean(js, "vquality_type_constant"))
3376         {
3377                 gdouble vquality;
3378                 vquality = ghb_settings_get_double(js, "VideoQualitySlider");
3379                 job->vquality =  vquality;
3380                 job->vbitrate = 0;
3381         }
3382         else if (ghb_settings_get_boolean(js, "vquality_type_bitrate"))
3383         {
3384                 job->vquality = -1.0;
3385                 job->vbitrate = ghb_settings_get_int(js, "VideoAvgBitrate");
3386         }
3387         // AVI container does not support variable frame rate.
3388         if (job->mux == HB_MUX_AVI)
3389         {
3390                 job->vfr = FALSE;
3391                 job->cfr = 1;
3392         }
3393
3394         if( vrate == 0 )
3395         {
3396                 job->vrate = title->rate;
3397                 job->vrate_base = title->rate_base;
3398                 job->cfr = 0;
3399         }
3400         else
3401         {
3402                 job->vrate = 27000000;
3403                 job->vrate_base = vrate;
3404                 job->cfr = 1;
3405         }
3406         // First remove any audios that are already in the list
3407         // This happens if you are encoding the same title a second time.
3408         gint num_audio_tracks = hb_list_count(job->list_audio);
3409         gint ii;
3410     for(ii = 0; ii < num_audio_tracks; ii++)
3411     {
3412         hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
3413         hb_list_rem(job->list_audio, audio);
3414     }
3415
3416         const GValue *audio_list;
3417         gint count;
3418         gint tcount = 0;
3419         
3420         audio_list = ghb_settings_get_value(js, "audio_list");
3421         count = ghb_array_len(audio_list);
3422         for (ii = 0; ii < count; ii++)
3423         {
3424                 GValue *asettings;
3425             hb_audio_config_t audio;
3426             hb_audio_config_t *taudio;
3427
3428                 hb_audio_config_init(&audio);
3429                 asettings = ghb_array_get_nth(audio_list, ii);
3430                 audio.in.track = ghb_settings_get_int(asettings, "AudioTrack");
3431                 audio.out.track = tcount;
3432                 audio.out.codec = ghb_settings_combo_int(asettings, "AudioEncoder");
3433         taudio = (hb_audio_config_t *) hb_list_audio_config_item(
3434                                                                         title->list_audio, audio.in.track );
3435                 if ((taudio->in.codec != HB_ACODEC_AC3 && 
3436              audio.out.codec == HB_ACODEC_AC3) ||
3437                     (taudio->in.codec != HB_ACODEC_DCA && 
3438                          audio.out.codec == HB_ACODEC_DCA))
3439                 {
3440                         // Not supported.  AC3 is passthrough only, so input must be AC3
3441                         if (job->mux == HB_MUX_AVI)
3442                         {
3443                                 audio.out.codec = HB_ACODEC_LAME;
3444                         }
3445                         else
3446                         {
3447                                 audio.out.codec = HB_ACODEC_FAAC;
3448                         }
3449                 }
3450                 if ((job->mux == HB_MUX_MP4) && 
3451                         ((audio.out.codec == HB_ACODEC_LAME) ||
3452                         (audio.out.codec == HB_ACODEC_VORBIS)))
3453                 {
3454                         // mp4/mp3|vorbis combination is not supported.
3455                         audio.out.codec = HB_ACODEC_FAAC;
3456                 }
3457                 if ((job->mux == HB_MUX_AVI) && 
3458                         ((audio.out.codec == HB_ACODEC_FAAC) ||
3459                         (audio.out.codec == HB_ACODEC_VORBIS)))
3460                 {
3461                         // avi/faac|vorbis combination is not supported.
3462                         audio.out.codec = HB_ACODEC_LAME;
3463                 }
3464                 if ((job->mux == HB_MUX_OGM) && 
3465                         ((audio.out.codec == HB_ACODEC_FAAC) ||
3466                         (audio.out.codec == HB_ACODEC_AC3) ||
3467                         (audio.out.codec == HB_ACODEC_DCA)))
3468                 {
3469                         // ogm/faac|ac3 combination is not supported.
3470                         audio.out.codec = HB_ACODEC_VORBIS;
3471                 }
3472         audio.out.dynamic_range_compression = 
3473                         ghb_settings_get_double(asettings, "AudioTrackDRCSlider");
3474                 // It would be better if this were done in libhb for us, but its not yet.
3475                 if (audio.out.codec == HB_ACODEC_AC3 || audio.out.codec == HB_ACODEC_DCA)
3476                 {
3477                         audio.out.mixdown = 0;
3478                 }
3479                 else
3480                 {
3481                         audio.out.mixdown = ghb_settings_combo_int(asettings, "AudioMixdown");
3482                         // Make sure the mixdown is valid and pick a new one if not.
3483                         audio.out.mixdown = ghb_get_best_mix(titleindex, 
3484                                 audio.in.track, audio.out.codec, audio.out.mixdown);
3485                         audio.out.bitrate = 
3486                                 ghb_settings_combo_int(asettings, "AudioBitrate");
3487                         gint srate = ghb_settings_combo_int(asettings, "AudioSamplerate");
3488                         if (srate == 0) // 0 is same as source
3489                                 audio.out.samplerate = taudio->in.samplerate;
3490                         else
3491                                 audio.out.samplerate = srate;
3492                 }
3493
3494                 // Add it to the jobs audio list
3495         hb_audio_add( job, &audio );
3496                 tcount++;
3497         }
3498         // I was tempted to move this up with the reset of the video quality
3499         // settings, but I suspect the settings above need to be made
3500         // first in order for hb_calc_bitrate to be accurate.
3501         if (ghb_settings_get_boolean(js, "vquality_type_target"))
3502         {
3503                 gint size;
3504                 
3505                 size = ghb_settings_get_int(js, "VideoTargetSize");
3506         job->vbitrate = hb_calc_bitrate( job, size );
3507                 job->vquality = -1.0;
3508         }
3509
3510         dest_str = ghb_settings_get_string(js, "destination");
3511         job->file = dest_str;
3512         job->crf = ghb_settings_get_boolean(js, "constant_rate_factor");
3513         // TODO: libhb holds onto a reference to the x264opts and is not
3514         // finished with it until encoding the job is done.  But I can't
3515         // find a way to get at the job before it is removed in order to
3516         // free up the memory I am allocating here.
3517         // The short story is THIS LEAKS.
3518         x264opts = ghb_build_x264opts_string(js);
3519         
3520         if( x264opts != NULL && *x264opts != '\0' )
3521         {
3522                 job->x264opts = x264opts;
3523         }
3524         else /*avoids a bus error crash when options aren't specified*/
3525         {
3526                 job->x264opts =  NULL;
3527         }
3528         gint subtitle;
3529         gchar *slang = ghb_settings_get_string(js, "Subtitles");
3530         subtitle = -2; // default to none
3531         if (strcmp(slang, "auto") == 0)
3532         {
3533                 subtitle = -1;
3534         }
3535         else
3536         {
3537                 gint scount;
3538         hb_subtitle_t * subt;
3539
3540                 scount = hb_list_count(title->list_subtitle);
3541                 for (ii = 0; ii < scount; ii++)
3542                 {
3543                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, ii);
3544                         if (strcmp(slang, subt->iso639_2) == 0)
3545                         {
3546                                 subtitle = ii;
3547                                 break;
3548                         }
3549                 }
3550         }
3551         gboolean forced_subtitles = ghb_settings_get_boolean(js, "SubtitlesForced");
3552         job->subtitle_force = forced_subtitles;
3553         if (subtitle >= 0)
3554                 job->subtitle = subtitle;
3555         else
3556                 job->subtitle = -1;
3557         if (subtitle == -1)
3558         {
3559                 // Subtitle scan. Look for subtitle matching audio language
3560                 char *x264opts_tmp;
3561
3562                 /*
3563                  * When subtitle scan is enabled do a fast pre-scan job
3564                  * which will determine which subtitles to enable, if any.
3565                  */
3566                 job->pass = -1;
3567                 job->indepth_scan = 1;
3568
3569                 x264opts_tmp = job->x264opts;
3570                 job->x264opts = NULL;
3571
3572                 job->select_subtitle = malloc(sizeof(hb_subtitle_t*));
3573                 *(job->select_subtitle) = NULL;
3574
3575                 /*
3576                  * Add the pre-scan job
3577                  */
3578                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3579                 hb_add( h, job );
3580                 //if (job->x264opts != NULL)
3581                 //      g_free(job->x264opts);
3582
3583                 job->x264opts = x264opts_tmp;
3584         }
3585         else
3586         {
3587                 job->select_subtitle = NULL;
3588         }
3589         if( ghb_settings_get_boolean(js, "VideoTwoPass") &&
3590                 !ghb_settings_get_boolean(js, "vquality_type_constant"))
3591         {
3592                 /*
3593                  * If subtitle_scan is enabled then only turn it on
3594                  * for the second pass and then off again for the
3595                  * second.
3596                  */
3597                 hb_subtitle_t **subtitle_tmp = job->select_subtitle;
3598                 job->select_subtitle = NULL;
3599                 job->pass = 1;
3600                 job->indepth_scan = 0;
3601                 gchar *x264opts2 = NULL;
3602                 if (x264opts)
3603                 {
3604                         x264opts2 = g_strdup(x264opts);
3605                 }
3606                 /*
3607                  * If turbo options have been selected then append them
3608                  * to the x264opts now (size includes one ':' and the '\0')
3609                  */
3610                 if( ghb_settings_get_boolean(js, "VideoTurboTwoPass") )
3611                 {
3612                         char *tmp_x264opts;
3613
3614                         if ( x264opts )
3615                         {
3616                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, turbo_opts);
3617                                 g_free(x264opts);
3618                         } 
3619                         else 
3620                         {
3621                                 /*
3622                                  * No x264opts to modify, but apply the turbo options
3623                                  * anyway as they may be modifying defaults
3624                                  */
3625                                 tmp_x264opts = g_strdup_printf("%s", turbo_opts);
3626                         }
3627                         x264opts = tmp_x264opts;
3628
3629                         job->x264opts = x264opts;
3630                 }
3631                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3632                 hb_add( h, job );
3633                 //if (job->x264opts != NULL)
3634                 //      g_free(job->x264opts);
3635
3636                 job->select_subtitle = subtitle_tmp;
3637                 job->pass = 2;
3638                 /*
3639                  * On the second pass we turn off subtitle scan so that we
3640                  * can actually encode using any subtitles that were auto
3641                  * selected in the first pass (using the whacky select-subtitle
3642                  * attribute of the job).
3643                  */
3644                 job->indepth_scan = 0;
3645                 job->x264opts = x264opts2;
3646                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3647                 hb_add( h, job );
3648                 //if (job->x264opts != NULL)
3649                 //      g_free(job->x264opts);
3650         }
3651         else
3652         {
3653                 job->indepth_scan = 0;
3654                 job->pass = 0;
3655                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
3656                 hb_add( h, job );
3657                 //if (job->x264opts != NULL)
3658                 //      g_free(job->x264opts);
3659         }
3660         if (detel_str) g_free(detel_str);
3661         if (decomb_str) g_free(decomb_str);
3662         if (deint_str) g_free(deint_str);
3663         if (deblock_str) g_free(deblock_str);
3664         if (denoise_str) g_free(denoise_str);
3665         if (dest_str) g_free(dest_str);
3666 }
3667
3668 void
3669 ghb_add_job(GValue *js, gint unique_id)
3670 {
3671         // Since I'm doing a scan of the single title I want just prior 
3672         // to adding the job, there is only the one title to choose from.
3673         add_job(h_queue, js, unique_id, 0);
3674 }
3675
3676 void
3677 ghb_add_live_job(GValue *js, gint unique_id)
3678 {
3679         // Since I'm doing a scan of the single title I want just prior 
3680         // to adding the job, there is only the one title to choose from.
3681         gint titleindex = ghb_settings_combo_int(js, "title");
3682         add_job(h_scan, js, unique_id, titleindex);
3683 }
3684
3685 void
3686 ghb_remove_job(gint unique_id)
3687 {
3688     hb_job_t * job;
3689     gint ii;
3690         
3691         // Multiples passes all get the same id
3692         // remove them all.
3693         // Go backwards through list, so reordering doesn't screw me.
3694         ii = hb_count(h_queue) - 1;
3695     while ((job = hb_job(h_queue, ii--)) != NULL)
3696     {
3697         if ((job->sequence_id & 0xFFFFFF) == unique_id)
3698                         hb_rem(h_queue, job);
3699     }
3700 }
3701
3702 void
3703 ghb_start_queue()
3704 {
3705         hb_start( h_queue );
3706 }
3707
3708 void
3709 ghb_stop_queue()
3710 {
3711         hb_stop( h_queue );
3712 }
3713
3714 void
3715 ghb_start_live_encode()
3716 {
3717         hb_start( h_scan );
3718 }
3719
3720 void
3721 ghb_stop_live_encode()
3722 {
3723         hb_stop( h_scan );
3724 }
3725
3726 void
3727 ghb_pause_queue()
3728 {
3729     hb_state_t s;
3730     hb_get_state2( h_queue, &s );
3731
3732     if( s.state == HB_STATE_PAUSED )
3733     {
3734         hb_resume( h_queue );
3735     }
3736     else
3737     {
3738         hb_pause( h_queue );
3739     }
3740 }
3741
3742 #define RED_HEIGHT      720.0
3743 #define RED_WIDTH       1280.0
3744
3745 GdkPixbuf*
3746 ghb_get_preview_image(
3747         gint titleindex, 
3748         gint index, 
3749         signal_user_data_t *ud,
3750         gboolean borders,
3751         gint *out_width,
3752         gint *out_height)
3753 {
3754         GValue *settings;
3755         hb_title_t *title;
3756         hb_list_t  *list;
3757         
3758         settings = ud->settings;
3759         list = hb_get_titles( h_scan );
3760         if( !hb_list_count( list ) )
3761         {
3762                 /* No valid title, stop right there */
3763                 return NULL;
3764         }
3765     title = hb_list_item( list, titleindex );
3766         if (title == NULL) return NULL;
3767         if (title->job == NULL) return NULL;
3768         set_preview_job_settings(title->job, settings);
3769
3770         // hb_get_preview can't handle sizes that are larger than the original title
3771         // dimensions
3772         if (title->job->width > title->width)
3773                 title->job->width = title->width;
3774         
3775         if (title->job->height > title->height)
3776                 title->job->height = title->height;
3777         // And also creates artifacts if the width is not a multiple of 8
3778         //title->job->width = ((title->job->width + 4) >> 3) << 3;
3779         // And the height must be a multiple of 2
3780         //title->job->height = ((title->job->height + 1) >> 1) << 1;
3781         
3782         // Make sure we have a big enough buffer to receive the image from libhb. libhb
3783         // creates images with a one-pixel border around the original content. Hence we
3784         // add 2 pixels horizontally and vertically to the buffer size.
3785         gint srcWidth = title->width + 2;
3786         gint srcHeight= title->height + 2;
3787         gint dstWidth = title->width;
3788         gint dstHeight= title->height;
3789         gint borderTop = 1;
3790         gint borderLeft = 1;
3791     if (borders)
3792     {
3793         //     |<---------- title->width ----------->|
3794         //     |   |<---- title->job->width ---->|   |
3795         //     |   |                             |   |
3796         //     .......................................
3797         //     ....+-----------------------------+....
3798         //     ....|                             |....<-- gray border
3799         //     ....|                             |....
3800         //     ....|                             |....
3801         //     ....|                             |<------- image
3802         //     ....|                             |....
3803         //     ....|                             |....
3804         //     ....|                             |....
3805         //     ....|                             |....
3806         //     ....|                             |....
3807         //     ....+-----------------------------+....
3808         //     .......................................
3809                 dstWidth = title->job->width;
3810         dstHeight = title->job->height;
3811                 borderTop = (srcHeight - dstHeight) / 2;
3812                 borderLeft = (srcWidth - dstWidth) / 2;
3813                 g_debug("boarders removed\n");
3814         }
3815
3816         g_debug("src %d x %d\n", srcWidth, srcHeight);
3817         g_debug("dst %d x %d\n", dstWidth, dstHeight);
3818         g_debug("job dim %d x %d\n", title->job->width, title->job->height);
3819         g_debug("title crop %d:%d:%d:%d\n", 
3820                         title->crop[0],
3821                         title->crop[1],
3822                         title->crop[2],
3823                         title->crop[3]);
3824         g_debug("job crop %d:%d:%d:%d\n", 
3825                         title->job->crop[0],
3826                         title->job->crop[1],
3827                         title->job->crop[2],
3828                         title->job->crop[3]);
3829         static guint8 *buffer = NULL;
3830         static gint bufferSize = 0;
3831
3832         gint newSize;
3833         newSize = srcWidth * srcHeight * 4;
3834         if( bufferSize < newSize )
3835         {
3836                 bufferSize = newSize;
3837                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
3838         }
3839         hb_get_preview( h_scan, title, index, buffer );
3840
3841         // Create an GdkPixbuf and copy the libhb image into it, converting it from
3842         // libhb's format something suitable. Along the way, we'll strip off the
3843         // border around libhb's image.
3844         
3845         // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format.
3846         // Alpha is ignored.
3847
3848         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
3849         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
3850         
3851         guint32 *src = (guint32*)buffer;
3852         guint8 *dst = pixels;
3853         src += borderTop * srcWidth;    // skip top rows in src to get to first row of dst
3854         src += borderLeft;              // skip left pixels in src to get to first pixel of dst
3855         gint ii, jj;
3856         gint channels = gdk_pixbuf_get_n_channels (preview);
3857         gint stride = gdk_pixbuf_get_rowstride (preview);
3858         guint8 *tmp;
3859         for (ii = 0; ii < dstHeight; ii++)
3860         {
3861                 tmp = dst;
3862                 for (jj = 0; jj < dstWidth; jj++)
3863                 {
3864                         tmp[0] = src[0] >> 16;
3865                         tmp[1] = src[0] >> 8;
3866                         tmp[2] = src[0] >> 0;
3867                         tmp += channels;
3868                         src++;
3869                 }
3870                 dst += stride;
3871                 src += (srcWidth - dstWidth);   // skip to next row in src
3872         }
3873         // Got it, but hb_get_preview doesn't compensate for anamorphic, so lets
3874         // scale
3875         gint width, height, par_width, par_height;
3876         gboolean anamorphic = ghb_settings_get_boolean(settings, "anamorphic");
3877         if (anamorphic)
3878         {
3879                 hb_set_anamorphic_size( title->job, &width, &height, &par_width, &par_height );
3880                 ghb_par_scale(ud, &dstWidth, &dstHeight, par_width, par_height);
3881         }
3882         else
3883         {
3884                 ghb_par_scale(ud, &dstWidth, &dstHeight, 1, 1);
3885         }
3886         *out_width = dstWidth;
3887         *out_height = dstHeight;
3888         if (ghb_settings_get_boolean(settings, "reduce_hd_preview"))
3889         {
3890                 GdkScreen *ss;
3891                 gint s_w, s_h;
3892                 gint num, den;
3893
3894                 ss = gdk_screen_get_default();
3895                 s_w = gdk_screen_get_width(ss);
3896                 s_h = gdk_screen_get_height(ss);
3897                 num = dstWidth * par_width;
3898                 den = dstHeight * par_height;
3899
3900                 if (dstWidth > s_w * 80 / 100)
3901                 {
3902                         dstWidth = s_w * 80 / 100;
3903                         dstHeight = dstWidth * den / num;
3904                 }
3905                 if (dstHeight > s_h * 80 / 100)
3906                 {
3907                         dstHeight = s_h * 80 / 100;
3908                         dstWidth = dstHeight * num / den;
3909                 }
3910         }
3911         g_debug("scaled %d x %d\n", dstWidth, dstHeight);
3912         GdkPixbuf *scaled_preview;
3913         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
3914         g_object_unref (preview);
3915         return scaled_preview;
3916 }
3917
3918 static void
3919 sanitize_volname(gchar *name)
3920 {
3921         gchar *a, *b;
3922
3923         a = b = name;
3924         while (*b)
3925         {
3926                 switch(*b)
3927                 {
3928                 case '<':
3929                         b++;
3930                         break;
3931                 case '>':
3932                         b++;
3933                         break;
3934                 default:
3935                         *a = *b;
3936                         a++; b++;
3937                         break;
3938                 }
3939         }
3940         *a = 0;
3941 }
3942
3943 gchar*
3944 ghb_dvd_volname(const gchar *device)
3945 {
3946         gchar *name;
3947         name = hb_dvd_name((gchar*)device);
3948         if (name != NULL)
3949         {
3950                 sanitize_volname(name);
3951                 return g_strdup(name);
3952         }
3953         return name;
3954 }