OSDN Git Service

4ed94d039fca44af1c65a0957ccdbde7016e7b9e
[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 "hbversion.h"
29 #include <gtk/gtk.h>
30 #include <glib/gstdio.h>
31 #include "hb-backend.h"
32 #include "settings.h"
33 #include "callbacks.h"
34
35 typedef struct
36 {
37         const gchar *option;
38         const gchar *shortOpt;
39         gint ivalue;
40         gdouble dvalue;
41         const gchar *svalue;
42 } options_map_t;
43
44 typedef struct
45 {
46         gint count;
47         options_map_t *map;
48         gint *grey_options;
49 } combo_opts_t;
50
51 static options_map_t d_container_opts[] =
52 {
53         {"MKV", "mkv", HB_MUX_MKV, 0.0, "mkv"},
54         {"MP4", "mp4", HB_MUX_MP4, 0.0, "mp4"},
55         {"M4V", "m4v", HB_MUX_MP4, 0.0, "m4v"},
56         {"AVI", "avi", HB_MUX_AVI, 0.0, "avi"},
57         {"OGM", "ogm", HB_MUX_OGM, 0.0, "ogm"},
58 };
59 combo_opts_t container_opts =
60 {
61         sizeof(d_container_opts)/sizeof(options_map_t),
62         d_container_opts
63 };
64
65 static options_map_t d_deint_opts[] =
66 {
67         {"None",   "none",   0, 0.0, ""},
68         {"Fast",   "fast",   1, 0.0, "-1:-1:-1:0:1"},
69         {"Slow",   "slow",   2, 0.0, "2:-1:-1:0:1"},
70         {"Slower", "slower", 3, 0.0, "0:-1:-1:0:1"},
71 };
72 combo_opts_t deint_opts =
73 {
74         sizeof(d_deint_opts)/sizeof(options_map_t),
75         d_deint_opts
76 };
77
78 static options_map_t d_denoise_opts[] =
79 {
80         {"None",   "none",   0, 0.0, ""},
81         {"Weak",   "weak",   1, 0.0, "2:1:2:3"},
82         {"Medium", "medium", 2, 0.0, "3:2:2:3"},
83         {"Strong", "strong", 3, 0.0, "7:7:5:5"},
84 };
85 combo_opts_t denoise_opts =
86 {
87         sizeof(d_denoise_opts)/sizeof(options_map_t),
88         d_denoise_opts
89 };
90
91 static options_map_t d_vcodec_opts[] =
92 {
93         {"H.264 (x264)",    "x264",   HB_VCODEC_X264, 0.0, ""},
94         {"MPEG-4 (XviD)",   "xvid",   HB_VCODEC_XVID, 0.0, ""},
95         {"MPEG-4 (FFMPEG)", "ffmpeg", HB_VCODEC_FFMPEG, 0.0, ""},
96         {"Theora",          "theora", HB_VCODEC_THEORA, 0.0, ""},
97 };
98 combo_opts_t vcodec_opts =
99 {
100         sizeof(d_vcodec_opts)/sizeof(options_map_t),
101         d_vcodec_opts
102 };
103
104 static options_map_t d_acodec_opts[] =
105 {
106         {"AAC (faac)",      "faac",   HB_ACODEC_FAAC, 0.0, ""},
107         {"MP3 (lame)",      "lame",   HB_ACODEC_LAME, 0.0, ""},
108         {"Vorbis",          "vorbis", HB_ACODEC_VORBIS, 0.0, ""},
109         {"AC3 (pass-thru)", "ac3",    HB_ACODEC_AC3, 0.0, ""},
110 };
111 combo_opts_t acodec_opts =
112 {
113         sizeof(d_acodec_opts)/sizeof(options_map_t),
114         d_acodec_opts
115 };
116
117 static options_map_t d_pref_acodec_opts[] =
118 {
119         {"None",            "none",   0, 0.0, ""},
120         {"AAC (faac)",      "faac",   HB_ACODEC_FAAC, 0.0, ""},
121         {"MP3 (lame)",      "lame",   HB_ACODEC_LAME, 0.0, ""},
122         {"Vorbis",          "vorbis", HB_ACODEC_VORBIS, 0.0, ""},
123         {"AC3 (pass-thru)", "ac3",    HB_ACODEC_AC3, 0.0, ""},
124 };
125 combo_opts_t pref_acodec_opts =
126 {
127         sizeof(d_pref_acodec_opts)/sizeof(options_map_t),
128         d_pref_acodec_opts
129 };
130
131 static options_map_t d_source_acodec_opts[] =
132 {
133         {"AC3",      "ac3",   HB_ACODEC_AC3, 0.0, ""},
134         {"DTS",      "dca",   HB_ACODEC_DCA, 0.0, ""},
135         {"MP2",      "mpga",   HB_ACODEC_MPGA, 0.0, ""},
136         {"LPCM",      "lpcm",   HB_ACODEC_LPCM, 0.0, ""},
137 };
138 combo_opts_t source_acodec_opts =
139 {
140         sizeof(d_source_acodec_opts)/sizeof(options_map_t),
141         d_source_acodec_opts
142 };
143
144 static options_map_t d_direct_opts[] =
145 {
146         {"None",      "none",     0, 0.0, "none"},
147         {"Spatial",   "spatial",  1, 0.0, "spatial"},
148         {"Temporal",  "temporal", 2, 0.0, "temporal"},
149         {"Automatic", "auto",     3, 0.0, "auto"},
150 };
151 combo_opts_t direct_opts =
152 {
153         sizeof(d_direct_opts)/sizeof(options_map_t),
154         d_direct_opts
155 };
156
157 static options_map_t d_me_opts[] =
158 {
159         {"Diamond",              "dia", 0, 0.0, "dia"},
160         {"Hexagon",              "hex", 1, 0.0, "hex"},
161         {"Uneven Multi-Hexagon", "umh", 2, 0.0, "umh"},
162         {"Exhaustive",           "esa", 3, 0.0, "esa"},
163 };
164 combo_opts_t me_opts =
165 {
166         sizeof(d_me_opts)/sizeof(options_map_t),
167         d_me_opts
168 };
169
170 static options_map_t d_subme_opts[] =
171 {
172         {"1", "1", 1, 0.0, "1"},
173         {"2", "2", 2, 0.0, "2"},
174         {"3", "3", 3, 0.0, "3"},
175         {"4", "4", 4, 0.0, "4"},
176         {"5", "5", 5, 0.0, "5"},
177         {"6", "6", 6, 0.0, "6"},
178         {"7", "7", 7, 0.0, "7"},
179 };
180 combo_opts_t subme_opts =
181 {
182         sizeof(d_subme_opts)/sizeof(options_map_t),
183         d_subme_opts
184 };
185
186 static options_map_t d_analyse_opts[] =
187 {
188         {"Some", "some", 0, 0.0, "some"},
189         {"None", "none", 1, 0.0, "none"},
190         {"All",  "all",  2, 0.0, "all:8x8dct=1"},
191 };
192 combo_opts_t analyse_opts =
193 {
194         sizeof(d_analyse_opts)/sizeof(options_map_t),
195         d_analyse_opts
196 };
197
198 static options_map_t d_trellis_opts[] =
199 {
200         {"Disabled",          "off",    0, 0.0, ""},
201         {"Final Macro Block", "fmb",    1, 0.0, ""},
202         {"Always",            "always", 2, 0.0, ""},
203 };
204 combo_opts_t trellis_opts =
205 {
206         sizeof(d_trellis_opts)/sizeof(options_map_t),
207         d_trellis_opts
208 };
209
210 typedef struct iso639_lang_t
211 {
212     char * eng_name;        /* Description in English */
213     char * native_name;     /* Description in native language */
214     char * iso639_1;       /* ISO-639-1 (2 characters) code */
215     char * iso639_2;        /* ISO-639-2/t (3 character) code */
216     char * iso639_2b;       /* ISO-639-2/b code (if different from above) */
217 } iso639_lang_t;
218
219 static const iso639_lang_t language_table[] =
220
221         { "Any", "", "zz", "und" },
222         { "Afar", "", "aa", "aar" },
223         { "Abkhazian", "", "ab", "abk" },
224         { "Afrikaans", "", "af", "afr" },
225         { "Akan", "", "ak", "aka" },
226         { "Albanian", "", "sq", "sqi", "alb" },
227         { "Amharic", "", "am", "amh" },
228         { "Arabic", "", "ar", "ara" },
229         { "Aragonese", "", "an", "arg" },
230         { "Armenian", "", "hy", "hye", "arm" },
231         { "Assamese", "", "as", "asm" },
232         { "Avaric", "", "av", "ava" },
233         { "Avestan", "", "ae", "ave" },
234         { "Aymara", "", "ay", "aym" },
235         { "Azerbaijani", "", "az", "aze" },
236         { "Bashkir", "", "ba", "bak" },
237         { "Bambara", "", "bm", "bam" },
238         { "Basque", "", "eu", "eus", "baq" },
239         { "Belarusian", "", "be", "bel" },
240         { "Bengali", "", "bn", "ben" },
241         { "Bihari", "", "bh", "bih" },
242         { "Bislama", "", "bi", "bis" },
243         { "Bosnian", "", "bs", "bos" },
244         { "Breton", "", "br", "bre" },
245         { "Bulgarian", "", "bg", "bul" },
246         { "Burmese", "", "my", "mya", "bur" },
247         { "Catalan", "", "ca", "cat" },
248         { "Chamorro", "", "ch", "cha" },
249         { "Chechen", "", "ce", "che" },
250         { "Chinese", "", "zh", "zho", "chi" },
251         { "Church Slavic", "", "cu", "chu" },
252         { "Chuvash", "", "cv", "chv" },
253         { "Cornish", "", "kw", "cor" },
254         { "Corsican", "", "co", "cos" },
255         { "Cree", "", "cr", "cre" },
256         { "Czech", "", "cs", "ces", "cze" },
257         { "Danish", "Dansk", "da", "dan" },
258         { "Divehi", "", "dv", "div" },
259         { "Dutch", "Nederlands", "nl", "nld", "dut" },
260         { "Dzongkha", "", "dz", "dzo" },
261         { "English", "English", "en", "eng" },
262         { "Esperanto", "", "eo", "epo" },
263         { "Estonian", "", "et", "est" },
264         { "Ewe", "", "ee", "ewe" },
265         { "Faroese", "", "fo", "fao" },
266         { "Fijian", "", "fj", "fij" },
267         { "Finnish", "Suomi", "fi", "fin" },
268         { "French", "Francais", "fr", "fra", "fre" },
269         { "Western Frisian", "", "fy", "fry" },
270         { "Fulah", "", "ff", "ful" },
271         { "Georgian", "", "ka", "kat", "geo" },
272         { "German", "Deutsch", "de", "deu", "ger" },
273         { "Gaelic (Scots)", "", "gd", "gla" },
274         { "Irish", "", "ga", "gle" },
275         { "Galician", "", "gl", "glg" },
276         { "Manx", "", "gv", "glv" },
277         { "Greek, Modern", "", "el", "ell", "gre" },
278         { "Guarani", "", "gn", "grn" },
279         { "Gujarati", "", "gu", "guj" },
280         { "Haitian", "", "ht", "hat" },
281         { "Hausa", "", "ha", "hau" },
282         { "Hebrew", "", "he", "heb" },
283         { "Herero", "", "hz", "her" },
284         { "Hindi", "", "hi", "hin" },
285         { "Hiri Motu", "", "ho", "hmo" },
286         { "Hungarian", "Magyar", "hu", "hun" },
287         { "Igbo", "", "ig", "ibo" },
288         { "Icelandic", "Islenska", "is", "isl", "ice" },
289         { "Ido", "", "io", "ido" },
290         { "Sichuan Yi", "", "ii", "iii" },
291         { "Inuktitut", "", "iu", "iku" },
292         { "Interlingue", "", "ie", "ile" },
293         { "Interlingua", "", "ia", "ina" },
294         { "Indonesian", "", "id", "ind" },
295         { "Inupiaq", "", "ik", "ipk" },
296         { "Italian", "Italiano", "it", "ita" },
297         { "Javanese", "", "jv", "jav" },
298         { "Japanese", "", "ja", "jpn" },
299         { "Kalaallisut", "", "kl", "kal" },
300         { "Kannada", "", "kn", "kan" },
301         { "Kashmiri", "", "ks", "kas" },
302         { "Kanuri", "", "kr", "kau" },
303         { "Kazakh", "", "kk", "kaz" },
304         { "Central Khmer", "", "km", "khm" },
305         { "Kikuyu", "", "ki", "kik" },
306         { "Kinyarwanda", "", "rw", "kin" },
307         { "Kirghiz", "", "ky", "kir" },
308         { "Komi", "", "kv", "kom" },
309         { "Kongo", "", "kg", "kon" },
310         { "Korean", "", "ko", "kor" },
311         { "Kuanyama", "", "kj", "kua" },
312         { "Kurdish", "", "ku", "kur" },
313         { "Lao", "", "lo", "lao" },
314         { "Latin", "", "la", "lat" },
315         { "Latvian", "", "lv", "lav" },
316         { "Limburgan", "", "li", "lim" },
317         { "Lingala", "", "ln", "lin" },
318         { "Lithuanian", "", "lt", "lit" },
319         { "Luxembourgish", "", "lb", "ltz" },
320         { "Luba-Katanga", "", "lu", "lub" },
321         { "Ganda", "", "lg", "lug" },
322         { "Macedonian", "", "mk", "mkd", "mac" },
323         { "Marshallese", "", "mh", "mah" },
324         { "Malayalam", "", "ml", "mal" },
325         { "Maori", "", "mi", "mri", "mao" },
326         { "Marathi", "", "mr", "mar" },
327         { "Malay", "", "ms", "msa", "msa" },
328         { "Malagasy", "", "mg", "mlg" },
329         { "Maltese", "", "mt", "mlt" },
330         { "Moldavian", "", "mo", "mol" },
331         { "Mongolian", "", "mn", "mon" },
332         { "Nauru", "", "na", "nau" },
333         { "Navajo", "", "nv", "nav" },
334         { "Ndebele, South", "", "nr", "nbl" },
335         { "Ndebele, North", "", "nd", "nde" },
336         { "Ndonga", "", "ng", "ndo" },
337         { "Nepali", "", "ne", "nep" },
338         { "Norwegian Nynorsk", "", "nn", "nno" },
339         { "Norwegian Bokmål", "", "nb", "nob" },
340         { "Norwegian", "Norsk", "no", "nor" },
341         { "Chichewa; Nyanja", "", "ny", "nya" },
342         { "Occitan", "", "oc", "oci" },
343         { "Ojibwa", "", "oj", "oji" },
344         { "Oriya", "", "or", "ori" },
345         { "Oromo", "", "om", "orm" },
346         { "Ossetian", "", "os", "oss" },
347         { "Panjabi", "", "pa", "pan" },
348         { "Persian", "", "fa", "fas", "per" },
349         { "Pali", "", "pi", "pli" },
350         { "Polish", "", "pl", "pol" },
351         { "Portuguese", "Portugues", "pt", "por" },
352         { "Pushto", "", "ps", "pus" },
353         { "Quechua", "", "qu", "que" },
354         { "Romansh", "", "rm", "roh" },
355         { "Romanian", "", "ro", "ron", "rum" },
356         { "Rundi", "", "rn", "run" },
357         { "Russian", "", "ru", "rus" },
358         { "Sango", "", "sg", "sag" },
359         { "Sanskrit", "", "sa", "san" },
360         { "Serbian", "", "sr", "srp", "scc" },
361         { "Croatian", "Hrvatski", "hr", "hrv", "scr" },
362         { "Sinhala", "", "si", "sin" },
363         { "Slovak", "", "sk", "slk", "slo" },
364         { "Slovenian", "", "sl", "slv" },
365         { "Northern Sami", "", "se", "sme" },
366         { "Samoan", "", "sm", "smo" },
367         { "Shona", "", "sn", "sna" },
368         { "Sindhi", "", "sd", "snd" },
369         { "Somali", "", "so", "som" },
370         { "Sotho, Southern", "", "st", "sot" },
371         { "Spanish", "Espanol", "es", "spa" },
372         { "Sardinian", "", "sc", "srd" },
373         { "Swati", "", "ss", "ssw" },
374         { "Sundanese", "", "su", "sun" },
375         { "Swahili", "", "sw", "swa" },
376         { "Swedish", "Svenska", "sv", "swe" },
377         { "Tahitian", "", "ty", "tah" },
378         { "Tamil", "", "ta", "tam" },
379         { "Tatar", "", "tt", "tat" },
380         { "Telugu", "", "te", "tel" },
381         { "Tajik", "", "tg", "tgk" },
382         { "Tagalog", "", "tl", "tgl" },
383         { "Thai", "", "th", "tha" },
384         { "Tibetan", "", "bo", "bod", "tib" },
385         { "Tigrinya", "", "ti", "tir" },
386         { "Tonga", "", "to", "ton" },
387         { "Tswana", "", "tn", "tsn" },
388         { "Tsonga", "", "ts", "tso" },
389         { "Turkmen", "", "tk", "tuk" },
390         { "Turkish", "", "tr", "tur" },
391         { "Twi", "", "tw", "twi" },
392         { "Uighur", "", "ug", "uig" },
393         { "Ukrainian", "", "uk", "ukr" },
394         { "Urdu", "", "ur", "urd" },
395         { "Uzbek", "", "uz", "uzb" },
396         { "Venda", "", "ve", "ven" },
397         { "Vietnamese", "", "vi", "vie" },
398         { "Volapük", "", "vo", "vol" },
399         { "Welsh", "", "cy", "cym", "wel" },
400         { "Walloon", "", "wa", "wln" },
401         { "Wolof", "", "wo", "wol" },
402         { "Xhosa", "", "xh", "xho" },
403         { "Yiddish", "", "yi", "yid" },
404         { "Yoruba", "", "yo", "yor" },
405         { "Zhuang", "", "za", "zha" },
406         { "Zulu", "", "zu", "zul" },
407 };
408 #define LANG_TABLE_SIZE (sizeof(language_table)/ sizeof(iso639_lang_t))
409
410 static void
411 del_tree(const gchar *name, gboolean del_top)
412 {
413         const gchar *file;
414
415         if (g_file_test(name, G_FILE_TEST_IS_DIR))
416         {
417                 GDir *gdir = g_dir_open(name, 0, NULL);
418                 file = g_dir_read_name(gdir);
419                 while (file)
420                 {
421                         gchar *path;
422                         path = g_strdup_printf("%s/%s", name, file);
423                         del_tree(path, TRUE);
424                         g_free(path);
425                         file = g_dir_read_name(gdir);
426                 }
427                 if (del_top)
428                         g_rmdir(name);
429         }
430         else
431         {
432                 g_unlink(name);
433         }
434 }
435
436 const gchar*
437 ghb_version()
438 {
439         return HB_VERSION;
440 }
441
442 void
443 ghb_vquality_range(signal_user_data_t *ud, gint *min, gint *max)
444 {
445         if (ghb_settings_get_bool(ud->settings, "directqp"))
446         {
447                 gint vcodec = ghb_settings_get_int(ud->settings, "video_codec");
448                 // Only x264 and ffmpeg currently support direct qp/crf entry
449                 if (vcodec == HB_VCODEC_X264)
450                 {
451                         *min = 0;
452                         *max = 51;
453                 }
454                 else if (vcodec == HB_VCODEC_FFMPEG)
455                 {
456                         *min = 0;
457                         *max = 31;
458                 }
459                 else
460                 {
461                         *min = 0;
462                         *max = 100;
463                 }
464         }
465         else
466         {
467                 *min = 0;
468                 *max = 100;
469         }
470 }
471
472 static setting_value_t*
473 get_acodec_value(gint val)
474 {
475         setting_value_t *value = NULL;
476         gint ii;
477
478         for (ii = 0; ii < acodec_opts.count; ii++)
479         {
480                 if (acodec_opts.map[ii].ivalue == val)
481                 {
482                         value = g_malloc(sizeof(setting_value_t));
483                         value->option = g_strdup(acodec_opts.map[ii].option);
484                         value->shortOpt = g_strdup(acodec_opts.map[ii].shortOpt);
485                         value->svalue = g_strdup(acodec_opts.map[ii].svalue);
486                         value->index = ii;
487                         value->ivalue = acodec_opts.map[ii].ivalue;
488                         value->dvalue = acodec_opts.map[ii].dvalue;
489                         break;
490                 }
491         }
492         return value;
493 }
494
495 static setting_value_t*
496 get_amix_value(gint val)
497 {
498         setting_value_t *value = NULL;
499         gint ii;
500
501         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
502         {
503                 if (hb_audio_mixdowns[ii].amixdown == val)
504                 {
505                         value = g_malloc(sizeof(setting_value_t));
506                         value->option = g_strdup(hb_audio_mixdowns[ii].human_readable_name);
507                         value->shortOpt = g_strdup(hb_audio_mixdowns[ii].short_name);
508                         value->svalue = g_strdup(hb_audio_mixdowns[ii].internal_name);
509                         value->index = ii;
510                         value->ivalue = hb_audio_mixdowns[ii].amixdown;
511                         value->dvalue = hb_audio_mixdowns[ii].amixdown;
512                         break;
513                 }
514         }
515         return value;
516 }
517
518 // Handle for libhb.  Gets set by ghb_backend_init()
519 static hb_handle_t * h = NULL;
520
521 extern void hb_get_tempory_directory(hb_handle_t *h, char path[512]);
522
523 void
524 ghb_hb_cleanup(gboolean partial)
525 {
526         char dir[512];
527
528         hb_get_tempory_directory(h, dir);
529         del_tree(dir, !partial);
530 }
531
532 static hb_audio_config_t*
533 get_hb_audio(gint titleindex, gint track)
534 {
535         hb_list_t  * list;
536         hb_title_t * title;
537     hb_audio_config_t *audio = NULL;
538         
539     if (h == NULL) return NULL;
540         list = hb_get_titles( h );
541         if( !hb_list_count( list ) )
542         {
543                 /* No valid title, stop right there */
544                 return NULL;
545         }
546     title = hb_list_item( list, titleindex );
547         if (title == NULL) return NULL; // Bad titleindex
548         if (!hb_list_count(title->list_audio))
549         {
550                 return NULL;
551         }
552     audio = (hb_audio_config_t *)hb_list_audio_config_item(title->list_audio, track);
553         return audio;
554 }
555
556 static gint
557 search_rates(hb_rate_t *rates, gint rate, gint count)
558 {
559         gint ii;
560         for (ii = 0; ii < count; ii++)
561         {
562                 if (rates[ii].rate == rate)
563                         return ii;
564         }
565         return -1;
566 }
567
568 static gboolean find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter);
569
570 static GtkListStore*
571 get_combo_box_store(GtkBuilder *builder, const gchar *name)
572 {
573         GtkComboBox *combo;
574         GtkListStore *store;
575
576         g_debug("get_combo_box_store() %s\n", name);
577         // First modify the combobox model to allow greying out of options
578         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
579         store = GTK_LIST_STORE(gtk_combo_box_get_model (combo));
580         return store;
581 }
582
583 static void
584 grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean grey)
585 {
586         GtkListStore *store;
587         GtkTreeIter iter;
588         
589         store = get_combo_box_store(builder, name);
590         if (find_combo_item_by_int(GTK_TREE_MODEL(store), value, &iter))
591         {
592                 gtk_list_store_set(store, &iter, 
593                                                    1, !grey, 
594                                                    -1);
595         }
596 }
597
598 void
599 ghb_grey_combo_options(GtkBuilder *builder)
600 {
601         GtkWidget *widget;
602         gint container, track, titleindex, acodec;
603         gboolean httpopt;
604     hb_audio_config_t *audio = NULL;
605         
606         widget = GHB_WIDGET (builder, "title");
607         titleindex = ghb_widget_int(widget);
608         widget = GHB_WIDGET (builder, "audio_track");
609         track = ghb_widget_int(widget);
610         audio = get_hb_audio(titleindex, track);
611         widget = GHB_WIDGET (builder, "container");
612         container = ghb_widget_int(widget);
613         widget = GHB_WIDGET (builder, "http_optimize_mp4");
614         httpopt = ghb_widget_int(widget);
615
616         grey_combo_box_item(builder, "audio_codec", HB_ACODEC_FAAC, FALSE);
617         grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_FAAC, FALSE);
618         grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_FAAC, FALSE);
619         grey_combo_box_item(builder, "audio_codec", HB_ACODEC_LAME, FALSE);
620         grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_LAME, FALSE);
621         grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_LAME, FALSE);
622         grey_combo_box_item(builder, "audio_codec", HB_ACODEC_VORBIS, FALSE);
623         grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_VORBIS, FALSE);
624         grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_VORBIS, FALSE);
625
626         gboolean allow_ac3 = TRUE;
627         allow_ac3 = 
628                 !(container == HB_MUX_MP4 && httpopt) &&
629                 (container != HB_MUX_OGM);
630
631         if (allow_ac3)
632         {
633                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_AC3, FALSE);
634                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_AC3, FALSE);
635                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_AC3, FALSE);
636         }
637         else
638         {
639                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_AC3, TRUE);
640                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_AC3, TRUE);
641                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_AC3, TRUE);
642         }
643         if (audio && audio->in.codec != HB_ACODEC_AC3)
644         {
645                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_AC3, TRUE);
646         }
647         grey_combo_box_item(builder, "video_codec", HB_VCODEC_THEORA, FALSE);
648
649         widget = GHB_WIDGET (builder, "audio_codec");
650         acodec = ghb_widget_int(widget);
651         if (acodec != HB_ACODEC_AC3)
652         {
653                 grey_combo_box_item(builder, "audio_mix", 0, TRUE);
654         }
655         if (container == HB_MUX_MP4)
656         {
657                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_LAME, TRUE);
658                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_LAME, TRUE);
659                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_LAME, TRUE);
660                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_VORBIS, TRUE);
661                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_VORBIS, TRUE);
662                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_VORBIS, TRUE);
663                 grey_combo_box_item(builder, "video_codec", HB_VCODEC_THEORA, TRUE);
664         }
665         else if (container == HB_MUX_AVI)
666         {
667                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_FAAC, TRUE);
668                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_FAAC, TRUE);
669                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_FAAC, TRUE);
670                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_VORBIS, TRUE);
671                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_VORBIS, TRUE);
672                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_VORBIS, TRUE);
673                 grey_combo_box_item(builder, "video_codec", HB_VCODEC_THEORA, TRUE);
674         }
675         else if (container == HB_MUX_OGM)
676         {
677                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_FAAC, TRUE);
678                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_FAAC, TRUE);
679                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_FAAC, TRUE);
680         }
681
682         gboolean allow_mono = TRUE;
683         gboolean allow_stereo = TRUE;
684         gboolean allow_dolby = TRUE;
685         gboolean allow_dpl2 = TRUE;
686         gboolean allow_6ch = TRUE;
687         if (audio)
688         {
689                 allow_mono =
690                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
691                         (acodec != HB_ACODEC_LAME);
692                 gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
693                 allow_stereo =
694                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
695                 allow_dolby =
696                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
697                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
698                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
699                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
700                 allow_6ch =
701                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
702                         (acodec != HB_ACODEC_LAME) &&
703                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
704                         (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
705         }
706         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_MONO, !allow_mono);
707         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_STEREO, !allow_stereo);
708         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_DOLBY, !allow_dolby);
709         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_DOLBYPLII, !allow_dpl2);
710         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_6CH, !allow_6ch);
711 }
712
713 gint
714 ghb_get_best_mix(gint titleindex, gint track, gint acodec, gint mix)
715 {
716     hb_audio_config_t *audio = NULL;
717         gboolean allow_mono = TRUE;
718         gboolean allow_stereo = TRUE;
719         gboolean allow_dolby = TRUE;
720         gboolean allow_dpl2 = TRUE;
721         gboolean allow_6ch = TRUE;
722         
723         if (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
724         {
725                 // Audio codec pass-thru.  No mixdown
726                 return 0;
727         }
728         audio = get_hb_audio(titleindex, track);
729         if (audio)
730         {
731                 allow_mono =
732                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
733                         (acodec != HB_ACODEC_LAME);
734                 gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
735                 allow_stereo =
736                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
737                 allow_dolby =
738                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
739                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
740                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
741                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
742                 allow_6ch =
743                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
744                         (acodec != HB_ACODEC_LAME) &&
745                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
746                         (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
747         }
748         gboolean greater = FALSE;
749         if (mix == 0) 
750         {
751                 // If no mix is specified, select the best available.
752                 mix = HB_AMIXDOWN_6CH;
753         }
754         if (mix == HB_AMIXDOWN_6CH)
755         {
756                 greater = TRUE;
757                 if (allow_6ch) return HB_AMIXDOWN_6CH;
758         }
759         if (mix == HB_AMIXDOWN_DOLBYPLII || greater)
760         {
761                 greater = TRUE;
762                 if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
763         }
764         if (mix == HB_AMIXDOWN_DOLBY || greater)
765         {
766                 greater = TRUE;
767                 if (allow_dolby) return HB_AMIXDOWN_DOLBY;
768         }
769         if (mix == HB_AMIXDOWN_STEREO || greater)
770         {
771                 greater = TRUE;
772                 if (allow_stereo) return HB_AMIXDOWN_STEREO;
773         }
774         if (mix == HB_AMIXDOWN_MONO || greater)
775         {
776                 greater = TRUE;
777                 if (allow_mono) return HB_AMIXDOWN_MONO;
778         }
779         if (allow_stereo) return HB_AMIXDOWN_STEREO;
780         if (allow_dolby) return HB_AMIXDOWN_DOLBY;
781         if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
782         if (allow_6ch) return HB_AMIXDOWN_6CH;
783         return 0;
784 }
785
786 // Set up the model for the combo box
787 static void
788 init_combo_box(GtkBuilder *builder, const gchar *name)
789 {
790         GtkComboBox *combo;
791         GtkListStore *store;
792         GtkCellRenderer *cell;
793
794         g_debug("init_combo_box() %s\n", name);
795         // First modify the combobox model to allow greying out of options
796         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
797         // Store contains:
798         // 1 - String to display
799         // 2 - bool indicating whether the entry is selectable (grey or not)
800         // 3 - String that is used for presets
801         // 4 - Int value determined by backend
802         // 5 - String value determined by backend
803         store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_BOOLEAN, 
804                                                            G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
805         gtk_combo_box_set_model(combo, GTK_TREE_MODEL(store));
806
807         gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo));
808     cell = GTK_CELL_RENDERER(gtk_cell_renderer_text_new());
809     gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
810     gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell,
811       "text", 0, "sensitive", 1, NULL);
812 }       
813
814 static void
815 audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
816 {
817         GtkTreeIter iter;
818         GtkListStore *store;
819         gint ii;
820         
821         g_debug("audio_bitrate_opts_set ()\n");
822         store = get_combo_box_store(builder, name);
823         gtk_list_store_clear(store);
824         for (ii = 0; ii < count; ii++)
825         {
826                 gtk_list_store_append(store, &iter);
827                 gtk_list_store_set(store, &iter, 
828                                                    0, rates[ii].string, 
829                                                    1, TRUE, 
830                                                    2, rates[ii].string, 
831                                                    3, rates[ii].rate * 1000, 
832                                                    4, rates[ii].string, 
833                                                    -1);
834         }
835 }
836
837 static gboolean
838 audio_bitrate_opts_clean(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
839 {
840         GtkTreeIter iter;
841         GtkListStore *store;
842         gint ivalue;
843         gboolean done = FALSE;
844         gboolean changed = FALSE;
845         
846         g_debug("audio_bitrate_opts_clean ()\n");
847         store = get_combo_box_store(builder, name);
848         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
849         {
850                 do
851                 {
852                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
853                         if (search_rates(rates, ivalue/1000, count) < 0)
854                         {
855                                 done = !gtk_list_store_remove(store, &iter);
856                                 changed = TRUE;
857                         }
858                         else
859                         {
860                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
861                         }
862                 } while (!done);
863         }
864         return changed;
865 }
866
867 static void
868 audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
869 {
870         GtkTreeIter iter;
871         GtkListStore *store;
872         gint ii;
873         
874         g_debug("audio_samplerate_opts_set ()\n");
875         store = get_combo_box_store(builder, name);
876         gtk_list_store_clear(store);
877         // Add an item for "Same As Source"
878         gtk_list_store_append(store, &iter);
879         gtk_list_store_set(store, &iter, 
880                                            0, "Same as source", 
881                                            1, TRUE, 
882                                            2, "source", 
883                                            3, 0, 
884                                            4, "source", 
885                                            -1);
886         for (ii = 0; ii < count; ii++)
887         {
888                 gtk_list_store_append(store, &iter);
889                 gtk_list_store_set(store, &iter, 
890                                                    0, rates[ii].string, 
891                                                    1, TRUE, 
892                                                    2, rates[ii].string, 
893                                                    3, rates[ii].rate, 
894                                                    4, rates[ii].string, 
895                                                    -1);
896         }
897 }
898
899 static void
900 video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
901 {
902         GtkTreeIter iter;
903         GtkListStore *store;
904         gint ii;
905         
906         g_debug("video_rate_opts_set ()\n");
907         store = get_combo_box_store(builder, name);
908         gtk_list_store_clear(store);
909         // Add an item for "Same As Source"
910         gtk_list_store_append(store, &iter);
911         gtk_list_store_set(store, &iter, 
912                                            0, "Same as source", 
913                                            1, TRUE, 
914                                            2, "source", 
915                                            3, 0, 
916                                            4, "source", 
917                                            -1);
918         for (ii = 0; ii < count; ii++)
919         {
920                 gchar *desc = "";
921                 gchar *option;
922                 if (strcmp(rates[ii].string, "23.976") == 0)
923                 {
924                         desc = "(NTSC Film)";
925                 }
926                 else if (strcmp(rates[ii].string, "25") == 0)
927                 {
928                         desc = "(PAL Film/Video)";
929                 }
930                 else if (strcmp(rates[ii].string, "29.97") == 0)
931                 {
932                         desc = "(NTSC Video)";
933                 }
934                 option = g_strdup_printf ("%s %s", rates[ii].string, desc);
935                 gtk_list_store_append(store, &iter);
936                 gtk_list_store_set(store, &iter, 
937                                                    0, option, 
938                                                    1, TRUE, 
939                                                    2, rates[ii].string, 
940                                                    3, rates[ii].rate, 
941                                                    4, rates[ii].string, 
942                                                    -1);
943                 g_free(option);
944         }
945 }
946
947 static void
948 mix_opts_set(GtkBuilder *builder, const gchar *name)
949 {
950         GtkTreeIter iter;
951         GtkListStore *store;
952         gint ii;
953         
954         g_debug("audio_bitrate_opts_set ()\n");
955         store = get_combo_box_store(builder, name);
956         gtk_list_store_clear(store);
957         gtk_list_store_append(store, &iter);
958         gtk_list_store_set(store, &iter, 
959                                            0, "None", 
960                                            1, TRUE, 
961                                            2, "none", 
962                                            3, 0, 
963                                            4, "none", 
964                                            -1);
965         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
966         {
967                 gtk_list_store_append(store, &iter);
968                 gtk_list_store_set(store, &iter, 
969                                                    0, hb_audio_mixdowns[ii].human_readable_name, 
970                                                    1, TRUE, 
971                                                    2, hb_audio_mixdowns[ii].short_name, 
972                                                    3, hb_audio_mixdowns[ii].amixdown, 
973                                                    4, hb_audio_mixdowns[ii].internal_name, 
974                                                    -1);
975         }
976 }
977
978 static void
979 language_opts_set(GtkBuilder *builder, const gchar *name)
980 {
981         GtkTreeIter iter;
982         GtkListStore *store;
983         gint ii;
984         
985         g_debug("audio_bitrate_opts_set ()\n");
986         store = get_combo_box_store(builder, name);
987         gtk_list_store_clear(store);
988         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
989         {
990                 gtk_list_store_append(store, &iter);
991                 gtk_list_store_set(store, &iter, 
992                                                    0, language_table[ii].eng_name, 
993                                                    1, TRUE, 
994                                                    2, language_table[ii].iso639_2, 
995                                                    3, ii, 
996                                                    4, language_table[ii].iso639_1, 
997                                                    -1);
998         }
999 }
1000
1001 void
1002 title_opts_set(GtkBuilder *builder, const gchar *name)
1003 {
1004         GtkTreeIter iter;
1005         GtkListStore *store;
1006         hb_list_t  * list;
1007         hb_title_t * title;
1008         gint ii;
1009         gint count = 0;
1010         
1011         g_debug("title_opts_set ()\n");
1012         store = get_combo_box_store(builder, name);
1013         gtk_list_store_clear(store);
1014         if (h != NULL)
1015         {
1016                 list = hb_get_titles( h );
1017                 count = hb_list_count( list );
1018                 if (count > 100) count = 100;
1019         }
1020         if( count <= 0 )
1021         {
1022                 // No titles.  Fill in a default.
1023                 gtk_list_store_append(store, &iter);
1024                 gtk_list_store_set(store, &iter, 
1025                                                    0, "No Titles", 
1026                                                    1, TRUE, 
1027                                                    2, "none", 
1028                                                    3, -1, 
1029                                                    4, "none", 
1030                                                    -1);
1031                 return;
1032         }
1033         for (ii = 0; ii < count; ii++)
1034         {
1035                 gchar *option;
1036                 
1037                 title = (hb_title_t*)hb_list_item(list, ii);
1038                 if (title->duration != 0)
1039                 {
1040                         option  = g_strdup_printf ("%d - %02dh%02dm%02ds",
1041                                 title->index, title->hours, title->minutes, title->seconds);
1042                 }
1043                 else
1044                 {
1045                         option  = g_strdup_printf ("%d - Unknown Length", title->index);
1046                 }
1047                 gtk_list_store_append(store, &iter);
1048                 gtk_list_store_set(store, &iter, 
1049                                                    0, option, 
1050                                                    1, TRUE, 
1051                                                    2, option, 
1052                                                    3, ii, 
1053                                                    4, option, 
1054                                                    -1);
1055         }
1056 }
1057
1058 static gboolean
1059 find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter)
1060 {
1061         gint ivalue;
1062         gboolean foundit = FALSE;
1063         
1064         if (gtk_tree_model_get_iter_first (store, iter))
1065         {
1066                 do
1067                 {
1068                         gtk_tree_model_get(store, iter, 3, &ivalue, -1);
1069                         if (value == ivalue)
1070                         {
1071                                 foundit = TRUE;
1072                                 break;
1073                         }
1074                 } while (gtk_tree_model_iter_next (store, iter));
1075         }
1076         return foundit;
1077 }
1078
1079 static gboolean
1080 audio_rate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
1081 {
1082         GtkTreeIter iter;
1083         GtkListStore *store;
1084         gchar *str;
1085         
1086         g_debug("audio_rate_opts_add ()\n");
1087         store = get_combo_box_store(builder, name);
1088         if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
1089         {
1090                 str = g_strdup_printf ("%.8g", (gdouble)rate/1000.0);
1091                 gtk_list_store_append(store, &iter);
1092                 gtk_list_store_set(store, &iter, 
1093                                                    0, str, 
1094                                                    1, TRUE, 
1095                                                    2, str, 
1096                                                    3, rate, 
1097                                                    4, str, 
1098                                                    -1);
1099                 return TRUE;
1100         }
1101         return FALSE;
1102 }
1103
1104 void
1105 audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1106 {
1107         GtkTreeIter iter;
1108         GtkListStore *store;
1109         hb_list_t  * list;
1110         hb_title_t * title;
1111     hb_audio_config_t * audio;
1112         gint ii;
1113         gint count = 0;
1114         
1115         g_debug("audio_track_opts_set ()\n");
1116         store = get_combo_box_store(builder, name);
1117         gtk_list_store_clear(store);
1118         if (h != NULL)
1119         {
1120                 list = hb_get_titles( h );
1121             title = (hb_title_t*)hb_list_item( list, titleindex );
1122                 if (title != NULL)
1123                 {
1124                         count = hb_list_count( title->list_audio );
1125                 }
1126         }
1127         if (count > 10) count = 10;
1128         if( count <= 0 )
1129         {
1130                 // No audio. set some default
1131                 gtk_list_store_append(store, &iter);
1132                 gtk_list_store_set(store, &iter, 
1133                                                    0, "No Audio", 
1134                                                    1, TRUE, 
1135                                                    2, "none", 
1136                                                    3, -1, 
1137                                                    4, "none", 
1138                                                    -1);
1139                 return;
1140         }
1141         for (ii = 0; ii < count; ii++)
1142         {
1143         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, ii );
1144                 gtk_list_store_append(store, &iter);
1145                 gtk_list_store_set(store, &iter, 
1146                                                    0, audio->lang.description, 
1147                                                    1, TRUE, 
1148                                                    2, audio->lang.description, 
1149                                                    3, ii, 
1150                                                    4, audio->lang.description, 
1151                                                    -1);
1152         }
1153 }
1154
1155 void
1156 subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1157 {
1158         GtkTreeIter iter;
1159         GtkListStore *store;
1160         hb_list_t  * list;
1161         hb_title_t * title;
1162     hb_subtitle_t * subtitle;
1163         gint ii;
1164         gint count = 0;
1165         
1166         g_debug("subtitle_opts_set ()\n");
1167         store = get_combo_box_store(builder, name);
1168         gtk_list_store_clear(store);
1169         if (h != NULL)
1170         {
1171                 list = hb_get_titles( h );
1172             title = (hb_title_t*)hb_list_item( list, titleindex );
1173                 if (title != NULL)
1174                 {
1175                         count = hb_list_count( title->list_subtitle );
1176                 }
1177         }
1178         if (count > 10) count = 10;
1179         // Add options for "none" and "autoselect"
1180         gtk_list_store_append(store, &iter);
1181         gtk_list_store_set(store, &iter, 
1182                                            0, "None", 
1183                                            1, TRUE, 
1184                                            2, "none", 
1185                                            3, -2, 
1186                                            4, "none", 
1187                                            -1);
1188         gtk_list_store_append(store, &iter);
1189         gtk_list_store_set(store, &iter, 
1190                                            0, "Same As Audio", 
1191                                            1, TRUE, 
1192                                            2, "auto", 
1193                                            3, -1, 
1194                                            4, "auto", 
1195                                            -1);
1196         for (ii = 0; ii < count; ii++)
1197         {
1198         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, ii );
1199                 gtk_list_store_append(store, &iter);
1200                 gtk_list_store_set(store, &iter, 
1201                                                    0, subtitle->lang, 
1202                                                    1, TRUE, 
1203                                                    2, subtitle->iso639_2, 
1204                                                    3, ii, 
1205                                                    4, subtitle->iso639_2, 
1206                                                    -1);
1207         }
1208         if (titleindex == -1)
1209         {
1210                 for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1211                 {
1212                         gtk_list_store_append(store, &iter);
1213                         gtk_list_store_set(store, &iter, 
1214                                 0, language_table[ii].eng_name, 
1215                                 1, TRUE, 
1216                                 2, language_table[ii].iso639_2, 
1217                                 3, ii, 
1218                                 4, language_table[ii].iso639_2, 
1219                                 -1);
1220                 }
1221         }
1222 }
1223
1224 gint
1225 ghb_longest_title()
1226 {
1227         hb_list_t  * list;
1228         hb_title_t * title;
1229         gint ii;
1230         gint count = 0;
1231         guint64 longest = 0;
1232         gint titleindex = 0;
1233         
1234         g_debug("ghb_longest_title ()\n");
1235         if (h == NULL) return 0;
1236         list = hb_get_titles( h );
1237         count = hb_list_count( list );
1238         if (count > 100) count = 100;
1239         for (ii = 0; ii < count; ii++)
1240         {
1241                 title = (hb_title_t*)hb_list_item(list, ii);
1242                 if (title->duration > longest)
1243                 {
1244                         titleindex = ii;
1245                         longest = title->duration;
1246                 }
1247         }
1248         return titleindex;
1249 }
1250
1251 gint
1252 ghb_find_audio_track(gint titleindex, const gchar *lang, gint acodec)
1253 {
1254         hb_list_t  * list;
1255         hb_title_t * title;
1256     hb_audio_config_t * audio;
1257         gint ii;
1258         gint count = 0;
1259         gint track = 0;
1260         
1261         g_debug("find_audio_track ()\n");
1262         if (h != NULL)
1263         {
1264                 list = hb_get_titles( h );
1265             title = (hb_title_t*)hb_list_item( list, titleindex );
1266                 if (title != NULL)
1267                 {
1268                         count = hb_list_count( title->list_audio );
1269                 }
1270         }
1271         if (count > 10) count = 10;
1272         for (ii = 0; ii < count; ii++)
1273         {
1274         audio = (hb_audio_config_t*)hb_list_audio_config_item( title->list_audio, ii );
1275                 if ((strcmp(lang, audio->lang.iso639_2) == 0) ||
1276                         (strcmp(lang, "und") == 0))
1277                 {
1278                         // Candidate track.  Will use if no better match found
1279                         track = ii;
1280                         if (audio->in.codec == acodec)
1281                         {
1282                                 // Perfect match
1283                                 return track;
1284                         }
1285                 }
1286         }
1287         return track;
1288 }
1289
1290 static void
1291 generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
1292 {
1293         GtkTreeIter iter;
1294         GtkListStore *store;
1295         gint ii;
1296         
1297         g_debug("generic_opts_set ()\n");
1298         store = get_combo_box_store(builder, name);
1299         gtk_list_store_clear(store);
1300         for (ii = 0; ii < opts->count; ii++)
1301         {
1302                 gtk_list_store_append(store, &iter);
1303                 gtk_list_store_set(store, &iter, 
1304                                                    0, opts->map[ii].option, 
1305                                                    1, TRUE, 
1306                                                    2, opts->map[ii].shortOpt, 
1307                                                    3, opts->map[ii].ivalue, 
1308                                                    4, opts->map[ii].svalue, 
1309                                                    -1);
1310         }
1311 }
1312
1313 void
1314 ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data, gboolean all)
1315 {
1316         GtkComboBox *combo = NULL;
1317         gint signal_id;
1318         gint handler_id = 0;
1319
1320         g_debug("ghb_update_ui_combo_box() %s\n", name);
1321         if (name != NULL)
1322         {               
1323                 // Clearing a combo box causes a rash of "changed" events, even when
1324                 // the active item is -1 (inactive).  To control things, I'm disabling
1325                 // the event till things are settled down.
1326                 combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
1327                 signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX);
1328                 if (signal_id > 0)
1329                 {
1330                         // Valid signal id found.  This should always succeed.
1331                         handler_id = g_signal_handler_find ((gpointer)combo, G_SIGNAL_MATCH_ID, 
1332                                                                                                 signal_id, 0, 0, 0, 0);
1333                         if (handler_id > 0)
1334                         {
1335                                 // This should also always succeed
1336                                 g_signal_handler_block ((gpointer)combo, handler_id);
1337                         }
1338                 }
1339         }       
1340         if (all || strcmp(name, "audio_bitrate") == 0)
1341                 audio_bitrate_opts_set(builder, "audio_bitrate", hb_audio_bitrates, hb_audio_bitrates_count);
1342         if (all || strcmp(name, "pref_audio_bitrate1") == 0)
1343                 audio_bitrate_opts_set(builder, "pref_audio_bitrate1", hb_audio_bitrates, hb_audio_bitrates_count);
1344         if (all || strcmp(name, "pref_audio_bitrate2") == 0)
1345                 audio_bitrate_opts_set(builder, "pref_audio_bitrate2", hb_audio_bitrates, hb_audio_bitrates_count);
1346         if (all || strcmp(name, "audio_sample_rate") == 0)
1347                 audio_samplerate_opts_set(builder, "audio_sample_rate", hb_audio_rates, hb_audio_rates_count);
1348         if (all || strcmp(name, "pref_audio_rate1") == 0)
1349                 audio_samplerate_opts_set(builder, "pref_audio_rate1", hb_audio_rates, hb_audio_rates_count);
1350         if (all || strcmp(name, "pref_audio_rate2") == 0)
1351                 audio_samplerate_opts_set(builder, "pref_audio_rate2", hb_audio_rates, hb_audio_rates_count);
1352         if (all || strcmp(name, "framerate") == 0)
1353                 video_rate_opts_set(builder, "framerate", hb_video_rates, hb_video_rates_count);
1354         if (all || strcmp(name, "audio_mix") == 0)
1355                 mix_opts_set(builder, "audio_mix");
1356         if (all || strcmp(name, "pref_audio_mix1") == 0)
1357                 mix_opts_set(builder, "pref_audio_mix1");
1358         if (all || strcmp(name, "pref_audio_mix2") == 0)
1359                 mix_opts_set(builder, "pref_audio_mix2");
1360         if (all || strcmp(name, "pref_source_audio_lang") == 0)
1361                 language_opts_set(builder, "pref_source_audio_lang");
1362         if (all || strcmp(name, "subtitle_lang") == 0)
1363                 subtitle_opts_set(builder, "subtitle_lang", user_data);
1364         if (all || strcmp(name, "title") == 0)
1365                 title_opts_set(builder, "title");
1366         if (all || strcmp(name, "audio_track") == 0)
1367                 audio_track_opts_set(builder, "audio_track", user_data);
1368         if (all || strcmp(name, "container") == 0)
1369                 generic_opts_set(builder, "container", &container_opts);
1370         if (all || strcmp(name, "deinterlace") == 0)
1371                 generic_opts_set(builder, "deinterlace", &deint_opts);
1372         if (all || strcmp(name, "denoise") == 0)
1373                 generic_opts_set(builder, "denoise", &denoise_opts);
1374         if (all || strcmp(name, "video_codec") == 0)
1375                 generic_opts_set(builder, "video_codec", &vcodec_opts);
1376         if (all || strcmp(name, "audio_codec") == 0)
1377                 generic_opts_set(builder, "audio_codec", &acodec_opts);
1378         if (all || strcmp(name, "pref_audio_codec1") == 0)
1379                 generic_opts_set(builder, "pref_audio_codec1", &pref_acodec_opts);
1380         if (all || strcmp(name, "pref_audio_codec2") == 0)
1381                 generic_opts_set(builder, "pref_audio_codec2", &pref_acodec_opts);
1382         if (all || strcmp(name, "pref_source_audio_codec") == 0)
1383                 generic_opts_set(builder, "pref_source_audio_codec", &source_acodec_opts);
1384         if (all || strcmp(name, "x264_direct") == 0)
1385                 generic_opts_set(builder, "x264_direct", &direct_opts);
1386         if (all || strcmp(name, "x264_me") == 0)
1387                 generic_opts_set(builder, "x264_me", &me_opts);
1388         if (all || strcmp(name, "x264_subme") == 0)
1389                 generic_opts_set(builder, "x264_subme", &subme_opts);
1390         if (all || strcmp(name, "x264_analyse") == 0)
1391                 generic_opts_set(builder, "x264_analyse", &analyse_opts);
1392         if (all || strcmp(name, "x264_trellis") == 0)
1393                 generic_opts_set(builder, "x264_trellis", &trellis_opts);
1394         if (handler_id > 0)
1395         {
1396                 g_signal_handler_unblock ((gpointer)combo, handler_id);
1397         }
1398 }
1399         
1400 static void
1401 init_ui_combo_boxes(GtkBuilder *builder)
1402 {
1403         init_combo_box(builder, "audio_bitrate");
1404         init_combo_box(builder, "pref_audio_bitrate1");
1405         init_combo_box(builder, "pref_audio_bitrate2");
1406         init_combo_box(builder, "audio_sample_rate");
1407         init_combo_box(builder, "pref_audio_rate1");
1408         init_combo_box(builder, "pref_audio_rate2");
1409         init_combo_box(builder, "framerate");
1410         init_combo_box(builder, "audio_mix");
1411         init_combo_box(builder, "pref_audio_mix1");
1412         init_combo_box(builder, "pref_audio_mix2");
1413         init_combo_box(builder, "pref_source_audio_lang");
1414         init_combo_box(builder, "subtitle_lang");
1415         init_combo_box(builder, "title");
1416         init_combo_box(builder, "audio_track");
1417         init_combo_box(builder, "container");
1418         init_combo_box(builder, "deinterlace");
1419         init_combo_box(builder, "denoise");
1420         init_combo_box(builder, "video_codec");
1421         init_combo_box(builder, "audio_codec");
1422         init_combo_box(builder, "pref_audio_codec1");
1423         init_combo_box(builder, "pref_audio_codec2");
1424         init_combo_box(builder, "pref_source_audio_codec");
1425         init_combo_box(builder, "x264_direct");
1426         init_combo_box(builder, "x264_me");
1427         init_combo_box(builder, "x264_subme");
1428         init_combo_box(builder, "x264_analyse");
1429         init_combo_box(builder, "x264_trellis");
1430 }
1431         
1432 static const char * turbo_opts = 
1433         "ref=1:subme=1:me=dia:analyse=none:trellis=0:"
1434         "no-fast-pskip=0:8x8dct=0:weightb=0";
1435
1436 // Construct the x264 options string
1437 // The result is allocated, so someone must free it at some point.
1438 gchar*
1439 ghb_build_x264opts_string(GHashTable *settings)
1440 {
1441         GString *x264opts = g_string_new("");
1442         gint refs = ghb_settings_get_int(settings, "x264_refs");
1443         if (refs != 1)
1444         {
1445                 g_string_append_printf(x264opts, "ref=%d:", refs);
1446         }
1447         if (refs > 1)
1448         {
1449                 if (ghb_settings_get_bool(settings, "x264_mixed_refs"))
1450                 {
1451                         g_string_append(x264opts, "mixed-refs=1:");
1452                 }
1453         }
1454         gint subme = ghb_settings_get_int(settings, "x264_subme");
1455         if (subme != 5) // 5 is default
1456         {
1457                 g_string_append_printf(x264opts, "subme=%d:", subme);
1458         }
1459         gint bframes = ghb_settings_get_int(settings, "x264_bframes");
1460         if (bframes > 0)
1461         {
1462                 g_string_append_printf(x264opts, "bframes=%d:", bframes);
1463                 if (ghb_settings_get_bool(settings, "x264_weighted_bframes"))
1464                 {
1465                         g_string_append(x264opts, "weightb=1:");
1466                 }
1467                 if (subme >= 6)
1468                 {
1469                         if (ghb_settings_get_bool(settings, "x264_brdo"))
1470                         {
1471                                 g_string_append(x264opts, "brdo=1:");
1472                         }
1473                 }
1474                 if (ghb_settings_get_bool(settings, "x264_bime"))
1475                 {
1476                         g_string_append(x264opts, "bime=1:");
1477                 }
1478         }
1479         if (bframes > 1)
1480         {
1481                 if (ghb_settings_get_bool(settings, "x264_bpyramid"))
1482                 {
1483                         g_string_append(x264opts, "b-pyramid=1:");
1484                 }
1485         }
1486         if (ghb_settings_get_bool(settings, "x264_no_fast_pskip"))
1487         {
1488                 g_string_append(x264opts, "no-fast-pskip=1:");
1489         }
1490         if (ghb_settings_get_bool(settings, "x264_no_dct_decimate"))
1491         {
1492                 g_string_append(x264opts, "no-dct-decimate=1:");
1493         }
1494         if (!ghb_settings_get_bool(settings, "x264_cabac"))
1495         {
1496                 g_string_append(x264opts, "cabac=0:");
1497         }
1498         else
1499         {
1500                 gint trellis = ghb_settings_get_int(settings, "x264_trellis");
1501                 if (trellis != 0); // != None
1502                 {
1503                         g_string_append_printf(x264opts, "trellis=%d:", trellis);
1504                 }
1505         }
1506         gint dba, dbb;
1507         dba = ghb_settings_get_int(settings, "x264_deblock_alpha");
1508         dbb = ghb_settings_get_int(settings, "x264_deblock_beta");
1509         if (dba != 0 || dbb != 0)
1510         {
1511                 g_string_append_printf(x264opts, "deblock=%d,%d:", dba, dbb);
1512         }
1513         const gchar *me = ghb_settings_get_string(settings, "x264_me");
1514         g_string_append_printf(x264opts, "me=%s:", me);
1515         gint analyse = ghb_settings_get_int(settings, "x264_analyse");
1516         if (analyse != 0) // != Some
1517         {
1518                 g_string_append_printf(x264opts, "analyse=%s:", 
1519                                                            ghb_settings_get_string(settings, "x264_analyse"));
1520         }
1521         if (analyse != 1) // != none
1522         {
1523                 gint direct = ghb_settings_get_int(settings, "x264_direct");
1524                 if (direct != 1) // !spatial
1525                 {
1526                         g_string_append_printf(x264opts, "direct=%s:", 
1527                                                                    ghb_settings_get_string(settings, "x264_direct"));
1528                 }
1529         }
1530         g_string_append_printf(x264opts, "merange=%d:", 
1531                                                    ghb_settings_get_int(settings, "x264_merange"));
1532
1533         const gchar *opts = ghb_settings_get_string(settings, "x264_options");
1534         if (opts != NULL && opts[0] != 0)
1535         {
1536                 g_string_append_printf(x264opts, "%s:", opts);
1537         }
1538         // strip the trailing ":"
1539         gchar *result;
1540         gint len;
1541         result = g_string_free(x264opts, FALSE);
1542         len = strlen(result);
1543         if (len > 0) result[len - 1] = 0;
1544         return result;
1545 }
1546
1547 gchar **
1548 ghb_get_chapters(gint titleindex)
1549 {
1550         hb_list_t  * list;
1551         hb_title_t * title;
1552     hb_chapter_t * chapter;
1553         gint count, ii;
1554         gchar **result = NULL;
1555         
1556         g_debug("ghb_get_chapters (title = %d)\n", titleindex);
1557         if (h == NULL) return NULL;
1558         list = hb_get_titles( h );
1559     title = (hb_title_t*)hb_list_item( list, titleindex );
1560         if (title == NULL) return NULL;
1561         count = hb_list_count( title->list_chapter );
1562         result = g_malloc((count+1) * sizeof(gchar*));
1563         for (ii = 0; ii < count; ii++)
1564         {
1565                 chapter = hb_list_item(title->list_chapter, ii);
1566                 if (chapter == NULL) break;
1567                 if (chapter->title == NULL || chapter->title[0] == 0)
1568                         result[ii] = g_strdup_printf ("Chapter %2d", ii);
1569                 else 
1570                         result[ii] = g_strdup(chapter->title);
1571         }
1572         result[ii] = NULL;
1573         return result;
1574 }
1575
1576 gboolean
1577 ghb_ac3_in_audio_list(GSList *audio_list)
1578 {
1579         GSList *link;
1580
1581         link = audio_list;
1582         while (link != NULL)
1583         {
1584                 GHashTable *asettings;
1585                 gint acodec;
1586
1587                 asettings = (GHashTable*)link->data;
1588                 acodec = ghb_settings_get_int(asettings, "audio_codec");
1589                 if (acodec == HB_ACODEC_AC3)
1590                         return TRUE;
1591                 link = link->next;
1592         }
1593         return FALSE;
1594 }
1595
1596 gboolean
1597 ghb_set_passthru_rate_opts(GtkBuilder *builder, gint bitrate)
1598 {
1599         gboolean changed = FALSE;
1600         changed = audio_rate_opts_add(builder, "audio_bitrate", bitrate);
1601         return changed;
1602 }
1603
1604 gboolean
1605 ghb_set_default_rate_opts(GtkBuilder *builder)
1606 {
1607         gboolean changed = FALSE;
1608         changed = audio_bitrate_opts_clean(builder, "audio_bitrate", hb_audio_bitrates, hb_audio_bitrates_count);
1609         return changed;
1610 }
1611
1612 static ghb_status_t hb_status;
1613
1614 void
1615 ghb_backend_init(GtkBuilder *builder, gint debug, gint update)
1616 {
1617     /* Init libhb */
1618     h = hb_init( debug, update );
1619         // Set up the list model for the combos
1620         init_ui_combo_boxes(builder);
1621         // Populate all the combos
1622         ghb_update_ui_combo_box(builder, NULL, 0, TRUE);
1623 }
1624
1625 void
1626 ghb_backend_scan(const gchar *path, gint titleindex)
1627 {
1628     hb_scan( h, path, titleindex );
1629         hb_status.state |= GHB_STATE_SCANNING;
1630         // initialize count and cur to something that won't cause FPE
1631         // when computing progress
1632         hb_status.title_count = 1;
1633         hb_status.title_cur = 0;
1634 }
1635
1636 gint
1637 ghb_get_state()
1638 {
1639         return hb_status.state;
1640 }
1641
1642 void
1643 ghb_clear_state(gint state)
1644 {
1645         hb_status.state &= ~state;
1646 }
1647
1648 void
1649 ghb_set_state(gint state)
1650 {
1651         hb_status.state |= state;
1652 }
1653
1654 void
1655 ghb_get_status(ghb_status_t *status)
1656 {
1657         memcpy(status, &hb_status, sizeof(ghb_status_t));
1658 }
1659
1660 void 
1661 ghb_track_status()
1662 {
1663     hb_state_t s;
1664         static gint scan_complete_count = 0;
1665         gint scans;
1666
1667         if (h == NULL) return;
1668     hb_get_state( h, &s );
1669         scans = hb_get_scancount(h);
1670         if (scans > scan_complete_count)
1671         {
1672                 hb_status.state &= ~GHB_STATE_SCANNING;
1673                 hb_status.state |= GHB_STATE_SCANDONE;
1674                 scan_complete_count = hb_get_scancount(h);
1675         }
1676         switch( s.state )
1677     {
1678         case HB_STATE_IDLE:
1679             /* Nothing to do */
1680             break;
1681
1682 #define p s.param.scanning
1683         case HB_STATE_SCANNING:
1684                 {
1685                         hb_status.state |= GHB_STATE_SCANNING;
1686                         hb_status.title_count = p.title_count;
1687                         hb_status.title_cur = p.title_cur;
1688                 } break;
1689 #undef p
1690
1691         case HB_STATE_SCANDONE:
1692         {
1693                         hb_status.state &= ~GHB_STATE_SCANNING;
1694                         hb_status.state |= GHB_STATE_SCANDONE;
1695         } break;
1696
1697 #define p s.param.working
1698         case HB_STATE_WORKING:
1699                         hb_status.state |= GHB_STATE_WORKING;
1700                         hb_status.state &= ~GHB_STATE_PAUSED;
1701                         hb_status.job_cur = p.job_cur;
1702                         hb_status.job_count = p.job_count;
1703                         hb_status.progress = p.progress;
1704                         hb_status.rate_cur = p.rate_cur;
1705                         hb_status.rate_avg = p.rate_avg;
1706                         hb_status.hours = p.hours;
1707                         hb_status.minutes = p.minutes;
1708                         hb_status.seconds = p.seconds;
1709                         hb_status.unique_id = p.sequence_id & 0xFFFFFF;
1710             break;
1711 #undef p
1712
1713         case HB_STATE_PAUSED:
1714                         hb_status.state |= GHB_STATE_PAUSED;
1715             break;
1716                                 
1717 #define p s.param.muxing
1718         case HB_STATE_MUXING:
1719         {
1720                         hb_status.state |= GHB_STATE_MUXING;
1721         } break;
1722 #undef p
1723
1724 #define p s.param.workdone
1725         case HB_STATE_WORKDONE:
1726                 {
1727             hb_job_t *job;
1728
1729                         hb_status.state |= GHB_STATE_WORKDONE;
1730                         hb_status.state &= ~GHB_STATE_MUXING;
1731                         hb_status.state &= ~GHB_STATE_PAUSED;
1732                         hb_status.state &= ~GHB_STATE_WORKING;
1733                         switch (p.error)
1734                         {
1735                         case HB_ERROR_NONE:
1736                                 hb_status.error = GHB_ERROR_NONE;
1737                         case HB_ERROR_CANCELED:
1738                                 hb_status.error = GHB_ERROR_CANCELED;
1739                         default:
1740                                 hb_status.error = GHB_ERROR_FAIL;
1741                         }
1742                         hb_status.error = p.error;
1743                         // Delete all remaining jobs of this encode.
1744                         // An encode can be composed of multiple associated jobs.
1745                         // When a job is stopped, libhb removes it from the job list,
1746                         // but does not remove other jobs that may be associated with it.
1747                         // Associated jobs are taged in the sequence id.
1748             while (((job = hb_job(h, 0)) != NULL) && ((job->sequence_id >> 24) != 0) ) 
1749                 hb_rem( h, job );
1750                 } break;
1751 #undef p
1752     }
1753 }
1754
1755 gboolean
1756 ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
1757 {
1758         hb_list_t  * list;
1759         hb_title_t * title;
1760         
1761     if (h == NULL) return FALSE;
1762         list = hb_get_titles( h );
1763         if( !hb_list_count( list ) )
1764         {
1765                 /* No valid title, stop right there */
1766                 return FALSE;
1767         }
1768
1769     title = hb_list_item( list, titleindex );
1770         if (title == NULL) return FALSE;        // Bad titleindex
1771         tinfo->width = title->width;
1772         tinfo->height = title->height;
1773         memcpy(tinfo->crop, title->crop, 4 * sizeof(int));
1774         // Don't allow crop to 0
1775         if (title->crop[0] + title->crop[1] >= title->height)
1776                 title->crop[0] = title->crop[1] = 0;
1777         if (title->crop[2] + title->crop[3] >= title->width)
1778                 title->crop[2] = title->crop[3] = 0;
1779         tinfo->num_chapters = hb_list_count(title->list_chapter);
1780         tinfo->rate_base = title->rate_base;
1781         tinfo->rate = title->rate;
1782         hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), 
1783                                 title->width * title->pixel_aspect_width, 
1784                                 title->height * title->pixel_aspect_height);
1785         tinfo->hours = title->hours;
1786         tinfo->minutes = title->minutes;
1787         tinfo->seconds = title->seconds;
1788         tinfo->duration = title->duration;
1789 g_message("duration %ld", title->duration);
1790         return TRUE;
1791 }
1792
1793 gboolean
1794 ghb_get_audio_info(ghb_audio_info_t *ainfo, gint titleindex, gint audioindex)
1795 {
1796     hb_audio_config_t *audio;
1797         
1798         audio = get_hb_audio(titleindex, audioindex);
1799         if (audio == NULL) return FALSE; // Bad audioindex
1800         ainfo->codec = audio->in.codec;
1801         ainfo->bitrate = audio->in.bitrate;
1802         ainfo->samplerate = audio->in.samplerate;
1803         return TRUE;
1804 }
1805
1806 gboolean
1807 ghb_audio_is_passthru(gint acodec)
1808 {
1809         g_debug("ghb_audio_is_passthru () \n");
1810         g_debug("acodec %d\n", acodec);
1811         return (acodec == HB_ACODEC_AC3);
1812 }
1813
1814 gint
1815 ghb_get_default_acodec()
1816 {
1817         return HB_ACODEC_FAAC;
1818 }
1819
1820 void
1821 ghb_set_scale(signal_user_data_t *ud, gint mode)
1822 {
1823         hb_list_t  * list;
1824         hb_title_t * title;
1825         hb_job_t   * job;
1826         GHashTable *settings = ud->settings;
1827         gboolean keep_aspect, round_dims, anamorphic;
1828         gboolean autocrop, autoscale, noscale;
1829         gint crop[4], width, height, par_width, par_height;
1830         gint crop_width, crop_height;
1831         gint aspect_n, aspect_d;
1832         gboolean keep_width = (mode == GHB_SCALE_KEEP_WIDTH);
1833         gboolean keep_height = (mode == GHB_SCALE_KEEP_HEIGHT);
1834         gint step;
1835         GtkWidget *widget;
1836         gint modshift;
1837         gint modround;
1838         gint max_width = 0;
1839         gint max_height = 0;
1840         
1841         g_debug("ghb_set_scale ()\n");
1842
1843         if (h == NULL) return;
1844         list = hb_get_titles( h );
1845         if( !hb_list_count( list ) )
1846         {
1847                 /* No valid title, stop right there */
1848                 return;
1849         }
1850         gint titleindex = ghb_settings_get_index(settings, "title");
1851     title = hb_list_item( list, titleindex );
1852         if (title == NULL) return;
1853         job   = title->job;
1854         if (job == NULL) return;
1855         
1856         // First configure widgets
1857         round_dims = ghb_settings_get_bool(ud->settings, "round_dimensions");
1858         anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
1859         keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
1860         autocrop = ghb_settings_get_bool(ud->settings, "autocrop");
1861         autoscale = ghb_settings_get_bool(ud->settings, "autoscale");
1862         // "Noscale" is a flag that says we prefer to crop extra to satisfy
1863         // alignment constraints rather than scaling to satisfy them.
1864         noscale = ghb_settings_get_bool(ud->settings, "noscale");
1865         // Align dimensions to either 16 or 2 pixels
1866         // The scaler crashes if the dimensions are not divisible by 2
1867         // x264 also will not accept dims that are not multiple of 2
1868         modshift = round_dims ? 4 : 1;
1869         modround = round_dims ? 8 : 1;
1870         if (autoscale)
1871         {
1872                 keep_width = FALSE;
1873                 keep_height = FALSE;
1874         }
1875         if (anamorphic || keep_aspect)
1876         {
1877                 keep_height = FALSE;
1878         }
1879         // Step needs to be at least 2 because odd widths cause scaler crash
1880         step = round_dims ? 16 : 2;
1881         widget = GHB_WIDGET (ud->builder, "scale_width");
1882         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
1883         widget = GHB_WIDGET (ud->builder, "scale_height");
1884         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
1885         if (autocrop)
1886         {
1887                 ghb_title_info_t tinfo;
1888
1889                 if (ghb_get_title_info (&tinfo, titleindex))
1890                 {
1891                         crop[0] = tinfo.crop[0];
1892                         crop[1] = tinfo.crop[1];
1893                         crop[2] = tinfo.crop[2];
1894                         crop[3] = tinfo.crop[3];
1895                         if (noscale)
1896                         {
1897                                 gint need1, need2;
1898
1899                                 // Adjust the cropping to accomplish the desired width and height
1900                                 crop_width = tinfo.width - crop[2] - crop[3];
1901                                 crop_height = tinfo.height - crop[0] - crop[1];
1902                                 width = (crop_width >> modshift) << modshift;
1903                                 height = (crop_height >> modshift) << modshift;
1904                                 need1 = (crop_height - height) / 2;
1905                                 need2 = crop_height - height - need1;
1906                                 crop[0] += need1;
1907                                 crop[1] += need2;
1908                                 need1 = (crop_width - width) / 2;
1909                                 need2 = crop_width - width - need1;
1910                                 crop[2] += need1;
1911                                 crop[3] += need2;
1912                         }
1913                         ghb_ui_update_int (ud, "crop_top", crop[0]);
1914                         ghb_ui_update_int (ud, "crop_bottom", crop[1]);
1915                         ghb_ui_update_int (ud, "crop_left", crop[2]);
1916                         ghb_ui_update_int (ud, "crop_right", crop[3]);
1917                 }
1918         }
1919         crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
1920         crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
1921         crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
1922         crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
1923         hb_reduce(&aspect_n, &aspect_d, 
1924                                 title->width * title->pixel_aspect_width, 
1925                                 title->height * title->pixel_aspect_height);
1926         crop_width = title->width - crop[2] - crop[3];
1927         crop_height = title->height - crop[0] - crop[1];
1928         if (autoscale)
1929         {
1930                 width = crop_width;
1931                 height = crop_height;
1932                 max_width = crop_width;
1933                 max_height = crop_height;
1934         }
1935         else
1936         {
1937                 width = ghb_settings_get_int(ud->settings, "scale_width");
1938                 height = ghb_settings_get_int(ud->settings, "scale_height");
1939                 max_width = ghb_settings_get_int(ud->settings, "max_width");
1940                 max_height = ghb_settings_get_int(ud->settings, "max_width");
1941                 // Align max dims 
1942                 max_width = (max_width >> modshift) << modshift;
1943                 max_height = (max_height >> modshift) << modshift;
1944                 // Adjust dims according to max values
1945                 if (!max_height)
1946                 {
1947                         max_height = crop_height;
1948                 }
1949                 if (!max_width)
1950                 {
1951                         max_width = crop_width;
1952                 }
1953                 height = MIN(height, max_height);
1954                 width = MIN(width, max_width);
1955                 g_debug("max_width %d, max_height %d\n", max_width, max_height);
1956         }
1957         if (width < 16)
1958                 width = title->width - crop[2] - crop[3];
1959         if (height < 16)
1960                 height = title->height - crop[0] - crop[1];
1961
1962         if (anamorphic)
1963         {
1964                 if (round_dims)
1965                 {
1966                         job->modulus = 0;
1967                 }
1968                 else
1969                 {
1970                         // The scaler crashes if the dimensions are not divisible by 2
1971                         // Align mod 2.  And so does something in x264_encoder_headers()
1972                         job->modulus = 2;
1973                 }
1974                 job->width = width;
1975                 if (max_height) 
1976                         job->maxHeight = max_height;
1977                 job->crop[0] = crop[0]; job->crop[1] = crop[1];
1978                 job->crop[2] = crop[2]; job->crop[3] = crop[3];
1979                 hb_set_anamorphic_size( job, &width, &height, &par_width, &par_height );
1980         }
1981         else 
1982         {
1983                 if (keep_aspect)
1984                 {
1985                         gdouble par;
1986                         gint new_width, new_height;
1987                         
1988                         g_debug("kw %s kh %s\n", keep_width ? "y":"n", keep_height ? "y":"n");
1989                         g_debug("w %d h %d\n", width, height);
1990                         // Compute pixel aspect ration.  
1991                         par = (gdouble)(title->height * aspect_n) / (title->width * aspect_d);
1992                         // Must scale so that par becomes 1:1
1993                         // Try to keep largest dimension
1994                         new_height = (crop_height * ((gdouble)width/crop_width) / par);
1995                         new_width = (crop_width * ((gdouble)height/crop_height) * par);
1996                         // Height and width are always multiples of 2, so do the rounding
1997                         new_height = ((new_height + 1) >> 1) << 1;
1998                         new_width = ((new_width + 1) >> 1) << 1;
1999                         g_debug("max w %d, new w %d\n", max_width, new_width);
2000                         if (max_width && (new_width > max_width))
2001                         {
2002                                 height = new_height;
2003                         }
2004                         else if (max_height && (new_height > max_height))
2005                         {
2006                                 width = new_width;
2007                         }
2008                         else if (keep_width)
2009                         {
2010                                 height = new_height;
2011                         }
2012                         else if (keep_height)
2013                         {
2014                                 width = new_width;
2015                         }
2016                         else if (width > new_width)
2017                         {
2018                                 height = new_height;
2019                         }
2020                         else
2021                         {
2022                                 width = new_width;
2023                         }
2024                         g_debug("new w %d h %d\n", width, height);
2025                 }
2026                 width = ((width + modround) >> modshift) << modshift;
2027                 height = ((height + modround) >> modshift) << modshift;
2028         }
2029         ghb_ui_update_int (ud, "scale_width", width);
2030         ghb_ui_update_int (ud, "scale_height", height);
2031 }
2032
2033 static void
2034 set_preview_job_settings(hb_job_t *job, GHashTable *settings)
2035 {
2036         job->crop[0] = ghb_settings_get_int(settings, "crop_top");
2037         job->crop[1] = ghb_settings_get_int(settings, "crop_bottom");
2038         job->crop[2] = ghb_settings_get_int(settings, "crop_left");
2039         job->crop[3] = ghb_settings_get_int(settings, "crop_right");
2040
2041         gboolean anamorphic = ghb_settings_get_bool(settings, "anamorphic");
2042         gboolean round_dimensions = ghb_settings_get_bool(settings, "round_dimensions");
2043         if (round_dimensions && anamorphic)
2044         {
2045                 job->modulus = 16;
2046                 job->pixel_ratio = 2;
2047         }
2048         else if (anamorphic)
2049         {
2050                 job->modulus = 2;
2051                 job->pixel_ratio = 2;
2052         }
2053         else
2054         {
2055                 job->modulus = 2;
2056                 job->pixel_ratio = 0;
2057         }
2058         job->width = ghb_settings_get_int(settings, "scale_width");
2059         job->height = ghb_settings_get_int(settings, "scale_height");
2060         gint deint = ghb_settings_get_int(settings, "deinterlace");
2061         gboolean decomb = ghb_settings_get_bool(settings, "decomb");
2062         job->deinterlace = (!decomb && deint == 0) ? 0 : 1;
2063 }
2064
2065 gint
2066 ghb_calculate_target_bitrate(GHashTable *settings, gint titleindex)
2067 {
2068         hb_list_t  * list;
2069         hb_title_t * title;
2070         hb_job_t   * job;
2071         gint size;
2072
2073         if (h == NULL) return 2000;
2074         list = hb_get_titles( h );
2075     title = hb_list_item( list, titleindex );
2076         if (title == NULL) return 2000;
2077         job   = title->job;
2078         if (job == NULL) return 2000;
2079         size = ghb_settings_get_int(settings, "video_target_size");
2080         return hb_calc_bitrate( job, size );
2081 }
2082
2083 gint
2084 ghb_guess_bitrate(GHashTable *settings)
2085 {
2086         gint bitrate;
2087         if (ghb_settings_get_bool(settings, "vquality_type_constant"))
2088         {
2089                 // This is really rough.  I'm trying to err on the high
2090                 // side since this is used to estimate if there is 
2091                 // sufficient disk space left
2092                 gint vcodec = ghb_settings_get_int(settings, "video_codec");
2093                 gdouble vquality = ghb_settings_get_dbl(settings, "video_quality")/100;
2094                 if (vcodec == HB_VCODEC_X264 && 
2095                                 !ghb_settings_get_bool(settings, "linear_vquality"))
2096                 {
2097                         vquality = 51.0 - vquality * 51.0;
2098                         // Convert log curve to linear
2099                         vquality = exp2((vquality-12)/6);
2100                         // Don't let it go to 0
2101                         if (vquality >= 31) vquality = 30;
2102                         vquality = (31 - vquality) / 31;
2103                 }
2104                 // bitrate seems to be a log relasionship to quality
2105                 // with typical source material
2106                 // This is a real wag
2107                 bitrate = 20*1024*1024*exp10(vquality*14)/exp10(14);
2108                 // Add some bits for audio
2109                 bitrate += 500*1024;
2110         }
2111         else
2112         {
2113                 // Add some fudge to the bitrate to leave breathing room
2114                 bitrate = ghb_settings_get_int(settings, "video_bitrate")*1024;
2115                 // Add some bits for audio
2116                 bitrate += 500*1024;
2117         }
2118         return bitrate;
2119 }
2120
2121 gboolean
2122 ghb_validate_video(signal_user_data_t *ud)
2123 {
2124         GHashTable *settings = ud->settings;
2125         gint vcodec, mux;
2126         gchar *message;
2127
2128         mux = ghb_settings_get_int(settings, "container");
2129         vcodec = ghb_settings_get_int(settings, "video_codec");
2130         if ((mux == HB_MUX_MP4 || mux == HB_MUX_AVI) && 
2131                 (vcodec == HB_VCODEC_THEORA))
2132         {
2133                 // mp4|avi/theora combination is not supported.
2134                 message = g_strdup_printf(
2135                                         "Theora is not supported in the MP4 and AVI containers.\n\n"
2136                                         "You should choose a different video codec or container.\n"
2137                                         "If you continue, XviD will be chosen for you.");
2138                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2139                 {
2140                         g_free(message);
2141                         return FALSE;
2142                 }
2143                 g_free(message);
2144                 vcodec = HB_VCODEC_XVID;
2145                 ghb_ui_update_int(ud, "video_codec", vcodec);
2146         }
2147         gboolean decomb = ghb_settings_get_bool(settings, "decomb");
2148         gboolean vfr = ghb_settings_get_bool(settings, "variable_frame_rate");
2149         if (decomb && !vfr)
2150         {
2151                 message = g_strdup_printf(
2152                                         "Decomb is intended to be used in conjunction\n"
2153                                         "with variable frame rate.\n\n"
2154                                         "Would you like me to enable VFR for you?");
2155                 if (ghb_message_dialog(GTK_MESSAGE_WARNING, message, "No", "Yes"))
2156                 {
2157                         ghb_ui_update_int(ud, "variable_frame_rate", TRUE);
2158                 }
2159                 g_free(message);
2160         }
2161         return TRUE;
2162 }
2163
2164 gboolean
2165 ghb_validate_container(signal_user_data_t *ud)
2166 {
2167         gint container;
2168         gchar *message;
2169
2170         container = ghb_settings_get_bool(ud->settings, "container");
2171         if (container == HB_MUX_MP4)
2172         {
2173                 gboolean httpopt;
2174                 httpopt = ghb_settings_get_bool(ud->settings, "http_optimize_mp4");
2175                 if (httpopt && ghb_ac3_in_audio_list(ud->audio_settings))
2176                 {
2177                         message = g_strdup_printf(
2178                                         "AC3 audio in HTTP optimized MP4 is not supported.\n\n"
2179                                         "You should choose a different audio codec.\n"
2180                                         "If you continue, FAAC will be chosen for you.");
2181                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2182                         {
2183                                 g_free(message);
2184                                 return FALSE;
2185                         }
2186                         g_free(message);
2187                         GSList *link = ud->audio_settings;
2188                         while (link != NULL)
2189                         {
2190                                 GHashTable *asettings;
2191                                 asettings = (GHashTable*)link->data;
2192                                 gint acodec = ghb_settings_get_int(asettings, "audio_codec");
2193                                 if (acodec == HB_ACODEC_AC3)
2194                                 {
2195                                         setting_value_t *value;
2196                                         value = get_acodec_value(HB_ACODEC_FAAC);
2197                                         ghb_settings_set(asettings, "audio_codec", value);
2198                                 }
2199                                 link = link->next;
2200                         }
2201                 }
2202         }
2203         return TRUE;
2204 }
2205
2206 gboolean
2207 ghb_validate_audio(signal_user_data_t *ud)
2208 {
2209         hb_list_t  * list;
2210         hb_title_t * title;
2211         GHashTable *settings = ud->settings;
2212         gchar *message;
2213         setting_value_t *value;
2214
2215         if (h == NULL) return FALSE;
2216         list = hb_get_titles( h );
2217         if( !hb_list_count( list ) )
2218         {
2219                 /* No valid title, stop right there */
2220                 g_message("No title found.\n");
2221                 return FALSE;
2222         }
2223
2224         gint titleindex = ghb_settings_get_index(settings, "title");
2225     title = hb_list_item( list, titleindex );
2226         if (title == NULL) return FALSE;
2227         GSList *link = ud->audio_settings;
2228         gint mux = ghb_settings_get_int(settings, "container");
2229         while (link != NULL)
2230         {
2231                 GHashTable *asettings;
2232             hb_audio_config_t *taudio;
2233
2234                 asettings = (GHashTable*)link->data;
2235                 gint track = ghb_settings_get_index(asettings, "audio_track");
2236                 gint codec = ghb_settings_get_int(asettings, "audio_codec");
2237         taudio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, track );
2238                 if ((taudio->in.codec != HB_ACODEC_AC3) && (codec == HB_ACODEC_AC3))
2239                 {
2240                         // Not supported.  AC3 is passthrough only, so input must be AC3
2241                         message = g_strdup_printf(
2242                                                 "The source does not support AC3 Pass-Thru.\n\n"
2243                                                 "You should choose a different audio codec.\n"
2244                                                 "If you continue, one will be chosen for you.");
2245                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2246                         {
2247                                 g_free(message);
2248                                 return FALSE;
2249                         }
2250                         g_free(message);
2251                         if (mux == HB_MUX_AVI)
2252                         {
2253                                 codec = HB_ACODEC_LAME;
2254                         }
2255                         else
2256                         {
2257                                 codec = HB_ACODEC_FAAC;
2258                         }
2259                         value = get_acodec_value(codec);
2260                         ghb_settings_set(asettings, "audio_codec", value);
2261                 }
2262                 gchar *a_unsup = NULL;
2263                 gchar *mux_s = NULL;
2264                 if (mux == HB_MUX_MP4)
2265                 { 
2266                         mux_s = "MP4";
2267                         // mp4/mp3|vorbis combination is not supported.
2268                         if (codec == HB_ACODEC_LAME)
2269                         {
2270                                 a_unsup = "MP3";
2271                                 codec = HB_ACODEC_FAAC;
2272                         }
2273                         if (codec == HB_ACODEC_VORBIS)
2274                         {
2275                                 a_unsup = "Vorbis";
2276                                 codec = HB_ACODEC_FAAC;
2277                         }
2278                 }
2279                 else if (mux == HB_MUX_AVI)
2280                 {
2281                         mux_s = "AVI";
2282                         // avi/faac|vorbis combination is not supported.
2283                         if (codec == HB_ACODEC_FAAC)
2284                         {
2285                                 a_unsup = "FAAC";
2286                                 codec = HB_ACODEC_LAME;
2287                         }
2288                         if (codec == HB_ACODEC_VORBIS)
2289                         {
2290                                 a_unsup = "Vorbis";
2291                                 codec = HB_ACODEC_LAME;
2292                         }
2293                 }
2294                 else if (mux == HB_MUX_OGM)
2295                 {
2296                         mux_s = "OGM";
2297                         // avi/faac|vorbis combination is not supported.
2298                         if (codec == HB_ACODEC_FAAC)
2299                         {
2300                                 a_unsup = "FAAC";
2301                                 codec = HB_ACODEC_VORBIS;
2302                         }
2303                         if (codec == HB_ACODEC_AC3)
2304                         {
2305                                 a_unsup = "AC-3";
2306                                 codec = HB_ACODEC_VORBIS;
2307                         }
2308                 }
2309                 if (a_unsup)
2310                 {
2311                         message = g_strdup_printf(
2312                                                 "%s is not supported in the %s container.\n\n"
2313                                                 "You should choose a different audio codec.\n"
2314                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
2315                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2316                         {
2317                                 g_free(message);
2318                                 return FALSE;
2319                         }
2320                         g_free(message);
2321                         value = get_acodec_value(codec);
2322                         ghb_settings_set(asettings, "audio_codec", value);
2323                 }
2324                 gint mix = ghb_settings_get_int (asettings, "audio_mix");
2325                 gboolean allow_mono = TRUE;
2326                 gboolean allow_stereo = TRUE;
2327                 gboolean allow_dolby = TRUE;
2328                 gboolean allow_dpl2 = TRUE;
2329                 gboolean allow_6ch = TRUE;
2330                 allow_mono =
2331                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
2332                         (codec != HB_ACODEC_LAME);
2333                 gint layout = taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
2334                 allow_stereo =
2335                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
2336                 allow_dolby =
2337                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
2338                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
2339                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
2340                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
2341                 allow_6ch =
2342                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
2343                         (codec != HB_ACODEC_LAME) &&
2344                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
2345                         (taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
2346
2347                 gchar *mix_unsup = NULL;
2348                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
2349                 {
2350                         mix_unsup = "mono";
2351                 }
2352                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
2353                 {
2354                         mix_unsup = "stereo";
2355                 }
2356                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
2357                 {
2358                         mix_unsup = "Dolby";
2359                 }
2360                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
2361                 {
2362                         mix_unsup = "Dolby Pro Logic II";
2363                 }
2364                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
2365                 {
2366                         mix_unsup = "6 Channel";
2367                 }
2368                 if (mix_unsup)
2369                 {
2370                         message = g_strdup_printf(
2371                                                 "The source audio does not support %s mixdown.\n\n"
2372                                                 "You should choose a different mixdown.\n"
2373                                                 "If you continue, one will be chosen for you.", mix_unsup);
2374                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2375                         {
2376                                 g_free(message);
2377                                 return FALSE;
2378                         }
2379                         g_free(message);
2380                         mix = ghb_get_best_mix(titleindex, track, codec, mix);
2381                         value = get_amix_value(mix);
2382                         ghb_settings_set(asettings, "audio_mix", value);
2383                 }
2384                 link = link->next;
2385         }
2386         return TRUE;
2387 }
2388
2389 gboolean
2390 ghb_validate_vquality(GHashTable *settings)
2391 {
2392         gint vcodec;
2393         gchar *message;
2394         gint min, max;
2395
2396         if (ghb_settings_get_bool(settings, "nocheckvquality")) return TRUE;
2397         vcodec = ghb_settings_get_int(settings, "video_codec");
2398         if (ghb_settings_get_bool(settings, "vquality_type_constant"))
2399         {
2400                 if (!ghb_settings_get_bool(settings, "directqp"))
2401                 {
2402                         if (vcodec != HB_VCODEC_X264 || 
2403                                 ghb_settings_get_bool(settings, "linear_vquality"))
2404                         {
2405                                 min = 68;
2406                                 max = 97;
2407                         }
2408                         else if (vcodec == HB_VCODEC_X264)
2409                         {
2410                                 min = 40;
2411                                 max = 70;
2412                         }
2413                 }
2414                 else
2415                 {
2416                         if (vcodec == HB_VCODEC_X264)
2417                         {
2418                                 min = 16;
2419                                 max = 30;
2420                         }
2421                         else if (vcodec == HB_VCODEC_FFMPEG)
2422                         {
2423                                 min = 1;
2424                                 max = 8;
2425                         }
2426                         else
2427                         {
2428                                 min = 68;
2429                                 max = 97;
2430                         }
2431                 }
2432                 gint vquality = ghb_settings_get_dbl(settings, "video_quality");
2433                 if (vquality < min || vquality > max)
2434                 {
2435                         message = g_strdup_printf(
2436                                                 "Interesting video quality choise: %d\n\n"
2437                                                 "Typical values range from %d to %d.\n"
2438                                                 "Are you sure you wish to use this setting?",
2439                                                 vquality, min, max);
2440                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
2441                                                                         "Cancel", "Continue"))
2442                         {
2443                                 g_free(message);
2444                                 return FALSE;
2445                         }
2446                         g_free(message);
2447                 }
2448         }
2449         return TRUE;
2450 }
2451
2452 void
2453 ghb_add_job(job_settings_t *js, gint unique_id)
2454 {
2455         hb_list_t  * list;
2456         hb_title_t * title;
2457         hb_job_t   * job;
2458         GHashTable *settings = js->settings;
2459         static gchar *x264opts;
2460         gint sub_id = 0;
2461
2462         g_debug("ghb_add_job()\n");
2463         if (h == NULL) return;
2464         list = hb_get_titles( h );
2465         if( !hb_list_count( list ) )
2466         {
2467                 /* No valid title, stop right there */
2468                 g_message("No title found.\n");
2469                 return;
2470         }
2471
2472         gint titleindex = ghb_settings_get_index(settings, "title");
2473     title = hb_list_item( list, titleindex );
2474         if (title == NULL) return;
2475
2476         /* Set job settings */
2477         job   = title->job;
2478         if (job == NULL) return;
2479
2480         job->mux = ghb_settings_get_int(settings, "container");
2481         if (job->mux == HB_MUX_MP4)
2482         {
2483                 job->largeFileSize = ghb_settings_get_bool(settings, "large_mp4");
2484                 job->mp4_optimize = ghb_settings_get_bool(settings, "http_optimize_mp4");
2485         }
2486         else
2487         {
2488                 job->largeFileSize = FALSE;
2489                 job->mp4_optimize = FALSE;
2490         }
2491         gint chapter_start, chapter_end;
2492         chapter_start = ghb_settings_get_int(settings, "start_chapter");
2493         chapter_end = ghb_settings_get_int(settings, "end_chapter");
2494         gint num_chapters = hb_list_count(title->list_chapter);
2495         job->chapter_start = MIN( num_chapters, chapter_start );
2496         job->chapter_end   = MAX( job->chapter_start, chapter_end );
2497
2498         job->chapter_markers = ghb_settings_get_bool(settings, "chapter_markers");
2499         if ( job->chapter_markers )
2500         {
2501                 gint chapter;
2502                 
2503                 for(chapter = chapter_start; chapter <= chapter_end; chapter++)
2504                 {
2505                         hb_chapter_t * chapter_s;
2506                         gchar *name;
2507                         
2508                         if (js->chapter_list == NULL || js->chapter_list[chapter-1] == 0)
2509                         {
2510                                 name = g_strdup_printf ("Chapter %2d", chapter);
2511                         }
2512                         else
2513                         {
2514                                 name = g_strdup(js->chapter_list[chapter-1]);
2515                         }
2516                         chapter_s = hb_list_item( job->title->list_chapter, chapter - 1);
2517                         strncpy(chapter_s->title, name, 1023);
2518                         chapter_s->title[1023] = '\0';
2519                         g_free(name);
2520                 }
2521         }
2522         job->crop[0] = ghb_settings_get_int(settings, "crop_top");
2523         job->crop[1] = ghb_settings_get_int(settings, "crop_bottom");
2524         job->crop[2] = ghb_settings_get_int(settings, "crop_left");
2525         job->crop[3] = ghb_settings_get_int(settings, "crop_right");
2526
2527         
2528         gboolean decomb = ghb_settings_get_bool(settings, "decomb");
2529         gint deint = ghb_settings_get_int(settings, "deinterlace");
2530         if (!decomb)
2531                 job->deinterlace = (deint == 0) ? 0 : 1;
2532         else
2533                 job->deinterlace = 0;
2534     job->grayscale   = ghb_settings_get_bool(settings, "grayscale");
2535
2536         gboolean anamorphic = ghb_settings_get_bool(settings, "anamorphic");
2537         gboolean round_dimensions = ghb_settings_get_bool(settings, "round_dimensions");
2538         if (round_dimensions && anamorphic)
2539         {
2540                 job->pixel_ratio = 2;
2541                 job->modulus = 16;
2542         }
2543         else if (anamorphic)
2544         {
2545                 // Huh! I thought I wanted to use pixel_ratio 1 for this case, but
2546                 // when its 1, libhb discards the width and height and uses original
2547                 // title dims - crop.  Thats not what I want.
2548                 // Also, x264 requires things to divisible by 2.
2549                 job->pixel_ratio = 2;
2550                 job->modulus = 2;
2551         }
2552         else
2553         {
2554                 job->pixel_ratio = 0;
2555                 job->modulus = 2;
2556         }
2557         job->vfr = ghb_settings_get_bool(settings, "variable_frame_rate");
2558         /* Add selected filters */
2559         job->filters = hb_list_init();
2560         if( ghb_settings_get_bool(settings, "detelecine" ) || job->vfr )
2561         {
2562                 hb_filter_detelecine.settings = NULL;
2563                 hb_list_add( job->filters, &hb_filter_detelecine );
2564         }
2565         if( decomb )
2566         {
2567                 // Use default settings
2568                 hb_filter_decomb.settings = NULL;
2569                 hb_list_add( job->filters, &hb_filter_decomb );
2570         }
2571         if( job->deinterlace )
2572         {
2573                 hb_filter_deinterlace.settings = (gchar*)ghb_settings_get_string(settings, "deinterlace");
2574                 hb_list_add( job->filters, &hb_filter_deinterlace );
2575         }
2576         if( ghb_settings_get_bool(settings, "deblock") )
2577         {
2578                 hb_filter_deblock.settings = NULL;
2579                 hb_list_add( job->filters, &hb_filter_deblock );
2580         }
2581         gint denoise = ghb_settings_get_int(settings, "denoise");
2582         if( denoise != 0 )
2583         {
2584                 hb_filter_denoise.settings = (gchar*)ghb_settings_get_string(settings, "denoise");
2585                 hb_list_add( job->filters, &hb_filter_denoise );
2586         }
2587         job->width = ghb_settings_get_int(settings, "scale_width");
2588         job->height = ghb_settings_get_int(settings, "scale_height");
2589
2590         job->vcodec = ghb_settings_get_int(settings, "video_codec");
2591         if ((job->mux == HB_MUX_MP4 || job->mux == HB_MUX_AVI) && 
2592                 (job->vcodec == HB_VCODEC_THEORA))
2593         {
2594                 // mp4|avi/theora combination is not supported.
2595                 job->vcodec = HB_VCODEC_XVID;
2596         }
2597         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
2598         {
2599                 job->ipod_atom = ghb_settings_get_bool(settings, "ipod_file");
2600         }
2601         if (ghb_settings_get_bool(settings, "vquality_type_constant"))
2602         {
2603                 gdouble vquality = ghb_settings_get_dbl(settings, "video_quality");
2604                 if (!ghb_settings_get_bool(settings, "directqp"))
2605                 {
2606                         vquality /= 100.0;
2607                         if (ghb_settings_get_bool(settings, "linear_vquality"))
2608                         {
2609                                 if (job->vcodec == HB_VCODEC_X264)
2610                                 {
2611                                         // Adjust to same range as xvid and ffmpeg
2612                                         vquality = 31.0 - vquality * 31.0;
2613                                         if (vquality > 0)
2614                                         {
2615                                                 // Convert linear to log curve
2616                                                 vquality = 12 + 6 * log2(vquality);
2617                                                 if (vquality > 51) vquality = 51;
2618                                                 if (vquality < 1) vquality = 1;
2619                                         }
2620                                         else
2621                                                 vquality = 0;
2622                                 }
2623                         }
2624                         else
2625                         {
2626                                 if (vquality == 0.0) vquality = 0.01;
2627                                 if (vquality == 1.0) vquality = 0.0;
2628                         }
2629                 }
2630                 job->vquality =  vquality;
2631                 job->vbitrate = 0;
2632         }
2633         else if (ghb_settings_get_bool(settings, "vquality_type_bitrate"))
2634         {
2635                 job->vquality = -1.0;
2636                 job->vbitrate = ghb_settings_get_int(settings, "video_bitrate");
2637         }
2638         // AVI container does not support variable frame rate.
2639         if (job->mux == HB_MUX_AVI)
2640         {
2641                 job->vfr = FALSE;
2642         }
2643
2644         gint vrate = ghb_settings_get_int(settings, "framerate");
2645         if( vrate == 0 || job->vfr )
2646         {
2647                 job->vrate = title->rate;
2648                 job->vrate_base = title->rate_base;
2649                 job->cfr = 0;
2650         }
2651         else
2652         {
2653                 job->vrate = 27000000;
2654                 job->vrate_base = vrate;
2655                 job->cfr = 1;
2656         }
2657         // First remove any audios that are already in the list
2658         // This happens if you are encoding the same title a second time.
2659         gint num_audio_tracks = hb_list_count(job->list_audio);
2660         gint ii;
2661     for(ii = 0; ii < num_audio_tracks; ii++)
2662     {
2663         hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
2664         hb_list_rem(job->list_audio, audio);
2665     }
2666         GSList *link = js->audio_settings;
2667         gint count = 0;
2668         while (link != NULL)
2669         {
2670                 GHashTable *asettings;
2671             hb_audio_config_t audio;
2672             hb_audio_config_t *taudio;
2673
2674                 hb_audio_config_init(&audio);
2675                 asettings = (GHashTable*)link->data;
2676                 audio.in.track = ghb_settings_get_index(asettings, "audio_track");
2677                 audio.out.track = count;
2678                 audio.out.codec = ghb_settings_get_int(asettings, "audio_codec");
2679         taudio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, audio.in.track );
2680                 if ((taudio->in.codec != HB_ACODEC_AC3) && (audio.out.codec == HB_ACODEC_AC3))
2681                 {
2682                         // Not supported.  AC3 is passthrough only, so input must be AC3
2683                         if (job->mux == HB_MUX_AVI)
2684                         {
2685                                 audio.out.codec = HB_ACODEC_LAME;
2686                         }
2687                         else
2688                         {
2689                                 audio.out.codec = HB_ACODEC_FAAC;
2690                         }
2691                 }
2692                 if ((job->mux == HB_MUX_MP4) && 
2693                         ((audio.out.codec == HB_ACODEC_LAME) ||
2694                         (audio.out.codec == HB_ACODEC_VORBIS)))
2695                 {
2696                         // mp4/mp3|vorbis combination is not supported.
2697                         audio.out.codec = HB_ACODEC_FAAC;
2698                 }
2699                 if ((job->mux == HB_MUX_AVI) && 
2700                         ((audio.out.codec == HB_ACODEC_FAAC) ||
2701                         (audio.out.codec == HB_ACODEC_VORBIS)))
2702                 {
2703                         // avi/faac|vorbis combination is not supported.
2704                         audio.out.codec = HB_ACODEC_LAME;
2705                 }
2706                 if ((job->mux == HB_MUX_OGM) && 
2707                         ((audio.out.codec == HB_ACODEC_FAAC) ||
2708                         (audio.out.codec == HB_ACODEC_AC3)))
2709                 {
2710                         // ogm/faac|ac3 combination is not supported.
2711                         audio.out.codec = HB_ACODEC_VORBIS;
2712                 }
2713         audio.out.dynamic_range_compression = ghb_settings_get_dbl(asettings, "audio_drc");
2714                 // It would be better if this were done in libhb for us, but its not yet.
2715                 if (audio.out.codec == HB_ACODEC_AC3 || audio.out.codec == HB_ACODEC_DCA)
2716                 {
2717                         audio.out.mixdown = 0;
2718                 }
2719                 else
2720                 {
2721                         audio.out.mixdown = ghb_settings_get_int (asettings, "audio_mix");
2722                         // Make sure the mixdown is valid and pick a new one if not.
2723                         audio.out.mixdown = ghb_get_best_mix(titleindex, audio.in.track, audio.out.codec, 
2724                                                                                                 audio.out.mixdown);
2725                         audio.out.bitrate = ghb_settings_get_int(asettings, "audio_bitrate") / 1000;
2726                         gint srate = ghb_settings_get_int(asettings, "audio_sample_rate");
2727                         if (srate == 0) // 0 is same as source
2728                                 audio.out.samplerate = taudio->in.samplerate;
2729                         else
2730                                 audio.out.samplerate = srate;
2731                 }
2732
2733                 // Add it to the jobs audio list
2734         hb_audio_add( job, &audio );
2735                 count++;
2736                 link = link->next;
2737         }
2738         // I was tempted to move this up with the reset of the video quality
2739         // settings, but I suspect the settings above need to be made
2740         // first in order for hb_calc_bitrate to be accurate.
2741         if (ghb_settings_get_bool(settings, "vquality_type_target"))
2742         {
2743                 gint size;
2744                 
2745                 size = ghb_settings_get_int(settings, "video_target_size");
2746         job->vbitrate = hb_calc_bitrate( job, size );
2747                 job->vquality = -1.0;
2748         }
2749
2750         job->file = ghb_settings_get_string(settings, "destination");
2751         job->crf = ghb_settings_get_bool(settings, "constant_rate_factor");
2752         // TODO: libhb holds onto a reference to the x264opts and is not
2753         // finished with it until encoding the job is done.  But I can't
2754         // find a way to get at the job before it is removed in order to
2755         // free up the memory I am allocating here.
2756         // The short story is THIS LEAKS.
2757         x264opts = ghb_build_x264opts_string(settings);
2758         
2759         if( x264opts != NULL && *x264opts != '\0' )
2760         {
2761                 job->x264opts = x264opts;
2762         }
2763         else /*avoids a bus error crash when options aren't specified*/
2764         {
2765                 job->x264opts =  NULL;
2766         }
2767         gint subtitle = ghb_settings_get_int(settings, "subtitle_lang");
2768         gboolean forced_subtitles = ghb_settings_get_bool (settings, "forced_subtitles");
2769         job->subtitle_force = forced_subtitles;
2770         if (subtitle >= 0)
2771                 job->subtitle = subtitle;
2772         else
2773                 job->subtitle = -1;
2774         if (subtitle == -1)
2775         {
2776                 // Subtitle scan. Look for subtitle matching audio language
2777                 char *x264opts_tmp;
2778
2779                 /*
2780                  * When subtitle scan is enabled do a fast pre-scan job
2781                  * which will determine which subtitles to enable, if any.
2782                  */
2783                 job->pass = -1;
2784                 job->indepth_scan = 1;
2785
2786                 x264opts_tmp = job->x264opts;
2787                 job->x264opts = NULL;
2788
2789                 job->select_subtitle = malloc(sizeof(hb_subtitle_t*));
2790                 *(job->select_subtitle) = NULL;
2791
2792                 /*
2793                  * Add the pre-scan job
2794                  */
2795                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2796                 hb_add( h, job );
2797                 //if (job->x264opts != NULL)
2798                 //      g_free(job->x264opts);
2799
2800                 job->x264opts = x264opts_tmp;
2801         }
2802         else
2803         {
2804                 job->select_subtitle = NULL;
2805         }
2806         if( ghb_settings_get_bool(settings, "two_pass") &&
2807                 !ghb_settings_get_bool(settings, "vquality_type_constant"))
2808         {
2809                 /*
2810                  * If subtitle_scan is enabled then only turn it on
2811                  * for the second pass and then off again for the
2812                  * second.
2813                  */
2814                 hb_subtitle_t **subtitle_tmp = job->select_subtitle;
2815                 job->select_subtitle = NULL;
2816                 job->pass = 1;
2817                 job->indepth_scan = 0;
2818                 gchar *x264opts2 = NULL;
2819                 if (x264opts)
2820                 {
2821                         x264opts2 = g_strdup(x264opts);
2822                 }
2823                 /*
2824                  * If turbo options have been selected then append them
2825                  * to the x264opts now (size includes one ':' and the '\0')
2826                  */
2827                 if( ghb_settings_get_bool(settings, "turbo") )
2828                 {
2829                         char *tmp_x264opts;
2830
2831                         if ( x264opts )
2832                         {
2833                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, turbo_opts);
2834                                 g_free(x264opts);
2835                         } 
2836                         else 
2837                         {
2838                                 /*
2839                                  * No x264opts to modify, but apply the turbo options
2840                                  * anyway as they may be modifying defaults
2841                                  */
2842                                 tmp_x264opts = g_strdup_printf("%s", turbo_opts);
2843                         }
2844                         x264opts = tmp_x264opts;
2845
2846                         job->x264opts = x264opts;
2847                 }
2848                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2849                 hb_add( h, job );
2850                 //if (job->x264opts != NULL)
2851                 //      g_free(job->x264opts);
2852
2853                 job->select_subtitle = subtitle_tmp;
2854                 job->pass = 2;
2855                 /*
2856                  * On the second pass we turn off subtitle scan so that we
2857                  * can actually encode using any subtitles that were auto
2858                  * selected in the first pass (using the whacky select-subtitle
2859                  * attribute of the job).
2860                  */
2861                 job->indepth_scan = 0;
2862                 job->x264opts = x264opts2;
2863                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2864                 hb_add( h, job );
2865                 //if (job->x264opts != NULL)
2866                 //      g_free(job->x264opts);
2867         }
2868         else
2869         {
2870                 job->indepth_scan = 0;
2871                 job->pass = 0;
2872                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2873                 hb_add( h, job );
2874                 //if (job->x264opts != NULL)
2875                 //      g_free(job->x264opts);
2876         }
2877 }
2878
2879 void
2880 ghb_remove_job(gint unique_id)
2881 {
2882     hb_job_t * job;
2883     gint ii;
2884         
2885         // Multiples passes all get the same id
2886         // remove them all.
2887         // Go backwards through list, so reordering doesn't screw me.
2888         ii = hb_count(h) - 1;
2889     while ((job = hb_job(h, ii--)) != NULL)
2890     {
2891         if ((job->sequence_id & 0xFFFFFF) == unique_id)
2892                         hb_rem(h, job);
2893     }
2894 }
2895
2896 void
2897 ghb_start_queue()
2898 {
2899         hb_start( h );
2900 }
2901
2902 void
2903 ghb_stop_queue()
2904 {
2905         hb_stop( h );
2906 }
2907
2908 void
2909 ghb_pause_queue()
2910 {
2911     hb_state_t s;
2912     hb_get_state2( h, &s );
2913
2914     if( s.state == HB_STATE_PAUSED )
2915     {
2916         hb_resume( h );
2917     }
2918     else
2919     {
2920         hb_pause( h );
2921     }
2922 }
2923
2924 GdkPixbuf*
2925 ghb_get_preview_image(gint titleindex, gint index, GHashTable *settings, gboolean borders)
2926 {
2927         hb_title_t *title;
2928         hb_list_t  *list;
2929         
2930         list = hb_get_titles( h );
2931         if( !hb_list_count( list ) )
2932         {
2933                 /* No valid title, stop right there */
2934                 return NULL;
2935         }
2936     title = hb_list_item( list, titleindex );
2937         if (title == NULL) return NULL;
2938         if (title->job == NULL) return NULL;
2939         set_preview_job_settings(title->job, settings);
2940
2941         // hb_get_preview can't handle sizes that are larger than the original title
2942         // dimensions
2943         if (title->job->width > title->width)
2944                 title->job->width = title->width;
2945         
2946         if (title->job->height > title->height)
2947                 title->job->height = title->height;
2948         // And also creates artifacts if the width is not a multiple of 8
2949         //title->job->width = ((title->job->width + 4) >> 3) << 3;
2950         // And the height must be a multiple of 2
2951         //title->job->height = ((title->job->height + 1) >> 1) << 1;
2952         
2953         // Make sure we have a big enough buffer to receive the image from libhb. libhb
2954         // creates images with a one-pixel border around the original content. Hence we
2955         // add 2 pixels horizontally and vertically to the buffer size.
2956         gint srcWidth = title->width + 2;
2957         gint srcHeight= title->height + 2;
2958         gint dstWidth = title->width;
2959         gint dstHeight= title->height;
2960         gint borderTop = 1;
2961         gint borderLeft = 1;
2962     if (borders)
2963     {
2964         //     |<---------- title->width ----------->|
2965         //     |   |<---- title->job->width ---->|   |
2966         //     |   |                             |   |
2967         //     .......................................
2968         //     ....+-----------------------------+....
2969         //     ....|                             |....<-- gray border
2970         //     ....|                             |....
2971         //     ....|                             |....
2972         //     ....|                             |<------- image
2973         //     ....|                             |....
2974         //     ....|                             |....
2975         //     ....|                             |....
2976         //     ....|                             |....
2977         //     ....|                             |....
2978         //     ....+-----------------------------+....
2979         //     .......................................
2980                 dstWidth = title->job->width;
2981         dstHeight = title->job->height;
2982                 borderTop = (srcHeight - dstHeight) / 2;
2983                 borderLeft = (srcWidth - dstWidth) / 2;
2984                 g_debug("boarders removed\n");
2985         }
2986
2987         g_debug("src %d x %d\n", srcWidth, srcHeight);
2988         g_debug("dst %d x %d\n", dstWidth, dstHeight);
2989         g_debug("job dim %d x %d\n", title->job->width, title->job->height);
2990         g_debug("title crop %d:%d:%d:%d\n", 
2991                         title->crop[0],
2992                         title->crop[1],
2993                         title->crop[2],
2994                         title->crop[3]);
2995         g_debug("job crop %d:%d:%d:%d\n", 
2996                         title->job->crop[0],
2997                         title->job->crop[1],
2998                         title->job->crop[2],
2999                         title->job->crop[3]);
3000         static guint8 *buffer = NULL;
3001         static gint bufferSize = 0;
3002
3003         gint newSize;
3004         newSize = srcWidth * srcHeight * 4;
3005         if( bufferSize < newSize )
3006         {
3007                 bufferSize = newSize;
3008                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
3009         }
3010         hb_get_preview( h, title, index, buffer );
3011
3012         // Create an GdkPixbuf and copy the libhb image into it, converting it from
3013         // libhb's format something suitable. Along the way, we'll strip off the
3014         // border around libhb's image.
3015         
3016         // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format.
3017         // Alpha is ignored.
3018
3019         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
3020         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
3021         
3022         guint32 *src = (guint32*)buffer;
3023         guint8 *dst = pixels;
3024         src += borderTop * srcWidth;    // skip top rows in src to get to first row of dst
3025         src += borderLeft;              // skip left pixels in src to get to first pixel of dst
3026         gint ii, jj;
3027         gint channels = gdk_pixbuf_get_n_channels (preview);
3028         gint stride = gdk_pixbuf_get_rowstride (preview);
3029         guint8 *tmp;
3030         for (ii = 0; ii < dstHeight; ii++)
3031         {
3032                 tmp = dst;
3033                 for (jj = 0; jj < dstWidth; jj++)
3034                 {
3035                         tmp[0] = src[0] >> 16;
3036                         tmp[1] = src[0] >> 8;
3037                         tmp[2] = src[0] >> 0;
3038                         tmp += channels;
3039                         src++;
3040                 }
3041                 dst += stride;
3042                 src += (srcWidth - dstWidth);   // skip to next row in src
3043         }
3044         // Got it, but hb_get_preview doesn't compensate for anamorphic, so lets
3045         // scale
3046         gint width, height, par_width, par_height;
3047         gboolean anamorphic = ghb_settings_get_bool (settings, "anamorphic");
3048         if (anamorphic)
3049         {
3050                 hb_set_anamorphic_size( title->job, &width, &height, &par_width, &par_height );
3051                 if (par_width > par_height)
3052                         dstWidth = dstWidth * par_width / par_height;
3053                 else
3054                         dstHeight = dstHeight * par_height / par_width;
3055         }
3056         
3057         g_debug("scaled %d x %d\n", dstWidth, dstHeight);
3058         GdkPixbuf *scaled_preview;
3059         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
3060         g_object_unref (preview);
3061         return scaled_preview;
3062 }
3063
3064 static void
3065 sanitize_volname(gchar *name)
3066 {
3067         gchar *a, *b;
3068
3069         a = b = name;
3070         while (*b)
3071         {
3072                 switch(*b)
3073                 {
3074                 case '<':
3075                         b++;
3076                         break;
3077                 case '>':
3078                         b++;
3079                         break;
3080                 default:
3081                         *a = *b;
3082                         a++; b++;
3083                         break;
3084                 }
3085         }
3086         *a = 0;
3087 }
3088
3089 gchar*
3090 ghb_dvd_volname(const gchar *device)
3091 {
3092         gchar *name;
3093         name = hb_dvd_name((gchar*)device);
3094         if (name != NULL)
3095         {
3096                 sanitize_volname(name);
3097                 return g_strdup(name);
3098         }
3099         return name;
3100 }