OSDN Git Service

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