OSDN Git Service

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