OSDN Git Service

LinGui: change extension from mp4 to m4v if there is an ac3 output track
[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 #if 0
569 const gchar*
570 ghb_get_rate_string(gint rate, gint type)
571 {
572         gint index;
573         
574         switch (type)
575         {
576                 case GHB_FRAMERATE:
577                 {
578                         index = search_rates(hb_video_rates, rate, hb_video_rates_count);
579                         if (index >= 0) return hb_video_rates[index].string;
580                 } break;
581                 case GHB_AUDIO_BITRATE:
582                 {
583                         rate /= 1000;
584                         index = search_rates(hb_audio_bitrates, rate, hb_audio_bitrates_count);
585                         if (index >= 0) return hb_audio_bitrates[index].string;
586                 } break;
587                 case GHB_AUDIO_SAMPLERATE:
588                 {
589                         index = search_rates(hb_audio_rates, rate, hb_audio_rates_count);
590                         if (index >= 0) return hb_audio_rates[index].string;
591                 } break;
592         }
593         return NULL;
594 }
595 #endif
596
597 static gboolean find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter);
598
599 static GtkListStore*
600 get_combo_box_store(GtkBuilder *builder, const gchar *name)
601 {
602         GtkComboBox *combo;
603         GtkListStore *store;
604
605         g_debug("get_combo_box_store() %s\n", name);
606         // First modify the combobox model to allow greying out of options
607         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
608         store = GTK_LIST_STORE(gtk_combo_box_get_model (combo));
609         return store;
610 }
611
612 static void
613 grey_combo_box_item(GtkBuilder *builder, const gchar *name, gint value, gboolean grey)
614 {
615         GtkListStore *store;
616         GtkTreeIter iter;
617         
618         store = get_combo_box_store(builder, name);
619         if (find_combo_item_by_int(GTK_TREE_MODEL(store), value, &iter))
620         {
621                 gtk_list_store_set(store, &iter, 
622                                                    1, !grey, 
623                                                    -1);
624         }
625 }
626
627 void
628 ghb_grey_combo_options(GtkBuilder *builder)
629 {
630         GtkWidget *widget;
631         gint container, track, titleindex, acodec;
632         gboolean httpopt;
633     hb_audio_config_t *audio = NULL;
634         
635         widget = GHB_WIDGET (builder, "title");
636         titleindex = ghb_widget_int(widget);
637         widget = GHB_WIDGET (builder, "audio_track");
638         track = ghb_widget_int(widget);
639         audio = get_hb_audio(titleindex, track);
640         widget = GHB_WIDGET (builder, "container");
641         container = ghb_widget_int(widget);
642         widget = GHB_WIDGET (builder, "http_optimize_mp4");
643         httpopt = ghb_widget_int(widget);
644
645         grey_combo_box_item(builder, "audio_codec", HB_ACODEC_FAAC, FALSE);
646         grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_FAAC, FALSE);
647         grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_FAAC, FALSE);
648         grey_combo_box_item(builder, "audio_codec", HB_ACODEC_LAME, FALSE);
649         grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_LAME, FALSE);
650         grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_LAME, FALSE);
651         grey_combo_box_item(builder, "audio_codec", HB_ACODEC_VORBIS, FALSE);
652         grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_VORBIS, FALSE);
653         grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_VORBIS, FALSE);
654
655         gboolean allow_ac3 = TRUE;
656         allow_ac3 = 
657                 !(container == HB_MUX_MP4 && httpopt) &&
658                 (container != HB_MUX_OGM);
659
660         if (allow_ac3)
661         {
662                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_AC3, FALSE);
663                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_AC3, FALSE);
664                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_AC3, FALSE);
665         }
666         else
667         {
668                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_AC3, TRUE);
669                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_AC3, TRUE);
670                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_AC3, TRUE);
671         }
672         if (audio && audio->in.codec != HB_ACODEC_AC3)
673         {
674                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_AC3, TRUE);
675         }
676         grey_combo_box_item(builder, "video_codec", HB_VCODEC_THEORA, FALSE);
677
678         widget = GHB_WIDGET (builder, "audio_codec");
679         acodec = ghb_widget_int(widget);
680         if (acodec != HB_ACODEC_AC3)
681         {
682                 grey_combo_box_item(builder, "audio_mix", 0, TRUE);
683         }
684         if (container == HB_MUX_MP4)
685         {
686                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_LAME, TRUE);
687                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_LAME, TRUE);
688                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_LAME, TRUE);
689                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_VORBIS, TRUE);
690                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_VORBIS, TRUE);
691                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_VORBIS, TRUE);
692                 grey_combo_box_item(builder, "video_codec", HB_VCODEC_THEORA, TRUE);
693         }
694         else if (container == HB_MUX_AVI)
695         {
696                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_FAAC, TRUE);
697                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_FAAC, TRUE);
698                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_FAAC, TRUE);
699                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_VORBIS, TRUE);
700                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_VORBIS, TRUE);
701                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_VORBIS, TRUE);
702                 grey_combo_box_item(builder, "video_codec", HB_VCODEC_THEORA, TRUE);
703         }
704         else if (container == HB_MUX_OGM)
705         {
706                 grey_combo_box_item(builder, "audio_codec", HB_ACODEC_FAAC, TRUE);
707                 grey_combo_box_item(builder, "pref_audio_codec1", HB_ACODEC_FAAC, TRUE);
708                 grey_combo_box_item(builder, "pref_audio_codec2", HB_ACODEC_FAAC, TRUE);
709         }
710
711         gboolean allow_mono = TRUE;
712         gboolean allow_stereo = TRUE;
713         gboolean allow_dolby = TRUE;
714         gboolean allow_dpl2 = TRUE;
715         gboolean allow_6ch = TRUE;
716         if (audio)
717         {
718                 allow_mono =
719                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
720                         (acodec != HB_ACODEC_LAME);
721                 gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
722                 allow_stereo =
723                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
724                 allow_dolby =
725                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
726                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
727                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
728                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
729                 allow_6ch =
730                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
731                         (acodec != HB_ACODEC_LAME) &&
732                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
733                         (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
734         }
735         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_MONO, !allow_mono);
736         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_STEREO, !allow_stereo);
737         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_DOLBY, !allow_dolby);
738         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_DOLBYPLII, !allow_dpl2);
739         grey_combo_box_item(builder, "audio_mix", HB_AMIXDOWN_6CH, !allow_6ch);
740 }
741
742 gint
743 ghb_get_best_mix(gint titleindex, gint track, gint acodec, gint mix)
744 {
745     hb_audio_config_t *audio = NULL;
746         gboolean allow_mono = TRUE;
747         gboolean allow_stereo = TRUE;
748         gboolean allow_dolby = TRUE;
749         gboolean allow_dpl2 = TRUE;
750         gboolean allow_6ch = TRUE;
751         
752         if (acodec & (HB_ACODEC_AC3 | HB_ACODEC_DCA))
753         {
754                 // Audio codec pass-thru.  No mixdown
755                 return 0;
756         }
757         audio = get_hb_audio(titleindex, track);
758         if (audio)
759         {
760                 allow_mono =
761                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
762                         (acodec != HB_ACODEC_LAME);
763                 gint layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
764                 allow_stereo =
765                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
766                 allow_dolby =
767                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
768                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
769                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
770                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
771                 allow_6ch =
772                         (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
773                         (acodec != HB_ACODEC_LAME) &&
774                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
775                         (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
776         }
777         gboolean greater = FALSE;
778         if (mix == 0) 
779         {
780                 // If no mix is specified, select the best available.
781                 mix = HB_AMIXDOWN_6CH;
782         }
783         if (mix == HB_AMIXDOWN_6CH)
784         {
785                 greater = TRUE;
786                 if (allow_6ch) return HB_AMIXDOWN_6CH;
787         }
788         if (mix == HB_AMIXDOWN_DOLBYPLII || greater)
789         {
790                 greater = TRUE;
791                 if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
792         }
793         if (mix == HB_AMIXDOWN_DOLBY || greater)
794         {
795                 greater = TRUE;
796                 if (allow_dolby) return HB_AMIXDOWN_DOLBY;
797         }
798         if (mix == HB_AMIXDOWN_STEREO || greater)
799         {
800                 greater = TRUE;
801                 if (allow_stereo) return HB_AMIXDOWN_STEREO;
802         }
803         if (mix == HB_AMIXDOWN_MONO || greater)
804         {
805                 greater = TRUE;
806                 if (allow_mono) return HB_AMIXDOWN_MONO;
807         }
808         if (allow_stereo) return HB_AMIXDOWN_STEREO;
809         if (allow_dolby) return HB_AMIXDOWN_DOLBY;
810         if (allow_dpl2) return HB_AMIXDOWN_DOLBYPLII;
811         if (allow_6ch) return HB_AMIXDOWN_6CH;
812         return 0;
813 }
814
815 // Set up the model for the combo box
816 static void
817 init_combo_box(GtkBuilder *builder, const gchar *name)
818 {
819         GtkComboBox *combo;
820         GtkListStore *store;
821         GtkCellRenderer *cell;
822
823         g_debug("init_combo_box() %s\n", name);
824         // First modify the combobox model to allow greying out of options
825         combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
826         // Store contains:
827         // 1 - String to display
828         // 2 - bool indicating whether the entry is selectable (grey or not)
829         // 3 - String that is used for presets
830         // 4 - Int value determined by backend
831         // 5 - String value determined by backend
832         store = gtk_list_store_new(5, G_TYPE_STRING, G_TYPE_BOOLEAN, 
833                                                            G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
834         gtk_combo_box_set_model(combo, GTK_TREE_MODEL(store));
835
836         gtk_cell_layout_clear(GTK_CELL_LAYOUT(combo));
837     cell = GTK_CELL_RENDERER(gtk_cell_renderer_text_new());
838     gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), cell, TRUE);
839     gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo), cell,
840       "text", 0, "sensitive", 1, NULL);
841 }       
842
843 static void
844 audio_bitrate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
845 {
846         GtkTreeIter iter;
847         GtkListStore *store;
848         gint ii;
849         
850         g_debug("audio_bitrate_opts_set ()\n");
851         store = get_combo_box_store(builder, name);
852         gtk_list_store_clear(store);
853         for (ii = 0; ii < count; ii++)
854         {
855                 gtk_list_store_append(store, &iter);
856                 gtk_list_store_set(store, &iter, 
857                                                    0, rates[ii].string, 
858                                                    1, TRUE, 
859                                                    2, rates[ii].string, 
860                                                    3, rates[ii].rate * 1000, 
861                                                    4, rates[ii].string, 
862                                                    -1);
863         }
864 }
865
866 static gboolean
867 audio_bitrate_opts_clean(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
868 {
869         GtkTreeIter iter;
870         GtkListStore *store;
871         gint ivalue;
872         gboolean done = FALSE;
873         gboolean changed = FALSE;
874         
875         g_debug("audio_bitrate_opts_clean ()\n");
876         store = get_combo_box_store(builder, name);
877         if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter))
878         {
879                 do
880                 {
881                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 3, &ivalue, -1);
882                         if (search_rates(rates, ivalue/1000, count) < 0)
883                         {
884                                 done = !gtk_list_store_remove(store, &iter);
885                                 changed = TRUE;
886                         }
887                         else
888                         {
889                                 done = !gtk_tree_model_iter_next (GTK_TREE_MODEL(store), &iter);
890                         }
891                 } while (!done);
892         }
893         return changed;
894 }
895
896 static void
897 audio_samplerate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
898 {
899         GtkTreeIter iter;
900         GtkListStore *store;
901         gint ii;
902         
903         g_debug("audio_samplerate_opts_set ()\n");
904         store = get_combo_box_store(builder, name);
905         gtk_list_store_clear(store);
906         // Add an item for "Same As Source"
907         gtk_list_store_append(store, &iter);
908         gtk_list_store_set(store, &iter, 
909                                            0, "Same as source", 
910                                            1, TRUE, 
911                                            2, "source", 
912                                            3, 0, 
913                                            4, "source", 
914                                            -1);
915         for (ii = 0; ii < count; ii++)
916         {
917                 gtk_list_store_append(store, &iter);
918                 gtk_list_store_set(store, &iter, 
919                                                    0, rates[ii].string, 
920                                                    1, TRUE, 
921                                                    2, rates[ii].string, 
922                                                    3, rates[ii].rate, 
923                                                    4, rates[ii].string, 
924                                                    -1);
925         }
926 }
927
928 static void
929 video_rate_opts_set(GtkBuilder *builder, const gchar *name, hb_rate_t *rates, gint count)
930 {
931         GtkTreeIter iter;
932         GtkListStore *store;
933         gint ii;
934         
935         g_debug("video_rate_opts_set ()\n");
936         store = get_combo_box_store(builder, name);
937         gtk_list_store_clear(store);
938         // Add an item for "Same As Source"
939         gtk_list_store_append(store, &iter);
940         gtk_list_store_set(store, &iter, 
941                                            0, "Same as source", 
942                                            1, TRUE, 
943                                            2, "source", 
944                                            3, 0, 
945                                            4, "source", 
946                                            -1);
947         for (ii = 0; ii < count; ii++)
948         {
949                 gchar *desc = "";
950                 gchar *option;
951                 if (strcmp(rates[ii].string, "23.976") == 0)
952                 {
953                         desc = "(NTSC Film)";
954                 }
955                 else if (strcmp(rates[ii].string, "25") == 0)
956                 {
957                         desc = "(PAL Film/Video)";
958                 }
959                 else if (strcmp(rates[ii].string, "29.97") == 0)
960                 {
961                         desc = "(NTSC Video)";
962                 }
963                 option = g_strdup_printf ("%s %s", rates[ii].string, desc);
964                 gtk_list_store_append(store, &iter);
965                 gtk_list_store_set(store, &iter, 
966                                                    0, option, 
967                                                    1, TRUE, 
968                                                    2, rates[ii].string, 
969                                                    3, rates[ii].rate, 
970                                                    4, rates[ii].string, 
971                                                    -1);
972                 g_free(option);
973         }
974 }
975
976 static void
977 mix_opts_set(GtkBuilder *builder, const gchar *name)
978 {
979         GtkTreeIter iter;
980         GtkListStore *store;
981         gint ii;
982         
983         g_debug("audio_bitrate_opts_set ()\n");
984         store = get_combo_box_store(builder, name);
985         gtk_list_store_clear(store);
986         gtk_list_store_append(store, &iter);
987         gtk_list_store_set(store, &iter, 
988                                            0, "None", 
989                                            1, TRUE, 
990                                            2, "none", 
991                                            3, 0, 
992                                            4, "none", 
993                                            -1);
994         for (ii = 0; ii < hb_audio_mixdowns_count; ii++)
995         {
996                 gtk_list_store_append(store, &iter);
997                 gtk_list_store_set(store, &iter, 
998                                                    0, hb_audio_mixdowns[ii].human_readable_name, 
999                                                    1, TRUE, 
1000                                                    2, hb_audio_mixdowns[ii].short_name, 
1001                                                    3, hb_audio_mixdowns[ii].amixdown, 
1002                                                    4, hb_audio_mixdowns[ii].internal_name, 
1003                                                    -1);
1004         }
1005 }
1006
1007 static void
1008 language_opts_set(GtkBuilder *builder, const gchar *name)
1009 {
1010         GtkTreeIter iter;
1011         GtkListStore *store;
1012         gint ii;
1013         
1014         g_debug("audio_bitrate_opts_set ()\n");
1015         store = get_combo_box_store(builder, name);
1016         gtk_list_store_clear(store);
1017         for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1018         {
1019                 gtk_list_store_append(store, &iter);
1020                 gtk_list_store_set(store, &iter, 
1021                                                    0, language_table[ii].eng_name, 
1022                                                    1, TRUE, 
1023                                                    2, language_table[ii].iso639_2, 
1024                                                    3, ii, 
1025                                                    4, language_table[ii].iso639_1, 
1026                                                    -1);
1027         }
1028 }
1029
1030 void
1031 title_opts_set(GtkBuilder *builder, const gchar *name)
1032 {
1033         GtkTreeIter iter;
1034         GtkListStore *store;
1035         hb_list_t  * list;
1036         hb_title_t * title;
1037         gint ii;
1038         gint count = 0;
1039         
1040         g_debug("title_opts_set ()\n");
1041         store = get_combo_box_store(builder, name);
1042         gtk_list_store_clear(store);
1043         if (h != NULL)
1044         {
1045                 list = hb_get_titles( h );
1046                 count = hb_list_count( list );
1047                 if (count > 100) count = 100;
1048         }
1049         if( count <= 0 )
1050         {
1051                 // No titles.  Fill in a default.
1052                 gtk_list_store_append(store, &iter);
1053                 gtk_list_store_set(store, &iter, 
1054                                                    0, "No Titles", 
1055                                                    1, TRUE, 
1056                                                    2, "none", 
1057                                                    3, -1, 
1058                                                    4, "none", 
1059                                                    -1);
1060                 return;
1061         }
1062         for (ii = 0; ii < count; ii++)
1063         {
1064                 gchar *option;
1065                 
1066                 title = (hb_title_t*)hb_list_item(list, ii);
1067                 option  = g_strdup_printf ("%d - %02dh%02dm%02ds",
1068                         title->index, title->hours, title->minutes, title->seconds);
1069                 gtk_list_store_append(store, &iter);
1070                 gtk_list_store_set(store, &iter, 
1071                                                    0, option, 
1072                                                    1, TRUE, 
1073                                                    2, option, 
1074                                                    3, ii, 
1075                                                    4, option, 
1076                                                    -1);
1077         }
1078 }
1079
1080 static gboolean
1081 find_combo_item_by_int(GtkTreeModel *store, gint value, GtkTreeIter *iter)
1082 {
1083         gint ivalue;
1084         gboolean foundit = FALSE;
1085         
1086         if (gtk_tree_model_get_iter_first (store, iter))
1087         {
1088                 do
1089                 {
1090                         gtk_tree_model_get(store, iter, 3, &ivalue, -1);
1091                         if (value == ivalue)
1092                         {
1093                                 foundit = TRUE;
1094                                 break;
1095                         }
1096                 } while (gtk_tree_model_iter_next (store, iter));
1097         }
1098         return foundit;
1099 }
1100
1101 static gboolean
1102 audio_rate_opts_add(GtkBuilder *builder, const gchar *name, gint rate)
1103 {
1104         GtkTreeIter iter;
1105         GtkListStore *store;
1106         gchar *str;
1107         
1108         g_debug("audio_rate_opts_add ()\n");
1109         store = get_combo_box_store(builder, name);
1110         if (!find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
1111         {
1112                 str = g_strdup_printf ("%.8g", (gdouble)rate/1000.0);
1113                 gtk_list_store_append(store, &iter);
1114                 gtk_list_store_set(store, &iter, 
1115                                                    0, str, 
1116                                                    1, TRUE, 
1117                                                    2, str, 
1118                                                    3, rate, 
1119                                                    4, str, 
1120                                                    -1);
1121                 return TRUE;
1122         }
1123         return FALSE;
1124 }
1125
1126 #if 0
1127 static gboolean
1128 audio_rate_opts_remove(GtkBuilder *builder, const gchar *name, gint rate)
1129 {
1130         GtkTreeIter iter;
1131         GtkListStore *store;
1132         
1133         g_debug("audio_rate_opts_remove ()\n");
1134         store = get_combo_box_store(builder, name);
1135         if (find_combo_item_by_int(GTK_TREE_MODEL(store), rate, &iter))
1136         {
1137                 gtk_list_store_remove (store, &iter);
1138                 return TRUE;
1139         }
1140         return FALSE;
1141 }
1142 #endif
1143
1144 void
1145 audio_track_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1146 {
1147         GtkTreeIter iter;
1148         GtkListStore *store;
1149         hb_list_t  * list;
1150         hb_title_t * title;
1151     hb_audio_config_t * audio;
1152         gint ii;
1153         gint count = 0;
1154         
1155         g_debug("audio_track_opts_set ()\n");
1156         store = get_combo_box_store(builder, name);
1157         gtk_list_store_clear(store);
1158         if (h != NULL)
1159         {
1160                 list = hb_get_titles( h );
1161             title = (hb_title_t*)hb_list_item( list, titleindex );
1162                 if (title != NULL)
1163                 {
1164                         count = hb_list_count( title->list_audio );
1165                 }
1166         }
1167         if (count > 10) count = 10;
1168         if( count <= 0 )
1169         {
1170                 // No audio. set some default
1171                 gtk_list_store_append(store, &iter);
1172                 gtk_list_store_set(store, &iter, 
1173                                                    0, "No Audio", 
1174                                                    1, TRUE, 
1175                                                    2, "none", 
1176                                                    3, -1, 
1177                                                    4, "none", 
1178                                                    -1);
1179                 return;
1180         }
1181         for (ii = 0; ii < count; ii++)
1182         {
1183         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, ii );
1184                 gtk_list_store_append(store, &iter);
1185                 gtk_list_store_set(store, &iter, 
1186                                                    0, audio->lang.description, 
1187                                                    1, TRUE, 
1188                                                    2, audio->lang.description, 
1189                                                    3, ii, 
1190                                                    4, audio->lang.description, 
1191                                                    -1);
1192         }
1193 }
1194
1195 void
1196 subtitle_opts_set(GtkBuilder *builder, const gchar *name, gint titleindex)
1197 {
1198         GtkTreeIter iter;
1199         GtkListStore *store;
1200         hb_list_t  * list;
1201         hb_title_t * title;
1202     hb_subtitle_t * subtitle;
1203         gint ii;
1204         gint count = 0;
1205         
1206         g_debug("subtitle_opts_set ()\n");
1207         store = get_combo_box_store(builder, name);
1208         gtk_list_store_clear(store);
1209         if (h != NULL)
1210         {
1211                 list = hb_get_titles( h );
1212             title = (hb_title_t*)hb_list_item( list, titleindex );
1213                 if (title != NULL)
1214                 {
1215                         count = hb_list_count( title->list_subtitle );
1216                 }
1217         }
1218         if (count > 10) count = 10;
1219         // Add options for "none" and "autoselect"
1220         gtk_list_store_append(store, &iter);
1221         gtk_list_store_set(store, &iter, 
1222                                            0, "None", 
1223                                            1, TRUE, 
1224                                            2, "none", 
1225                                            3, -2, 
1226                                            4, "none", 
1227                                            -1);
1228         gtk_list_store_append(store, &iter);
1229         gtk_list_store_set(store, &iter, 
1230                                            0, "Same As Audio", 
1231                                            1, TRUE, 
1232                                            2, "auto", 
1233                                            3, -1, 
1234                                            4, "auto", 
1235                                            -1);
1236         for (ii = 0; ii < count; ii++)
1237         {
1238         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, ii );
1239                 gtk_list_store_append(store, &iter);
1240                 gtk_list_store_set(store, &iter, 
1241                                                    0, subtitle->lang, 
1242                                                    1, TRUE, 
1243                                                    2, subtitle->iso639_2, 
1244                                                    3, ii, 
1245                                                    4, subtitle->iso639_2, 
1246                                                    -1);
1247         }
1248         if (titleindex == -1)
1249         {
1250                 for (ii = 0; ii < LANG_TABLE_SIZE; ii++)
1251                 {
1252                         gtk_list_store_append(store, &iter);
1253                         gtk_list_store_set(store, &iter, 
1254                                 0, language_table[ii].eng_name, 
1255                                 1, TRUE, 
1256                                 2, language_table[ii].iso639_2, 
1257                                 3, ii, 
1258                                 4, language_table[ii].iso639_2, 
1259                                 -1);
1260                 }
1261         }
1262 }
1263
1264 gint
1265 ghb_longest_title()
1266 {
1267         hb_list_t  * list;
1268         hb_title_t * title;
1269         gint ii;
1270         gint count = 0;
1271         guint64 longest = 0;
1272         gint titleindex = 0;
1273         
1274         g_debug("ghb_longest_title ()\n");
1275         if (h == NULL) return 0;
1276         list = hb_get_titles( h );
1277         count = hb_list_count( list );
1278         if (count > 100) count = 100;
1279         for (ii = 0; ii < count; ii++)
1280         {
1281                 title = (hb_title_t*)hb_list_item(list, ii);
1282                 if (title->duration > longest)
1283                 {
1284                         titleindex = ii;
1285                         longest = title->duration;
1286                 }
1287         }
1288         return titleindex;
1289 }
1290
1291 gint
1292 ghb_find_audio_track(gint titleindex, const gchar *lang, gint acodec)
1293 {
1294         hb_list_t  * list;
1295         hb_title_t * title;
1296     hb_audio_config_t * audio;
1297         gint ii;
1298         gint count = 0;
1299         gint track = 0;
1300         
1301         g_debug("find_audio_track ()\n");
1302         if (h != NULL)
1303         {
1304                 list = hb_get_titles( h );
1305             title = (hb_title_t*)hb_list_item( list, titleindex );
1306                 if (title != NULL)
1307                 {
1308                         count = hb_list_count( title->list_audio );
1309                 }
1310         }
1311         if (count > 10) count = 10;
1312         for (ii = 0; ii < count; ii++)
1313         {
1314         audio = (hb_audio_config_t*)hb_list_audio_config_item( title->list_audio, ii );
1315                 if ((strcmp(lang, audio->lang.iso639_2) == 0) ||
1316                         (strcmp(lang, "und") == 0))
1317                 {
1318                         // Candidate track.  Will use if no better match found
1319                         track = ii;
1320                         if (audio->in.codec == acodec)
1321                         {
1322                                 // Perfect match
1323                                 return track;
1324                         }
1325                 }
1326         }
1327         return track;
1328 }
1329
1330 static void
1331 generic_opts_set(GtkBuilder *builder, const gchar *name, combo_opts_t *opts)
1332 {
1333         GtkTreeIter iter;
1334         GtkListStore *store;
1335         gint ii;
1336         
1337         g_debug("generic_opts_set ()\n");
1338         store = get_combo_box_store(builder, name);
1339         gtk_list_store_clear(store);
1340         for (ii = 0; ii < opts->count; ii++)
1341         {
1342                 gtk_list_store_append(store, &iter);
1343                 gtk_list_store_set(store, &iter, 
1344                                                    0, opts->map[ii].option, 
1345                                                    1, TRUE, 
1346                                                    2, opts->map[ii].shortOpt, 
1347                                                    3, opts->map[ii].ivalue, 
1348                                                    4, opts->map[ii].svalue, 
1349                                                    -1);
1350         }
1351 }
1352
1353 void
1354 ghb_update_ui_combo_box(GtkBuilder *builder, const gchar *name, gint user_data, gboolean all)
1355 {
1356         GtkComboBox *combo = NULL;
1357         gint signal_id;
1358         gint handler_id = 0;
1359
1360         g_debug("ghb_update_ui_combo_box() %s\n", name);
1361         if (name != NULL)
1362         {               
1363                 // Clearing a combo box causes a rash of "changed" events, even when
1364                 // the active item is -1 (inactive).  To control things, I'm disabling
1365                 // the event till things are settled down.
1366                 combo = GTK_COMBO_BOX(GHB_WIDGET(builder, name));
1367                 signal_id = g_signal_lookup("changed", GTK_TYPE_COMBO_BOX);
1368                 if (signal_id > 0)
1369                 {
1370                         // Valid signal id found.  This should always succeed.
1371                         handler_id = g_signal_handler_find ((gpointer)combo, G_SIGNAL_MATCH_ID, 
1372                                                                                                 signal_id, 0, 0, 0, 0);
1373                         if (handler_id > 0)
1374                         {
1375                                 // This should also always succeed
1376                                 g_signal_handler_block ((gpointer)combo, handler_id);
1377                         }
1378                 }
1379         }       
1380         if (all || strcmp(name, "audio_bitrate") == 0)
1381                 audio_bitrate_opts_set(builder, "audio_bitrate", hb_audio_bitrates, hb_audio_bitrates_count);
1382         if (all || strcmp(name, "pref_audio_bitrate1") == 0)
1383                 audio_bitrate_opts_set(builder, "pref_audio_bitrate1", hb_audio_bitrates, hb_audio_bitrates_count);
1384         if (all || strcmp(name, "pref_audio_bitrate2") == 0)
1385                 audio_bitrate_opts_set(builder, "pref_audio_bitrate2", hb_audio_bitrates, hb_audio_bitrates_count);
1386         if (all || strcmp(name, "audio_sample_rate") == 0)
1387                 audio_samplerate_opts_set(builder, "audio_sample_rate", hb_audio_rates, hb_audio_rates_count);
1388         if (all || strcmp(name, "pref_audio_rate1") == 0)
1389                 audio_samplerate_opts_set(builder, "pref_audio_rate1", hb_audio_rates, hb_audio_rates_count);
1390         if (all || strcmp(name, "pref_audio_rate2") == 0)
1391                 audio_samplerate_opts_set(builder, "pref_audio_rate2", hb_audio_rates, hb_audio_rates_count);
1392         if (all || strcmp(name, "framerate") == 0)
1393                 video_rate_opts_set(builder, "framerate", hb_video_rates, hb_video_rates_count);
1394         if (all || strcmp(name, "audio_mix") == 0)
1395                 mix_opts_set(builder, "audio_mix");
1396         if (all || strcmp(name, "pref_audio_mix1") == 0)
1397                 mix_opts_set(builder, "pref_audio_mix1");
1398         if (all || strcmp(name, "pref_audio_mix2") == 0)
1399                 mix_opts_set(builder, "pref_audio_mix2");
1400         if (all || strcmp(name, "pref_source_audio_lang") == 0)
1401                 language_opts_set(builder, "pref_source_audio_lang");
1402         if (all || strcmp(name, "subtitle_lang") == 0)
1403                 subtitle_opts_set(builder, "subtitle_lang", user_data);
1404         if (all || strcmp(name, "title") == 0)
1405                 title_opts_set(builder, "title");
1406         if (all || strcmp(name, "audio_track") == 0)
1407                 audio_track_opts_set(builder, "audio_track", user_data);
1408         if (all || strcmp(name, "container") == 0)
1409                 generic_opts_set(builder, "container", &container_opts);
1410         if (all || strcmp(name, "deinterlace") == 0)
1411                 generic_opts_set(builder, "deinterlace", &deint_opts);
1412         if (all || strcmp(name, "denoise") == 0)
1413                 generic_opts_set(builder, "denoise", &denoise_opts);
1414         if (all || strcmp(name, "video_codec") == 0)
1415                 generic_opts_set(builder, "video_codec", &vcodec_opts);
1416         if (all || strcmp(name, "audio_codec") == 0)
1417                 generic_opts_set(builder, "audio_codec", &acodec_opts);
1418         if (all || strcmp(name, "pref_audio_codec1") == 0)
1419                 generic_opts_set(builder, "pref_audio_codec1", &pref_acodec_opts);
1420         if (all || strcmp(name, "pref_audio_codec2") == 0)
1421                 generic_opts_set(builder, "pref_audio_codec2", &pref_acodec_opts);
1422         if (all || strcmp(name, "pref_source_audio_codec") == 0)
1423                 generic_opts_set(builder, "pref_source_audio_codec", &source_acodec_opts);
1424         if (all || strcmp(name, "x264_direct") == 0)
1425                 generic_opts_set(builder, "x264_direct", &direct_opts);
1426         if (all || strcmp(name, "x264_me") == 0)
1427                 generic_opts_set(builder, "x264_me", &me_opts);
1428         if (all || strcmp(name, "x264_subme") == 0)
1429                 generic_opts_set(builder, "x264_subme", &subme_opts);
1430         if (all || strcmp(name, "x264_analyse") == 0)
1431                 generic_opts_set(builder, "x264_analyse", &analyse_opts);
1432         if (all || strcmp(name, "x264_trellis") == 0)
1433                 generic_opts_set(builder, "x264_trellis", &trellis_opts);
1434         if (handler_id > 0)
1435         {
1436                 g_signal_handler_unblock ((gpointer)combo, handler_id);
1437         }
1438 }
1439         
1440 static void
1441 init_ui_combo_boxes(GtkBuilder *builder)
1442 {
1443         init_combo_box(builder, "audio_bitrate");
1444         init_combo_box(builder, "pref_audio_bitrate1");
1445         init_combo_box(builder, "pref_audio_bitrate2");
1446         init_combo_box(builder, "audio_sample_rate");
1447         init_combo_box(builder, "pref_audio_rate1");
1448         init_combo_box(builder, "pref_audio_rate2");
1449         init_combo_box(builder, "framerate");
1450         init_combo_box(builder, "audio_mix");
1451         init_combo_box(builder, "pref_audio_mix1");
1452         init_combo_box(builder, "pref_audio_mix2");
1453         init_combo_box(builder, "pref_source_audio_lang");
1454         init_combo_box(builder, "subtitle_lang");
1455         init_combo_box(builder, "title");
1456         init_combo_box(builder, "audio_track");
1457         init_combo_box(builder, "container");
1458         init_combo_box(builder, "deinterlace");
1459         init_combo_box(builder, "denoise");
1460         init_combo_box(builder, "video_codec");
1461         init_combo_box(builder, "audio_codec");
1462         init_combo_box(builder, "pref_audio_codec1");
1463         init_combo_box(builder, "pref_audio_codec2");
1464         init_combo_box(builder, "pref_source_audio_codec");
1465         init_combo_box(builder, "x264_direct");
1466         init_combo_box(builder, "x264_me");
1467         init_combo_box(builder, "x264_subme");
1468         init_combo_box(builder, "x264_analyse");
1469         init_combo_box(builder, "x264_trellis");
1470 }
1471         
1472 static const char * turbo_opts = 
1473         "ref=1:subme=1:me=dia:analyse=none:trellis=0:"
1474         "no-fast-pskip=0:8x8dct=0:weightb=0";
1475
1476 // Construct the x264 options string
1477 // The result is allocated, so someone must free it at some point.
1478 gchar*
1479 ghb_build_x264opts_string(GHashTable *settings)
1480 {
1481         GString *x264opts = g_string_new("");
1482         gint refs = ghb_settings_get_int(settings, "x264_refs");
1483         if (refs != 1)
1484         {
1485                 g_string_append_printf(x264opts, "ref=%d:", refs);
1486         }
1487         if (refs > 1)
1488         {
1489                 if (ghb_settings_get_bool(settings, "x264_mixed_refs"))
1490                 {
1491                         g_string_append(x264opts, "mixed-refs=1:");
1492                 }
1493         }
1494         gint subme = ghb_settings_get_int(settings, "x264_subme");
1495         if (subme != 5) // 5 is default
1496         {
1497                 g_string_append_printf(x264opts, "subme=%d:", subme);
1498         }
1499         gint bframes = ghb_settings_get_int(settings, "x264_bframes");
1500         if (bframes > 0)
1501         {
1502                 g_string_append_printf(x264opts, "bframes=%d:", bframes);
1503                 if (ghb_settings_get_bool(settings, "x264_weighted_bframes"))
1504                 {
1505                         g_string_append(x264opts, "weightb=1:");
1506                 }
1507                 if (subme >= 6)
1508                 {
1509                         if (ghb_settings_get_bool(settings, "x264_brdo"))
1510                         {
1511                                 g_string_append(x264opts, "brdo=1:");
1512                         }
1513                 }
1514                 if (ghb_settings_get_bool(settings, "x264_bime"))
1515                 {
1516                         g_string_append(x264opts, "bime=1:");
1517                 }
1518         }
1519         if (bframes > 1)
1520         {
1521                 if (ghb_settings_get_bool(settings, "x264_bpyramid"))
1522                 {
1523                         g_string_append(x264opts, "b-pyramid=1:");
1524                 }
1525         }
1526         if (ghb_settings_get_bool(settings, "x264_no_fast_pskip"))
1527         {
1528                 g_string_append(x264opts, "no-fast-pskip=1:");
1529         }
1530         if (ghb_settings_get_bool(settings, "x264_no_dct_decimate"))
1531         {
1532                 g_string_append(x264opts, "no-dct-decimate=1:");
1533         }
1534         if (!ghb_settings_get_bool(settings, "x264_cabac"))
1535         {
1536                 g_string_append(x264opts, "cabac=0:");
1537         }
1538         else
1539         {
1540                 gint trellis = ghb_settings_get_int(settings, "x264_trellis");
1541                 if (trellis != 0); // != None
1542                 {
1543                         g_string_append_printf(x264opts, "trellis=%d:", trellis);
1544                 }
1545         }
1546         gint dba, dbb;
1547         dba = ghb_settings_get_int(settings, "x264_deblock_alpha");
1548         dbb = ghb_settings_get_int(settings, "x264_deblock_beta");
1549         if (dba != 0 || dbb != 0)
1550         {
1551                 g_string_append_printf(x264opts, "deblock=%d,%d:", dba, dbb);
1552         }
1553         const gchar *me = ghb_settings_get_string(settings, "x264_me");
1554         g_string_append_printf(x264opts, "me=%s:", me);
1555         gint analyse = ghb_settings_get_int(settings, "x264_analyse");
1556         if (analyse != 0) // != Some
1557         {
1558                 g_string_append_printf(x264opts, "analyse=%s:", 
1559                                                            ghb_settings_get_string(settings, "x264_analyse"));
1560         }
1561         if (analyse != 1) // != none
1562         {
1563                 gint direct = ghb_settings_get_int(settings, "x264_direct");
1564                 if (direct != 1) // !spatial
1565                 {
1566                         g_string_append_printf(x264opts, "direct=%s:", 
1567                                                                    ghb_settings_get_string(settings, "x264_direct"));
1568                 }
1569         }
1570         g_string_append_printf(x264opts, "merange=%d:", 
1571                                                    ghb_settings_get_int(settings, "x264_merange"));
1572
1573         const gchar *opts = ghb_settings_get_string(settings, "x264_options");
1574         if (opts != NULL && opts[0] != 0)
1575         {
1576                 g_string_append_printf(x264opts, "%s:", opts);
1577         }
1578         // strip the trailing ":"
1579         gchar *result;
1580         gint len;
1581         result = g_string_free(x264opts, FALSE);
1582         len = strlen(result);
1583         if (len > 0) result[len - 1] = 0;
1584         return result;
1585 }
1586
1587 gchar **
1588 ghb_get_chapters(gint titleindex)
1589 {
1590         hb_list_t  * list;
1591         hb_title_t * title;
1592     hb_chapter_t * chapter;
1593         gint count, ii;
1594         gchar **result = NULL;
1595         
1596         g_debug("ghb_get_chapters (title = %d)\n", titleindex);
1597         if (h == NULL) return NULL;
1598         list = hb_get_titles( h );
1599     title = (hb_title_t*)hb_list_item( list, titleindex );
1600         if (title == NULL) return NULL;
1601         count = hb_list_count( title->list_chapter );
1602         result = g_malloc((count+1) * sizeof(gchar*));
1603         for (ii = 0; ii < count; ii++)
1604         {
1605                 chapter = hb_list_item(title->list_chapter, ii);
1606                 if (chapter == NULL) break;
1607                 if (chapter->title == NULL || chapter->title[0] == 0)
1608                         result[ii] = g_strdup_printf ("Chapter %2d", ii);
1609                 else 
1610                         result[ii] = g_strdup(chapter->title);
1611         }
1612         result[ii] = NULL;
1613         return result;
1614 }
1615
1616 gboolean
1617 ghb_ac3_in_audio_list(GSList *audio_list)
1618 {
1619         GSList *link;
1620
1621         link = audio_list;
1622         while (link != NULL)
1623         {
1624                 GHashTable *asettings;
1625                 gint acodec;
1626
1627                 asettings = (GHashTable*)link->data;
1628                 acodec = ghb_settings_get_int(asettings, "audio_codec");
1629                 if (acodec == HB_ACODEC_AC3)
1630                         return TRUE;
1631                 link = link->next;
1632         }
1633         return FALSE;
1634 }
1635
1636 gboolean
1637 ghb_set_passthru_rate_opts(GtkBuilder *builder, gint bitrate)
1638 {
1639         gboolean changed = FALSE;
1640         changed = audio_rate_opts_add(builder, "audio_bitrate", bitrate);
1641         return changed;
1642 }
1643
1644 gboolean
1645 ghb_set_default_rate_opts(GtkBuilder *builder)
1646 {
1647         gboolean changed = FALSE;
1648         changed = audio_bitrate_opts_clean(builder, "audio_bitrate", hb_audio_bitrates, hb_audio_bitrates_count);
1649         return changed;
1650 }
1651
1652 static ghb_status_t hb_status;
1653
1654 void
1655 ghb_backend_init(GtkBuilder *builder, gint debug, gint update)
1656 {
1657     /* Init libhb */
1658     h = hb_init( debug, update );
1659         // Set up the list model for the combos
1660         init_ui_combo_boxes(builder);
1661         // Populate all the combos
1662         ghb_update_ui_combo_box(builder, NULL, 0, TRUE);
1663 }
1664
1665 void
1666 ghb_backend_scan(const gchar *path, gint titleindex)
1667 {
1668     hb_scan( h, path, titleindex );
1669         hb_status.state |= GHB_STATE_SCANNING;
1670 }
1671
1672 static void 
1673 track_state()
1674 {
1675     hb_state_t s;
1676         static gint scan_complete_count = 0;
1677         gint scans;
1678
1679     hb_get_state( h, &s );
1680         scans = hb_get_scancount(h);
1681         if (scans > scan_complete_count)
1682         {
1683                 hb_status.state &= ~GHB_STATE_SCANNING;
1684                 hb_status.state |= GHB_STATE_SCANDONE;
1685                 scan_complete_count = hb_get_scancount(h);
1686         }
1687         switch( s.state )
1688     {
1689         case HB_STATE_IDLE:
1690             /* Nothing to do */
1691             break;
1692
1693 #define p s.param.scanning
1694         case HB_STATE_SCANNING:
1695                 {
1696                         hb_status.state |= GHB_STATE_SCANNING;
1697                         hb_status.title_count = p.title_count;
1698                         hb_status.title_cur = p.title_cur;
1699                 } break;
1700 #undef p
1701
1702         case HB_STATE_SCANDONE:
1703         {
1704                         hb_status.state &= ~GHB_STATE_SCANNING;
1705                         hb_status.state |= GHB_STATE_SCANDONE;
1706         } break;
1707
1708 #define p s.param.working
1709         case HB_STATE_WORKING:
1710                         hb_status.state |= GHB_STATE_WORKING;
1711                         hb_status.state &= ~GHB_STATE_PAUSED;
1712                         hb_status.job_cur = p.job_cur;
1713                         hb_status.job_count = p.job_count;
1714                         hb_status.progress = p.progress;
1715                         hb_status.rate_cur = p.rate_cur;
1716                         hb_status.rate_avg = p.rate_avg;
1717                         hb_status.hours = p.hours;
1718                         hb_status.minutes = p.minutes;
1719                         hb_status.seconds = p.seconds;
1720                         hb_status.unique_id = p.sequence_id & 0xFFFFFF;
1721             break;
1722 #undef p
1723
1724         case HB_STATE_PAUSED:
1725                         hb_status.state |= GHB_STATE_PAUSED;
1726             break;
1727                                 
1728 #define p s.param.muxing
1729         case HB_STATE_MUXING:
1730         {
1731                         hb_status.state |= GHB_STATE_MUXING;
1732         } break;
1733 #undef p
1734
1735 #define p s.param.workdone
1736         case HB_STATE_WORKDONE:
1737                 {
1738             hb_job_t *job;
1739
1740                         hb_status.state |= GHB_STATE_WORKDONE;
1741                         hb_status.state &= ~GHB_STATE_MUXING;
1742                         hb_status.state &= ~GHB_STATE_PAUSED;
1743                         hb_status.state &= ~GHB_STATE_WORKING;
1744                         hb_status.error = p.error;
1745                         // Delete all remaining jobs of this encode.
1746                         // An encode can be composed of multiple associated jobs.
1747                         // When a job is stopped, libhb removes it from the job list,
1748                         // but does not remove other jobs that may be associated with it.
1749                         // Associated jobs are taged in the sequence id.
1750             while (((job = hb_job(h, 0)) != NULL) && ((job->sequence_id >> 24) != 0) ) 
1751                 hb_rem( h, job );
1752                 } break;
1753 #undef p
1754     }
1755 }
1756
1757 gint
1758 ghb_backend_events(signal_user_data_t *ud, gint *unique_id)
1759 {
1760         gchar *status;
1761         GtkProgressBar *progress;
1762         
1763         if (h == NULL) return GHB_EVENT_NONE;
1764         track_state();
1765         progress = GTK_PROGRESS_BAR(GHB_WIDGET (ud->builder, "progressbar"));
1766         *unique_id = hb_status.unique_id;
1767         if (hb_status.state & GHB_STATE_SCANNING)
1768         {
1769                 status = g_strdup_printf ("Scanning title %d of %d...", 
1770                                                                   hb_status.title_cur, hb_status.title_count );
1771                 gtk_progress_bar_set_text (progress, status);
1772                 g_free(status);
1773                 gtk_progress_bar_set_fraction (progress, 
1774                         (gdouble)hb_status.title_cur / hb_status.title_count);
1775         }
1776         else if (hb_status.state & GHB_STATE_SCANDONE)
1777         {
1778                 status = g_strdup_printf ("Scan done"); 
1779                 gtk_progress_bar_set_text (progress, status);
1780                 g_free(status);
1781                 gtk_progress_bar_set_fraction (progress, 1.0);
1782                 hb_status.state &= ~GHB_STATE_SCANDONE;
1783                 return GHB_EVENT_SCAN_DONE;
1784         }
1785         else if (hb_status.state & GHB_STATE_WORKING)
1786         {
1787                 if(hb_status.seconds > -1)
1788                 {
1789                         status= g_strdup_printf(
1790                                 "Encoding: task %d of %d, %.2f %%"
1791                                 " (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)",
1792                                 hb_status.job_cur, hb_status.job_count, 
1793                                 100.0 * hb_status.progress,
1794                                 hb_status.rate_cur, hb_status.rate_avg, hb_status.hours, 
1795                                 hb_status.minutes, hb_status.seconds );
1796                 }
1797                 else
1798                 {
1799                         status= g_strdup_printf(
1800                                 "Encoding: task %d of %d, %.2f %%",
1801                                 hb_status.job_cur, hb_status.job_count, 
1802                                 100.0 * hb_status.progress );
1803                 }
1804                 gtk_progress_bar_set_text (progress, status);
1805                 gtk_progress_bar_set_fraction (progress, hb_status.progress);
1806                 g_free(status);
1807                 return GHB_EVENT_WORKING;
1808         }
1809         else if (hb_status.state & GHB_STATE_WORKDONE)
1810         {
1811                 switch( hb_status.error )
1812                 {
1813                         case HB_ERROR_NONE:
1814                                 gtk_progress_bar_set_text( progress, "Rip done!" );
1815                                 break;
1816                         case HB_ERROR_CANCELED:
1817                                 gtk_progress_bar_set_text( progress, "Rip canceled." );
1818                                 return GHB_EVENT_WORK_CANCELED;
1819                                 break;
1820                         default:
1821                                 gtk_progress_bar_set_text( progress, "Rip failed.");
1822                 }
1823                 gtk_progress_bar_set_fraction (progress, 1.0);
1824                 hb_status.state &= ~GHB_STATE_WORKDONE;
1825                 return GHB_EVENT_WORK_DONE;
1826         }
1827         else if (hb_status.state & GHB_STATE_PAUSED)
1828         {
1829                 status = g_strdup_printf ("Paused"); 
1830                 gtk_progress_bar_set_text (progress, status);
1831                 g_free(status);
1832                 return GHB_EVENT_PAUSED;
1833         }
1834         else if (hb_status.state & GHB_STATE_MUXING)
1835         {
1836                 gtk_progress_bar_set_text(progress, "Muxing: this may take awhile...");
1837         }
1838         return GHB_EVENT_NONE;
1839 }
1840
1841 gboolean
1842 ghb_get_title_info(ghb_title_info_t *tinfo, gint titleindex)
1843 {
1844         hb_list_t  * list;
1845         hb_title_t * title;
1846         
1847     if (h == NULL) return FALSE;
1848         list = hb_get_titles( h );
1849         if( !hb_list_count( list ) )
1850         {
1851                 /* No valid title, stop right there */
1852                 return FALSE;
1853         }
1854
1855     title = hb_list_item( list, titleindex );
1856         if (title == NULL) return FALSE;        // Bad titleindex
1857         tinfo->width = title->width;
1858         tinfo->height = title->height;
1859         memcpy(tinfo->crop, title->crop, 4 * sizeof(int));
1860         // Don't allow crop to 0
1861         if (title->crop[0] + title->crop[1] >= title->height)
1862                 title->crop[0] = title->crop[1] = 0;
1863         if (title->crop[2] + title->crop[3] >= title->width)
1864                 title->crop[2] = title->crop[3] = 0;
1865         tinfo->num_chapters = hb_list_count(title->list_chapter);
1866         tinfo->rate_base = title->rate_base;
1867         tinfo->rate = title->rate;
1868         hb_reduce(&(tinfo->aspect_n), &(tinfo->aspect_d), 
1869                                 title->width * title->pixel_aspect_width, 
1870                                 title->height * title->pixel_aspect_height);
1871         tinfo->hours = title->hours;
1872         tinfo->minutes = title->minutes;
1873         tinfo->seconds = title->seconds;
1874         return TRUE;
1875 }
1876
1877 gboolean
1878 ghb_get_audio_info(ghb_audio_info_t *ainfo, gint titleindex, gint audioindex)
1879 {
1880     hb_audio_config_t *audio;
1881         
1882         audio = get_hb_audio(titleindex, audioindex);
1883         if (audio == NULL) return FALSE; // Bad audioindex
1884         ainfo->codec = audio->in.codec;
1885         ainfo->bitrate = audio->in.bitrate;
1886         ainfo->samplerate = audio->in.samplerate;
1887         return TRUE;
1888 }
1889
1890 gboolean
1891 ghb_audio_is_passthru(gint acodec)
1892 {
1893         g_debug("ghb_audio_is_passthru () \n");
1894         g_debug("acodec %d\n", acodec);
1895         return (acodec == HB_ACODEC_AC3);
1896 }
1897
1898 gint
1899 ghb_get_default_acodec()
1900 {
1901         return HB_ACODEC_FAAC;
1902 }
1903
1904 void
1905 ghb_set_scale(signal_user_data_t *ud, gint mode)
1906 {
1907         hb_list_t  * list;
1908         hb_title_t * title;
1909         hb_job_t   * job;
1910         GHashTable *settings = ud->settings;
1911         gboolean keep_aspect, round_dims, anamorphic;
1912         gboolean autocrop, autoscale, noscale;
1913         gint crop[4], width, height, par_width, par_height;
1914         gint crop_width, crop_height;
1915         gint aspect_n, aspect_d;
1916         gboolean keep_width = (mode == GHB_SCALE_KEEP_WIDTH);
1917         gboolean keep_height = (mode == GHB_SCALE_KEEP_HEIGHT);
1918         gint step;
1919         GtkWidget *widget;
1920         gint modshift;
1921         gint modround;
1922         gint max_width = 0;
1923         gint max_height = 0;
1924         
1925         g_debug("ghb_set_scale ()\n");
1926
1927         if (h == NULL) return;
1928         list = hb_get_titles( h );
1929         if( !hb_list_count( list ) )
1930         {
1931                 /* No valid title, stop right there */
1932                 return;
1933         }
1934         gint titleindex = ghb_settings_get_index(settings, "title");
1935     title = hb_list_item( list, titleindex );
1936         if (title == NULL) return;
1937         job   = title->job;
1938         if (job == NULL) return;
1939         
1940         // First configure widgets
1941         round_dims = ghb_settings_get_bool(ud->settings, "round_dimensions");
1942         anamorphic = ghb_settings_get_bool(ud->settings, "anamorphic");
1943         keep_aspect = ghb_settings_get_bool(ud->settings, "keep_aspect");
1944         autocrop = ghb_settings_get_bool(ud->settings, "autocrop");
1945         autoscale = ghb_settings_get_bool(ud->settings, "autoscale");
1946         // "Noscale" is a flag that says we prefer to crop extra to satisfy
1947         // alignment constraints rather than scaling to satisfy them.
1948         noscale = ghb_settings_get_bool(ud->settings, "noscale");
1949         // Align dimensions to either 16 or 2 pixels
1950         // The scaler crashes if the dimensions are not divisible by 2
1951         // x264 also will not accept dims that are not multiple of 2
1952         modshift = round_dims ? 4 : 1;
1953         modround = round_dims ? 8 : 1;
1954         if (autoscale)
1955         {
1956                 keep_width = FALSE;
1957                 keep_height = FALSE;
1958         }
1959         if (anamorphic || keep_aspect)
1960         {
1961                 keep_height = FALSE;
1962         }
1963         // Step needs to be at least 2 because odd widths cause scaler crash
1964         step = round_dims ? 16 : 2;
1965         widget = GHB_WIDGET (ud->builder, "scale_width");
1966         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
1967         widget = GHB_WIDGET (ud->builder, "scale_height");
1968         gtk_spin_button_set_increments (GTK_SPIN_BUTTON(widget), step, 16);
1969         if (autocrop)
1970         {
1971                 ghb_title_info_t tinfo;
1972
1973                 if (ghb_get_title_info (&tinfo, titleindex))
1974                 {
1975                         crop[0] = tinfo.crop[0];
1976                         crop[1] = tinfo.crop[1];
1977                         crop[2] = tinfo.crop[2];
1978                         crop[3] = tinfo.crop[3];
1979                         if (noscale)
1980                         {
1981                                 gint need1, need2;
1982
1983                                 // Adjust the cropping to accomplish the desired width and height
1984                                 crop_width = tinfo.width - crop[2] - crop[3];
1985                                 crop_height = tinfo.height - crop[0] - crop[1];
1986                                 width = (crop_width >> modshift) << modshift;
1987                                 height = (crop_height >> modshift) << modshift;
1988                                 need1 = (crop_height - height) / 2;
1989                                 need2 = crop_height - height - need1;
1990                                 crop[0] += need1;
1991                                 crop[1] += need2;
1992                                 need1 = (crop_width - width) / 2;
1993                                 need2 = crop_width - width - need1;
1994                                 crop[2] += need1;
1995                                 crop[3] += need2;
1996                         }
1997                         ghb_ui_update_int (ud, "crop_top", crop[0]);
1998                         ghb_ui_update_int (ud, "crop_bottom", crop[1]);
1999                         ghb_ui_update_int (ud, "crop_left", crop[2]);
2000                         ghb_ui_update_int (ud, "crop_right", crop[3]);
2001                 }
2002         }
2003         crop[0] = ghb_settings_get_int(ud->settings, "crop_top");
2004         crop[1] = ghb_settings_get_int(ud->settings, "crop_bottom");
2005         crop[2] = ghb_settings_get_int(ud->settings, "crop_left");
2006         crop[3] = ghb_settings_get_int(ud->settings, "crop_right");
2007         hb_reduce(&aspect_n, &aspect_d, 
2008                                 title->width * title->pixel_aspect_width, 
2009                                 title->height * title->pixel_aspect_height);
2010         crop_width = title->width - crop[2] - crop[3];
2011         crop_height = title->height - crop[0] - crop[1];
2012         if (autoscale)
2013         {
2014                 width = crop_width;
2015                 height = crop_height;
2016                 max_width = crop_width;
2017                 max_height = crop_height;
2018         }
2019         else
2020         {
2021                 width = ghb_settings_get_int(ud->settings, "scale_width");
2022                 height = ghb_settings_get_int(ud->settings, "scale_height");
2023                 max_width = ghb_settings_get_int(ud->settings, "max_width");
2024                 max_height = ghb_settings_get_int(ud->settings, "max_width");
2025                 // Align max dims 
2026                 max_width = (max_width >> modshift) << modshift;
2027                 max_height = (max_height >> modshift) << modshift;
2028                 // Adjust dims according to max values
2029                 if (!max_height)
2030                 {
2031                         max_height = crop_height;
2032                 }
2033                 if (!max_width)
2034                 {
2035                         max_width = crop_width;
2036                 }
2037                 height = MIN(height, max_height);
2038                 width = MIN(width, max_width);
2039                 g_debug("max_width %d, max_height %d\n", max_width, max_height);
2040         }
2041         if (width < 16)
2042                 width = title->width - crop[2] - crop[3];
2043         if (height < 16)
2044                 height = title->height - crop[0] - crop[1];
2045
2046         if (anamorphic)
2047         {
2048                 if (round_dims)
2049                 {
2050                         job->modulus = 0;
2051                 }
2052                 else
2053                 {
2054                         // The scaler crashes if the dimensions are not divisible by 2
2055                         // Align mod 2.  And so does something in x264_encoder_headers()
2056                         job->modulus = 2;
2057                 }
2058                 job->width = width;
2059                 if (max_height) 
2060                         job->maxHeight = max_height;
2061                 job->crop[0] = crop[0]; job->crop[1] = crop[1];
2062                 job->crop[2] = crop[2]; job->crop[3] = crop[3];
2063                 hb_set_anamorphic_size( job, &width, &height, &par_width, &par_height );
2064         }
2065         else 
2066         {
2067                 if (keep_aspect)
2068                 {
2069                         gdouble par;
2070                         gint new_width, new_height;
2071                         
2072                         g_debug("kw %s kh %s\n", keep_width ? "y":"n", keep_height ? "y":"n");
2073                         g_debug("w %d h %d\n", width, height);
2074                         // Compute pixel aspect ration.  
2075                         par = (gdouble)(title->height * aspect_n) / (title->width * aspect_d);
2076                         // Must scale so that par becomes 1:1
2077                         // Try to keep largest dimension
2078                         new_height = (crop_height * ((gdouble)width/crop_width) / par);
2079                         new_width = (crop_width * ((gdouble)height/crop_height) * par);
2080                         // Height and width are always multiples of 2, so do the rounding
2081                         new_height = ((new_height + 1) >> 1) << 1;
2082                         new_width = ((new_width + 1) >> 1) << 1;
2083                         g_debug("max w %d, new w %d\n", max_width, new_width);
2084                         if (max_width && (new_width > max_width))
2085                         {
2086                                 height = new_height;
2087                         }
2088                         else if (max_height && (new_height > max_height))
2089                         {
2090                                 width = new_width;
2091                         }
2092                         else if (keep_width)
2093                         {
2094                                 height = new_height;
2095                         }
2096                         else if (keep_height)
2097                         {
2098                                 width = new_width;
2099                         }
2100                         else if (width > new_width)
2101                         {
2102                                 height = new_height;
2103                         }
2104                         else
2105                         {
2106                                 width = new_width;
2107                         }
2108                         g_debug("new w %d h %d\n", width, height);
2109                 }
2110                 width = ((width + modround) >> modshift) << modshift;
2111                 height = ((height + modround) >> modshift) << modshift;
2112         }
2113         ghb_ui_update_int (ud, "scale_width", width);
2114         ghb_ui_update_int (ud, "scale_height", height);
2115 }
2116
2117 static void
2118 set_preview_job_settings(hb_job_t *job, GHashTable *settings)
2119 {
2120         job->crop[0] = ghb_settings_get_int(settings, "crop_top");
2121         job->crop[1] = ghb_settings_get_int(settings, "crop_bottom");
2122         job->crop[2] = ghb_settings_get_int(settings, "crop_left");
2123         job->crop[3] = ghb_settings_get_int(settings, "crop_right");
2124
2125         gboolean anamorphic = ghb_settings_get_bool(settings, "anamorphic");
2126         gboolean round_dimensions = ghb_settings_get_bool(settings, "round_dimensions");
2127         if (round_dimensions && anamorphic)
2128         {
2129                 job->modulus = 16;
2130                 job->pixel_ratio = 2;
2131         }
2132         else if (anamorphic)
2133         {
2134                 job->modulus = 2;
2135                 job->pixel_ratio = 2;
2136         }
2137         else
2138         {
2139                 job->modulus = 2;
2140                 job->pixel_ratio = 0;
2141         }
2142         job->width = ghb_settings_get_int(settings, "scale_width");
2143         job->height = ghb_settings_get_int(settings, "scale_height");
2144         gint deint = ghb_settings_get_int(settings, "deinterlace");
2145         gboolean decomb = ghb_settings_get_bool(settings, "decomb");
2146         job->deinterlace = (!decomb && deint == 0) ? 0 : 1;
2147 }
2148
2149 gint
2150 ghb_calculate_target_bitrate(GHashTable *settings, gint titleindex)
2151 {
2152         hb_list_t  * list;
2153         hb_title_t * title;
2154         hb_job_t   * job;
2155         gint size;
2156
2157         if (h == NULL) return 2000;
2158         list = hb_get_titles( h );
2159     title = hb_list_item( list, titleindex );
2160         if (title == NULL) return 2000;
2161         job   = title->job;
2162         if (job == NULL) return 2000;
2163         size = ghb_settings_get_int(settings, "video_target_size");
2164         return hb_calc_bitrate( job, size );
2165 }
2166
2167 gint
2168 ghb_guess_bitrate(GHashTable *settings)
2169 {
2170         gint bitrate;
2171         if (ghb_settings_get_bool(settings, "vquality_type_constant"))
2172         {
2173                 // This is really rough.  I'm trying to err on the high
2174                 // side since this is used to estimate if there is 
2175                 // sufficient disk space left
2176                 gint vcodec = ghb_settings_get_int(settings, "video_codec");
2177                 gdouble vquality = ghb_settings_get_dbl(settings, "video_quality")/100;
2178                 if (vcodec == HB_VCODEC_X264 && 
2179                                 !ghb_settings_get_bool(settings, "linear_vquality"))
2180                 {
2181                         vquality = 51.0 - vquality * 51.0;
2182                         // Convert log curve to linear
2183                         vquality = exp2((vquality-12)/6);
2184                         // Don't let it go to 0
2185                         if (vquality >= 31) vquality = 30;
2186                         vquality = (31 - vquality) / 31;
2187                 }
2188                 // bitrate seems to be a log relasionship to quality
2189                 // with typical source material
2190                 // This is a real wag
2191                 bitrate = 20*1024*1024*exp10(vquality*14)/exp10(14);
2192                 // Add some bits for audio
2193                 bitrate += 500*1024;
2194         }
2195         else
2196         {
2197                 // Add some fudge to the bitrate to leave breathing room
2198                 bitrate = ghb_settings_get_int(settings, "video_bitrate")*1024;
2199                 // Add some bits for audio
2200                 bitrate += 500*1024;
2201         }
2202         return bitrate;
2203 }
2204
2205 gboolean
2206 ghb_validate_video(signal_user_data_t *ud)
2207 {
2208         GHashTable *settings = ud->settings;
2209         gint vcodec, mux;
2210         gchar *message;
2211
2212         mux = ghb_settings_get_int(settings, "container");
2213         vcodec = ghb_settings_get_int(settings, "video_codec");
2214         if ((mux == HB_MUX_MP4 || mux == HB_MUX_AVI) && 
2215                 (vcodec == HB_VCODEC_THEORA))
2216         {
2217                 // mp4|avi/theora combination is not supported.
2218                 message = g_strdup_printf(
2219                                         "Theora is not supported in the MP4 and AVI containers.\n\n"
2220                                         "You should choose a different video codec or container.\n"
2221                                         "If you continue, XviD will be chosen for you.");
2222                 if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2223                 {
2224                         g_free(message);
2225                         return FALSE;
2226                 }
2227                 g_free(message);
2228                 vcodec = HB_VCODEC_XVID;
2229                 ghb_ui_update_int(ud, "video_codec", vcodec);
2230         }
2231         gboolean decomb = ghb_settings_get_bool(settings, "decomb");
2232         gboolean vfr = ghb_settings_get_bool(settings, "variable_frame_rate");
2233         if (decomb && !vfr)
2234         {
2235                 message = g_strdup_printf(
2236                                         "Decomb is intended to be used in conjunction\n"
2237                                         "with variable frame rate.\n\n"
2238                                         "Would you like me to enable VFR for you?");
2239                 if (ghb_message_dialog(GTK_MESSAGE_WARNING, message, "No", "Yes"))
2240                 {
2241                         ghb_ui_update_int(ud, "variable_frame_rate", TRUE);
2242                 }
2243                 g_free(message);
2244         }
2245         return TRUE;
2246 }
2247
2248 gboolean
2249 ghb_validate_container(signal_user_data_t *ud)
2250 {
2251         gint container;
2252         gchar *message;
2253
2254         container = ghb_settings_get_bool(ud->settings, "container");
2255         if (container == HB_MUX_MP4)
2256         {
2257                 gboolean httpopt;
2258                 httpopt = ghb_settings_get_bool(ud->settings, "http_optimize_mp4");
2259                 if (httpopt && ghb_ac3_in_audio_list(ud->audio_settings))
2260                 {
2261                         message = g_strdup_printf(
2262                                         "AC3 audio in HTTP optimized MP4 is not supported.\n\n"
2263                                         "You should choose a different audio codec.\n"
2264                                         "If you continue, FAAC will be chosen for you.");
2265                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2266                         {
2267                                 g_free(message);
2268                                 return FALSE;
2269                         }
2270                         g_free(message);
2271                         GSList *link = ud->audio_settings;
2272                         while (link != NULL)
2273                         {
2274                                 GHashTable *asettings;
2275                                 asettings = (GHashTable*)link->data;
2276                                 gint acodec = ghb_settings_get_int(asettings, "audio_codec");
2277                                 if (acodec == HB_ACODEC_AC3)
2278                                 {
2279                                         setting_value_t *value;
2280                                         value = get_acodec_value(HB_ACODEC_FAAC);
2281                                         ghb_settings_set(asettings, "audio_codec", value);
2282                                 }
2283                                 link = link->next;
2284                         }
2285                 }
2286         }
2287         return TRUE;
2288 }
2289
2290 gboolean
2291 ghb_validate_audio(signal_user_data_t *ud)
2292 {
2293         hb_list_t  * list;
2294         hb_title_t * title;
2295         GHashTable *settings = ud->settings;
2296         gchar *message;
2297         setting_value_t *value;
2298
2299         if (h == NULL) return FALSE;
2300         list = hb_get_titles( h );
2301         if( !hb_list_count( list ) )
2302         {
2303                 /* No valid title, stop right there */
2304                 g_message("No title found.\n");
2305                 return FALSE;
2306         }
2307
2308         gint titleindex = ghb_settings_get_index(settings, "title");
2309     title = hb_list_item( list, titleindex );
2310         if (title == NULL) return FALSE;
2311         GSList *link = ud->audio_settings;
2312         gint mux = ghb_settings_get_int(settings, "container");
2313         while (link != NULL)
2314         {
2315                 GHashTable *asettings;
2316             hb_audio_config_t *taudio;
2317
2318                 asettings = (GHashTable*)link->data;
2319                 gint track = ghb_settings_get_index(asettings, "audio_track");
2320                 gint codec = ghb_settings_get_int(asettings, "audio_codec");
2321         taudio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, track );
2322                 if ((taudio->in.codec != HB_ACODEC_AC3) && (codec == HB_ACODEC_AC3))
2323                 {
2324                         // Not supported.  AC3 is passthrough only, so input must be AC3
2325                         message = g_strdup_printf(
2326                                                 "The source does not support AC3 Pass-Thru.\n\n"
2327                                                 "You should choose a different audio codec.\n"
2328                                                 "If you continue, one will be chosen for you.");
2329                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2330                         {
2331                                 g_free(message);
2332                                 return FALSE;
2333                         }
2334                         g_free(message);
2335                         if (mux == HB_MUX_AVI)
2336                         {
2337                                 codec = HB_ACODEC_LAME;
2338                         }
2339                         else
2340                         {
2341                                 codec = HB_ACODEC_FAAC;
2342                         }
2343                         value = get_acodec_value(codec);
2344                         ghb_settings_set(asettings, "audio_codec", value);
2345                 }
2346                 gchar *a_unsup = NULL;
2347                 gchar *mux_s = NULL;
2348                 if (mux == HB_MUX_MP4)
2349                 { 
2350                         mux_s = "MP4";
2351                         // mp4/mp3|vorbis combination is not supported.
2352                         if (codec == HB_ACODEC_LAME)
2353                         {
2354                                 a_unsup = "MP3";
2355                                 codec = HB_ACODEC_FAAC;
2356                         }
2357                         if (codec == HB_ACODEC_VORBIS)
2358                         {
2359                                 a_unsup = "Vorbis";
2360                                 codec = HB_ACODEC_FAAC;
2361                         }
2362                 }
2363                 else if (mux == HB_MUX_AVI)
2364                 {
2365                         mux_s = "AVI";
2366                         // avi/faac|vorbis combination is not supported.
2367                         if (codec == HB_ACODEC_FAAC)
2368                         {
2369                                 a_unsup = "FAAC";
2370                                 codec = HB_ACODEC_LAME;
2371                         }
2372                         if (codec == HB_ACODEC_VORBIS)
2373                         {
2374                                 a_unsup = "Vorbis";
2375                                 codec = HB_ACODEC_LAME;
2376                         }
2377                 }
2378                 else if (mux == HB_MUX_OGM)
2379                 {
2380                         mux_s = "OGM";
2381                         // avi/faac|vorbis combination is not supported.
2382                         if (codec == HB_ACODEC_FAAC)
2383                         {
2384                                 a_unsup = "FAAC";
2385                                 codec = HB_ACODEC_VORBIS;
2386                         }
2387                         if (codec == HB_ACODEC_AC3)
2388                         {
2389                                 a_unsup = "AC-3";
2390                                 codec = HB_ACODEC_VORBIS;
2391                         }
2392                 }
2393                 if (a_unsup)
2394                 {
2395                         message = g_strdup_printf(
2396                                                 "%s is not supported in the %s container.\n\n"
2397                                                 "You should choose a different audio codec.\n"
2398                                                 "If you continue, one will be chosen for you.", a_unsup, mux_s);
2399                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2400                         {
2401                                 g_free(message);
2402                                 return FALSE;
2403                         }
2404                         g_free(message);
2405                         value = get_acodec_value(codec);
2406                         ghb_settings_set(asettings, "audio_codec", value);
2407                 }
2408                 gint mix = ghb_settings_get_int (asettings, "audio_mix");
2409                 gboolean allow_mono = TRUE;
2410                 gboolean allow_stereo = TRUE;
2411                 gboolean allow_dolby = TRUE;
2412                 gboolean allow_dpl2 = TRUE;
2413                 gboolean allow_6ch = TRUE;
2414                 allow_mono =
2415                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
2416                         (codec != HB_ACODEC_LAME);
2417                 gint layout = taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
2418                 allow_stereo =
2419                         ((layout == HB_INPUT_CH_LAYOUT_MONO && !allow_mono) || layout >= HB_INPUT_CH_LAYOUT_STEREO);
2420                 allow_dolby =
2421                         (layout == HB_INPUT_CH_LAYOUT_3F1R) || 
2422                         (layout == HB_INPUT_CH_LAYOUT_3F2R) || 
2423                         (layout == HB_INPUT_CH_LAYOUT_DOLBY);
2424                 allow_dpl2 = (layout == HB_INPUT_CH_LAYOUT_3F2R);
2425                 allow_6ch =
2426                         (taudio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
2427                         (codec != HB_ACODEC_LAME) &&
2428                         (layout == HB_INPUT_CH_LAYOUT_3F2R) && 
2429                         (taudio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE);
2430
2431                 gchar *mix_unsup = NULL;
2432                 if (mix == HB_AMIXDOWN_MONO && !allow_mono)
2433                 {
2434                         mix_unsup = "mono";
2435                 }
2436                 if (mix == HB_AMIXDOWN_STEREO && !allow_stereo)
2437                 {
2438                         mix_unsup = "stereo";
2439                 }
2440                 if (mix == HB_AMIXDOWN_DOLBY && !allow_dolby)
2441                 {
2442                         mix_unsup = "Dolby";
2443                 }
2444                 if (mix == HB_AMIXDOWN_DOLBYPLII && !allow_dpl2)
2445                 {
2446                         mix_unsup = "Dolby Pro Logic II";
2447                 }
2448                 if (mix == HB_AMIXDOWN_6CH && !allow_6ch)
2449                 {
2450                         mix_unsup = "6 Channel";
2451                 }
2452                 if (mix_unsup)
2453                 {
2454                         message = g_strdup_printf(
2455                                                 "The source audio does not support %s mixdown.\n\n"
2456                                                 "You should choose a different mixdown.\n"
2457                                                 "If you continue, one will be chosen for you.", mix_unsup);
2458                         if (!ghb_message_dialog(GTK_MESSAGE_WARNING, message, "Cancel", "Continue"))
2459                         {
2460                                 g_free(message);
2461                                 return FALSE;
2462                         }
2463                         g_free(message);
2464                         mix = ghb_get_best_mix(titleindex, track, codec, mix);
2465                         value = get_amix_value(mix);
2466                         ghb_settings_set(asettings, "audio_mix", value);
2467                 }
2468                 link = link->next;
2469         }
2470         return TRUE;
2471 }
2472
2473 gboolean
2474 ghb_validate_vquality(GHashTable *settings)
2475 {
2476         gint vcodec;
2477         gchar *message;
2478         gint min, max;
2479
2480         if (ghb_settings_get_bool(settings, "nocheckvquality")) return TRUE;
2481         vcodec = ghb_settings_get_int(settings, "video_codec");
2482         if (ghb_settings_get_bool(settings, "vquality_type_constant"))
2483         {
2484                 if (!ghb_settings_get_bool(settings, "directqp"))
2485                 {
2486                         if (vcodec != HB_VCODEC_X264 || 
2487                                 ghb_settings_get_bool(settings, "linear_vquality"))
2488                         {
2489                                 min = 68;
2490                                 max = 97;
2491                         }
2492                         else if (vcodec == HB_VCODEC_X264)
2493                         {
2494                                 min = 40;
2495                                 max = 70;
2496                         }
2497                 }
2498                 else
2499                 {
2500                         if (vcodec == HB_VCODEC_X264)
2501                         {
2502                                 min = 16;
2503                                 max = 30;
2504                         }
2505                         else if (vcodec == HB_VCODEC_FFMPEG)
2506                         {
2507                                 min = 1;
2508                                 max = 8;
2509                         }
2510                         else
2511                         {
2512                                 min = 68;
2513                                 max = 97;
2514                         }
2515                 }
2516                 gint vquality = ghb_settings_get_dbl(settings, "video_quality");
2517                 if (vquality < min || vquality > max)
2518                 {
2519                         message = g_strdup_printf(
2520                                                 "Interesting video quality choise: %d\n\n"
2521                                                 "Typical values range from %d to %d.\n"
2522                                                 "Are you sure you wish to use this setting?",
2523                                                 vquality, min, max);
2524                         if (!ghb_message_dialog(GTK_MESSAGE_QUESTION, message, 
2525                                                                         "Cancel", "Continue"))
2526                         {
2527                                 g_free(message);
2528                                 return FALSE;
2529                         }
2530                         g_free(message);
2531                 }
2532         }
2533         return TRUE;
2534 }
2535
2536 void
2537 ghb_add_job(job_settings_t *js, gint unique_id)
2538 {
2539         hb_list_t  * list;
2540         hb_title_t * title;
2541         hb_job_t   * job;
2542         GHashTable *settings = js->settings;
2543         static gchar *x264opts;
2544         gint sub_id = 0;
2545
2546         g_debug("ghb_add_job()\n");
2547         if (h == NULL) return;
2548         list = hb_get_titles( h );
2549         if( !hb_list_count( list ) )
2550         {
2551                 /* No valid title, stop right there */
2552                 g_message("No title found.\n");
2553                 return;
2554         }
2555
2556         gint titleindex = ghb_settings_get_index(settings, "title");
2557     title = hb_list_item( list, titleindex );
2558         if (title == NULL) return;
2559
2560         /* Set job settings */
2561         job   = title->job;
2562         if (job == NULL) return;
2563
2564         job->mux = ghb_settings_get_int(settings, "container");
2565         if (job->mux == HB_MUX_MP4)
2566         {
2567                 job->largeFileSize = ghb_settings_get_bool(settings, "large_mp4");
2568                 job->mp4_optimize = ghb_settings_get_bool(settings, "http_optimize_mp4");
2569         }
2570         else
2571         {
2572                 job->largeFileSize = FALSE;
2573                 job->mp4_optimize = FALSE;
2574         }
2575         gint chapter_start, chapter_end;
2576         chapter_start = ghb_settings_get_int(settings, "start_chapter");
2577         chapter_end = ghb_settings_get_int(settings, "end_chapter");
2578         gint num_chapters = hb_list_count(title->list_chapter);
2579         job->chapter_start = MIN( num_chapters, chapter_start );
2580         job->chapter_end   = MAX( job->chapter_start, chapter_end );
2581
2582         job->chapter_markers = ghb_settings_get_bool(settings, "chapter_markers");
2583         if ( job->chapter_markers )
2584         {
2585                 gint chapter;
2586                 
2587                 for(chapter = chapter_start; chapter <= chapter_end; chapter++)
2588                 {
2589                         hb_chapter_t * chapter_s;
2590                         gchar *name;
2591                         
2592                         if (js->chapter_list == NULL || js->chapter_list[chapter-1] == 0)
2593                         {
2594                                 name = g_strdup_printf ("Chapter %2d", chapter);
2595                         }
2596                         else
2597                         {
2598                                 name = g_strdup(js->chapter_list[chapter-1]);
2599                         }
2600                         chapter_s = hb_list_item( job->title->list_chapter, chapter - 1);
2601                         strncpy(chapter_s->title, name, 1023);
2602                         chapter_s->title[1023] = '\0';
2603                         g_free(name);
2604                 }
2605         }
2606         job->crop[0] = ghb_settings_get_int(settings, "crop_top");
2607         job->crop[1] = ghb_settings_get_int(settings, "crop_bottom");
2608         job->crop[2] = ghb_settings_get_int(settings, "crop_left");
2609         job->crop[3] = ghb_settings_get_int(settings, "crop_right");
2610
2611         
2612         gboolean decomb = ghb_settings_get_bool(settings, "decomb");
2613         gint deint = ghb_settings_get_int(settings, "deinterlace");
2614         if (!decomb)
2615                 job->deinterlace = (deint == 0) ? 0 : 1;
2616         else
2617                 job->deinterlace = 0;
2618     job->grayscale   = ghb_settings_get_bool(settings, "grayscale");
2619
2620         gboolean anamorphic = ghb_settings_get_bool(settings, "anamorphic");
2621         gboolean round_dimensions = ghb_settings_get_bool(settings, "round_dimensions");
2622         if (round_dimensions && anamorphic)
2623         {
2624                 job->pixel_ratio = 2;
2625                 job->modulus = 16;
2626         }
2627         else if (anamorphic)
2628         {
2629                 // Huh! I thought I wanted to use pixel_ratio 1 for this case, but
2630                 // when its 1, libhb discards the width and height and uses original
2631                 // title dims - crop.  Thats not what I want.
2632                 // Also, x264 requires things to divisible by 2.
2633                 job->pixel_ratio = 2;
2634                 job->modulus = 2;
2635         }
2636         else
2637         {
2638                 job->pixel_ratio = 0;
2639                 job->modulus = 2;
2640         }
2641         job->vfr = ghb_settings_get_bool(settings, "variable_frame_rate");
2642         /* Add selected filters */
2643         job->filters = hb_list_init();
2644         if( ghb_settings_get_bool(settings, "detelecine" ) || job->vfr )
2645         {
2646                 hb_filter_detelecine.settings = NULL;
2647                 hb_list_add( job->filters, &hb_filter_detelecine );
2648         }
2649         if( decomb )
2650         {
2651                 // Use default settings
2652                 hb_filter_decomb.settings = NULL;
2653                 hb_list_add( job->filters, &hb_filter_decomb );
2654         }
2655         if( job->deinterlace )
2656         {
2657                 hb_filter_deinterlace.settings = (gchar*)ghb_settings_get_string(settings, "deinterlace");
2658                 hb_list_add( job->filters, &hb_filter_deinterlace );
2659         }
2660         if( ghb_settings_get_bool(settings, "deblock") )
2661         {
2662                 hb_filter_deblock.settings = NULL;
2663                 hb_list_add( job->filters, &hb_filter_deblock );
2664         }
2665         gint denoise = ghb_settings_get_int(settings, "denoise");
2666         if( denoise != 0 )
2667         {
2668                 hb_filter_denoise.settings = (gchar*)ghb_settings_get_string(settings, "denoise");
2669                 hb_list_add( job->filters, &hb_filter_denoise );
2670         }
2671         job->width = ghb_settings_get_int(settings, "scale_width");
2672         job->height = ghb_settings_get_int(settings, "scale_height");
2673
2674         job->vcodec = ghb_settings_get_int(settings, "video_codec");
2675         if ((job->mux == HB_MUX_MP4 || job->mux == HB_MUX_AVI) && 
2676                 (job->vcodec == HB_VCODEC_THEORA))
2677         {
2678                 // mp4|avi/theora combination is not supported.
2679                 job->vcodec = HB_VCODEC_XVID;
2680         }
2681         if ((job->vcodec == HB_VCODEC_X264) && (job->mux == HB_MUX_MP4))
2682         {
2683                 job->ipod_atom = ghb_settings_get_bool(settings, "ipod_file");
2684         }
2685         if (ghb_settings_get_bool(settings, "vquality_type_constant"))
2686         {
2687                 gdouble vquality = ghb_settings_get_dbl(settings, "video_quality");
2688                 if (!ghb_settings_get_bool(settings, "directqp"))
2689                 {
2690                         vquality /= 100.0;
2691                         if (ghb_settings_get_bool(settings, "linear_vquality"))
2692                         {
2693                                 if (job->vcodec == HB_VCODEC_X264)
2694                                 {
2695                                         // Adjust to same range as xvid and ffmpeg
2696                                         vquality = 31.0 - vquality * 31.0;
2697                                         if (vquality > 0)
2698                                         {
2699                                                 // Convert linear to log curve
2700                                                 vquality = 12 + 6 * log2(vquality);
2701                                                 if (vquality > 51) vquality = 51;
2702                                                 if (vquality < 1) vquality = 1;
2703                                         }
2704                                         else
2705                                                 vquality = 0;
2706                                 }
2707                         }
2708                         else
2709                         {
2710                                 if (vquality == 0.0) vquality = 0.01;
2711                                 if (vquality == 1.0) vquality = 0.0;
2712                         }
2713                 }
2714                 job->vquality =  vquality;
2715                 job->vbitrate = 0;
2716         }
2717         else if (ghb_settings_get_bool(settings, "vquality_type_bitrate"))
2718         {
2719                 job->vquality = -1.0;
2720                 job->vbitrate = ghb_settings_get_int(settings, "video_bitrate");
2721         }
2722         // AVI container does not support variable frame rate.
2723         if (job->mux == HB_MUX_AVI)
2724         {
2725                 job->vfr = FALSE;
2726         }
2727
2728         gint vrate = ghb_settings_get_int(settings, "framerate");
2729         if( vrate == 0 || job->vfr )
2730         {
2731                 job->vrate = title->rate;
2732                 job->vrate_base = title->rate_base;
2733                 job->cfr = 0;
2734         }
2735         else
2736         {
2737                 job->vrate = 27000000;
2738                 job->vrate_base = vrate;
2739                 job->cfr = 1;
2740         }
2741         // First remove any audios that are already in the list
2742         // This happens if you are encoding the same title a second time.
2743         gint num_audio_tracks = hb_list_count(job->list_audio);
2744         gint ii;
2745     for(ii = 0; ii < num_audio_tracks; ii++)
2746     {
2747         hb_audio_t *audio = (hb_audio_t*)hb_list_item(job->list_audio, 0);
2748         hb_list_rem(job->list_audio, audio);
2749     }
2750         GSList *link = js->audio_settings;
2751         gint count = 0;
2752         while (link != NULL)
2753         {
2754                 GHashTable *asettings;
2755             hb_audio_config_t audio;
2756             hb_audio_config_t *taudio;
2757
2758                 hb_audio_config_init(&audio);
2759                 asettings = (GHashTable*)link->data;
2760                 audio.in.track = ghb_settings_get_index(asettings, "audio_track");
2761                 audio.out.track = count;
2762                 audio.out.codec = ghb_settings_get_int(asettings, "audio_codec");
2763         taudio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, audio.in.track );
2764                 if ((taudio->in.codec != HB_ACODEC_AC3) && (audio.out.codec == HB_ACODEC_AC3))
2765                 {
2766                         // Not supported.  AC3 is passthrough only, so input must be AC3
2767                         if (job->mux == HB_MUX_AVI)
2768                         {
2769                                 audio.out.codec = HB_ACODEC_LAME;
2770                         }
2771                         else
2772                         {
2773                                 audio.out.codec = HB_ACODEC_FAAC;
2774                         }
2775                 }
2776                 if ((job->mux == HB_MUX_MP4) && 
2777                         ((audio.out.codec == HB_ACODEC_LAME) ||
2778                         (audio.out.codec == HB_ACODEC_VORBIS)))
2779                 {
2780                         // mp4/mp3|vorbis combination is not supported.
2781                         audio.out.codec = HB_ACODEC_FAAC;
2782                 }
2783                 if ((job->mux == HB_MUX_AVI) && 
2784                         ((audio.out.codec == HB_ACODEC_FAAC) ||
2785                         (audio.out.codec == HB_ACODEC_VORBIS)))
2786                 {
2787                         // avi/faac|vorbis combination is not supported.
2788                         audio.out.codec = HB_ACODEC_LAME;
2789                 }
2790                 if ((job->mux == HB_MUX_OGM) && 
2791                         ((audio.out.codec == HB_ACODEC_FAAC) ||
2792                         (audio.out.codec == HB_ACODEC_AC3)))
2793                 {
2794                         // ogm/faac|ac3 combination is not supported.
2795                         audio.out.codec = HB_ACODEC_VORBIS;
2796                 }
2797         audio.out.dynamic_range_compression = ghb_settings_get_dbl(asettings, "audio_drc");
2798                 // It would be better if this were done in libhb for us, but its not yet.
2799                 if (audio.out.codec == HB_ACODEC_AC3 || audio.out.codec == HB_ACODEC_DCA)
2800                 {
2801                         audio.out.mixdown = 0;
2802                 }
2803                 else
2804                 {
2805                         audio.out.mixdown = ghb_settings_get_int (asettings, "audio_mix");
2806                         // Make sure the mixdown is valid and pick a new one if not.
2807                         audio.out.mixdown = ghb_get_best_mix(titleindex, audio.in.track, audio.out.codec, 
2808                                                                                                 audio.out.mixdown);
2809                         audio.out.bitrate = ghb_settings_get_int(asettings, "audio_bitrate") / 1000;
2810                         gint srate = ghb_settings_get_int(asettings, "audio_sample_rate");
2811                         if (srate == 0) // 0 is same as source
2812                                 audio.out.samplerate = taudio->in.samplerate;
2813                         else
2814                                 audio.out.samplerate = srate;
2815                 }
2816
2817                 // Add it to the jobs audio list
2818         hb_audio_add( job, &audio );
2819                 count++;
2820                 link = link->next;
2821         }
2822         // I was tempted to move this up with the reset of the video quality
2823         // settings, but I suspect the settings above need to be made
2824         // first in order for hb_calc_bitrate to be accurate.
2825         if (ghb_settings_get_bool(settings, "vquality_type_target"))
2826         {
2827                 gint size;
2828                 
2829                 size = ghb_settings_get_int(settings, "video_target_size");
2830         job->vbitrate = hb_calc_bitrate( job, size );
2831                 job->vquality = -1.0;
2832         }
2833
2834         job->file = ghb_settings_get_string(settings, "destination");
2835         job->crf = ghb_settings_get_bool(settings, "constant_rate_factor");
2836         // TODO: libhb holds onto a reference to the x264opts and is not
2837         // finished with it until encoding the job is done.  But I can't
2838         // find a way to get at the job before it is removed in order to
2839         // free up the memory I am allocating here.
2840         // The short story is THIS LEAKS.
2841         x264opts = ghb_build_x264opts_string(settings);
2842         
2843         if( x264opts != NULL && *x264opts != '\0' )
2844         {
2845                 job->x264opts = x264opts;
2846         }
2847         else /*avoids a bus error crash when options aren't specified*/
2848         {
2849                 job->x264opts =  NULL;
2850         }
2851         gint subtitle = ghb_settings_get_int(settings, "subtitle_lang");
2852         gboolean forced_subtitles = ghb_settings_get_bool (settings, "forced_subtitles");
2853         job->subtitle_force = forced_subtitles;
2854         if (subtitle >= 0)
2855                 job->subtitle = subtitle;
2856         else
2857                 job->subtitle = -1;
2858         if (subtitle == -1)
2859         {
2860                 // Subtitle scan. Look for subtitle matching audio language
2861                 char *x264opts_tmp;
2862
2863                 /*
2864                  * When subtitle scan is enabled do a fast pre-scan job
2865                  * which will determine which subtitles to enable, if any.
2866                  */
2867                 job->pass = -1;
2868                 job->indepth_scan = 1;
2869
2870                 x264opts_tmp = job->x264opts;
2871                 job->x264opts = NULL;
2872
2873                 job->select_subtitle = malloc(sizeof(hb_subtitle_t*));
2874                 *(job->select_subtitle) = NULL;
2875
2876                 /*
2877                  * Add the pre-scan job
2878                  */
2879                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2880                 hb_add( h, job );
2881                 //if (job->x264opts != NULL)
2882                 //      g_free(job->x264opts);
2883
2884                 job->x264opts = x264opts_tmp;
2885         }
2886         else
2887         {
2888                 job->select_subtitle = NULL;
2889         }
2890         if( ghb_settings_get_bool(settings, "two_pass") &&
2891                 !ghb_settings_get_bool(settings, "vquality_type_constant"))
2892         {
2893                 /*
2894                  * If subtitle_scan is enabled then only turn it on
2895                  * for the second pass and then off again for the
2896                  * second.
2897                  */
2898                 hb_subtitle_t **subtitle_tmp = job->select_subtitle;
2899                 job->select_subtitle = NULL;
2900                 job->pass = 1;
2901                 job->indepth_scan = 0;
2902                 gchar *x264opts2 = NULL;
2903                 if (x264opts)
2904                 {
2905                         x264opts2 = g_strdup(x264opts);
2906                 }
2907                 /*
2908                  * If turbo options have been selected then append them
2909                  * to the x264opts now (size includes one ':' and the '\0')
2910                  */
2911                 if( ghb_settings_get_bool(settings, "turbo") )
2912                 {
2913                         char *tmp_x264opts;
2914
2915                         if ( x264opts )
2916                         {
2917                                 tmp_x264opts = g_strdup_printf("%s:%s", x264opts, turbo_opts);
2918                                 g_free(x264opts);
2919                         } 
2920                         else 
2921                         {
2922                                 /*
2923                                  * No x264opts to modify, but apply the turbo options
2924                                  * anyway as they may be modifying defaults
2925                                  */
2926                                 tmp_x264opts = g_strdup_printf("%s", turbo_opts);
2927                         }
2928                         x264opts = tmp_x264opts;
2929
2930                         job->x264opts = x264opts;
2931                 }
2932                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2933                 hb_add( h, job );
2934                 //if (job->x264opts != NULL)
2935                 //      g_free(job->x264opts);
2936
2937                 job->select_subtitle = subtitle_tmp;
2938                 job->pass = 2;
2939                 /*
2940                  * On the second pass we turn off subtitle scan so that we
2941                  * can actually encode using any subtitles that were auto
2942                  * selected in the first pass (using the whacky select-subtitle
2943                  * attribute of the job).
2944                  */
2945                 job->indepth_scan = 0;
2946                 job->x264opts = x264opts2;
2947                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2948                 hb_add( h, job );
2949                 //if (job->x264opts != NULL)
2950                 //      g_free(job->x264opts);
2951         }
2952         else
2953         {
2954                 job->indepth_scan = 0;
2955                 job->pass = 0;
2956                 job->sequence_id = (unique_id & 0xFFFFFF) | (sub_id++ << 24);
2957                 hb_add( h, job );
2958                 //if (job->x264opts != NULL)
2959                 //      g_free(job->x264opts);
2960         }
2961 }
2962
2963 void
2964 ghb_remove_job(gint unique_id)
2965 {
2966     hb_job_t * job;
2967     gint ii;
2968         
2969         // Multiples passes all get the same id
2970         // remove them all.
2971         // Go backwards through list, so reordering doesn't screw me.
2972         ii = hb_count(h) - 1;
2973     while ((job = hb_job(h, ii--)) != NULL)
2974     {
2975         if ((job->sequence_id & 0xFFFFFF) == unique_id)
2976                         hb_rem(h, job);
2977     }
2978 }
2979
2980 void
2981 ghb_start_queue()
2982 {
2983         hb_start( h );
2984 }
2985
2986 void
2987 ghb_stop_queue()
2988 {
2989         hb_stop( h );
2990 }
2991
2992 void
2993 ghb_pause_queue()
2994 {
2995     hb_state_t s;
2996     hb_get_state2( h, &s );
2997
2998     if( s.state == HB_STATE_PAUSED )
2999     {
3000         hb_resume( h );
3001     }
3002     else
3003     {
3004         hb_pause( h );
3005     }
3006 }
3007
3008 GdkPixbuf*
3009 ghb_get_preview_image(gint titleindex, gint index, GHashTable *settings, gboolean borders)
3010 {
3011         hb_title_t *title;
3012         hb_list_t  *list;
3013         
3014         list = hb_get_titles( h );
3015         if( !hb_list_count( list ) )
3016         {
3017                 /* No valid title, stop right there */
3018                 return NULL;
3019         }
3020     title = hb_list_item( list, titleindex );
3021         if (title == NULL) return NULL;
3022         if (title->job == NULL) return NULL;
3023         set_preview_job_settings(title->job, settings);
3024
3025         // hb_get_preview can't handle sizes that are larger than the original title
3026         // dimensions
3027         if (title->job->width > title->width)
3028                 title->job->width = title->width;
3029         
3030         if (title->job->height > title->height)
3031                 title->job->height = title->height;
3032         // And also creates artifacts if the width is not a multiple of 8
3033         //title->job->width = ((title->job->width + 4) >> 3) << 3;
3034         // And the height must be a multiple of 2
3035         //title->job->height = ((title->job->height + 1) >> 1) << 1;
3036         
3037         // Make sure we have a big enough buffer to receive the image from libhb. libhb
3038         // creates images with a one-pixel border around the original content. Hence we
3039         // add 2 pixels horizontally and vertically to the buffer size.
3040         gint srcWidth = title->width + 2;
3041         gint srcHeight= title->height + 2;
3042         gint dstWidth = title->width;
3043         gint dstHeight= title->height;
3044         gint borderTop = 1;
3045         gint borderLeft = 1;
3046     if (borders)
3047     {
3048         //     |<---------- title->width ----------->|
3049         //     |   |<---- title->job->width ---->|   |
3050         //     |   |                             |   |
3051         //     .......................................
3052         //     ....+-----------------------------+....
3053         //     ....|                             |....<-- gray border
3054         //     ....|                             |....
3055         //     ....|                             |....
3056         //     ....|                             |<------- image
3057         //     ....|                             |....
3058         //     ....|                             |....
3059         //     ....|                             |....
3060         //     ....|                             |....
3061         //     ....|                             |....
3062         //     ....+-----------------------------+....
3063         //     .......................................
3064                 dstWidth = title->job->width;
3065         dstHeight = title->job->height;
3066                 borderTop = (srcHeight - dstHeight) / 2;
3067                 borderLeft = (srcWidth - dstWidth) / 2;
3068                 g_debug("boarders removed\n");
3069         }
3070
3071         g_debug("src %d x %d\n", srcWidth, srcHeight);
3072         g_debug("dst %d x %d\n", dstWidth, dstHeight);
3073         g_debug("job dim %d x %d\n", title->job->width, title->job->height);
3074         g_debug("title crop %d:%d:%d:%d\n", 
3075                         title->crop[0],
3076                         title->crop[1],
3077                         title->crop[2],
3078                         title->crop[3]);
3079         g_debug("job crop %d:%d:%d:%d\n", 
3080                         title->job->crop[0],
3081                         title->job->crop[1],
3082                         title->job->crop[2],
3083                         title->job->crop[3]);
3084         static guint8 *buffer = NULL;
3085         static gint bufferSize = 0;
3086
3087         gint newSize;
3088         newSize = srcWidth * srcHeight * 4;
3089         if( bufferSize < newSize )
3090         {
3091                 bufferSize = newSize;
3092                 buffer     = (guint8*) g_realloc( buffer, bufferSize );
3093         }
3094         hb_get_preview( h, title, index, buffer );
3095
3096         // Create an GdkPixbuf and copy the libhb image into it, converting it from
3097         // libhb's format something suitable. Along the way, we'll strip off the
3098         // border around libhb's image.
3099         
3100         // The image data returned by hb_get_preview is 4 bytes per pixel, BGRA format.
3101         // Alpha is ignored.
3102
3103         GdkPixbuf *preview = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, dstWidth, dstHeight);
3104         guint8 *pixels = gdk_pixbuf_get_pixels (preview);
3105         
3106         guint32 *src = (guint32*)buffer;
3107         guint8 *dst = pixels;
3108         src += borderTop * srcWidth;    // skip top rows in src to get to first row of dst
3109         src += borderLeft;              // skip left pixels in src to get to first pixel of dst
3110         gint ii, jj;
3111         gint channels = gdk_pixbuf_get_n_channels (preview);
3112         gint stride = gdk_pixbuf_get_rowstride (preview);
3113         guint8 *tmp;
3114         for (ii = 0; ii < dstHeight; ii++)
3115         {
3116                 tmp = dst;
3117                 for (jj = 0; jj < dstWidth; jj++)
3118                 {
3119                         tmp[0] = src[0] >> 16;
3120                         tmp[1] = src[0] >> 8;
3121                         tmp[2] = src[0] >> 0;
3122                         tmp += channels;
3123                         src++;
3124                 }
3125                 dst += stride;
3126                 src += (srcWidth - dstWidth);   // skip to next row in src
3127         }
3128         // Got it, but hb_get_preview doesn't compensate for anamorphic, so lets
3129         // scale
3130         gint width, height, par_width, par_height;
3131         gboolean anamorphic = ghb_settings_get_bool (settings, "anamorphic");
3132         if (anamorphic)
3133         {
3134                 hb_set_anamorphic_size( title->job, &width, &height, &par_width, &par_height );
3135                 if (par_width > par_height)
3136                         dstWidth = dstWidth * par_width / par_height;
3137                 else
3138                         dstHeight = dstHeight * par_height / par_width;
3139         }
3140         
3141         g_debug("scaled %d x %d\n", dstWidth, dstHeight);
3142         GdkPixbuf *scaled_preview;
3143         scaled_preview = gdk_pixbuf_scale_simple(preview, dstWidth, dstHeight, GDK_INTERP_HYPER);
3144         g_object_unref (preview);
3145         return scaled_preview;
3146 }
3147
3148 static void
3149 sanitize_volname(gchar *name)
3150 {
3151         gchar *a, *b;
3152
3153         a = b = name;
3154         while (*b)
3155         {
3156                 switch(*b)
3157                 {
3158                 case '<':
3159                         b++;
3160                         break;
3161                 case '>':
3162                         b++;
3163                         break;
3164                 default:
3165                         *a = *b;
3166                         a++; b++;
3167                         break;
3168                 }
3169         }
3170         *a = 0;
3171 }
3172
3173 gchar*
3174 ghb_dvd_volname(const gchar *device)
3175 {
3176         gchar *name;
3177         name = hb_dvd_name((gchar*)device);
3178         if (name != NULL)
3179         {
3180                 sanitize_volname(name);
3181                 return g_strdup(name);
3182         }
3183         return name;
3184 }